devmandan's picture
Claude Opus 5.5
Add levels, confidence and picture checks
6f28f9e verified
|
Raw History Blame Contribute Delete
14.6 kB
---
title: QR Scan Difficulty Check
emoji: 📷
colorFrom: gray
colorTo: red
sdk: docker
app_port: 7860
pinned: false
disable_embedding: true
license: other
short_description: Where your QR code falls among thousands of measured codes
---
# How hard is your QR code to scan?
All 6,499 codes [QR Scan Difficulty](https://huggingface.co/spaces/devmandan/qr-scan-difficulty) measured at seven
sizes, on one scale from easy to hard, shaded by how many of eight scanners read each one at 1280 pixels. Add
pictures of your own codes and each one appears as a numbered line where it falls. Move the slider to see a
measured code from any spot, with what the eight scanners did on codes there. Each picture also gets a level (Easy,
Everyday, Tough or Advanced), how confident that level is, and checks on the picture that explain it.
## How a picture is placed
Each picture is read the way every measured code was: turned grey and shrunk, never enlarged, to seven sizes
from 1920 down to 224 pixels on its long side, and read at each size by the five of the eight scanners that run
on a Linux server, with the measurement's versions and settings:
| Scanner | What runs here |
|---|---|
| Android Settings' scanner | [ZXing](https://github.com/zxing/zxing/releases/tag/zxing-3.5.2) 3.5.2, called as Android's Settings app calls it (QR only, inverted retry) |
| WeChat's scanner | [WeChatQRCode](https://docs.opencv.org/4.12.0/d5/d04/classcv_1_1wechat__qrcode_1_1WeChatQRCode.html), OpenCV contrib 4.12.0.88, with its detector and super-resolution models (the app's own build may differ) |
| zxing-cpp | [zxing-cpp](https://github.com/zxing-cpp/zxing-cpp/releases/tag/v3.1.1) 3.1.1, library defaults, QR only |
| OpenCV, newer | [QRCodeDetectorAruco](https://docs.opencv.org/4.12.0/d3/db0/classcv_1_1QRCodeDetectorAruco.html), OpenCV 4.12, single-code `detectAndDecode` |
| OpenCV, original | [QRCodeDetector](https://docs.opencv.org/4.12.0/de/dc3/classcv_1_1QRCodeDetector.html), OpenCV 4.12, single-code `detectAndDecode` |
Transparent parts count as white, as on a printed page. A scanner reads a picture when it returns the content that
more of the five return than any other, even if only one returns any (the measurement scored each code against its
true content instead); a picture with several codes is placed by that one. A decode that runs past 20 seconds counts
as a miss, as in the measurement, and a picture's reading stops after 40 seconds, so that each request ends within a
minute; reads not done by then count as misses, and the page says so. Read again on this Space's Linux server, 416
of the measured codes gave the measured result in all but 7 of their 14,560 reads: on this processor WeChat's
scanner and OpenCV's newer detector come out differently on a few borderline pictures.
The other three scanners, Apple's, Google's and Huawei's (Scan Kit), can't run here: Apple's runs only on Apple
devices, and Google's and Huawei's, as measured, need Android. So a picture is placed from its 35 reads (five
scanners at seven sizes) on the scale all eight set, which stays as measured: the five scanners' reader curves from
the measurement's two-parameter item-response fit are held fixed, and the picture's difficulty is the most likely
one given its reads. On the measured codes, codes that at least two of the five read at 1280 pixels land within
about 4 points of where all eight put them, 9 times in 10, on a 0 to 100 scale where clean prints sit near 19 and
tough prints near 56. Where only one reads it at 1280 pixels, or none does but some do at another size, only about
half land that close. A dashed line means low confidence; a reading cut short by the time limit is always low. A
picture none of the five read at any size goes to the pile on the right, where its place is least sure. Of the
measured codes like that, most are distorted research images; the phones' own scanners still read about 1 in 6 of
them (280 of 1,754, at some size), and 33 of the 59 photos and prints among them (BoofCV's photos, Broken QR 104's
codes from the web, and the simulated everyday and tough prints).
The page shows how many of the five read a picture at 1280 pixels, its level and how confident that is, checks on
the picture with advice, and, for its place on the scale, how much of the curve there is codes all eight read at
1280 pixels. The curve is an illustrative mix of the sets, not a count of them: half everyday prints, a fifth each
clean and tough prints, a tenth the research sets. The page never claims what a phone would do with your picture.
## Levels, confidence and checks
Each picture also gets a level from its difficulty d, with the cut points in `web/data/levels.json`, which the
server and the page both read: Easy below 30 (the left pile included), Everyday from 30, Tough from 50 and Advanced
from 60 (the right pile included); a d on a cut goes to the level above. On the curve, the levels line up with the
simulated prints: most clean prints are Easy (184 of 200), most everyday prints Everyday (443 of 600) and most
tough prints Tough (433 of 600).
What a level means depends on the picture's size, because the measured codes come in two kinds: 1,553 pictures over
1280 pixels on the long side, mostly simulated prints with some real photos, and 4,946 smaller ones, mostly
512-pixel research images, which are read 'at 1280 pixels' as they are, never enlarged. So beside your picture the
page describes its level by the measured codes in pictures of the same size class that the five scanners here place
at that level (`meaning` in levels.json), except in the right pile, where it describes the level in general terms
only: the codes the five place at Advanced were read far more often by the phones' own scanners than the pile's
own. For pictures over 1280 pixels, at 1280 pixels: at Easy (309 codes) all three phones' own scanners read 98% and
Android Settings' 92%; at Everyday (687) all three 98%, Android Settings' 88%; at Tough (429) each phone's own 94
to 96%, all three together 88%, Android Settings' 44%; at Advanced (128) each phone's own 43 to 69%, at least one
of them 78%, Android Settings' 2%. For smaller pictures: at Easy (1,383) all three over 99%, Android Settings' over
99%; at Everyday (542) all three 97%, Android Settings' 42%; at Tough (302) each 80 to 92%, all three 65%, Android
Settings' 12%; at Advanced (2,719) each 13 to 31%, at least one 38%, Android Settings' under 1%. The levels list
under the curve describes all measured codes at each level, by all eight scanners' level, counted as they are (not
in the curve's illustrative mix) and named by what they mostly are.
A level's confidence (high, medium or low) measures one thing: how well the five scanners here stand in for all
eight. On the 6,499 measured codes, the level from the five scanners' place matched the level from all eight for
5,832 (90%). A picture takes the share that matched among measured codes with the same evidence: on a pile, the
codes in that pile; otherwise how many of the five read it at 1280 pixels (fewer than two, or more) and how far d
is from the nearest cut (under 2 points, 2 to 4, or more), and, with two or more reads, also the picture's size
class (over 1280 pixels on the long side, or not) and, within 4 points of a cut, the side of the cut d is on. It is
high where at least 90% matched, medium from 70%, and low below. The size class and the side matter because the
eight scanners' d is offset from the five's. For pictures over 1280 pixels with two or more reads, near cuts 30 and
50 it sits about 2 to 3 points higher, so just below those cuts such a picture is often a level harder for all
eight (55% and 20% matched), and just above them 99% matched. Near 60 it is pulled towards the cut from both sides
(1.9 points higher just below it, 1.6 lower just above it, where 5 of 21 matched), so a picture over 1280 pixels
within 4 points of 60 counts as below the cut on either side. For smaller pictures the offset is smaller, and just
above a cut a picture is more often a level easier for all eight (66% matched just above 50, 91% just below). A
reading cut short by the time limit is always low. The right pile is high only on the condition that the picture
holds a code: all 1,754 measured codes there do, and 1,742 of them were Advanced for all eight too; a picture with
no QR code at all lands there as well, so the page always says 'if it holds a code'. Confidence doesn't cover the
photo itself: another photo of the same code can land at another level.
The checks are image measurements made in the decoder worker with NumPy and OpenCV only, on the largest frame read
(at most 1920 pixels on the long side), at the corners of the code that the scanners agreeing on its content found:
camera pixels per square at 1280 pixels (before any tilt, which the angle check covers); size (version, squares
across, pixel width, share of the picture); margin; sharpness; contrast; lighting (shadows and washed-out patches);
and angle. The same picture always gives the same results. Each check is Fine, Borderline or a Problem (`ok`,
`watch` or `problem` in `/api/measure`) by [QR Scan
Difficulty](https://huggingface.co/spaces/devmandan/qr-scan-difficulty)'s factor tests (the `ladders` in its
`site.json`: one code all eight scanners read, changed one thing at a time, 80 synthetic codes a step, read at 1280
pixels), counting a scanner as reading a step when it reads at least 9 in 10 of its codes, as that Space does: Fine
where all eight read the step, Borderline where the phones' own scanners did but another didn't, and a Problem
where one of the phones' own didn't. Each limit sits halfway between the check's median values on the last step
with one status and the first step with the next, measured as the Space measures a visitor's picture; where two
tests set one limit (version and square size for pixels per square, focus and shake for sharpness), it sits in the
middle of the range both allow. For pixels per square the Problem limit rises with the version: the tests set it at
versions 3 and 13, and it rises at the same rate in between and on to version 21. The margin is Fine from the 4
squares the QR standard asks for, Borderline below that, and a Problem with next to none (under a quarter square),
though all eight still read the margin test's codes with half a square; for small or blurred codes the margin may
only be known to be under a bound, and the page says so. A code filling 30% or more of the picture's long side,
more than any simulated print, gets a framing note, not a status: a close view or a tight crop gives each square
more camera pixels than a photo from where people stand. A picture up to 1280 pixels is read at its own size, never
enlarged, so, unless it is Easy, it gets a note that a full-size original can land at an easier level. The checks
are diagnostics only: they never change d, the level or the confidence, and the five scanners' reads are unchanged.
The page lets you say what each picture shows: not sure (the default), the original graphic, a printed code or a
code on a screen. The choice stays in your browser, new pictures take the last one, and it changes only which
explanations and advice are shown.
`/api/measure` keeps every earlier field and adds `rating` (`level`, `confidence`, `agree` and `n` for the measured
codes behind it, `why` naming its main reason, and `big` for the size class) and `checks` (null when nothing could
be measured, and for a reading cut short, which the checks never measure).
## Privacy
A picture is written to a temporary file, read, and deleted as soon as the reading ends. Nothing is stored, and
this server keeps no access log. The decoded content is sent back to your browser only, so you can see which code
was read. Hugging Face, which hosts the Space, has its own [privacy policy](https://huggingface.co/privacy). What
you say a picture shows stays in your browser: it is never sent.
## Limits
Up to 25 MB and 50 megapixels a picture, and 40 at a time; the page sends them one by one, and each must arrive
within a minute. JPEG, PNG and WebP are read as sent. Other formats your browser can open (such as GIF, AVIF, or
HEIC in Safari) are converted by your browser first, as it shows them: transparent parts on white, at most 16
megapixels, as PNG, or as a high-quality JPEG when the PNG would be over 25 MB. SVG files are not read. The server
reads two pictures at once and keeps up to 16 more waiting; one that would wait longer than 10 seconds is turned
away with a request to try again in a minute. On Hugging Face's free hardware the Space sleeps when nobody has used
it for a while, and the first visit after that wakes it up.
## Credits
- Scanners: ZXing (Apache-2.0), zxing-cpp (Apache-2.0), OpenCV and opencv_contrib (Apache-2.0), WeChat's QR
models (© THL A29 Limited, a Tencent company; Apache-2.0) from WeChatCV's
[opencv_3rdparty](https://github.com/WeChatCV/opencv_3rdparty/tree/3487ef7cde71d93c6a01bb0b84aa0f22c6128f6b),
fetched at build time with their licence and checked against pinned SHA-256 sums.
- Server: Starlette and Uvicorn (BSD-3-Clause), NumPy (BSD-3-Clause); Java: OpenJDK 17 (GPL-2.0 with the
Classpath Exception). Libraries bundled in these packages keep their own licences.
- Codes on the curve: made for the measurement
([QR Scan Difficulty: synthetic codes](https://huggingface.co/datasets/devmandan/qr-scan-difficulty), CC BY 4.0), and
from research datasets, each under its own terms:
[BoofCV QR singles](https://huggingface.co/datasets/devmandan/boofcv-qr-singles) (Peter Abeles' BoofCV QR
Code Performance Benchmark photos, published openly without an explicit licence grant),
[QR-DN1.0](https://huggingface.co/datasets/devmandan/qr-dn1.0) (CC BY 4.0, Mendeley Data,
doi:10.17632/t2bdr663ms.2),
[syn10k](https://huggingface.co/datasets/devmandan/syn10k-huawei-barcodes) (Bodnár, Grósz and Tóth; CC BY 4.0)
and [Broken QR 104](https://huggingface.co/datasets/devmandan/broken-qr-codes-104) (annotations CC BY 4.0).
Pictures are cropped and resized from their datasets; to have one removed, open a discussion on its dataset page.
## Disclosures
Independent work, not affiliated with or endorsed by Apple, Google, Huawei, Tencent or DENSO WAVE, nor by the
open-source projects and dataset authors credited above. QR Code is a registered trademark of DENSO WAVE
INCORPORATED. Apple and iPhone are trademarks of Apple Inc.; Android and Google Play of Google LLC;
Huawei of Huawei Technologies Co., Ltd.; WeChat of Tencent. Other names are trademarks of their owners.