OpenCV学习笔记9 (Hough线变换)

来源:互联网 发布:如何优化win10系统 编辑:程序博客网 时间:2024/06/15 18:58


1.hough变换调试程序


#include "stdafx.h"#include "cv.h"#include "highgui.h"#include "cxcore.h"int _tmain(int argc, _TCHAR* argv[]){IplImage* src = cvLoadImage("D:\\PERSONAL\\VC++\\2016\\毕业论文\\论文图表文件he文字资料\\模式识别\\picture\\模式1和2处理\\canny\\J11.jpg",CV_LOAD_IMAGE_GRAYSCALE);IplImage* src3 = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,3);//三通道显示CvMemStorage *storage = cvCreateMemStorage();      CvSeq *lines = 0;  cvMerge(src,src,src,NULL,src3);cvNamedWindow("1");cvShowImage("1",src);lines = cvHoughLines2(src,storage,CV_HOUGH_STANDARD,1,CV_PI/180,100,0,0); int i = 0; H: if(i<lines->total){float* line = (float*)cvGetSeqElem(lines,i);float rho = line[0];float theta = line[1];CvPoint pt1, pt2;double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000*(-b));pt1.y = cvRound(y0 + 1000*(a));pt2.x = cvRound(x0 - 1000*(-b));pt2.y = cvRound(y0 - 1000*(a));cvLine( src3, pt1, pt2, CV_RGB(255,0,0), 1, CV_AA, 0 );cvCircle(src3,pt1,5,CV_RGB(0,255,0),2,8,0);cvCircle(src3,pt2,5,CV_RGB(0,255,0),2,8,0);cvShowImage("3",src3);printf("i = %d\n",i);printf("a = %f,b = %f\n",a,b);printf("roh = %f,theta = %f\n",rho,theta);printf("x0 = %f,y0 = %f\n",x0,y0);printf("x1 = %d,y1 = %d\n",pt1.x,pt1.y);printf("x2 = %d,y2 = %d\n",pt2.x,pt2.y);i++;}        char c(0);while (1){cvShowImage("3",src3);c = cvWaitKey(1);if(c == 13)goto H;if(c == 27)break;}cvDestroyWindow("1");cvReleaseImage(&src);return 0;}

//if(theta>2.9 || theta<0.2) //vertical


2.hough提取水平线程序

// deal.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "cv.h"#include "highgui.h"#include "cxcore.h"int _tmain(int argc, _TCHAR* argv[]){IplImage* src = cvLoadImage("D:\\...\\H11.jpg",CV_LOAD_IMAGE_GRAYSCALE);IplImage* src3 = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,3);//三通道显示CvMemStorage *storage = cvCreateMemStorage();      CvSeq *lines = 0;  cvMerge(src,src,src,NULL,src3);cvNamedWindow("1");cvShowImage("1",src);lines = cvHoughLines2(src,storage,CV_HOUGH_STANDARD,1,CV_PI/180,100,0,0);int y_median(0);int temp(0);int n_horizon(0);for(int i = 0; i < MIN(lines->total,100); i++ ){float* line = (float*)cvGetSeqElem(lines,i);float rho = line[0];float theta = line[1];CvPoint pt1, pt2;if(theta>1.3 && theta<1.7){double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000*(-b));pt1.y = cvRound(y0 + 1000*(a));pt2.x = cvRound(x0 - 1000*(-b));pt2.y = cvRound(y0 - 1000*(a));//cvLine( src3, pt1, pt2, CV_RGB(255,0,0), 1, CV_AA, 0 );n_horizon++;y_median += ( (pt1.y + pt2.y)/2 );/*if(y_median!=0)y_median = (temp + y_median)/2;elsey_median = temp;*/}else{double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 1000*(-b));pt1.y = cvRound(y0 + 1000*(a));pt2.x = cvRound(x0 - 1000*(-b));pt2.y = cvRound(y0 - 1000*(a));//cvLine( src3, pt1, pt2, CV_RGB(255,0,0), 1, CV_AA, 0 );}printf("i = %d\n",i);printf("x1 = %d,y1 = %d\n",pt1.x,pt1.y);printf("x2 = %d,y2 = %d\n",pt2.x,pt2.y);}y_median = y_median/n_horizon;cvRectangle(src3,cvPoint(0,y_median+25),cvPoint(640,y_median-25),CV_RGB(0,0,0),CV_FILLED,8,0);    cvShowImage("3",src3);printf("y_median = %d\n",y_median); cvSaveImage("C:\\xiu.jpg",src3);cvWaitKey(0);cvDestroyWindow("1");cvReleaseImage(&src);return 0;}//if(theta>2.9 || theta<0.2) //vertical/**for(int i = 0; i < MIN(lines->total,100); i++ )    {        float* line = (float*)cvGetSeqElem(lines,i);        float rho = line[0];        float theta = line[1];        CvPoint pt1, pt2;        double a = cos(theta), b = sin(theta);        double x0 = a*rho, y0 = b*rho;        pt1.x = cvRound(x0 + 1000*(-b));        pt1.y = cvRound(y0 + 1000*(a));        pt2.x = cvRound(x0 - 1000*(-b));        pt2.y = cvRound(y0 - 1000*(a));        cvLine( src3, pt1, pt2, CV_RGB(255,0,0), 1, CV_AA, 0 );cvShowImage("3",src3);printf("i = %d\n",i);printf("x1 = %d,y1 = %d\n",pt1.x,pt1.y);printf("x2 = %d,y2 = %d\n",pt2.x,pt2.y);}**/



