数字图象处理之二维码图像提取算法(十二)
来源:互联网 发布:搜房帮经纪人登录端口 编辑:程序博客网 时间: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
- 数字图象处理之二维码图像提取算法(十二)
- 数字图象处理之二维码图像提取算法(四)
- 数字图象处理之二维码图像提取算法(五)
- 数字图象处理之二维码图像提取算法(六)
- 数字图象处理之二维码图像提取算法(七)
- 数字图象处理之二维码图像提取算法(八)
- 数字图象处理之二维码图像提取算法(九)
- 数字图象处理之二维码图像提取算法(九)
- 数字图像处理之二维码图像提取算法(一)
- 数字图像处理之二维码图像提取算法(二)
- 数字图像处理之二维码图像提取算法(三)
- 数字图像处理之二维码图像提取算法(十)
- 数字图像处理之二维码图像提取算法(十一)
- VTK学习(十二)图像切面提取
- 计算机视觉----图像底层特征提取之边缘提取(二) Canny算法
- 图像算法之二:特征提取算法系列之Harris
- 图像算法之四:特征提取算法之SURF
- 图像算法之五:特征提取算法之HOG
- FileSystem以标准输出格式显示Hadoop文件中的文件
- NYOJ--264 国王的魔镜【水题】
- 组合模式
- 单播、广播、组播的区别和特点
- 《人物》专访庞明涛
- 数字图象处理之二维码图像提取算法(十二)
- 遗传算法
- Msm8960(APQ8064)平台的MSM-AOSP-kitkat编译适配(3):寻找正确的代码版本
- NYOJ--277 车牌号【水题】
- poj 3420 Quad Tiling 状压dp
- (API GUIDE 4)Activity(活动)
- WinForm打开文件
- 11
- Ubuntu 16.04中创建SWAP交换分区文件