名片、身份证、银行卡定位矫正算法:基于LSD直线检测,角点确定,透视变换
2017-11-21 20:06
1326 查看
lsd直线提取程序说明
函数模型:
ntuple_list lsd(image_double image);
直线提取程序是C语言,若使用C++,需要在头文件说明:
extern "C" { #include "lsd.h" };
该程序处理的数据类型是作者自己定义的image_double类型,所以无论编程者将图像存在何种格式下,必须进行类型转化。image_double类型定义如下:
typedef struct image_double_s { double * data; unsigned int xsize,ysize; } * image_double;
以为图像的坐标原点在左上角,x轴表示宽度,水平向右,y轴表示高度,竖直向下,因此,图像中一点(x,y)的值为image->data[ x + y * image->xsize ]。
因为C++将图像存储为IplImage格式,而C语言的程序中无法使用C++的头文件,因此IplImage与image_double类型的转换必须在函数外进行,无法整合在lsd函数中,因此,在使用该函数前需要一小段代码:
IplImage* im_gray = cvCreateImage(cvSize(m_im->width,m_im->height),IPL_DEPTH_8U,1); cvCvtColor(m_im,im_gray,CV_RGB2GRAY); image_double image = new_image_double(im_gray->width, im_gray->height); BYTE* im_src = (BYTE*)im_gray->imageData; int xsize = image->xsize;//宽度 int ysize = image->ysize;//高度 int y,x; for (y = 0;y < ysize;y++) { for (x = 0;x < xsize;x++) //x是横坐标,y是纵坐标 { image->data[y*xsize + x] = im_src[y*im_gray->widthStep + x]; } } cvReleaseImage(&im_gray);
上述代码中,m_im是输入的彩色图像,为IplImage* 格式,因为sld函数处理的是灰度图像,所以上述代码中,将输入的彩色图像转化为灰度图像。在这段代码后,image_double格式的image就可以直接送入lsd函数:
detected_lines = lsd(image);
detected_lines中存储着直线检测的结果,类型是作者自己定义的ntuple_list型,该类型的结构定义如下:
typedef struct ntuple_list_s { unsigned int size; unsigned int max_size; unsigned int dim; double * values; } * ntuple_list;
detected_lines中存储的是所有线段的信息,每一条线段都可以看做是一个子单元:detected_lines->size是指子单元的个数,即直线段的条数;
detected_lines->max_size是指最大可以存储的子单元个数(一般不会用到,程序内部自动分配空间,该项数字只是记录作用);
detected_lines->dim是指每一个子单元中数据的维数,一般是5,即线段首端点的x、y坐标,线段尾端点的x、y坐标,线段的宽度(这个指标一般不为1,但是没有用过,一般只是将线段首尾点相连作为提取到的线段);
这些指标具体的值存在value中,detected_lines->values[j*dim+0]和detected_lines->values[j*dim+1]分别是线段一个端点的x、y坐标,detected_lines->values[j*dim+2]和detected_lines->values[j*dim+3]分别是线段另一个端点的x、y坐标,detected_lines->values[j*dim+4]为线段的宽度。其中,j为某一条线段的索引号。
主调用例子
#include "IDCardRec.h" char * configFile = "config.txt"; char* trainSetPosPath = (char *)malloc(200*sizeof(char)); void readConfig(char* configFile, char* trainSetPosPath){ fstream f; char cstring[1000]; int readS=0; f.open(configFile, fstream::in); char param1[200]; strcpy(param1,""); char param2[200]; strcpy(param2,""); char param3[200]; strcpy(param3,""); f.getline(cstring, sizeof(cstring)); readS=sscanf (cstring, "%s %s %s", param1,param2, param3); strcpy(trainSetPosPath,param3); } vector<string> imgNames; int labelTemp = 0; void dfsFolder(string folderPath){ _finddata_t FileInfo; string strfind = folderPath + "\\*"; long Handle = _findfirst(strfind.c_str(), &FileInfo); if (Handle == -1L){ cerr << "can not match the folder path" << endl; exit(-1); } do{ if (FileInfo.attrib & _A_SUBDIR) { if( (strcmp(FileInfo.name,".") != 0 ) &&(strcmp(FileInfo.name,"..") != 0)) { string newPath = folderPath + "\\" + FileInfo.name; labelTemp = atoi(FileInfo.name); dfsFolder(newPath); } }else { string finalName = folderPath + "\\" + FileInfo.name; imgNames.push_back(finalName); } }while (_findnext(Handle, &FileInfo) == 0); _findclose(Handle); } void initTrainImage(){ readConfig(configFile, trainSetPosPath); string folderPath = trainSetPosPath; dfsFolder(folderPath); } void processingTotal(){ initTrainImage(); int imgNum = imgNames.size(); for(int iNum=0;iNum<imgNum;iNum++){ cout<<endl<<iNum<<endl; cout<<imgNames[iNum].c_str()<<endl; IplImage * src=cvLoadImage(imgNames[iNum].c_str(),1); if(!src) continue; if(1){ cvNamedWindow("image",1); cvShowImage("image",src); } processingOne(src); } } extern IplImage* res_im; void processingOne(IplImage * src){ cvNamedWindow("dst",1); // IplImage * dst = jiaoZheng(src); char *vif = vifLine(src); // cout<<vif<<endl; IplImage * dst = jiaozheng2(res_im); cvShowImage("dst",dst); cvWaitKey(0); } void main() { processingTotal(); }
矫正部分判断筛选:
#include "jiaoZheng.h" //===================判断点在矩形内===================,这里把贴边的去掉 bool InRectYesOrNo(CvPoint pt,CvRect rect){ if( ( (pt.x >rect.x)&&(pt.x <(rect.x+rect.width)) )&&((pt.y >rect.y)&&(pt.y <(rect.y+rect.height))) ) return true; else return false; } //=============计算两点之间的距离 float lenghtOf2P(CvPoint pt1,CvPoint pt2){ return sqrt((float)(pt1.x - pt2.x)*(pt1.x - pt2.x)+(pt1.y - pt2.y)*(pt1.y - pt2.y)); } //===============根据顶部或者底部线段,筛选出同角度下总长度最长的线段====================/ vector<cv::Vec4i> chooseLine1(IplImage* src,vector<linePtAngle> lineTop){ //第一步:确定所有线段都是首小于尾部(以X轴为参考计算) for(unsigned int i = 0; i < lineTop.size() ; i++){ if( lineTop[i].startPt.x >lineTop[i].endPt.x ){ CvPoint temp; temp.x = lineTop[i].startPt.x; temp.y = lineTop[i].startPt.y; lineTop[i].startPt.x = lineTop[i].endPt.x; lineTop[i].startPt.y = lineTop[i].endPt.y; lineTop[i].endPt.x = temp.x; lineTop[i].endPt.y = temp.y; } } //显示首尾ok后的线 if(showSteps){ for(unsigned int i = 0; i < lineTop.size() ; i++){ cvLine(src,lineTop[i].startPt,lineTop[i].endPt,CV_RGB(0,255,255),6,CV_AA); printf("======================== %d,%d\n",lineTop[i].startPt.x,lineTop[i].endPt.x); } cvShowImage("src",src); cvWaitKey(0); } //找出堆在一起的平行线,这个一般是银联的标志 int a[20]; for(int n=0;n<20;n++) a = -1; int n = 0; //将平行,且两条线段中的一条首与一条尾相距很小时将这两天先合并 for(unsigned int i = 0; i < lineTop.size()-1 ; i++){ for(unsigned int j = i+1; j < lineTop.size() ; j++){ if( (abs(lineTop[i].angle - lineTop[j].angle)<=3 )&&( abs(lineTop[i].startPt.x - lineTop[j].startPt.x )<=10 )&&(abs(lineTop[i].endPt.x - lineTop[j].endPt.x )<=30)&&(i!=j) ){ a[n++] = i; a[n++] = j; } } } //显示去掉银联标志后的正确的图 if(showSteps){ for(unsigned int j = 0; j < lineTop.size() ; j++){ if( (j!=a[0])&&(j!=a[1])&&(j!=a[2])&&(j!=a[3])&&(j!=a[4])&&(j!=a[5])&&(j!=a[6])&&(j!=a[7])&&(j!=a[8]) &&(j!=a[9])&&(j!=a[10])&&(j!=a[11])&&(j!=a[12])&&(j!=a[13])&&(j!=a[14])&&(j!=a[15])&&(j!=a[16])&&(j!=a[17]) &&(j!=a[18])&&(j!=a[19]) ) cvLine(src,lineTop[j].startPt,lineTop[j].endPt,CV_RGB(0,0,255),6,CV_AA); } cvShowImage("src",src); cvWaitKey(0); } //将堆在一起的平行线,角度赋大值,去掉他们。 for(int n=0;n<20;n++){ for(unsigned int j = 0; j < lineTop.size() ; j++){ if(j == a ){ lineTop[j].angle = 45; } } } /*cvShowImage("src",src); cvWaitKey(0);*/ ////将数条平行在一起的线去掉 //vector<linePtAngle>::iterator it; //int flagNum = 0; //for(it=lineTop.begin();it!=lineTop.end();++it){ //// flagNum ++; // if( flagNum==a[0] ){ // it=lineTop.erase(it); // break; // }else // ++it; //} //for(int n=0;n<20;n++){ // int flagNum = 0; // for(vector<linePtAngle>::iterator it=lineTop.begin(); it!=lineTop.end(); ){ // flagNum ++; // if(flagNum==a ){ // it = lineTop.erase(it); //不能写成arr.erase(it); // }else{ // ++it; // } // } //} // //for(unsigned int i = 0; i < lineTop.size() ; i++){ // cvLine(src,lineTop[i].startPt,lineTop[i].endPt,CV_RGB(255,0,0),6,CV_AA); //} //cvShowImage("src",src); //cvWaitKey(0); //将平行,且两条线段中的一条首与一条尾相距很小时将这两天先合并 for(unsigned int i = 0; i < lineTop.size()-1 ; i++){ for(unsigned int j = i+1; j < lineTop.size() ; j++){ if( (abs(lineTop[i].angle - lineTop[j].angle)<=3 )&&( abs(lineTop[i].endPt.x - lineTop[j].startPt.x )<=5 )&&(lineTop[i].startPt.x < lineTop[j].startPt.x) ){ lineTop[i].startPt.x = lineTop[i].startPt.x; lineTop[i].startPt.y = lineTop[i].startPt.y; lineTop[i].endPt.x = lineTop[j].endPt.x; lineTop[i].endPt.y = lineTop[j].endPt.y; } } } float *angleTop; angleTop = (float *)malloc(lineTop.size()*sizeof(float)); int sumTop[40] = {0}; for(int jAngle = -20;jAngle<20;jAngle ++){ for(unsigned int i = 0; i < lineTop.size() ; i++){ if( (lineTop[i].angle == jAngle) ) sumTop[jAngle+20] += lineTop[i].lineLength; } } if(showSteps){ for(int jAngle = -20;jAngle<20;jAngle ++) cout<<sumTop[jAngle+20]<<" "; } int maxSumTop = sumTop[0]; for(int jAngle = -20;jAngle<20;jAngle ++){ if (maxSumTop<sumTop[jAngle+20]) { maxSumTop = sumTop[jAngle+20]; } } if(showSteps) cout<<maxSumTop<<endl; vector<cv::Vec4i> lines; for(int jAngle = -20;jAngle<20;jAngle ++){ if(maxSumTop == sumTop[jAngle+20]){ for(int j = 0; j<lineTop.size();j++){ if((jAngle == lineTop[j].angle)||((jAngle+1) == lineTop[j].angle)||((jAngle-1) == lineTop[j].angle)) { if(showSteps) cvLine(src,lineTop[j].startPt,lineTop[j].endPt,CV_RGB(255,255,255),6,CV_AA); Vec4i v; v[0] = lineTop[j].startPt.x; v[1] = lineTop[j].startPt.y; v[2] = lineTop[j].endPt.x; v[3] = lineTop[j].endPt.y; lines.push_back(v); } } } } return lines; } //===============根据顶部或者底部线段,筛选出同角度下总长度最长的线段====================/ vector<cv::Vec4i> chooseLine(IplImage* src,vector<linePtAngle> lineTop){ float *angleTop; angleTop = (float *)malloc(lineTop.size()*sizeof(float)); int sumTop[40] = {0}; for(int jAngle = -20;jAngle<20;jAngle ++){ for(unsigned int i = 0; i < lineTop.size() ; i++){ if( (lineTop[i].angle == jAngle) ) sumTop[jAngle+20] += lineTop[i].lineLength; } } if(showSteps){ for(int jAngle = -20;jAngle<20;jAngle ++) cout<<sumTop[jAngle+20]<<" "; } int maxSumTop = sumTop[0]; for(int jAngle = -20;jAngle<20;jAngle ++){ if (maxSumTop<sumTop[jAngle+20]) { maxSumTop = sumTop[jAngle+20]; } } if(showSteps) cout<<maxSumTop<<endl; vector<cv::Vec4i> lines; for(int jAngle = -20;jAngle<20;jAngle ++){ if(maxSumTop == sumTop[jAngle+20]){ for(int j = 0; j<lineTop.size();j++){ if((jAngle == lineTop[j].angle)||((jAngle+1) == lineTop[j].angle)||((jAngle-1) == lineTop[j].angle)) { if(showSteps) cvLine(src,lineTop[j].startPt,lineTop[j].endPt,CV_RGB(255,255,255),6,CV_AA); Vec4i v; v[0] = lineTop[j].startPt.x; v[1] = lineTop[j].startPt.y; v[2] = lineTop[j].endPt.x; v[3] = lineTop[j].endPt.y; lines.push_back(v); } } } } return lines; } vector<cv::Vec4i> chooseLineLR(IplImage* src,vector<linePtAngle> lineTop){ float *angleTop; angleTop = (float *)malloc(lineTop.size()*sizeof(float)); //===========垂直===============/ int sumTop[41] = {0}; for(int iAngle = -90; iAngle<-70 ; iAngle ++ ){ for(unsigned int i = 0; i < lineTop.size() ; i++){ if(lineTop[i].angle == iAngle) sumTop[iAngle+90] += lineTop[i].lineLength; } } for( int jAngle = 70; jAngle<=90; jAngle ++){ for(unsigned int i = 0; i < lineTop.size() ; i++){ if(lineTop[i].angle == jAngle) sumTop[jAngle-50] += lineTop[i].lineLength; } } if(showSteps){ for(int i=0;i<41;i++) cout<<sumTop[i]<<" "; } int maxSumTop = sumTop[0]; for(int i=0;i<41;i++){ if (maxSumTop<sumTop[i]) { maxSumTop = sumTop[i]; } } if(showSteps) cout<<maxSumTop<<endl; vector<cv::Vec4i> lines; for(int iAngle = -90; iAngle<-70 ; iAngle ++ ){ if(maxSumTop == sumTop[iAngle+90]){ for(int j = 0; j<lineTop.size();j++) if( (iAngle == lineTop[j].angle)||((iAngle+1) == lineTop[j].angle)||((iAngle-1) == lineTop[j].angle) ){ if(showSteps) cvLine(src,lineTop[j].startPt,lineTop[j].endPt,CV_RGB(255,255,255),6,CV_AA); Vec4i v; v[0] = lineTop[j].startPt.x; v[1] = lineTop[j].startPt.y; v[2] = lineTop[j].endPt.x; v[3] = lineTop[j].endPt.y; lines.push_back(v); } } } for( int jAngle = 70; jAngle<=90; jAngle ++){ if(maxSumTop == sumTop[jAngle-50]){ for(int j = 0; j<lineTop.size();j++) if( (jAngle == lineTop[j].angle)||((jAngle+1) == lineTop[j].angle)||((jAngle-1) == lineTop[j].angle) ){ if(showSteps) cvLine(src,lineTop[j].startPt,lineTop[j].endPt,CV_RGB(255,255,255),6,CV_AA); Vec4i v; v[0] = lineTop[j].startPt.x; v[1] = lineTop[j].startPt.y; v[2] = lineTop[j].endPt.x; v[3] = lineTop[j].endPt.y; lines.push_back(v); } } } return lines; } //========================已知直线上两点,求直线的交点===================/ void GetLinePara(Line &l) { l.a=l.p1.y-l.p2.y; l.b=l.p2.x-l.p1.x; l.c=l.p1.x*l.p2.y-l.p1.y*l.p2.x; } pPoint getCrossPoint(Line &l1,Line &l2) { GetLinePara(l1); GetLinePara(l2); double D=l1.a*l2.b-l2.a*l1.b; pPoint p; p.x=(l1.b*l2.c-l2.b*l1.c)/D; p.y=(l1.c*l2.a-l2.c*l1.a)/D; return p; } /* 返回顶角在o点,起始边为os,终止边为oe的夹角(单位:弧度) 角度小于pi,返回正值 角度大于pi,返回负值 可以用于求线段之间的夹角 原理: r = dotmultiply(s,e,o) / (dist(o,s)*dist(o,e)) r'= multiply(s,e,o) r >= 1 angle = 0; r <= -1 angle = -PI -1<r<1 && r'>0 angle = arccos(r) -1<r<1 && r'<=0 angle = -arccos(r) */ double angle(pPoint o,pPoint s,pPoint e) { double cosfi,fi,norm; double dsx = s.x - o.x; double dsy = s.y - o.y; double dex = e.x - o.x; double dey = e.y - o.y; cosfi=dsx*dex+dsy*dey; norm=(dsx*dsx+dsy*dsy)*(dex*dex+dey*dey); cosfi /= sqrt( norm ); if (cosfi >= 1.0 ) return 0; if (cosfi <= -1.0 ) return -3.1415926; fi=acos(cosfi); if (dsx*dey-dsy*dex>0) return fi; // 说明矢量os 在矢量 oe的顺时针方向 return -fi; } //====================计算角度=========================/ ptAndAngle computeIntersect(cv::Vec4i a,cv::Vec4i b) { Line L1,L2; L1.p1.x = a[0]; L1.p1.y = a[1]; L1.p2.x = a[2]; L1.p2.y = a[3]; L2.p1.x = b[0]; L2.p1.y = b[1]; L2.p2.x = b[2]; L2.p2.y = b[3]; pPoint PointCross=getCrossPoint(L1,L2); if(showSteps){ cout<<"CrossPoint.x:"<<PointCross.x<<endl; cout<<"CrossPoint.y:"<<PointCross.y<<endl; } ptAndAngle pt; pt.ptf.x = PointCross.x; pt.ptf.y = PointCross.y; double pAngle = angle(PointCross,L1.p1,L2.p1) ; double temp = pAngle*180/3.1415962; pt.Angle = temp; //两条直线夹角在70 if( ( (temp>=70)&&(temp<=110) )||((temp>=-110)&&(temp<=-70)) ){ if(showSteps) cout<<"角度: "<<pAngle*180/3.1415962<<endl; return pt; }else { pt.ptf.x = -100; pt.ptf.y = -100; return pt; } } //==================计算数组的最大 最小值=======================/ void GetMaxAndMin(double *arr , int n , double &max , double &min) { int i = 0 ; if(n & 1) // 奇数 { max = min = arr[i++]; } else { if(arr[0] > arr[1]) { max = arr[0]; min = arr[1]; } else { max = arr[1]; min = arr[0]; } i += 2; } for( ; i < n ; i += 2) { if(arr[i] > arr[i+1]) { if(arr[i] > max) max = arr[i]; if(arr[i+1] < min) min = arr[i+1]; } else { if(arr[i+1] > max) max = arr[i+1]; if(arr[i] < min) min = arr[i]; } } } //=======================计算所有线中的最长值=======================/ cv::Vec4i chooseLongest(vector<cv::Vec4i> lineT ){ float len = 0; for (unsigned int i = 0;i<lineT.size();i++){ CvPoint start_pt; start_pt.x = lineT[i][0]; start_pt.y = lineT[i][1]; CvPoint end_pt; end_pt.x = lineT[i][2]; end_pt.y = lineT[i][3]; float tempLen = lenghtOf2P(start_pt,end_pt); if( len < tempLen){ len = tempLen; } } for (unsigned int i = 0;i<lineT.size();i++){ CvPoint start_pt; start_pt.x = lineT[i][0]; start_pt.y = lineT[i][1]; CvPoint end_pt; end_pt.x = lineT[i][2]; end_pt.y = lineT[i][3]; float tempLen = lenghtOf2P(start_pt,end_pt); if( len == tempLen){ if(showSteps) cout<<"最长线的长度是:"<<len<<endl; Vec4i lineLonges; lineLonges[0] = lineT[i][0]; lineLonges[1] = lineT[i][1]; lineLonges[2] = lineT[i][2]; lineLonges[3] = lineT[i][3]; return lineLonges; } } return NULL; } //===================按顺序给四点排序===============/ void sortCorners(std::vector<cv::Point2f>& corners,cv::Point2f center) { std::vector<cv::Point2f> top,bot; for (unsigned int i =0;i< corners.size();i++){ if (corners[i].y<center.y){ top.push_back(corners[i]); }else{ bot.push_back(corners[i]); } } cv::Point2f tl = top[0].x > top[1].x ? top[1] : top[0]; cv::Point2f tr = top[0].x > top[1].x ? top[0] : top[1]; cv::Point2f bl = bot[0].x > bot[1].x ? bot[1] : bot[0]; cv::Point2f br = bot[0].x > bot[1].x ? bot[0] : bot[1]; corners.clear(); //注意以下存放顺序是顺时针,当时这里出错了,如果想任意顺序下文开辟的四边形矩阵注意对应 corners.push_back(tl); corners.push_back(tr); corners.push_back(br); corners.push_back(bl); } IplImage * jiaoZheng1(IplImage * m_im){ ntuple_list detected_lines; clock_t start,finish; double duration,rate; start = clock(); //lsd函数处理灰度图像,需要进行转换 IplImage* im_gray = cvCreateImage(cvSize(m_im->width,m_im->height),IPL_DEPTH_8U,1); cvCvtColor(m_im,im_gray,CV_RGB2GRAY); image_double image = new_image_double(im_gray->width, im_gray->height); uchar* im_src = (uchar*)im_gray->imageData; int xsize = image->xsize;//宽度 int ysize = image->ysize;//高度 int y,x; for (y = 0;y < ysize;y++) { for (x = 0;x < xsize;x++) //x是横坐标,y是纵坐标 { image->data[y*xsize + x] = im_src[y*im_gray->widthStep + x];//im_gray是灰度图像,没有颜色通道 } } cvReleaseImage(&im_gray); detected_lines = lsd(image);//detected_lines中存储提取直线的首位坐标及宽度,具体意义见说明文档 free_image_double(image); finish = clock(); duration = (double)(finish - start)/CLOCKS_PER_SEC; if(showSteps) cout<<"total time of extract lines is:"<<duration<<endl;//提取所有直线需要的总时间 rate = duration/detected_lines->size; if(showSteps) cout<<"time of extract per line is :"<<rate<<endl;//提取一条直线需要的平均时间 //将检测出的直线绘制在载入的彩色图像上 int dim = detected_lines->dim; IplImage* res_im = cvCreateImage(cvGetSize(m_im),8,m_im->nChannels); cvCopy(m_im,res_im); cvReleaseImage(&m_im); vector<double> angle(detected_lines->size,0); double angletemp; vector<linePtAngle> lineTop;vector<linePtAngle> lineBottom;vector<linePtAngle> lineLeft;vector<linePtAngle> lineRight; for (unsigned int j = 0;j < detected_lines->size;j++) { CvPoint start_pt = cvPoint((int)detected_lines->values[j*dim+0],(int)detected_lines->values[j*dim+1]); CvPoint end_pt = cvPoint((int)detected_lines->values[j*dim+2],(int)detected_lines->values[j*dim+3]); if(showSteps)//===========画出所有检测到的直线==============/ cvLine(res_im,start_pt,end_pt,CV_RGB(255,0,0),4,CV_AA); angletemp = (int)(atan((detected_lines->values[j*dim+1]-detected_lines->values[j*dim+3])/(detected_lines->values[j*dim+0]-detected_lines->values[j*dim+2]))*180/3.1416); angle[j] = angletemp; if(showSteps) cout<<"angle "<<j<<" = "<<angle[j]<<endl; //===========根据上下左右四个方向,分别做筛选================/ if(lenghtOf2P(start_pt,end_pt) > 30) //筛选,长度大于30的线 { int tempWidth = 50; //==========确定图片四周,的宽度内做筛选,这个宽度定为50. CvRect rectL; rectL.x = 0; rectL.y = 0; rectL.width = tempWidth; rectL.height = res_im->height; if( ( InRectYesOrNo(start_pt,rectL)&&InRectYesOrNo(end_pt,rectL) )&&((angle[j] < -70) || (angle[j] > 70) ) ){ if(showSteps){ cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineLeft.push_back(temp); } CvRect rectR; rectR.x = res_im->width - tempWidth; rectR.y = 0; rectR.width = tempWidth; rectR.height = res_im->height; if( ( InRectYesOrNo(start_pt,rectR)&&InRectYesOrNo(end_pt,rectR) )&&((angle[j] < -70) || (angle[j] > 70) ) ){ if(showSteps){ cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineRight.push_back(temp); } CvRect rectT; rectT.x = 0; rectT.y = 0; rectT.width = res_im->width; rectT.height = tempWidth; if( ( InRectYesOrNo(start_pt,rectT)&&InRectYesOrNo(end_pt,rectT) )&&((angle[j] >-20)&&(angle[j] < 20)) ){ if(showSteps){ cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineTop.push_back(temp); } CvRect rectB; rectB.x = 0; rectB.y = res_im->height - tempWidth; rectB.width = res_im->width; rectB.height = tempWidth; if( ( InRectYesOrNo(start_pt,rectB)&&InRectYesOrNo(end_pt,rectB) )&&((angle[j] >-20)&&(angle[j] < 20)) ){ if(showSteps) cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineBottom.push_back(temp); } } } vector<double>(angle).swap(angle); //==================对 线段进行筛选处理 vector<cv::Vec4i> linesAll ; vector<cv::Vec4i> lineT = chooseLine(res_im,lineTop); vector<cv::Vec4i> lineB = chooseLine(res_im,lineBottom); vector<cv::Vec4i> lineL = chooseLineLR(res_im,lineLeft); vector<cv::Vec4i> lineR = chooseLineLR(res_im,lineRight); //============如果四条边没有找全========// if( (lineT.size()==0)||(lineB.size()==0)||(lineL.size()==0)||(lineR.size()==0)){ return res_im; } vector<linePtAngle> (lineTop).swap(lineTop); vector<linePtAngle> (lineBottom).swap(lineBottom); vector<linePtAngle> (lineLeft).swap(lineLeft); vector<linePtAngle> (lineRight).swap(lineRight); cv::Vec4i lineTLongest = chooseLongest(lineT); cv::Vec4i lineBLongest = chooseLongest(lineB); cv::Vec4i lineLLongest = chooseLongest(lineL); cv::Vec4i lineRLongest = chooseLongest(lineR); vector<cv::Vec4i> (lineT).swap(lineT); vector<cv::Vec4i> (lineB).swap(lineB); vector<cv::Vec4i> (lineL).swap(lineL); vector<cv::Vec4i> (lineR).swap(lineR); linesAll.push_back(lineTLongest); linesAll.push_back(lineBLongest); linesAll.push_back(lineLLongest); linesAll.push_back(lineRLongest); //needed for visualization only//这里是将检测的线调整到延长至全屏,即射线的效果,其实可以不必这么做 for (unsigned int i = 0;i<linesAll.size();i++) { cv::Vec4i v = linesAll[i]; linesAll[i][0] = 0; linesAll[i][1] = ((float)v[1] - v[3])/(v[0] - v[2])* -v[0] + v[1]; linesAll[i][2] = res_im->width; linesAll[i][3] = ((float)v[1] - v[3])/(v[0] - v[2])*(res_im->width - v[2]) + v[3]; if(((v[0] - v[2]))==0) { linesAll[i][0] = v[0]; linesAll[i][1] = 0; linesAll[i][2] = v[2]; linesAll[i][3] = res_im->height; } if(showSteps) printf("[%d %d %d %d ]\n",linesAll[i][0],linesAll[i][1],linesAll[i][2],linesAll[i][3]); } //Draw Lines if(showSteps){ for (unsigned int i = 0;i<linesAll.size();i++){ cv::Vec4i v = linesAll[i]; cvLine(res_im,cvPoint(v[0],v[1]),cvPoint(v[2],v[3]),CV_RGB(0,255,255),1,CV_AA); } } std::vector<ptAndAngle> corners;//线的交点存储 for (unsigned int i = 0;i<linesAll.size()-1;i++){ for (unsigned int j=i+1;j<linesAll.size();j++){ //===========线的交点=============/ ptAndAngle pt = computeIntersect(linesAll[i],linesAll[j]); if( (pt.ptf.x >= -10 && pt.ptf.y >=-10) &&(pt.ptf.x<res_im->width+20)&&(pt.ptf.y<res_im->height+20) ) { corners.push_back(pt); } } } vector<cv::Vec4i> (linesAll).swap(linesAll) ; if(showSteps){ for (unsigned int i = 0;i<corners.size();i++){ cout<<corners[i].ptf.x<<" "<<corners[i].ptf.y<<endl; cvCircle(res_im,corners[i].ptf,3,CV_RGB(255,255,0),2); } } std::vector<cv::Point2f> cornersPt; for (unsigned int i = 0;i<corners.size();i++){ cornersPt.push_back(corners[i].ptf); } std::vector<cv::Point2f> approx; cv::approxPolyDP(cv::Mat(cornersPt),approx,cv::arcLength(cv::Mat(cornersPt),true)*0.02,false); if (approx.size()!=4){ std::cout<<"The object is not quadrilateral(四边形)!"<<std::endl; return res_im; } if(showSteps){ //=============画出四边形拟合的顶点结果==================/ for (unsigned int i = 0;i<approx.size();i++){ cvCircle(res_im,approx[i],3,CV_RGB(0,0,255),3); printf("[ %f\t %f ]\n",approx[i].x,approx[i].y); } } std::vector<cv::Point2f> (approx).swap(approx); cv::Point2f center(0,0); //get mass center for (unsigned int i = 0;i < corners.size();i++) { center += cornersPt[i]; } center *=(1./corners.size()); std::vector<ptAndAngle> (corners).swap(corners); if(showSteps) cvCircle(res_im,center,3,CV_RGB(255,255,0),6); //========对四个顶点按照顺序排序=============/ sortCorners(cornersPt,center); std::vector<cv::Point2f> (cornersPt).swap(cornersPt); //==========确定 银行卡的宽高==============/ cv::Mat quad = cv::Mat::zeros(281,442,CV_8UC3);//设定校正过的图片从320*240变为300*220 //corners of the destination image std::vector<cv::Point2f> quad_pts; quad_pts.push_back(cv::Point2f(0,0)); quad_pts.push_back(cv::Point2f(quad.cols,0));//(220,0) quad_pts.push_back(cv::Point2f(quad.cols,quad.rows));//(220,300) quad_pts.push_back(cv::Point2f(0,quad.rows)); std::vector<cv::Point2f> (quad_pts).swap(quad_pts); // Get transformation matrix cv::Mat transmtx = cv::getPerspectiveTransform(cornersPt,quad_pts); //求源坐标系(已畸变的)与目标坐标系的转换矩阵 Mat src(res_im); // Apply perspective transformation透视转换 cv::warpPerspective(src,quad,transmtx,quad.size()); IplImage *dst = cvCreateImage(cvSize(quad.cols,quad.rows),8,res_im->nChannels); uchar *dataDst = (uchar *)(dst->imageData); for( size_t nrow = 0; nrow < quad.rows; nrow++) { for(size_t ncol = 0; ncol < quad.cols; ncol++) { Vec3i bgr = quad.at<Vec3b>(nrow,ncol);//用Vec3b也行 for(size_t k =0; k<quad.channels(); k++){ dataDst[nrow*(dst->widthStep)+ncol*(dst->nChannels)+k] = bgr.val[k]; } } } if(showSteps){ cvNamedWindow("dst",1); cvShowImage("dst",dst); cvNamedWindow("Image",1); cvShowImage("Image",res_im); cvWaitKey(0); } cvReleaseImage(&res_im); return dst; } IplImage * jiaoZheng(IplImage * m_im){ IplImage * m_imResize = cvCreateImage(cvSize(444,280),8,m_im->nChannels); cvResize(m_im,m_imResize,CV_INTER_LINEAR); ntuple_list detected_lines; clock_t start,finish; double duration,rate; start = clock(); //lsd函数处理灰度图像,需要进行转换 IplImage* im_gray = cvCreateImage(cvSize(m_imResize->width,m_imResize->height),IPL_DEPTH_8U,1); cvCvtColor(m_imResize,im_gray,CV_BGR2GRAY); image_double image = new_image_double(im_gray->width, im_gray->height); uchar* im_src = (uchar*)im_gray->imageData; int xsize = image->xsize;//宽度 int ysize = image->ysize;//高度 int y,x; for (y = 0;y < ysize;y++) { for (x = 0;x < xsize;x++) //x是横坐标,y是纵坐标 { image->data[y*xsize + x] = im_src[y*im_gray->widthStep + x];//im_gray是灰度图像,没有颜色通道 } } cvReleaseImage(&im_gray); detected_lines = lsd(image);//detected_lines中存储提取直线的首位坐标及宽度,具体意义见说明文档 free_image_double(image); finish = clock(); duration = (double)(finish - start)/CLOCKS_PER_SEC; if(showSteps) cout<<"total time of extract lines is:"<<duration<<endl;//提取所有直线需要的总时间 rate = duration/detected_lines->size; if(showSteps) cout<<"time of extract per line is :"<<rate<<endl;//提取一条直线需要的平均时间 //将检测出的直线绘制在载入的彩色图像上 int dim = detected_lines->dim; IplImage* res_im = cvCreateImage(cvGetSize(m_imResize),8,m_imResize->nChannels); cvCopy(m_imResize,res_im); cvReleaseImage(&m_imResize); vector<double> angle(detected_lines->size,0); double angletemp; vector<linePtAngle> lineTop;vector<linePtAngle> lineBottom;vector<linePtAngle> lineLeft;vector<linePtAngle> lineRight; for (unsigned int j = 0;j < detected_lines->size;j++) { CvPoint start_pt = cvPoint((int)detected_lines->values[j*dim+0],(int)detected_lines->values[j*dim+1]); CvPoint end_pt = cvPoint((int)detected_lines->values[j*dim+2],(int)detected_lines->values[j*dim+3]); //if(showSteps)//===========画出所有检测到的直线==============/ // cvLine(res_im,start_pt,end_pt,CV_RGB(255,0,0),4,CV_AA); angletemp = (int)(atan((detected_lines->values[j*dim+1]-detected_lines->values[j*dim+3])/(detected_lines->values[j*dim+0]-detected_lines->values[j*dim+2]))*180/3.1416); angle[j] = angletemp; if(showSteps) cout<<"angle "<<j<<" = "<<angle[j]<<endl; //===========根据上下左右四个方向,分别做筛选================/ if(lenghtOf2P(start_pt,end_pt) > 20) //筛选,长度大于30的线 { int tempWidth = 30; //==========确定图片四周,的宽度内做筛选,这个宽度定为50. if(lenghtOf2P(start_pt,end_pt) > 30) //筛选,长度大于30的线 { CvRect rectL; rectL.x = 0; rectL.y = 0; rectL.width = tempWidth; rectL.height = res_im->height; if( ( InRectYesOrNo(start_pt,rectL)&&InRectYesOrNo(end_pt,rectL) )&&((angle[j] < -70) || (angle[j] > 70) ) ){ if(showSteps){ // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineLeft.push_back(temp); } } CvRect rectR; rectR.x = res_im->width - tempWidth; rectR.y = 0; rectR.width = tempWidth; rectR.height = res_im->height; if( ( InRectYesOrNo(start_pt,rectR)&&InRectYesOrNo(end_pt,rectR) )&&((angle[j] < -70) || (angle[j] > 70) ) ){ if(showSteps){ // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineRight.push_back(temp); } CvRect rectT; rectT.x = 0; rectT.y = 0; rectT.width = res_im->width; rectT.height = tempWidth; if( ( InRectYesOrNo(start_pt,rectT)&&InRectYesOrNo(end_pt,rectT) )&&((angle[j] >-20)&&(angle[j] < 20)) ){ if(showSteps){ // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineTop.push_back(temp); } CvRect rectB; rectB.x = 0; rectB.y = res_im->height - tempWidth; rectB.width = res_im->width; rectB.height = tempWidth; if( ( InRectYesOrNo(start_pt,rectB)&&InRectYesOrNo(end_pt,rectB) )&&((angle[j] >-20)&&(angle[j] < 20)) ){ //if(showSteps) // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineBottom.push_back(temp); } } } vector<double>(angle).swap(angle); //==================对 线段进行筛选处理 vector<cv::Vec4i> linesAll ; vector<cv::Vec4i> lineT = chooseLine(res_im,lineTop); vector<cv::Vec4i> lineB = chooseLine(res_im,lineBottom); vector<cv::Vec4i> lineL = chooseLineLR(res_im,lineLeft); vector<cv::Vec4i> lineR = chooseLineLR(res_im,lineRight); //============如果四条边没有找全========// if( (lineT.size()==0)||(lineB.size()==0)||(lineL.size()==0)||(lineR.size()==0)){ return res_im; } vector<linePtAngle> (lineTop).swap(lineTop); vector<linePtAngle> (lineBottom).swap(lineBottom); vector<linePtAngle> (lineLeft).swap(lineLeft); vector<linePtAngle> (lineRight).swap(lineRight); cv::Vec4i lineTLongest = chooseLongest(lineT); cv::Vec4i lineBLongest = chooseLongest(lineB); cv::Vec4i lineLLongest = chooseLongest(lineL); cv::Vec4i lineRLongest = chooseLongest(lineR); vector<cv::Vec4i> (lineT).swap(lineT); vector<cv::Vec4i> (lineB).swap(lineB); vector<cv::Vec4i> (lineL).swap(lineL); vector<cv::Vec4i> (lineR).swap(lineR); linesAll.push_back(lineTLongest); linesAll.push_back(lineBLongest); linesAll.push_back(lineLLongest); linesAll.push_back(lineRLongest); //needed for visualization only//这里是将检测的线调整到延长至全屏,即射线的效果,其实可以不必这么做 for (unsigned int i = 0;i<linesAll.size();i++) { cv::Vec4i v = linesAll[i]; linesAll[i][0] = 0; linesAll[i][1] = ((float)v[1] - v[3])/(v[0] - v[2])* -v[0] + v[1]; linesAll[i][2] = res_im->width; linesAll[i][3] = ((float)v[1] - v[3])/(v[0] - v[2])*(res_im->width - v[2]) + v[3]; if(((v[0] - v[2]))==0) { linesAll[i][0] = v[0]; linesAll[i][1] = 0; linesAll[i][2] = v[2]; linesAll[i][3] = res_im->height; } if(showSteps) printf("[%d %d %d %d ]\n",linesAll[i][0],linesAll[i][1],linesAll[i][2],linesAll[i][3]); } //Draw Lines if(showSteps){ for (unsigned int i = 0;i<linesAll.size();i++){ cv::Vec4i v = linesAll[i]; cvLine(res_im,cvPoint(v[0],v[1]),cvPoint(v[2],v[3]),CV_RGB(0,255,255),1,CV_AA); } } std::vector<ptAndAngle> corners;//线的交点存储 for (unsigned int i = 0;i<linesAll.size()-1;i++){ for (unsigned int j=i+1;j<linesAll.size();j++){ //===========线的交点=============/ ptAndAngle pt = computeIntersect(linesAll[i],linesAll[j]); if( (pt.ptf.x >= -10 && pt.ptf.y >=-10) &&(pt.ptf.x<res_im->width+20)&&(pt.ptf.y<res_im->height+20) ) { corners.push_back(pt); } } } vector<cv::Vec4i> (linesAll).swap(linesAll) ; if(showSteps){ for (unsigned int i = 0;i<corners.size();i++){ cout<<corners[i].ptf.x<<" "<<corners[i].ptf.y<<endl; cvCircle(res_im,corners[i].ptf,3,CV_RGB(255,255,0),2); } } std::vector<cv::Point2f> cornersPt; for (unsigned int i = 0;i<corners.size();i++){ cornersPt.push_back(corners[i].ptf); } std::vector<cv::Point2f> approx; cv::approxPolyDP(cv::Mat(cornersPt),approx,cv::arcLength(cv::Mat(cornersPt),true)*0.02,false); if (approx.size()!=4){ std::cout<<"The object is not quadrilateral(四边形)!"<<std::endl; return res_im; } if(showSteps){ //=============画出四边形拟合的顶点结果==================/ for (unsigned int i = 0;i<approx.size();i++){ cvCircle(res_im,approx[i],3,CV_RGB(0,0,255),3); printf("[ %f\t %f ]\n",approx[i].x,approx[i].y); } } std::vector<cv::Point2f> (approx).swap(approx); cv::Point2f center(0,0); //get mass center for (unsigned int i = 0;i < corners.size();i++) { center += cornersPt[i]; } center *=(1./corners.size()); std::vector<ptAndAngle> (corners).swap(corners); if(showSteps) cvCircle(res_im,center,3,CV_RGB(255,255,0),6); //========对四个顶点按照顺序排序=============/ sortCorners(cornersPt,center); std::vector<cv::Point2f> (cornersPt).swap(cornersPt); //==========确定 银行卡的宽高==============/ cv::Mat quad = cv::Mat::zeros(281,442,CV_8UC3);//设定校正过的图片从320*240变为300*220 //corners of the destination image std::vector<cv::Point2f> quad_pts; quad_pts.push_back(cv::Point2f(0,0)); quad_pts.push_back(cv::Point2f(quad.cols,0));//(220,0) quad_pts.push_back(cv::Point2f(quad.cols,quad.rows));//(220,300) quad_pts.push_back(cv::Point2f(0,quad.rows)); std::vector<cv::Point2f> (quad_pts).swap(quad_pts); // Get transformation matrix cv::Mat transmtx = cv::getPerspectiveTransform(cornersPt,quad_pts); //求源坐标系(已畸变的)与目标坐标系的转换矩阵 Mat src(res_im); // Apply perspective transformation透视转换 cv::warpPerspective(src,quad,transmtx,quad.size()); IplImage *dst = cvCreateImage(cvSize(quad.cols,quad.rows),8,res_im->nChannels); uchar *dataDst = (uchar *)(dst->imageData); for( size_t nrow = 0; nrow < quad.rows; nrow++) { for(size_t ncol = 0; ncol < quad.cols; ncol++) { Vec3i bgr = quad.at<Vec3b>(nrow,ncol);//用Vec3b也行 for(size_t k =0; k<quad.channels(); k++){ dataDst[nrow*(dst->widthStep)+ncol*(dst->nChannels)+k] = bgr.val[k]; } } } if(showSteps){ cvNamedWindow("dst1",1); cvShowImage("dst1",dst); cvNamedWindow("Image1",1); cvShowImage("Image1",res_im); cvWaitKey(0); } cvReleaseImage(&res_im); return dst; } //==定义四条边==// vector<cv::Vec4i> lineT; vector<cv::Vec4i> lineB; vector<cv::Vec4i> lineL; vector<cv::Vec4i> lineR; IplImage* res_im; char *vifLine(IplImage * m_im){ IplImage * m_imResize = cvCreateImage(cvSize(444,280),8,m_im->nChannels); cvResize(m_im,m_imResize,CV_INTER_LINEAR); ntuple_list detected_lines; clock_t start,finish; double duration,rate; start = clock(); //lsd函数处理灰度图像,需要进行转换 IplImage* im_gray = cvCreateImage(cvSize(m_imResize->width,m_imResize->height),IPL_DEPTH_8U,1); cvCvtColor(m_imResize,im_gray,CV_BGR2GRAY); image_double image = new_image_double(im_gray->width, im_gray->height); uchar* im_src = (uchar*)im_gray->imageData; int xsize = image->xsize;//宽度 int ysize = image->ysize;//高度 int y,x; for (y = 0;y < ysize;y++) { for (x = 0;x < xsize;x++) //x是横坐标,y是纵坐标 { image->data[y*xsize + x] = im_src[y*im_gray->widthStep + x];//im_gray是灰度图像,没有颜色通道 } } cvReleaseImage(&im_gray); detected_lines = lsd(image);//detected_lines中存储提取直线的首位坐标及宽度,具体意义见说明文档 free_image_double(image); finish = clock(); duration = (double)(finish - start)/CLOCKS_PER_SEC; if(showSteps) cout<<"total time of extract lines is:"<<duration<<endl;//提取所有直线需要的总时间 rate = duration/detected_lines->size; if(showSteps) cout<<"time of extract per line is :"<<rate<<endl;//提取一条直线需要的平均时间 //将检测出的直线绘制在载入的彩色图像上 int dim = detected_lines->dim; res_im = cvCreateImage(cvGetSize(m_imResize),8,m_imResize->nChannels); cvCopy(m_imResize,res_im); cvReleaseImage(&m_imResize); vector<double> angle(detected_lines->size,0); double angletemp; vector<linePtAngle> lineTop;vector<linePtAngle> lineBottom;vector<linePtAngle> lineLeft;vector<linePtAngle> lineRight; for (unsigned int j = 0;j < detected_lines->size;j++) { CvPoint start_pt = cvPoint((int)detected_lines->values[j*dim+0],(int)detected_lines->values[j*dim+1]); CvPoint end_pt = cvPoint((int)detected_lines->values[j*dim+2],(int)detected_lines->values[j*dim+3]); //if(showSteps)//===========画出所有检测到的直线==============/ // cvLine(res_im,start_pt,end_pt,CV_RGB(255,0,0),4,CV_AA); angletemp = (int)(atan((detected_lines->values[j*dim+1]-detected_lines->values[j*dim+3])/(detected_lines->values[j*dim+0]-detected_lines->values[j*dim+2]))*180/3.1416); angle[j] = angletemp; if(showSteps) cout<<"angle "<<j<<" = "<<angle[j]<<endl; //===========根据上下左右四个方向,分别做筛选================/ if(lenghtOf2P(start_pt,end_pt) > 20) //筛选,长度大于30的线 { int tempWidth = 30; //==========确定图片四周,的宽度内做筛选,这个宽度定为50. if(lenghtOf2P(start_pt,end_pt) > 30) //筛选,长度大于30的线 { CvRect rectL; rectL.x = 0; rectL.y = 0; rectL.width = tempWidth; rectL.height = res_im->height; if( ( InRectYesOrNo(start_pt,rectL)&&InRectYesOrNo(end_pt,rectL) )&&((angle[j] < -70) || (angle[j] > 70) ) ){ if(showSteps){ // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineLeft.push_back(temp); } } CvRect rectR; rectR.x = res_im->width - tempWidth; rectR.y = 0; rectR.width = tempWidth; rectR.height = res_im->height; if( ( InRectYesOrNo(start_pt,rectR)&&InRectYesOrNo(end_pt,rectR) )&&((angle[j] < -70) || (angle[j] > 70) ) ){ if(showSteps){ // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineRight.push_back(temp); } CvRect rectT; rectT.x = 0; rectT.y = 0; rectT.width = res_im->width; rectT.height = tempWidth; if( ( InRectYesOrNo(start_pt,rectT)&&InRectYesOrNo(end_pt,rectT) )&&((angle[j] >-20)&&(angle[j] < 20)) ){ if(showSteps){ // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); cout<<"角度为 "<<angle[j]<<" 时,直线序号为 "<<j<<endl; } linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineTop.push_back(temp); } CvRect rectB; rectB.x = 0; rectB.y = res_im->height - tempWidth; rectB.width = res_im->width; rectB.height = tempWidth; if( ( InRectYesOrNo(start_pt,rectB)&&InRectYesOrNo(end_pt,rectB) )&&((angle[j] >-20)&&(angle[j] < 20)) ){ //if(showSteps) // cvLine(res_im,start_pt,end_pt,CV_RGB(j%255,(5*j)%255,(9*j)%255),4,CV_AA); linePtAngle temp; temp.startPt = start_pt; temp.endPt = end_pt; temp.angle = angle[j]; temp.lineLength = lenghtOf2P(start_pt,end_pt); lineBottom.push_back(temp); } } } vector<double>(angle).swap(angle); //==================对 线段进行筛选处理 lineT = chooseLine(res_im,lineTop); lineB = chooseLine(res_im,lineBottom); lineL = chooseLineLR(res_im,lineLeft); lineR = chooseLineLR(res_im,lineRight); vector<linePtAngle> (lineTop).swap(lineTop); vector<linePtAngle> (lineBottom).swap(lineBottom); vector<linePtAngle> (lineLeft).swap(lineLeft); vector<linePtAngle> (lineRight).swap(lineRight); char *vifAllLine; vifAllLine = (char *)malloc(5*sizeof(char)); for(int i=0;i<4;i++){ vifAllLine[i] = '1'; } if((lineT.size()==0)) vifAllLine[0] = '0'; if((lineB.size()==0)) vifAllLine[1] = '0'; if((lineL.size()==0)) vifAllLine[2] = '0'; if((lineR.size()==0)) vifAllLine[3] = '0'; return vifAllLine; } //===先调用vifLine 对 lineT,lineB, lineL, lineR赋值。 IplImage *jiaozheng2(IplImage *res_im){ //============如果四条边没有找全========// if( (lineT.size()==0)||(lineB.size()==0)||(lineL.size()==0)||(lineR.size()==0)){ return res_im; } cv::Vec4i lineTLongest = chooseLongest(lineT); cv::Vec4i lineBLongest = chooseLongest(lineB); cv::Vec4i lineLLongest = chooseLongest(lineL); cv::Vec4i lineRLongest = chooseLongest(lineR); /*vector<cv::Vec4i> (lineT).swap(lineT); vector<cv::Vec4i> (lineB).swap(lineB); vector<cv::Vec4i> (lineL).swap(lineL); vector<cv::Vec4i> (lineR).swap(lineR);*/ lineT.clear(); lineB.clear(); lineL.clear(); lineR.clear(); vector<cv::Vec4i> linesAll ; linesAll.push_back(lineTLongest); linesAll.push_back(lineBLongest); linesAll.push_back(lineLLongest); linesAll.push_back(lineRLongest); //needed for visualization only//这里是将检测的线调整到延长至全屏,即射线的效果,其实可以不必这么做 for (unsigned int i = 0;i<linesAll.size();i++) { cv::Vec4i v = linesAll[i]; linesAll[i][0] = 0; linesAll[i][1] = ((float)v[1] - v[3])/(v[0] - v[2])* -v[0] + v[1]; linesAll[i][2] = res_im->width; linesAll[i][3] = ((float)v[1] - v[3])/(v[0] - v[2])*(res_im->width - v[2]) + v[3]; if(((v[0] - v[2]))==0) { linesAll[i][0] = v[0]; linesAll[i][1] = 0; linesAll[i][2] = v[2]; linesAll[i][3] = res_im->height; } if(showSteps) printf("[%d %d %d %d ]\n",linesAll[i][0],linesAll[i][1],linesAll[i][2],linesAll[i][3]); } //Draw Lines if(showSteps){ for (unsigned int i = 0;i<linesAll.size();i++){ cv::Vec4i v = linesAll[i]; cvLine(res_im,cvPoint(v[0],v[1]),cvPoint(v[2],v[3]),CV_RGB(0,255,255),1,CV_AA); } } std::vector<ptAndAngle> corners;//线的交点存储 for (unsigned int i = 0;i<linesAll.size()-1;i++){ for (unsigned int j=i+1;j<linesAll.size();j++){ //===========线的交点=============/ ptAndAngle pt = computeIntersect(linesAll[i],linesAll[j]); if( (pt.ptf.x >= -10 && pt.ptf.y >=-10) &&(pt.ptf.x<res_im->width+20)&&(pt.ptf.y<res_im->height+20) ) { corners.push_back(pt); } } } vector<cv::Vec4i> (linesAll).swap(linesAll) ; if(showSteps){ for (unsigned int i = 0;i<corners.size();i++){ cout<<corners[i].ptf.x<<" "<<corners[i].ptf.y<<endl; cvCircle(res_im,corners[i].ptf,3,CV_RGB(255,255,0),2); } } std::vector<cv::Point2f> cornersPt; for (unsigned int i = 0;i<corners.size();i++){ cornersPt.push_back(corners[i].ptf); } std::vector<cv::Point2f> approx; cv::approxPolyDP(cv::Mat(cornersPt),approx,cv::arcLength(cv::Mat(cornersPt),true)*0.02,false); if (approx.size()!=4){ std::cout<<"The object is not quadrilateral(四边形)!"<<std::endl; return res_im; } if(showSteps){ //=============画出四边形拟合的顶点结果==================/ for (unsigned int i = 0;i<approx.size();i++){ cvCircle(res_im,approx[i],3,CV_RGB(0,0,255),3); printf("[ %f\t %f ]\n",approx[i].x,approx[i].y); } } std::vector<cv::Point2f> (approx).swap(approx); cv::Point2f center(0,0); //get mass center for (unsigned int i = 0;i < corners.size();i++) { center += cornersPt[i]; } center *=(1./corners.size()); std::vector<ptAndAngle> (corners).swap(corners); if(showSteps) cvCircle(res_im,center,3,CV_RGB(255,255,0),6); //========对四个顶点按照顺序排序=============/ sortCorners(cornersPt,center); std::vector<cv::Point2f> (cornersPt).swap(cornersPt); //==========确定 银行卡的宽高==============/ cv::Mat quad = cv::Mat::zeros(281,442,CV_8UC3);//设定校正过的图片从320*240变为300*220 //corners of the destination image std::vector<cv::Point2f> quad_pts; quad_pts.push_back(cv::Point2f(0,0)); quad_pts.push_back(cv::Point2f(quad.cols,0));//(220,0) quad_pts.push_back(cv::Point2f(quad.cols,quad.rows));//(220,300) quad_pts.push_back(cv::Point2f(0,quad.rows)); std::vector<cv::Point2f> (quad_pts).swap(quad_pts); // Get transformation matrix cv::Mat transmtx = cv::getPerspectiveTransform(cornersPt,quad_pts); //求源坐标系(已畸变的)与目标坐标系的转换矩阵 Mat src(res_im); // Apply perspective transformation透视转换 cv::warpPerspective(src,quad,transmtx,quad.size()); IplImage *dst = cvCreateImage(cvSize(quad.cols,quad.rows),8,res_im->nChannels); uchar *dataDst = (uchar *)(dst->imageData); for( size_t nrow = 0; nrow < quad.rows; nrow++) { for(size_t ncol = 0; ncol < quad.cols; ncol++) { Vec3i bgr = quad.at<Vec3b>(nrow,ncol);//用Vec3b也行 for(size_t k =0; k<quad.channels(); k++){ dataDst[nrow*(dst->widthStep)+ncol*(dst->nChannels)+k] = bgr.val[k]; } } } if(showSteps){ cvNamedWindow("dst1",1); cvShowImage("dst1",dst); cvNamedWindow("Image1",1); cvShowImage("Image1",res_im); cvWaitKey(0); } cvReleaseImage(&res_im); return dst; }
数据结构
#ifndef _JIAOZHENG_H
#define _JIAOZHENG_H
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <cmath>
#include <stdio.h>
#include <time.h>
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <io.h>
#include<math.h>
#define showSteps 0
using namespace std;
extern "C" { #include "lsd.h" };
using namespace cv;
//===========两点,以及两点与x轴的角度,两点之间的距离
struct linePtAngle{
CvPoint startPt;
CvPoint endPt;
double angle;
float lineLength;
};
struct pPoint
{
double x;
double y;
};
struct Line
{
pPoint p1,p2;
double a,b,c;
};
//================定义角度和点================/
struct ptAndAngle
{
double Angle;
Point2f ptf;
};
bool InRectYesOrNo(CvPoint pt,CvRect rect);
float lenghtOf2P(CvPoint pt1,CvPoint pt2);
vector<cv::Vec4i> chooseLine(IplImage* src,vector<linePtAngle> lineTop);
vector<cv::Vec4i> chooseLineLR(IplImage* src,vector<linePtAngle> lineTop);
void GetLinePara(Line &l) ;
pPoint getCrossPoint(Line &l1,Line &l2) ;
double angle(pPoint o,pPoint s,pPoint e) ;
ptAndAngle computeIntersect(cv::Vec4i a,cv::Vec4i b);
void GetMaxAndMin(double *arr , int n , double &max , double &min);
cv::Vec4i chooseLongest(vector<cv::Vec4i> lineT );
void sortCorners(std::vector<cv::Point2f>& corners,cv::Point2f center);
char *vifLine(IplImage * m_im);
IplImage *jiaozheng2(IplImage *res_im);
IplImage * jiaoZheng(IplImage * m_im);
#endif
相关文章推荐
- LSD:一种直线检测算法
- LSD:一种直线检测算法简介
- 基于肤色和眼睛定位的人脸检测算法——MATLAB实现
- LSD 直线检测分割算法
- 基于LSD的直线提取算法
- LSD:一种直线检测算法简介
- 计算机视觉中经常需要识别或者定位某些几何图形,比如直线、圆、椭圆,还有其他一些图形。检测直线的霍夫变换提供了在图像中寻找直线的一种算法,是最简单的一种情形,后来发展到检测圆、椭圆、还有一般图形的霍夫变
- 直线检测算法 LSD 的相关介绍及其在 OpenCV 和 MATLAB 中的可视化
- 基于LSD的直线提取算法
- LSD:一种直线检测算法简介
- 基于LSD的直线提取算法
- LSD:一种直线检测算法简介
- 基于肤色和眼睛定位的人脸检测算法——MATLAB实现【转】
- LSD:一种直线检测算法简介
- LSD:一种直线检测算法简介
- [opencv]中霍夫变换检测直线中pt1、pt2点的确定
- <<一种基于δ函数的图象边缘检测算法>>一文算法的实现。
- 6个流行的直线提取算法——基于2D测距数据(摘自自主移动机器人导论)
- 基于OpenGL的三种直线生成算法
- 基于分离轴定理的二维游戏碰撞检测算法