3.直线方程计算

通过测试可以知道,以上代码计算出来的直线,其实是由两个坐标值超出图像显示区域的点连线而成的。

笔者在程序中需要对直线区域进行填充,使用的是cvrectangle(fill),发现在水平和垂直线上填充效果很好,但是斜线往往有蛮大偏差,不能完全覆盖直线区域。最后发现原因就是没有搞清楚以上代码中的pt1、pt2的含义。使用pt3、pt4才是我想要的效果。



所以需要利用pt1、pt2计算出直线的方程,然后推知pt3、pt4的坐标,代码修改如下:

if(theta>1.3 && theta<1.7)   //horizon{  double a = cos(theta), b = sin(theta);  double x0 = a*rho, y0 = b*rho;  pt_1.x = cvRound(x0 + 1000*(-b));  //88pt_1.y = cvRound(y0 + 1000*(a));  pt_2.x = cvRound(x0 - 1000*(-b));  //88pt_2.y = cvRound(y0 - 1000*(a));  double KK;KK = (double)(pt_1.y - pt_2.y)/(double)(pt_1.x - pt_2.x);int yL = cvRound( KK*(0 - pt_2.x) + pt_2.y );int yR = cvRound( KK*(640 - pt_2.x) + pt_2.y );CvPoint pt1;CvPoint pt2;CvPoint pt3;CvPoint pt4;pt1.x = 0;pt1.y = yL - 25;pt2.x = 0;pt2.y = yL + 25;pt3.x = 640;pt3.y = yR + 25;pt4.x = 640;pt4.y = yR - 25;fillArbitaryRectangle(temp,pt1,pt2,pt3,pt4);cvLine( src_original_3, pt_1, pt_2, CV_RGB(160,32,240), 1, CV_AA, 0 ); }if(theta>2.9 || theta<0.2) //vertical{  double a = cos(theta), b = sin(theta);  double x0 = a*rho, y0 = b*rho;  pt_1.x = cvRound(x0 + 1000*(-b));  pt_1.y = cvRound(y0 + 1000*(a));  //888pt_2.x = cvRound(x0 - 1000*(-b));  pt_2.y = cvRound(y0 - 1000*(a));  //888double KK;KK = (double)(pt_1.x - pt_2.x)/(double)(pt_1.y - pt_2.y);int xT = cvRound( KK*(0 - pt_2.y) + pt_2.x );int xB = cvRound( KK*(480 - pt_2.y) + pt_2.x );CvPoint pt1;CvPoint pt2;CvPoint pt3;CvPoint pt4;pt1.x = xT - 25;pt1.y = 0;pt2.x = xT + 25;pt2.y = 0;pt3.x = xB + 25;pt3.y = 480;pt4.x = xB - 25;pt4.y = 480;fillArbitaryRectangle(temp,cvPoint(0,0),cvPoint(0,480),pt4,pt1);fillArbitaryRectangle(temp,pt2,pt3,cvPoint(640,480),cvPoint(640,0));cvLine( src_original_3, pt_1, pt_2, CV_RGB(160,32,240), 1, CV_AA, 0 ); }}

其中的填充函数fillArbitaryRectangle如下:

//src 3 channels and will be filledvoid CALEXDlg::fillArbitaryRectangle(IplImage* src,CvPoint pt1,CvPoint pt2,CvPoint pt3,CvPoint pt4){int arr[1];  arr[0] = 4;  CvPoint ** pt = new CvPoint*[1];  pt[0] = new CvPoint[4];  pt[0][0] = pt1;  pt[0][1] = pt2;  pt[0][2] = pt3;  pt[0][3] = pt4;  cvPolyLine( src_original_hough, pt, arr, 1, 1, CV_RGB(255,97,0));  cvFillPoly(src,pt,arr,1,CV_RGB(0,0,0)); }







0 0