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;
else
y_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)); //88
pt_1.y = cvRound(y0 + 1000*(a));
pt_2.x = cvRound(x0 - 1000*(-b)); //88
pt_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)); //888
pt_2.x = cvRound(x0 - 1000*(-b));
pt_2.y = cvRound(y0 - 1000*(a)); //888
double 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 filled
void 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));
}