在opencv学习中,圆和椭圆的拟合是必不可少的,下面我就用一个简单的例子介绍一下我们如何用opencv来拟合。
实验描述:
输入:图像文件seal1.jpg、seal2.jpg、coin1.jpg
任务: 尝试将上述三个图像中圆或椭圆信息提取出来
输出要求 1、拟合相应的圆以及椭圆
2. 每个拟合圆或椭圆的中心坐标,半径或长短轴长度;
3. 将主要的中间结果及最终拟合结果用OpenCV的cvShowImage显示出来。
编程工具:Visual C++/Visual Studio,OpenCV
提示(可能用到的处理方法,不一定全部用到):二值化
形态学操作
Canny边缘检测
轮廓提取
椭圆拟合
Hough圆检测
好了,废话不多说,还是直接上代码吧,其中的注释已经写得非常详细了,大家应该看了就能懂了
程序说明:本程序首先读取图像和图像预处理,将读入的图像转换为灰度图,在对它进行二值化,接着抽取图像中对象的轮廓属性,然后进行图像拟合,最后输出结果。在这里,主要输出拟合后的图像,原来读入的图像,方便人对前后结果进行比较,还输出了每个拟合圆或椭圆的中心坐标,半径或长短轴长度,用数字来说话,一目了然。最后记得释放资源销毁窗口。
#include "stdafx.h"
#include
#include
#include
#include
#include
int main( int argc, char** argv )
{
/****************1.读取图像和图像预处理****************/
argv[1]="seal1.jpg"; /*读入图像,分别输入seal1,seal2和coin1,并更改下列两处参数值*/
IplImage* image = cvLoadImage(argv[1]);
IplImage* gray;/*保存灰度图*/
IplImage* result;/*保存结果*/
gray=cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1); /*创建输出图像,位无符号深度,通道*/
result=cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1); /*创建输出图像,位无符号深度,通道*/
cvZero(result);
CvMemStorage* storage=cvCreateMemStorage(0);
CvSeq *contour;
int count;
CvPoint *PointArray;
CvPoint center;
CvPoint2D32f *PointArray2D32f;
/* 创建动态结构序列*/
storage = cvCreateMemStorage(0);
contour = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),storage);
CvBox2D *box;
CvSize size;
/****************2.将图像转换为二值图像****************/
cvCvtColor(image,gray,CV_BGR2GRAY); /*把image转换成灰度放到gray中*/
cvSmooth(gray,gray);
cvThreshold( gray, gray, 195, 255, CV_THRESH_BINARY ); /*将灰度图像二值化,需要针对输入图像进行调整,seal1时对应(195, 255),seal2时对应(190, 255),coin1时对应(70, 200)*/
/****************3.抽取图像中对象的轮廓属性****************/
cvFindContours( gray, storage, &contour, sizeof(CvContour),CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); /*找轮廓*/
/*遍历每个轮廓*/
for(;contour;contour=contour->h_next){
count=contour->total;
if(count<250) /*去掉轮廓小于一定数值的圆,要根据输入图像进行调整,seal1时对应250,seal2时对应160,coin1时对应75*/
continue;
// Alloc memory for contour point set.
PointArray = (CvPoint*)malloc( count*sizeof(CvPoint) );
PointArray2D32f= (CvPoint2D32f*)malloc( count*sizeof(CvPoint2D32f) );
// Alloc memory for ellipse data.
box = (CvBox2D32f*)malloc(sizeof(CvBox2D32f));
/*格式转化,contour -- PointArray -- PointArray2D32f*/
cvCvtSeqToArray(contour, PointArray, CV_WHOLE_SEQ);
for(int i=0;icenter.x); /*确定椭圆box的值center、size、angle*/
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;
cvDrawContours(gray,contour,CV_RGB(255,255,255),CV_RGB(255,255,255),0,1,8,cvPoint(0,0)); /*画轮廓*/
cvEllipse(result,center,size,box->angle,0,360,CV_RGB(0,0,255),1,CV_AA,0); /*画椭圆到result*/
/****************5.输出结果*********************/
printf("中心位置:x=%d,y=%d\n",center.x,center.y); /*输出中心位置*/
printf("半径或长短轴长度:w=%d,h=%d\n",size.width,size.height); /*输出半径或长短轴长度*/
printf("---------------------------------------------------------------------\n");/*不同圆或椭圆数据输出分割线*/
/*释放空间*/
free(PointArray);
free(PointArray2D32f);
free(box);
}
/*图像输出*/
cvNamedWindow("原图",1);
cvShowImage("原图",image);
cvSaveImage( "拟合.jpg", result );/*将图片保存到本地*/
cvNamedWindow( "拟合", 1 );/*窗口命名*/
cvShowImage( "拟合", result );/*显示图片*/
// Wait for a key stroke; the same function arranges events processing
cvWaitKey(0);
cvReleaseImage(&image);//释放图片资源
cvReleaseImage(&result);
cvDestroyWindow("原图");//销毁窗口
cvDestroyWindow("拟合");
return 0;
}
seal1图片处理后结果:
相关数据输出: