#include "stdafx.h"
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <math.h>
int main()
{
IplImage *img=cvCreateImage(cvSize(500,500),8,3);//开辟500×500的8位3通道的图像内存空间。
CvRNG rng=CvRNG(-1);//产生随机数产生器的状态。
cvNamedWindow("fitline",0);
for (;;)
{
char key;
int i;
int count =cvRandInt(&rng)%100+1;//产生1~100之间的随机整数
int outliers=count/5;//选取1/5数量的点作为outliers。
float a=cvRandReal(&rng)*200;//产生0~1随机浮点数
float b=cvRandReal(&rng)*40;
float angle=cvRandReal(&rng)*CV_PI;//随机产生弧度
float cos_a=cos(angle);
float sin_a=sin(angle);
CvPoint pt1 , pt2;
CvPoint * points=(CvPoint*)malloc(count *sizeof(points[0]));
CvMat pointMat=cvMat(1,count,CV_32SC2,points);
float line[4];
float d,t;
b=MIN(a*0.3,b);
//产生噪声点
for (i=0;i<count-outliers;i++)//被噪声污染的直线上的点
{
float x=(cvRandReal(&rng)*2-1)*a;
float y=(cvRandReal(&rng)*2-1)*b;
points[i].x=cvRound(x*cos_a-y*sin_a+img->width/2);
points[i].y=cvRound(x*cos_a+y*sin_a+img->height/2);
}
for (;i<count;i++)//异常点
{
points[i].x=cvRandInt(&rng) % img->width;
points[i].y=cvRandInt(&rng) % img->height;
}
//拟合直线
cvFitLine(&pointMat,CV_DIST_L1,1,0.001,0.001,line);
cvZero(img);
//画图
for (i=0;i<count;i++)
{
cvCircle(img,points[i],2,(i<count-outliers)?CV_RGB(255,0,0):CV_RGB(255,255,0),
CV_FILLED,CV_AA,0);
}
t=(float)(img->width+img->height);
pt1.x=cvRound(line[2]-line[0]*t);//将直线上的点(line[2],line[3])沿直线移动一段距离
pt1.y=cvRound(line[3]-line[1]*t);//将直线上的点(line[2],line[3])沿直线移动一段距离
pt2.x=cvRound(line[2]+line[0]*t);//将直线上的点(line[2],line[3])沿直线移动一段距离
pt2.y=cvRound(line[3]+line[1]*t);//将直线上的点(line[2],line[3])沿直线移动一段距离
cvLine(img,pt1,pt2,CV_RGB(0,255,0),3,CV_AA,0);
cvShowImage("fitline",img);
key=(char)cvWaitKey(0);
if (key==27||key=='q'||key=='Q')
break;
free(points);
}
cvDestroyWindow("fitline");
cvReleaseImage(&img);
return 0;
}
注意:
(1):(line[0],line[1])不是直线上的点。它表示的是一个与拟合的直线平行的向量。且(line[0]*line[0]+line[1]*line[1]=1),所以直线的倾斜角度=asin(line[1])=acos(line[0])=atg(line[1]/line[0])。
(2):很明显,已知一个直线的方向(即向量)和直线上的一点(line[2],line[3]),当然能唯一确定一条直线。