This project was inspired by Dan Hollick's article, which gives a nice overview of how QR-codes work. It is an educational demo used to explain how QR-codes work, it is not meant to be used in real-life applications.
If you need an efficient and complete QR-code reader written in Go, you may use the powerful makiuchi-d/gozxing library.
Or if you really want to rely on OpenCV, then use QRCodeDetector.DetectAndDecode method from gocv.io bindings.
The presentation slides can be found in the slides
folder.
To be able to compile and run this tool, OpenCV 4 library is required.
Install it using official instructions or using Homebrew.
Then, compile the application with go build
or run with go run .
The first build/run may be slow, because OpenCV files need to be compiled beforehand.
The application can be stopped by pressing Esc
key at any time.
A different capture device may be chosen with parameter --device-id
(default to 0
).
The application captures frames from the webcam, then tries to detect QR-codes in each frame.
Image capture and processing is performed thanks to OpenCV 4 Go bindings from gocv.io.
-
For each frame, try to detect a QR-code with QRCodeDetector.Detect.
This function returns a set of 4 points delimiting a QR-code candidate in the image.
-
Eliminate false positives by keeping only coordinates forming a square (with some tolerance).
-
Project and display the detected QR-code in the top-left corner, using WarpPerspective function
Enhance QR-code image contrast (with AddWeighted) and "open" image to remove noise (with GetStructuringElement)
-
Compute QR-code dots width in pixels, then scan the image pixel to construct the dot matrix, and display it on the console.
When all steps are successful, the QR-code is highlighted in the image, and the video freezes for a few seconds to show the result.
Once the QR-code dots have been detected, the code contents bits are extracted from it.
-
Get metadata from the QR-code: version information (the "size" of the code), the mask ID to apply to the dots and the error correction level used on the contents.
For the last two (the code "format"), error correction is used on the selected dots to make sure the value found is correct. This error correction implements the Reed-Solomon algorithm, as explained on this page.
-
Read the contents bits in the correct order, starting from the bottom-right, 2 columns at a time from right to left, alternating upwards and downwards and avoiding reserved areas.
See explanations and picture for an illustration.
Note that the current implementation supports only 1 alignement pattern, and thus works only with QR-codes version 6 and below.
The returned bits contain metadata (content type and length), and the contents with error correction data.
Finally, decode the message from the bits contents.
-
First of all, use the Reed-Solomon algorithm to perform error correction on the full contents bits, to correct any errors that may have been introduced during the scanning process. Library http://github.com/colin-davis/reedSolomon is used for this purpose.
Note that interleaved blocks are not supported yes, hence the higher version-error correction level pairs will not be decoded.
-
Then, read data from the contents bits: first, metadata (character mode and message length), then the message itself. See this page for more details on how data is encoded.
Note that Kanji mode is not supported at all, and ECI (unicode) may produce strange results.
If the QR-code is successfully decoded, the message is revealed in the console.
The following explanations have been used to implement this project. Many thanks to their authors.
- Dan Hollick's blog: https://typefully.com/DanHollick/qr-codes-T7tLlNi
- Thonky's guide: https://www.thonky.com/qr-code-tutorial
- Linux Magazine n°194: https://connect.ed-diamond.com/GNU-Linux-Magazine/glmf-194/decoder-un-code-qr (French)
- Linux Magazine n°198: https://connect.ed-diamond.com/GNU-Linux-Magazine/glmf-198/reparer-un-code-qr (French)
- Wikiversity: https://en.m.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders