opencv 椭圆拟合

#include "cv.h"  
#include "highgui.h"  
#include <iostream>
using namespace std;
int slider_pos=23;//阈值  

IplImage *image02 =0,*image03 = 0,*image04 = 0;  
void process_image(int h);  
 
int main(int argc ,char **argv)  
{  
    const char *filename ="D:\\test\\18.jpg";  
	cout<<slider_pos<<" ";
    if ((image03 = cvLoadImage(filename,0))==0)//读入图像为灰度图像  
    {  
        return -1;  
    }  
    image02 = cvCloneImage(image03);  
   image04 = cvCloneImage(image03);  
      
    cvNamedWindow("Source",1);  
   cvNamedWindow("Result",1);  
  
    cvShowImage("Source",image03);  
  
    cvCreateTrackbar("Threshold","Result",&slider_pos,255,process_image);  
 
    process_image(0);  
  
    cvWaitKey(0);  
    cvSaveImage("1.jpg",image04);  
  
    cvReleaseImage(&image02);  
    cvReleaseImage(&image03);  
  
   cvDestroyWindow("Source");  
    cvDestroyWindow("Result");  
   return 0;  
 
}  

// 删除小面积图形
IplImage* bwareaopen(IplImage *img, int areaThreshold)
{	
	CvSeq* contour = NULL;      
    double tmparea = 0.0;   
    CvMemStorage* storage = cvCreateMemStorage(0);   
       
    // IplImage* img= cvLoadImage(dlg.GetPathName(),CV_LOAD_IMAGE_ANYCOLOR);   
    IplImage* img_Clone=cvCloneImage(img);   
    // 访问二值图像每个点的值   
    uchar *pp;    
       
    //------------搜索二值图中的轮廓,并从轮廓树中删除面积小于某个阈值minarea的轮廓-------------//   
    CvScalar color = cvScalar(255,0,0);//CV_RGB(128,0,0);   
    CvContourScanner scanner = NULL;   
    scanner = cvStartFindContours(img,storage,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0));   
    // 开始遍历轮廓树   
    CvRect rect;   
    while (contour=cvFindNextContour(scanner))   
    {   
        tmparea = fabs(cvContourArea(contour));   
            rect = cvBoundingRect(contour,0);      
        if (tmparea < areaThreshold)   
        {   
			// 当连通域的中心点为黑色时,而且面积较小则用白色进行填充   
            pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*(rect.y+rect.height/2)+rect.x+rect.width/2);   
            if (pp[0]==255)   
            {   
                for(int y = rect.y;y<rect.y+rect.height;y++)   
                {   
                    for(int x =rect.x;x<rect.x+rect.width;x++)   
                    {   
                        pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*y+x);   
                           
                        if (pp[0]==255)   
                        {   
                            pp[0]=0;   
                        }   
                    }   
                }   
            }         
		} 
	}
	return img_Clone;
}

// 对图像进行闭操作
IplImage* imclose(IplImage* img)
{
	// 创建5*5结构元素等同于strel('disk',2)的效果
	int mask[25]={0, 0, 1, 0, 0,
	              0, 1, 1, 1, 0,
	              1, 1, 1, 1, 1,
	              0, 1, 1, 1, 0,
	              0, 0, 1, 0, 0};
	IplConvKernel* element=cvCreateStructuringElementEx( 5, 5, 0, 0,CV_SHAPE_CUSTOM, mask);
    // 先膨胀
	cvDilate(img,img,element,1);
	// 后腐蚀
	cvErode(img,img,element,1);
	return img;
}

// 对图像空洞进行填充
IplImage* imfill(IplImage* img)
{
    CvScalar white = CV_RGB( 255, 255, 255 );

    IplImage* dst = cvCreateImage( cvGetSize(img), 8, 3);
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* contour = 0;

    cvFindContours(img, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
    cvZero( dst );

    for( ; contour != 0; contour = contour->h_next )
    {
        cvDrawContours( dst, contour, white, white, 0, CV_FILLED);
    }

    IplImage* bin_imgFilled = cvCreateImage(cvGetSize(img), 8, 1);
    cvInRangeS(dst, white, white, bin_imgFilled);

    return bin_imgFilled;
}

//这个函数寻找出轮廓、用椭圆拟合画出  
void process_image(int h)  
{  
    CvMemStorage *stor;  
    CvSeq *cont;  
    CvBox2D32f *box;  
    CvPoint *PointArray;  
   CvPoint2D32f *PointArray2D32f;  
  
    stor = cvCreateMemStorage(0);  
    cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor);  
  
    cvThreshold(image03,image02,slider_pos,255,CV_THRESH_BINARY);  
    
	// 删除小面积
	bwareaopen(image02,100);
	// 闭操作
    imclose(image02);
	// 填充
	imfill(image02);

    cvFindContours(image02,stor,&cont,sizeof(CvContour),  
        CV_RETR_LIST,CV_CHAIN_APPROX_NONE,cvPoint(0,0));  
  
   cvZero(image02);  
    cvZero(image04);  
  
    //绘制所有轮廓并用椭圆拟合  
   for (;cont;cont = cont ->h_next)  
    {  
        int i;  
        int count= cont->total;//轮廓个数  
        CvPoint center;  
       CvSize size;  
  
        /*个数必须大于6,这是cvFitEllipse_32f的要求*/  
        if (count<6)  
       {  
            continue;  
        }  
        //分配内存给点集  
        PointArray = (CvPoint *)malloc(count*sizeof(CvPoint));  
       PointArray2D32f = (CvPoint2D32f*)malloc(count*sizeof(CvPoint2D32f));  
      
      //分配内存给椭圆数据  
        box = (CvBox2D32f *)malloc(sizeof(CvBox2D32f));  
  
        //得到点集(这个方法值得借鉴)  
       cvCvtSeqToArray(cont,PointArray,CV_WHOLE_SEQ);  
      
       //将CvPoint点集转化为CvBox2D32f集合  
        for (i=0;i<count;i++)  
        {  
           PointArray2D32f[i].x=(float)PointArray[i].x;  
            PointArray2D32f[i].y=(float)PointArray[i].y;  
       }  
 
       //拟合当前轮廓  
        cvFitEllipse(PointArray2D32f,count,box);  
		double c=sqrt((box->size.height)*(box->size.height)/4-(box->size.width)*(box->size.width)/4);
		double lxl=2*c/box->size.height;
		if(box->size.height>50 || box->size.width>50){
		cout<<"离心率:"<<lxl<<" ";
		std::cout<<box->size.height<<" ";
		std::cout<<box->size.width<<" ";
		std::cout<<box->size.height/box->size.width<<endl;}
       //绘制当前轮廓  
      cvDrawContours(image04,cont,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;  
  
        //画椭圆  
       cvEllipse(image04,center,size,box->angle,0,360,CV_RGB(0,0,255),1,CV_AA,0);  
  
       free(PointArray);  
       free(PointArray2D32f);  
       free(box);  
    }  
    cvShowImage("Result",image04);  
} 



 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值