数字图象处理之二维码图像提取算法(十二)

来源:互联网 发布:搜房帮经纪人登录端口 编辑:程序博客网 时间:2024/05/19 08:38

新年代码大放送:

// test1.cpp : Defines the entry point for the console application.#include "stdafx.h"#include "highgui.h"#include "cv.h"#include "cvaux.h"#include "stdio.h"#pragma comment(lib, "ml.lib")  #pragma comment(lib, "cv.lib")  #pragma comment(lib, "cvaux.lib")  #pragma comment(lib, "cxcore.lib")//边缘检测void EdgeTrack(IplImage* src,int threshold1,int threshold2){IplImage *edge=NULL;edge=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);cvCanny(src,edge,threshold1,threshold2,3);   //threshold1,threshold2中较小的控制边缘连接,大的控制边缘的初始分割    cvNamedWindow("canny", CV_WINDOW_AUTOSIZE);    cvShowImage("canny",edge); cvSaveImage("13.jpg",edge);    cvWaitKey(0);cvDestroyWindow("canny");cvReleaseImage(&edge);}void move(){ IplImage* src; src=cvLoadImage("11.jpg",0); IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );//,创建图像头并分配数据;返回矩阵或图像的行数和列数 IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 ); CvMemStorage* storage = cvCreateMemStorage(0);//创建一内存块并返回指向块首的指针 CvSeq* lines = 0; int m;    IplImage* src1=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);//cvsize以像素为单位定义矩形框大小  //  cvCvtColor(src, src1, CV_BGR2GRAY);   cvCopy(src,src1);//将数组src(输入数组)复制给src1(输出数组) cvCanny( src1, dst, 50, 200, 3 );//采用canny算法寻找输入图像src1的边缘并在输出图形中标志这些边缘;dst表示输出的边缘图像;50,200是阈值  cvCvtColor( dst, color_dst, CV_GRAY2BGR );//进行色彩空间转化,将输入图像color_dst进行色彩空间转换,dst为输出图像  //cvNamedWindow("src",1); //cvShowImage("src",dst);  // cvNamedWindow("dst",1); // cvShowImage("dst",dst);  // cvSaveImage("dst.bmp",dst); lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 10, 30, 10 );//利用hough变换在二值图像中寻找直线,dst为输入图像 //printf("%d\n",lines->total); int dis=0; int max=0; int n=0; CvPoint* line;//定义二维整型坐标上的点 CvPoint pointOne; CvPoint pointTwo; int a[1003]={0}; //定义数组a,其中元素都为0  for( m = 0; m< lines->total; m++ ) {  line = (CvPoint*)cvGetSeqElem(lines,m);//返回索引指定的元素指针    dis=(line[1].y-line[0].y)*(line[1].y-line[0].y)+(line[1].x-line[0].x)*(line[1].x-line[0].x);//两点之间的距离;line[1].y为点line[1]的纵坐标,  a[4*m]=line[0].x;//以下找出两个点  a[4*m+1]=line[0].y;  a[4*m+2]=line[1].x;  a[4*m+3]=line[1].y;  if(dis>max)  {   max=dis;   n=m;  } cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 ); } pointOne.x=a[4*n]; pointOne.y=a[4*n+1]; pointTwo.x=a[4*n+2]; pointTwo.y=a[4*n+3]; cvLine( color_dst, pointOne, pointTwo, CV_RGB(0,255,0), 3, 8 );    //画出最长的直线   double Angle=0.0;  Angle =-atan2(fabs(pointTwo.y-pointOne.y),fabs(pointTwo.x-pointOne.x));   //得到最长直线与水平夹角,arctan()求解  if(pointTwo.x>pointOne.x && pointTwo.y>pointOne.y) {  Angle=-Angle; }  Angle=Angle*180/CV_PI; // cvNamedWindow( "Source", 1 ); //cvShowImage( "Source", src ); cvNamedWindow( "Hough", 1 );cvShowImage( "Hough", color_dst ); //cvSaveImage("dst.bmp",dst);cvWaitKey(0);//以下的内容为旋转,目前的正确率为80%      、、、、、、、、、、图像旋转、、、、、、、、、、、、、、、 IplImage* src3; IplImage* dst3; dst3 = 0; src3 = cvLoadImage( "14.jpg" );    int delta = 1;double angle=(Angle>=0.0)?Angle-90.0:Angle+90.0;//这里涉及到了角度的选择问题,                int opt = 0;// 1: 旋转加缩放                 // 0:  仅仅旋转              double factor;              dst3 = cvCloneImage (src3);  cvNamedWindow ("src3", 1);  cvShowImage ("src3", src3);              for (;;){float m[6];CvMat M = cvMat (2, 3, CV_32F, m);int w = src3->width;int h = src3->height;if (opt)// 旋转加缩放factor = (cos (angle * CV_PI / 180.) + 1.0) * 2;else//  仅仅旋转factor = 1;m[0] = (float) (factor * cos (-angle  * CV_PI / 180.));m[1] = (float) (factor * sin (-angle  * CV_PI / 180.));m[3] = -m[1];m[4] = m[0];// 将旋转中心移至图像中间m[2] = w * 0.5f;m[5] = h * 0.5f;//  dst(x,y) = A * src(x,y) + bcvZero (dst3);cvGetQuadrangleSubPix (src3, dst3, &M);cvNamedWindow ("dst3", 1);cvShowImage ("dst3", dst3);cvWaitKey(0);//if (cvWaitKey (1) == 27)//ESC//break;}}int main(int argc, char *argv[]){              const char * filename = "5.jpg";       // Matlab风格的cvLoadImage 函数的另一种调用       IplImage *img = cvLoadImage("5.jpg",1);       if(!img)//载入失败       {              fprintf(stderr,"Can not load image %s /n",filename);              return -1;       }       if(!img->imageData)//载入的图像数据是否正确       {              return -1;       }        cvNamedWindow("image",CV_WINDOW_AUTOSIZE );//创建窗口,窗口名字为image       cvShowImage("image",img);//在刚创建的image窗口中载入图像       //创建一个与img相同大小的图像img1       IplImage *img1 = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);       //色彩空间转换,将源彩色图像img转化成目标灰色图像imag1       cvCvtColor(img,img1,CV_BGR2GRAY); //关键       cvNamedWindow("GrayImage",CV_WINDOW_AUTOSIZE);//创建窗口,窗口名字GrayImage       cvShowImage("GrayImage",img1);//载入转化后的图像       cvSaveImage("5_2.jpg",img1);       cvWaitKey(0);//===========================================================================================================         IplImage *img2 = cvLoadImage("zaosheng.jpg",0);         cvNamedWindow("image2",CV_WINDOW_AUTOSIZE );//创建窗口,窗口名字为image         cvShowImage("image2",img2);//在刚创建的image窗口中载入图像                   IplImage * im_median_filter =cvCreateImage(cvGetSize(img2),IPL_DEPTH_8U,1);         cvSmooth(img2, im_median_filter, CV_MEDIAN);//默认窗口大小为3*3          cvNamedWindow("after");          cvShowImage("after",im_median_filter);  cvSaveImage("11.jpg",im_median_filter);        cvWaitKey(0);//=========================================================================================IplImage *pimg = cvLoadImage( "11.jpg",0 ); //载入图像,转化为灰度图像IplImage *xwk = cvCreateImage( cvSize(pimg->width,pimg->height), IPL_DEPTH_8U,1);  for( int j = 0; j<pimg->height; j++)//二值化处理阈值超过95的数,置位255;否则置0.for( int i = 0; i<pimg->width; i++){if (((uchar *)pimg->imageData + j * pimg->widthStep)[i]>90)((uchar *)xwk->imageData + j * xwk->widthStep)[i] = 255;else ((uchar *)xwk->imageData + j * xwk->widthStep)[i] = 0;}    cvThreshold( pimg, xwk ,95, 255, 0 ); cvNamedWindow( "EZH",1 );cvShowImage( "EZH",xwk );cvSaveImage("12.jpg",xwk);cvWaitKey(0);cvReleaseImage(&pimg);cvReleaseImage(&xwk);cvReleaseImage(&img);    cvReleaseImage(&img1);cvReleaseImage(&img2);    cvDestroyAllWindows( );//边缘检测   IplImage *src = cvLoadImage("12.jpg", CV_LOAD_IMAGE_UNCHANGED);    EdgeTrack(src,50,200);    move();    return 0;}

