A Simple QR Code Scanner [part 1]

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.

qr1

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.

bigbook

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)

bin

 

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

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.

finderp

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.

qrcode

 TEST RESULTS

book

jesus

tshirt

woman

youtube

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

🙂

This entry was posted in Algorithm, OpenCV and tagged , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

9 Comments

  1. Alvaro
    Posted July 10, 2014 at 4:42 am | Permalink

    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
      Posted April 20, 2016 at 6:06 am | Permalink

      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

  2. Amir
    Posted August 27, 2014 at 8:28 am | Permalink

    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
      Posted August 27, 2014 at 11:45 pm | Permalink

      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
        Posted August 28, 2014 at 3:12 am | Permalink

        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 😉

  3. Qai Jong
    Posted December 14, 2014 at 11:30 am | Permalink

    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.

  4. preeti
    Posted April 23, 2016 at 11:55 am | Permalink

    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.

  5. Chris
    Posted January 14, 2017 at 9:41 pm | Permalink

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

Post a Comment

Your email is never published nor shared. Required fields are marked *

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*
*