qr-scanner icon indicating copy to clipboard operation
qr-scanner copied to clipboard

small qr codes

Open fpirotti opened this issue 6 years ago • 8 comments

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 avatar Aug 05 '18 12:08 fpirotti

@fpirotti It's been a while since your comment, how did you go about? I need to scan codes that are 8mm sides

kimdah3 avatar Apr 03 '19 14:04 kimdah3

You could try to experiment with the canvas size setting.

danimoh avatar Jul 09 '20 20:07 danimoh

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: IMG_20210710_132504_539

Now… the same camera scans that barcode successfully using this tool.

Screenshot_2021-07-10-13-24-20

sjlongland avatar Jul 10 '21 03:07 sjlongland

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)?

danimoh avatar Feb 04 '22 14:02 danimoh

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;
        }
      }
    );

andreashauschild avatar Sep 20 '22 08:09 andreashauschild

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

SystemR avatar Oct 18 '22 03:10 SystemR

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?

davidg1822 avatar May 10 '24 21:05 davidg1822

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);
        }
`

ngothanhtai avatar Jun 18 '24 06:06 ngothanhtai