所用库函数如下:
//拷贝序列中的元素到一个连续的内存块中
void* cvCvtSeqToArray( const CvSeq* seq, void* elements, CvSlice slice=CV_WHOLE_SEQ );
//对给定的一组二维点集作椭圆的最佳拟合(最小二乘意义上的)
回的结构与 cvEllipse 中的意义类似,除了 size 表示椭圆轴的整个长度,而不是一半长度。
void cvFitEllipse( const CvPoint2D32f* points, int count, CvBox2D* box )(绘制时候box的angle要翻转下)
精简的拟合代码如下:
#include<cv.h>
#include<highgui.h>
#include<stdio.h>
#include<malloc.h>
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cxcore.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cvaux.lib")
/********************************************************************************
*
*
* 本程序是精简的最小二乘意义上的椭圆拟合
* 作者:xlh145
* 博客:http://blog.csdn.net/xlh145/
*
*
********************************************************************************/
IplImage * image = NULL;//源图像
IplImage * dst =NULL;//用于输出结果的目标单通道图像
const char* windowname = "椭圆拟合demo";
const char* windowresult = "拟合结果";
int threshold = 70;//阈值
CvPoint *PointArray;//数组点
CvPoint2D32f *PointArray32f;//供椭圆拟合的数组点
CvBox2D* box;//拟合后的存储盒子
void OnTrack(int pos)
{
CvPoint center;//拟合后的椭圆的中心点
CvSize size;//绘制椭圆需要的参数
CvMemStorage* storage=cvCreateMemStorage(0);//存储空间
CvSeq* seq=cvCreateSeq(CV_SEQ_POINT_SET,sizeof(CvSeq),sizeof(CvPoint),storage);//储存轮廓序列
IplImage * temp = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,1); //创建临时图像
cvThreshold(image,temp,threshold,255,CV_THRESH_BINARY);//阈值化
//查找边缘
cvFindContours(temp,storage,&seq,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0));
cvZero(dst); //清空输出图像
for(;seq;seq=seq->h_next)
{
int count = seq->total;//外轮廓的点数
if(count<6) //椭圆拟合必须大于6个点
continue;
PointArray= (CvPoint*)malloc(count*sizeof(CvPoint)); //创建点集的存储空间
PointArray32f = (CvPoint2D32f*)malloc(count*sizeof(CvPoint2D32f)); //创建32f点集的存储空间
box = (CvBox2D*)malloc(sizeof(CvBox2D)); //创建盒子的存储空间
cvCvtSeqToArray(seq,PointArray);//将轮廓点储存到数组中
//将点的存储类型转换为32f
for(int i=0;i<count;i++)
{
PointArray32f[i].x = (float)PointArray[i].x ;
PointArray32f[i].y = (float)PointArray[i].y ;
}
//开始拟合
cvFitEllipse(PointArray32f,count,box);
//在输出图像上绘制轮廓
cvDrawContours(dst,seq,CV_RGB(255,255,255),CV_RGB(255,255,255),0,1,8,cvPoint(0,0));//绘制轮廓
center.x = cvRound(box->center.x);
center.y = cvRound(box->center.y);
size.width = cvRound(box->size.width*0.5);
size.height = cvRound(box->size.height*0.5);
box->angle = -box->angle;//关于Y翻转
//绘制拟合的椭圆
cvEllipse(dst,center,size,box->angle,0,360,CV_RGB(255,0,0));
//释放存储空间
free(PointArray);
free(PointArray32f);
free(box);
}
cvShowImage(windowresult,dst);
}
int main()
{
image = cvLoadImage("stuff.jpg",0);//加载目标函数
dst = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3); //创建目标显示的图像
cvNamedWindow(windowname,1);//创建窗口
cvNamedWindow(windowresult,1);//创建窗口
cvCreateTrackbar("阈值",windowname,&threshold,255,OnTrack);
OnTrack(70);
while(true)
{
cvShowImage(windowname,image);
if(cvWaitKey(0)>=0) break;
}
cvReleaseImage(&image);
cvReleaseImage(&dst);
cvDestroyWindow(windowname);
cvDestroyWindow(windowresult);
return 0;
}