• OpenCV第二个assignment:检测QR code的3个 finder centers


    这是我第二个加第三个OpenCV assignment的代码,贴出来和大家共享,我用的是visual studio 2008 pro+OpenCV,如果大家有更好的建议可以跟我讨论~

     代码实现功能:

    (1). detect qr finder locations and mark them as red crosshairs
    (2). determine an affine mapping from the detected mark locations to predefined output locations and create a normalized version of each image.
    (3). manually mark the finder locations as green crosshairs

      1 #include "stdafx.h"
      2 #include <opencv2/opencv.hpp>
      3 #include <stdio.h>
      4 #include <vector>
      5 #include <iostream>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <math.h>
      9 
     10 // we can adjust these parameters for different qr code images
     11 #define tol_factor 0.5
     12 #define tol_distance 8
     13 
     14 using namespace std;
     15 using namespace cv;
     16 
     17 
     18 Mat gray_img,bw_img;
     19 Mat src;
     20 int stateCount[5] = {0};// store the number of pixels in each state of the state machine
     21 int totalFinderSize;// store the size of the Finder
     22 vector<Point> points_row;// store the possible locations of finders
     23 Point qr_point1; // final finder center locations
     24 Point qr_point2;
     25 Point qr_point3;
     26 int thresholdValue = 0;//the threshold for each image
     27 //for on_mouse() function 
     28 char chek_cut_state = 0;
     29 Point origin;
     30 
     31 void threshold_selection(int,void*);// by sliding the trackbar to select a good threshold
     32 void qr_find_row();// search finder locations row by row
     33 void qr_find_col();// search finder locations column by column
     34 bool qr_checkRatio();// judge whether a similar pattern is a possible finder or not
     35 void group_points(vector<Point>& points);// find the three largest vote locations in the accumulator array
     36 void draw_crosshair(Point qr_point,Mat src,CvScalar color);// draw a red crosshair on some point of the image
     37 void affine_trans(); // through affine transformation to create a normalized version of each image
     38 void on_mouse( int event, int x, int y, int flags, void* param); 
     39 
     40 //-----------------------------------------Main Function------------------------------------------------------------------------------
     41 int main (int argc, char** argv)
     42 {
     43 
     44     // read a color qr code image which is used to display the red crosshairs(detected finder locations) and green crosshairs(manually marked finder locations)
     45     const char* imagename = "1.jpg";
     46     src = imread(imagename,1);
     47     namedWindow("original image", CV_WINDOW_AUTOSIZE);
     48     imshow("original image",src);
     49 
     50     // convert the color image into gray image
     51     cvtColor(src,gray_img,CV_BGR2GRAY);
     52 
     53     // slide the threshold value trackbar to observe the binary image until the finder locations in the binary image are clear, then we get a good threshold value
     54     namedWindow("binary image",CV_WINDOW_AUTOSIZE);
     55     createTrackbar("threshold value","binary image",&thresholdValue,255, threshold_selection);
     56     threshold_selection(0,0);
     57     bw_img = gray_img > thresholdValue; //bw_img is our final binary image
     58 
     59     cout<<"press c to continue after choosing a threshold"<<endl;
     60     char c;
     61     while(1)
     62     {
     63         c = cvWaitKey(0);
     64         if(c =='c') break;
     65     }
     66         
     67     // detect qr code finders and mark finder centers as red crosshairs
     68     qr_find_row();
     69     //qr_find_col();
     70     group_points(points_row);
     71     imshow("original image",src); // display the color qr code image with red crosshairs
     72 
     73     //determine an affine mapping from the detected mark locations to predefined locations and use this mapping to create a normalized image
     74     affine_trans();
     75 
     76     //manually mark the finder locations as green crosshairs
     77     cout<<"manually marked finder locations"<<endl;
     78     cvSetMouseCallback("original image", on_mouse,0);
     79 
     80 
     81     // wait for any key to quit
     82     waitKey(0);
     83 
     84     // release memory for images and destroy windows
     85     src.release();
     86     gray_img.release();
     87     bw_img.release();
     88     cvDestroyWindow("original image");
     89     cvDestroyWindow("binary image");
     90  
     91     return 0;
     92 
     93 }
     94 //-----------------------------------------------------------------------------------------------------------------------------------
     95 
     96 // use trackbar to get the threshold value
     97 void threshold_selection(int,void*)
     98 {
     99     threshold(gray_img, bw_img, thresholdValue, 255 ,0);
    100     imshow("binary image", bw_img);
    101 }
    102 
    103 
    104 
    105 /* search possible qr finder locations row by row
    106 This function goes through every row and keeps a track of the number of white or black
    107 pixels it encounters. It also keeps a track of the order in which they're found. whenever
    108 it founds something like b:w:b:w:b = 1:1:3:1:1, it will put the location of this possible
    109 finder into vector<Point> points_row
    110 */
    111 
    112 void qr_find_row()
    113 {
    114     int skipRows = 1;
    115     int currentState=0;
    116     int x,y;
    117     for (int row = skipRows-1; row< bw_img.rows; row += skipRows)
    118     {
    119         stateCount[0] = 0; // inside black pixels
    120         stateCount[1] = 0; // inside white pixels
    121         stateCount[2] = 0; // inside black pixels
    122         stateCount[3] = 0; // inside white pixels
    123         stateCount[4] = 0; // inside black pixels
    124         currentState = 0; // record the current state, b,w,b,w,b
    125         
    126         uchar* ptr_row = bw_img.ptr<uchar>(row); // get a pointer to the current row
    127         for(int col = 0; col< bw_img.cols; col++)
    128         {
    129             if(ptr_row[col]<128)
    130             {
    131                 // we are at a black pixel
    132 
    133                 if((currentState & 0x1) == 1)
    134                 {
    135                     // W->B transition
    136                     currentState++;
    137                 }
    138 
    139                 // works for W->B and B->B
    140                 stateCount[currentState]++;
    141             }
    142             else
    143             {
    144                 // we are at a white pixel
    145 
    146                 if((currentState & 0x1) == 1)
    147                 {
    148                     // the current state is state 1 or state 3 (white pixel state)
    149                     // W->W
    150                     stateCount[currentState]++;
    151                 }
    152                 else
    153                 {   
    154                     // the current state is state 0, state 2 or state 4 (black pixel state)
    155 
    156                     if(currentState == 4)
    157                     {
    158                         // we found the "white" area after one finder pattern
    159                         // use ratio requirement to check whether it is a possible finder or not
    160                         if(qr_checkRatio())
    161                         {
    162                             // ratio is correct, push this possible location into vector
    163                             y = row;
    164                             x = col-totalFinderSize/2;
    165                             points_row.push_back(Point(x,y));
    166                             currentState = 0;
    167                             stateCount[0] = 0;
    168                             stateCount[1] = 0;
    169                             stateCount[2] = 0;
    170                             stateCount[3] = 0;
    171                             stateCount[4] = 0;
    172                             // for debug
    173                             //cout<<Point(x,y)<<endl;
    174                             //draw_crosshair(Point(x,y),src);
    175                         }
    176                         else
    177                         {
    178                             // ratio is not correct, do the switch
    179                             currentState = 3;
    180                             stateCount[0] = stateCount[2];
    181                             stateCount[1] = stateCount[3];
    182                             stateCount[2] = stateCount[4];
    183                             stateCount[3] = 1;
    184                             stateCount[4] = 0;
    185                         }
    186 
    187                     }
    188                     else
    189                     {
    190                         // the current state is state 0 or state 2
    191                         // B->W transition
    192                         currentState++;
    193                         stateCount[currentState]++;
    194                     }
    195                 }
    196             }
    197         }
    198     }
    199 }
    200 
    201 
    202 /* search possible qr finder locations column by column
    203 This function is similar to qr_find_row(). And the possible finder locations are
    204 still pushed into vector points_row
    205 */
    206 void qr_find_col()
    207 {
    208     int skipCols = 1;
    209     int currentState=0;
    210     int x,y;
    211     for (int col = skipCols-1; col< bw_img.cols; col += skipCols)
    212     {
    213         stateCount[0] = 0;
    214         stateCount[1] = 0; 
    215         stateCount[2] = 0; 
    216         stateCount[3] = 0; 
    217         stateCount[4] = 0; 
    218         currentState = 0; 
    219         
    220         uchar* ptr_col = bw_img.ptr<uchar>(col);
    221         for(int row = 0; row< bw_img.rows; row++)
    222         {
    223             if(ptr_col[row]<128)
    224             {
    225                 if((currentState & 0x1) == 1)
    226                 {
    227                     currentState++;
    228                 }
    229                 stateCount[currentState]++;
    230             }
    231             else
    232             {
    233                 if((currentState & 0x1) == 1)
    234                 {
    235                     stateCount[currentState]++;
    236                 }
    237                 else
    238                 {
    239                     if(currentState == 4)
    240                     {
    241                         if(qr_checkRatio())
    242                         {
    243                             y = row-totalFinderSize/2;;
    244                             x = col;
    245                             points_row.push_back(Point(x,y));
    246                             currentState = 0;
    247                             stateCount[0] = 0;
    248                             stateCount[1] = 0;
    249                             stateCount[2] = 0;
    250                             stateCount[3] = 0;
    251                             stateCount[4] = 0;
    252                            //cout<<Point(x,y)<<endl;
    253                            //draw_crosshair(Point(x,y),src);
    254                         }
    255                         else
    256                         {
    257                             currentState = 3;
    258                             stateCount[0] = stateCount[2];
    259                             stateCount[1] = stateCount[3];
    260                             stateCount[2] = stateCount[4];
    261                             stateCount[3] = 1;
    262                             stateCount[4] = 0;
    263                         }
    264                         
    265                     }
    266                     else
    267                     {
    268                         currentState++;
    269                         stateCount[currentState]++;
    270                     }
    271                 }
    272             }
    273         }
    274     }
    275 }
    276 
    277 
    278 // check ratio requirement b:w:b:w:b = 1:1:3:1:1
    279 bool qr_checkRatio()
    280 {
    281     totalFinderSize = 0;    
    282     for(int i =0;i<5; i++)
    283     {
    284         int count = stateCount[i];
    285         totalFinderSize += count;
    286         if(count == 0)
    287             return false;
    288     }
    289     if(totalFinderSize<7)
    290         return false;
    291 
    292     int moduleSize = ceil(totalFinderSize / 7.0); // scale factor of the finder
    293     
    294     // tolerate some "slop" of the ratio
    295     double maxVariance = moduleSize*tol_factor;
    296     bool retVal = ((abs(moduleSize - (stateCount[0]))< maxVariance) &&
    297     (abs(moduleSize - (stateCount[1]))< maxVariance) &&
    298     (abs(3*moduleSize - (stateCount[2]))< 3*maxVariance) &&
    299     (abs(moduleSize - (stateCount[3]))< maxVariance) &&
    300     (abs(moduleSize - (stateCount[4]))< maxVariance));
    301 
    302     return retVal;
    303 }
    304 
    305 /* group possible finder locations, that is, each location vote in an array, so that 
    306 we can find three largest votes, calculate the mean location of these three groups and
    307 finally draw them on the image
    308 */
    309 void group_points(vector<Point>& points)
    310 {
    311     
    312    CvScalar red = CV_RGB(255,0,0);
    313     /* if the size of vector, number of possible finder locations is greater than 3,
    314     we need to group them. if not, then just draw them on the image
    315     */
    316     if (points.size()>= 3)
    317     {
    318         double distance;
    319         vector<vector<Point>> group(points.size());// every vector stores the finder locations which belong to one group
    320         vector<int> score(points.size());// store the number of votes
    321         vector<int> score_index(points.size());// store the index of score when we sort the score
    322         int temp1;
    323         int temp2;
    324 
    325         // set values for score_index
    326         for(size_t k=0; k < points.size();++k)
    327         {
    328             score_index[k] = k;
    329         }
    330 
    331         /* group the points by distance
    332         check whether point i is near enough to point j (j<i), if so, then vote for j.
    333         No matter whether i is near to j or not, it will vote for itself
    334         */
    335         for(size_t i = 0; i < points.size(); ++i)
    336         {
    337             for (size_t j=0; j < i; ++j)
    338             {
    339                 distance = sqrt(double((points[i].x-points[j].x)*(points[i].x-points[j].x)+(points[i].y-points[j].y)*(points[i].y-points[j].y)));
    340                 if (distance < tol_distance)
    341                 {
    342                     score[j] += 1;
    343                     group[j].push_back(points[i]);
    344                     break;
    345                  }
    346              }
    347              score[i] += 1;
    348              group[i].push_back(points[i]);
    349          }
    350 
    351 
    352         // sort the score and write new index into score_index
    353          for(size_t m = 0; m < points.size()-1; ++m)
    354          {
    355             for(size_t n = m; n < points.size(); ++n)
    356             {
    357                if (score[m]<=score[n])
    358                {
    359                 temp1 = score_index[m];
    360                 score_index[m] = score_index[n];
    361                 score_index[n] = temp1;
    362                 temp2 = score[m];
    363                 score[m] = score[n];
    364                 score[n] = temp2;
    365                 }
    366             }
    367          }
    368 
    369          // calculate the mean location of three groups with largest votes
    370          vector<Point>::iterator it;
    371          for (it = group[score_index[0]].begin(); it != group[score_index[0]].end(); ++it)
    372          {
    373              qr_point1 += (*it);
    374          }
    375          qr_point1.x = qr_point1.x/score[0];
    376          qr_point1.y = qr_point1.y/score[0];
    377 
    378          for (it = group[score_index[1]].begin(); it != group[score_index[1]].end(); ++it)
    379          {
    380              qr_point2 += (*it);
    381          }
    382          qr_point2.x = qr_point2.x/score[1];
    383          qr_point2.y = qr_point2.y/score[1];
    384 
    385          for (it = group[score_index[2]].begin(); it != group[score_index[2]].end(); ++it)
    386          {
    387             qr_point3 += (*it);
    388          }
    389          qr_point3.x = qr_point3.x/score[2];
    390          qr_point3.y = qr_point3.y/score[2];
    391 
    392          // output the final finder center location and its corresponding score
    393          //cout<<score[0]<<endl;
    394          //cout<<score[1]<<endl;
    395          //cout<<score[2]<<endl;
    396          //cout<<qr_point1<<endl;
    397          //cout<<qr_point2<<endl;
    398          //cout<<qr_point3<<endl;
    399          draw_crosshair(qr_point1,src,red);
    400          draw_crosshair(qr_point2,src,red);
    401          draw_crosshair(qr_point3,src,red);
    402     }
    403     else
    404     {
    405         for(int v = 0; v < points.size(); ++v)
    406         {
    407             draw_crosshair(points[v],src,red);
    408         }
    409     }
    410 
    411 }
    412 
    413 
    414 //draw a red crosshair on some point of the image
    415 void draw_crosshair(Point qr_point,Mat src,CvScalar color)
    416 {
    417     Point up1,up2;
    418     up1.x = qr_point.x;
    419     up1.y = qr_point.y -2;
    420     up2.x = qr_point.x;
    421     up2.y = qr_point.y +2;
    422     Point down1,down2;
    423     down1.x = qr_point.x -2;
    424     down1.y = qr_point.y;
    425     down2.x = qr_point.x + 2;
    426     down2.y = qr_point.y;
    427     // draw two lines that intersects on qr_point
    428     line(src,up1,up2,color,1,8);
    429     line(src,down1,down2,color,1,8);
    430 }
    431 
    432 
    433 void affine_trans()
    434 {
    435   Point2f srcPoints[3];
    436   Point2f dstPoints[3];
    437 
    438   Mat mapping(2,3,CV_32FC1);
    439   Mat src_img,wrap_dst_img;
    440   src_img = imread("1.jpg",1);//for final affine transform result because src has red crosshairs now
    441   wrap_dst_img = Mat::zeros(700,700,CV_8UC3); // create an output image of size 700*700 and 24-bit color
    442 
    443   //set detected mark locations 
    444   srcPoints[0] = qr_point1;
    445   srcPoints[1] = qr_point2;;
    446   srcPoints[2] = qr_point3;
    447   cout<<"original finder locations"<<endl;
    448   cout<<srcPoints[0]<<'\n'<<srcPoints[1]<<'\n'<<srcPoints[2]<<endl;
    449 
    450   //decide which one is finder mark location 1
    451   double diffx0,diffy0,diffx1,diffy1,diffx2,diffy2;
    452   diffx0 = srcPoints[0].x-srcPoints[1].x;
    453   diffy0 = srcPoints[0].y-srcPoints[1].y;
    454   diffx1 = srcPoints[1].x-srcPoints[2].x;
    455   diffy1 = srcPoints[1].y-srcPoints[2].y;
    456   diffx2 = srcPoints[2].x-srcPoints[0].x;
    457   diffy2 = srcPoints[2].y-srcPoints[0].y;
    458 
    459   //use cos(theta)=<x,y>/(|x||y|) to calculate angle
    460   double norm[3];
    461   norm[0] = sqrt(diffx0*diffx0+diffy0*diffy0);
    462   norm[1] = sqrt(diffx1*diffx1+diffy1*diffy1);
    463   norm[2] = sqrt(diffx2*diffx2+diffy2*diffy2);
    464 
    465   double angle[3];
    466   angle[0] = acos((-diffx0*diffx2-diffy0*diffy2)/(norm[0]*norm[2]));
    467   angle[1] = acos((-diffx0*diffx1-diffy0*diffy1)/(norm[0]*norm[1]));
    468   angle[2] = acos((-diffx2*diffx1-diffy2*diffy1)/(norm[2]*norm[1]));
    469   cout<<"angles between any two of the three edges"<<endl;
    470   cout<<angle[0]<<'\n'<<angle[1]<<'\n'<<angle[2]<<endl;
    471   
    472 
    473   Point2f temp;
    474   if((angle[1]>angle[0]) && (angle[1]>angle[2]))
    475   {
    476       temp = srcPoints[0];
    477       srcPoints[0] = srcPoints[1];
    478       srcPoints[1] = temp;
    479   }
    480   else if ((angle[2]>angle[1]) && (angle[2]>angle[0]))
    481   {
    482       temp = srcPoints[0];
    483       srcPoints[0] = srcPoints[2];
    484       srcPoints[2] = temp;
    485   }
    486   
    487   //decide which one is finder mark location 2 and finder mark location 3
    488   //note in the example of assignment 3, direction from vector 12 to vector 13 is clockwise
    489   diffx0 = srcPoints[1].x-srcPoints[0].x;
    490   diffy0 = srcPoints[1].y-srcPoints[0].y;
    491   diffx2 = srcPoints[2].x-srcPoints[0].x;
    492   diffy2 = srcPoints[2].y-srcPoints[0].y;
    493 
    494   double det = diffx0*diffy2-diffy0*diffx2;
    495   if(det<0)
    496   {
    497       temp = srcPoints[1];
    498       srcPoints[1] = srcPoints[2];
    499       srcPoints[2] = temp;
    500   }
    501 
    502   cout<<"final ordered finder locations"<<endl;
    503   cout<<srcPoints[0]<<'\n'<<srcPoints[1]<<'\n'<<srcPoints[2]<<endl;
    504 
    505   //set 3 predefined output locations
    506   dstPoints[0] = Point2f(400,50);
    507   dstPoints[1] = Point2f(600,50);
    508   dstPoints[2] = Point2f(400,250);
    509   
    510   //get the Affine Transform
    511   mapping = getAffineTransform(srcPoints, dstPoints);
    512   cout<<"mapping = "<<mapping<<endl;
    513  
    514   //check whether the mapping is correct or not
    515   cout<<"test the mapping is correct or not"<<endl;
    516   Point2f test;
    517   for (int i =0; i < 3; i++)
    518   {
    519     double* ptr_row = mapping.ptr<double>(0);
    520     //cout<<ptr_row[0]<<endl;
    521     test.x = (ptr_row[0]*srcPoints[i].x + ptr_row[1]*srcPoints[i].y + ptr_row[2]*1);
    522     ptr_row = mapping.ptr<double>(1);
    523     test.y = (ptr_row[0]*srcPoints[i].x + ptr_row[1]*srcPoints[i].y + ptr_row[2]*1);
    524     cout<<test<<endl;
    525   }
    526 
    527   //apply the Affine Transform just found to the src_img
    528   warpAffine(src_img, wrap_dst_img, mapping, wrap_dst_img.size());
    529   imwrite("1.normalized.jpg",wrap_dst_img);
    530 
    531   //display the normalized version of each image
    532   namedWindow("transform image", CV_WINDOW_AUTOSIZE);
    533   imshow("transform image",wrap_dst_img);
    534 
    535   wrap_dst_img.release();
    536   src_img.release();
    537 }
    538 
    539 
    540 //manually mark points on images
    541 void on_mouse( int event, int x, int y, int flags, void* param )
    542 
    543 { 
    544     CvScalar green = CV_RGB(0,255,0); //green
    545     if( (event==CV_EVENT_LBUTTONDOWN) )
    546     {
    547         origin = Point(x,y);;
    548         chek_cut_state=1; 
    549 
    550     }
    551 
    552     if( chek_cut_state && event==CV_EVENT_LBUTTONUP )
    553     {
    554         chek_cut_state=0;
    555         draw_crosshair(origin,src,green);
    556         imshow("original image",src);
    557         cout<<origin<<endl;
    558         imwrite("1_finder.jpg",src);
    559     }
    560 
    561 }
  • 相关阅读:
    GoCN每日新闻(2019-11-03)
    GoCN每日新闻(2019-11-02)
    GoCN每日新闻(2019-11-01)
    GoCN每日新闻(2019-10-31)
    GoCN每日新闻(2019-10-30)
    GoCN每日新闻(2019-10-29)
    xms西软预定列表-房类市场
    GoCN每日新闻(2019-10-28)
    GoCN每日新闻(2019-10-27)
    GoCN每日新闻(2019-10-26)
  • 原文地址:https://www.cnblogs.com/meinvlv/p/2710090.html
Copyright © 2020-2023  润新知