QR Code is kind of matrix barcode, it is recently very popular because of its fast read speed and big storage capacity, we can see it everywhere, Jeky even wanted to tattoo one on his body.

A QR code makes up by black square dots and white square grid, black dots arrange in white background, any kind of imaging device (in most situations, we use our smart phones) can read it, after processed by software, we can easily get information carried in the QR code.

Since half year ago, I wanted to make a QR code scanner using c++ and OpenCV, but I rarely had time, so before the new semester’s beginning, I must try to finish it, at least part of it.

### IDEA

First thing a QR code reader need to do is to find the position of QR code in image. It is convenient because QR code provide three finder patterns in the top-left, top-right, and bottom left corner, so our aim became simply finding these three finder patterns. When finder patterns found, the orientation of QR code is also known.

A QR code is something like above, we can see the 3 finder patterns, each of them can be decomposed into 3 parts: a 3 * 3 black square, a 5 * 5 white square frame, and a 7 * 7 square frame.

People use a lot of ways to finding these funky things, For instance, Viola-Jones framework, Boosting, Blob analysis, cluster analysis and so on, here I’ll try to use binary image contour analysis, the most simple way to do it.

Given this image, the back surface of a book with a QR code on it, we want to find the QR code. First let’s convert this image into gray scale, and change it to binary image. (Here I simply use Otsu-Method to get gray image binarized, about how to make the binary process self-adapted, that’s another story)

Using findContours() to find contours in this image, we can find plenty of contours.

And next step is eliminate all trash contours. Because the specific formation of finder pattern, we can find which of the contours are inside other contours, and the ratio of these inner pattern and outer pattern is in specific range.

Now we’ve found the three finder patterns, and we can do some judge and find the orientation of this QR code. In regular camera orientation, distance between top-right pattern and bottom-left pattern should be longer than their distance between top-left pattern, so by finding the longest distance among the three patterns, we can easily get the orientation of this QR code.

With the three patterns’ position, we can get an affine transform matrix by using OpenCV’s “getAffineTransform()” function, and using “warpAffine()” function get the final QR code image.

### TEST RESULTS

Next step is about read and decode QR code, I will go forward doing it when I have time these days.

🙂

Alvaro

Hi Eric,

I have found this article very interesting. I am trying to build an Android app with OpenCV native functions and I was wondering if you could share your code for the QR code localization and perspective correction with me.

Thanks in advance,

A.

kapil

Hii Eric

i need a favor from u. i m creating a android project on the same , but facing some difficulty . if u don’t mind can i have ur code as a reference

–saytokapil01@gmail.com

Amir

this article helped me to find a way for doing my project! i’m implementing the flag detection part right now but I think the part where you said “we can find which of the contours are inside other contours,” is really time consuming (OR am I wrong) consider we have 500 contours then the loop will execute 499*499+ checking all points in each contours !

for (int i=0; i<contours.size()-1; i++)

{

for (int j=1; j100&&contours[j].size()>100)

{

if (contours[i].size()>contours[j].size())

{

//check if (contours j) is inside

}

else if(contours[i].size()<contours[j].size())

{

//check if (contours i) is inside

}

}

}

}

would you pls give me some guidance ?

Eric

Hey Amir,

Yes it is time-consuming, and maybe we are able to use something like dynamic programming, say we already know that contour_a is inside contour_b, and contour_b is inside contour_c, in this case, we can know contour_a must be inside contour_c. Besides, the above trick maybe works better if we randomize the vector of contours before the 2-layers loop (still 2-layers loop, but maybe much faster).

Amir

thanks a lot for your help 😉

In my project I have to detect a rectangle in the image and extract some transformation parameters ; fortunately the camera will not move after that and I can run the main process which is in real time!

but I will work on the time as you guide me ,thanks again 😉

Qai Jong

Excellent article. Did you get to implement this? I am looking to implement the same for my project, if you could also share your implementation/code, it will be really helpful.

Eric

Hi, it is an uncompleted code, you can find it here https://github.com/xingdi-eric-yuan/qr-decoder

preeti

Hello,

I found this Article related to my project.Can anyone share a complete code for QR code localization.It will be a great help for me.My email id is preethychowdary@gmail.com

Thanks in Advance.

Chris

How are you doin the transformation with three points and getting the whole qr code? shouldnt u need all 4 points of the corners?

Anonyous

Hi, a question for a million:

have u tried to split ur code (github link given before) on .h and .cpp file? I got some problems making a class from ur code , something I cant get yet, like how goes custing from v<v<v>> to v when u use sort on vecpair[i].begin/end and why it doesnt work during class implementation…

Anonyous

got an answer for my question, dont know yet if it works, but it compiled:

so, just set compareContourAreas static and calling it like class:compareContourAreas.