qr-scanner
qr-scanner copied to clipboard
small qr codes
I was playing around with small (1-2 cm x side) qr codes, and it is very difficult to get a reading. I also added a zoom bar to zoom with camera using "mediaStreamTrack.applyConstraints()", but reading did not improve, even if the QR code was finely focused and covered half of the stream window. Do you have any suggestions on how to improve performance in these cases? I can do some tests.
@fpirotti It's been a while since your comment, how did you go about? I need to scan codes that are 8mm sides
You could try to experiment with the canvas size setting.
I'm having a similar problem, curious to know whether we're supposed to make the canvas bigger or smaller. I'm using QR codes as part of an inventory system, and in some cases due to the size of the container the label is being applied to (extreme example being DIP IC tubes… 10mm high is as big as I can make them).
I've found 10mm×10mm QR codes very hit-and-miss… even with a "better" camera. An example:
Now… the same camera scans that barcode successfully using this tool.
Have you guys experimented with providing a custom calculateScanRegion
method that disables the downsampling by ommiting downScaledWidth
and downScaledHeight
, as mentioned in https://github.com/nimiq/qr-scanner/issues/9#issuecomment-656328819 (back then the option was called canvasSize
)?
I can confirm that @danimoh suggestion works with small qr codes. I also had the problem that the default scanner settings can't scan small qr codes (10mm) with high data density. Here is my working solution:
new QrScanner(
this.video?.nativeElement,
result => {
this._qrData.next(result.data);
},
{
highlightScanRegion: true,
highlightCodeOutline: true,
calculateScanRegion:(v)=>{
const smallestDimension = Math.min(v.videoWidth, v.videoHeight);
// Make scan region smaller to match better small qr codes
const scanRegionSize = Math.round(1 / 4 * smallestDimension);
let region:QrScanner.ScanRegion = {
x: Math.round((v.videoWidth - scanRegionSize) / 2),
y: Math.round((v.videoHeight - scanRegionSize) / 2),
width: scanRegionSize,
height: scanRegionSize,
};
return region;
}
}
);
Adding resolution constraints on the getUserMediaCall() also helps: https://stackoverflow.com/questions/27420581/get-maximum-video-resolution-with-getusermedia
I added the advanced: { width: 2560... }
lines and it works better for small QR.
There's no API to specify getUserMediaCall() constraints though. I had to pull the source into my app and add those lines in constraintsWithoutCamera
: https://github.com/nimiq/qr-scanner/blob/master/src/qr-scanner.ts#L861
I can confirm that @danimoh suggestion works with small qr codes. I also had the problem that the default scanner settings can't scan small qr codes (10mm) with high data density. Here is my working solution:
new QrScanner( this.video?.nativeElement, result => { this._qrData.next(result.data); }, { highlightScanRegion: true, highlightCodeOutline: true, calculateScanRegion:(v)=>{ const smallestDimension = Math.min(v.videoWidth, v.videoHeight); // Make scan region smaller to match better small qr codes const scanRegionSize = Math.round(1 / 4 * smallestDimension); let region:QrScanner.ScanRegion = { x: Math.round((v.videoWidth - scanRegionSize) / 2), y: Math.round((v.videoHeight - scanRegionSize) / 2), width: scanRegionSize, height: scanRegionSize, }; return region; } } );
Was there any other setup you had to do to get this working? I've implemented this solution and am still not able to scan a qr code that is 1cm x 1cm in size. How dense is the data in your codes?
I solve this by using a barcode-detector polyfill and also increase the video constraints. Here is my working code (tested on iOS Safari):
import "barcode-detector/side-effects";
import { BarcodeDetector } from "barcode-detector/pure";
try {
// Use video without audio
const constraints: MediaStreamConstraints = {
video: {
facingMode: { exact: "environment" },
width: { min: 1024, ideal: 4096, max: 4096 },
height: { min: 540, ideal: 2160, max: 2160 },
frameRate: { ideal: 60, max: 60 },
},
audio: false,
};
// Start video stream
stream = await navigator.mediaDevices.getUserMedia(constraints);
videoElmRef.current.srcObject = stream;
const barcodeDetector = new BarcodeDetector({
formats: ["qr_code"],
});
const detectCode = async () => {
if (videoElmRef.current) {
// Start detecting codes on to the video element
const codes = await barcodeDetector.detect(videoElmRef.current);
// If no codes exit function
if (codes.length === 0) return;
setStartScanned(false);
onDone(codes[0].rawValue);
}
};
intervalId = setInterval(() => detectCode(), 100);
} catch (e: any) {
setErrorMessage(e);
}
`