完整代码:

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <opencv2/opencv.hpp>#include <stdio.h>#include <vector>#include <iostream>#include <cmath>#include <algorithm>#include <math.h>// we can adjust these parameters for different qr code images#define tol_factor 0.5#define tol_distance 8using namespace std;using namespace cv;Mat gray_img,bw_img;Mat src;int stateCount[5] = {0};// store the number of pixels in each state of the state machineint totalFinderSize;// store the size of the Findervector<Point> points_row;// store the possible locations of findersPoint qr_point1; // final finder center locationsPoint qr_point2;Point qr_point3;int thresholdValue = 110;//the threshold for each image=============================================================================================void threshold_selection(int,void*);// by sliding the trackbar to select a good thresholdvoid qr_find_row();// search finder locations row by rowvoid qr_find_col();// search finder locations column by columnbool qr_checkRatio();// judge whether a similar pattern is a possible finder or notvoid group_points(vector<Point>& points);// find the three largest vote locations in the accumulator arrayvoid draw_crosshair(Point qr_point,Mat src,CvScalar color);// draw a red crosshair on some point of the imagevoid affine_trans(); // through affine transformation to create a normalized version of each image //-----------------------------------------Main Function------------------------------------------------------------------------------int _tmain (int argc, char** argv){    // read a color qr code image which is used to display the red crosshairs(detected finder locations) and green crosshairs(manually marked finder locations)    const char* imagename = "F:\\My_opencv\\as.jpg";    src = imread(imagename,1);    namedWindow("original image", CV_WINDOW_AUTOSIZE);    imshow("original image",src);    // convert the color image into gray image    cvtColor(src,gray_img,CV_BGR2GRAY);    // 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    namedWindow("binary image",CV_WINDOW_AUTOSIZE);    createTrackbar("threshold value","binary image",&thresholdValue,255, threshold_selection);    threshold_selection(0,0);    bw_img = gray_img > thresholdValue; //bw_img is our final binary image    //cout<<"press c to continue after choosing a threshold"<<endl;    //char c;    /*while(1)    {        c = waitKey(0);        if(c =='c') break;    }*/            // detect qr code finders and mark finder centers as red crosshairs    qr_find_row();    //qr_find_col();    group_points(points_row);    imshow("original image",src); // display the color qr code image with red crosshairs    //determine an affine mapping from the detected mark locations to predefined locations and use this mapping to create a normalized image //affine_trans();    // wait for any key to quit    waitKey(0);    // release memory for images and destroy windows    src.release();    gray_img.release();    bw_img.release();    cvDestroyWindow("original image");    cvDestroyWindow("binary image");     return 0;}//-----------------------------------------------------------------------------------------------------------------------------------// use trackbar to get the threshold valuevoid threshold_selection(int,void*){    threshold(gray_img, bw_img, thresholdValue, 255 ,0);    imshow("binary image", bw_img);}/* search possible qr finder locations row by rowThis function goes through every row and keeps a track of the number of white or blackpixels it encounters. It also keeps a track of the order in which they're found. wheneverit founds something like b:w:b:w:b = 1:1:3:1:1, it will put the location of this possiblefinder into vector<Point> points_row*/void qr_find_row(){    int skipRows = 1;    int currentState=0;    int x,y;    for (int row = skipRows-1; row< bw_img.rows; row += skipRows)    {        stateCount[0] = 0; // inside black pixels        stateCount[1] = 0; // inside white pixels        stateCount[2] = 0; // inside black pixels        stateCount[3] = 0; // inside white pixels        stateCount[4] = 0; // inside black pixels        currentState = 0; // record the current state, b,w,b,w,b                uchar* ptr_row = bw_img.ptr<uchar>(row); // get a pointer to the current row        for(int col = 0; col< bw_img.cols; col++)        {            if(ptr_row[col]<128)            {                // we are at a black pixel                if((currentState & 0x1) == 1)                {                    // W->B transition                    currentState++;                }                // works for W->B and B->B                stateCount[currentState]++;            }            else            {                // we are at a white pixel                if((currentState & 0x1) == 1)                {                    // the current state is state 1 or state 3 (white pixel state)                    // W->W                    stateCount[currentState]++;                }                else                {                       // the current state is state 0, state 2 or state 4 (black pixel state)                    if(currentState == 4)                    {                        // we found the "white" area after one finder pattern                        // use ratio requirement to check whether it is a possible finder or not                        if(qr_checkRatio())                        {                            // ratio is correct, push this possible location into vector                            y = row;                            x = col-totalFinderSize/2;                            points_row.push_back(Point(x,y));                            currentState = 0;                            stateCount[0] = 0;                            stateCount[1] = 0;                            stateCount[2] = 0;                            stateCount[3] = 0;                            stateCount[4] = 0;                                                 }                        else                        {                            // ratio is not correct, do the switch                            currentState = 3;                            stateCount[0] = stateCount[2];                            stateCount[1] = stateCount[3];                            stateCount[2] = stateCount[4];                            stateCount[3] = 1;                            stateCount[4] = 0;                        }                    }                    else                    {                        // the current state is state 0 or state 2                        // B->W transition                        currentState++;                        stateCount[currentState]++;                    }                }            }        }    }}/* search possible qr finder locations column by columnThis function is similar to qr_find_row(). And the possible finder locations arestill pushed into vector points_row*/void qr_find_col(){    int skipCols = 1;    int currentState=0;    int x,y;    for (int col = skipCols-1; col< bw_img.cols; col += skipCols)    {        stateCount[0] = 0;        stateCount[1] = 0;         stateCount[2] = 0;         stateCount[3] = 0;         stateCount[4] = 0;         currentState = 0;                 uchar* ptr_col = bw_img.ptr<uchar>(col);        for(int row = 0; row< bw_img.rows; row++)        {            if(ptr_col[row]<128)            {                if((currentState & 0x1) == 1)                {                    currentState++;                }                stateCount[currentState]++;            }            else            {                if((currentState & 0x1) == 1)                {                    stateCount[currentState]++;                }                else                {                    if(currentState == 4)                    {                        if(qr_checkRatio())                        {                            y = row-totalFinderSize/2;;                            x = col;                            points_row.push_back(Point(x,y));                            currentState = 0;                            stateCount[0] = 0;                            stateCount[1] = 0;                            stateCount[2] = 0;                            stateCount[3] = 0;                            stateCount[4] = 0;                                              }                        else                        {                            currentState = 3;                            stateCount[0] = stateCount[2];                            stateCount[1] = stateCount[3];                            stateCount[2] = stateCount[4];                            stateCount[3] = 1;                            stateCount[4] = 0;                        }                                            }                    else                    {                        currentState++;                        stateCount[currentState]++;                    }                }            }        }    }}// check ratio requirement b:w:b:w:b = 1:1:3:1:1bool qr_checkRatio(){    totalFinderSize = 0;        for(int i =0;i<5; i++)    {        int count = stateCount[i];        totalFinderSize += count;        if(count == 0)            return false;    }    if(totalFinderSize<7)        return false;    int moduleSize = ceil(totalFinderSize / 7.0); // scale factor of the finder        // tolerate some "slop" of the ratio    double maxVariance = moduleSize*tol_factor;    bool retVal = ((abs(moduleSize - (stateCount[0]))< maxVariance) &&    (abs(moduleSize - (stateCount[1]))< maxVariance) &&    (abs(3*moduleSize - (stateCount[2]))< 3*maxVariance) &&    (abs(moduleSize - (stateCount[3]))< maxVariance) &&    (abs(moduleSize - (stateCount[4]))< maxVariance));    return retVal;}/* group possible finder locations, that is, each location vote in an array, so that we can find three largest votes, calculate the mean location of these three groups andfinally draw them on the image*/void group_points(vector<Point>& points){       CvScalar red = CV_RGB(255,0,0);    /* if the size of vector, number of possible finder locations is greater than 3,    we need to group them. if not, then just draw them on the image    */    if (points.size()>= 3)    {        double distance;        vector<vector<Point>> group(points.size());// every vector stores the finder locations which belong to one group        vector<int> score(points.size());// store the number of votes        vector<int> score_index(points.size());// store the index of score when we sort the score        int temp1;        int temp2;        // set values for score_index        for(size_t k=0; k < points.size();++k)        {            score_index[k] = k;        }        /* group the points by distance        check whether point i is near enough to point j (j<i), if so, then vote for j.        No matter whether i is near to j or not, it will vote for itself        */        for(size_t i = 0; i < points.size(); ++i)        {            for (size_t j=0; j < i; ++j)            {                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)));                if (distance < tol_distance)                {                    score[j] += 1;                    group[j].push_back(points[i]);                    break;                 }             }             score[i] += 1;             group[i].push_back(points[i]);         }        // sort the score and write new index into score_index         for(size_t m = 0; m < points.size()-1; ++m)         {            for(size_t n = m; n < points.size(); ++n)            {               if (score[m]<=score[n])               {                temp1 = score_index[m];                score_index[m] = score_index[n];                score_index[n] = temp1;                temp2 = score[m];                score[m] = score[n];                score[n] = temp2;                }            }         }         // calculate the mean location of three groups with largest votes         vector<Point>::iterator it;         for (it = group[score_index[0]].begin(); it != group[score_index[0]].end(); ++it)         {             qr_point1 += (*it);         }         qr_point1.x = qr_point1.x/score[0];         qr_point1.y = qr_point1.y/score[0];         for (it = group[score_index[1]].begin(); it != group[score_index[1]].end(); ++it)         {             qr_point2 += (*it);         }         qr_point2.x = qr_point2.x/score[1];         qr_point2.y = qr_point2.y/score[1];         for (it = group[score_index[2]].begin(); it != group[score_index[2]].end(); ++it)         {            qr_point3 += (*it);         }         qr_point3.x = qr_point3.x/score[2];         qr_point3.y = qr_point3.y/score[2];         // output the final finder center location               cout<<qr_point1<<endl;         cout<<qr_point2<<endl;         cout<<qr_point3<<endl;         draw_crosshair(qr_point1,src,red);         draw_crosshair(qr_point2,src,red);         draw_crosshair(qr_point3,src,red);    }    else    {        for(int v = 0; v < points.size(); ++v)        {            draw_crosshair(points[v],src,red);        }    }}//draw a red crosshair on some point of the imagevoid draw_crosshair(Point qr_point,Mat src,CvScalar color){    Point up1,up2;    up1.x = qr_point.x;    up1.y = qr_point.y -2;    up2.x = qr_point.x;    up2.y = qr_point.y +2;    Point down1,down2;    down1.x = qr_point.x -2;    down1.y = qr_point.y;    down2.x = qr_point.x + 2;    down2.y = qr_point.y;    // draw two lines that intersects on qr_point    line(src,up1,up2,color,1,8);    line(src,down1,down2,color,1,8);}void affine_trans(){  Point2f srcPoints[3];  Point2f dstPoints[3];  Mat mapping(2,3,CV_32FC1);  Mat src_img,wrap_dst_img;  src_img = imread("1.jpg",1);//for final affine transform result because src has red crosshairs now  wrap_dst_img = Mat::zeros(700,700,CV_8UC3); // create an output image of size 700*700 and 24-bit color  //set detected mark locations   srcPoints[0] = qr_point1;  srcPoints[1] = qr_point2;;  srcPoints[2] = qr_point3;  cout<<"original finder locations"<<endl;  cout<<srcPoints[0]<<'\n'<<srcPoints[1]<<'\n'<<srcPoints[2]<<endl;  //decide which one is finder mark location 1  double diffx0,diffy0,diffx1,diffy1,diffx2,diffy2;  diffx0 = srcPoints[0].x-srcPoints[1].x;  diffy0 = srcPoints[0].y-srcPoints[1].y;  diffx1 = srcPoints[1].x-srcPoints[2].x;  diffy1 = srcPoints[1].y-srcPoints[2].y;  diffx2 = srcPoints[2].x-srcPoints[0].x;  diffy2 = srcPoints[2].y-srcPoints[0].y;  //use cos(theta)=<x,y>/(|x||y|) to calculate angle  double norm[3];  norm[0] = sqrt(diffx0*diffx0+diffy0*diffy0);  norm[1] = sqrt(diffx1*diffx1+diffy1*diffy1);  norm[2] = sqrt(diffx2*diffx2+diffy2*diffy2);  double angle[3];  angle[0] = acos((-diffx0*diffx2-diffy0*diffy2)/(norm[0]*norm[2]));  angle[1] = acos((-diffx0*diffx1-diffy0*diffy1)/(norm[0]*norm[1]));  angle[2] = acos((-diffx2*diffx1-diffy2*diffy1)/(norm[2]*norm[1]));  cout<<"angles between any two of the three edges"<<endl;  cout<<angle[0]<<'\n'<<angle[1]<<'\n'<<angle[2]<<endl;    Point2f temp;  if((angle[1]>angle[0]) && (angle[1]>angle[2]))  {      temp = srcPoints[0];      srcPoints[0] = srcPoints[1];      srcPoints[1] = temp;  }  else if ((angle[2]>angle[1]) && (angle[2]>angle[0]))  {      temp = srcPoints[0];      srcPoints[0] = srcPoints[2];      srcPoints[2] = temp;  }    //decide which one is finder mark location 2 and finder mark location 3  //note in the example of assignment 3, direction from vector 12 to vector 13 is clockwise  diffx0 = srcPoints[1].x-srcPoints[0].x;  diffy0 = srcPoints[1].y-srcPoints[0].y;  diffx2 = srcPoints[2].x-srcPoints[0].x;  diffy2 = srcPoints[2].y-srcPoints[0].y;  double det = diffx0*diffy2-diffy0*diffx2;  if(det<0)  {      temp = srcPoints[1];      srcPoints[1] = srcPoints[2];      srcPoints[2] = temp;  }  cout<<"final ordered finder locations"<<endl;  cout<<srcPoints[0]<<'\n'<<srcPoints[1]<<'\n'<<srcPoints[2]<<endl;  //set 3 predefined output locations  dstPoints[0] = Point2f(400,50);  dstPoints[1] = Point2f(600,50);  dstPoints[2] = Point2f(400,250);    //get the Affine Transform  mapping = getAffineTransform(srcPoints, dstPoints);  cout<<"mapping = "<<mapping<<endl;   //check whether the mapping is correct or not  cout<<"test the mapping is correct or not"<<endl;  Point2f test;  for (int i =0; i < 3; i++)  {    double* ptr_row = mapping.ptr<double>(0);    //cout<<ptr_row[0]<<endl;    test.x = (ptr_row[0]*srcPoints[i].x + ptr_row[1]*srcPoints[i].y + ptr_row[2]*1);    ptr_row = mapping.ptr<double>(1);    test.y = (ptr_row[0]*srcPoints[i].x + ptr_row[1]*srcPoints[i].y + ptr_row[2]*1);    cout<<test<<endl;  }  //apply the Affine Transform just found to the src_img  warpAffine(src_img, wrap_dst_img, mapping, wrap_dst_img.size());  imwrite("1.normalized.jpg",wrap_dst_img);  //display the normalized version of each image  namedWindow("transform image", CV_WINDOW_AUTOSIZE);  imshow("transform image",wrap_dst_img);  wrap_dst_img.release();  src_img.release();}


1 0
原创粉丝点击