opencv中的椭圆拟合

------------------------------------2014年4月26日编辑--------------------

   opencv中的椭圆拟合函数是:

  C++: fitEllipse

  C  : cvFitEllipse2

   函数原型:

   C++: RotatedRect fitEllipse(InputArray points)

   C  : CvBox2D cvFitEllipse2(const CvArr* points)

   对应C++接口,fitEllipse的输入2维点集可以以std::vector<> or Mat形式存储。函数的返回是RotatedRect 类型,它具有3个成员变量:

   center(块中心(x,y)), size(宽和高), angle(旋转角),刚好与椭圆具备的5个参数[a,b,x,y,w,h]吻合

   类RotatedRect的原型声明:

   

class CV_EXPORTS RotatedRect
{
public:
    //! various constructors
    RotatedRect();
    RotatedRect(const Point2f& center, const Size2f& size, float angle);
    RotatedRect(const CvBox2D& box);

    //! returns 4 vertices of the rectangle
    void points(Point2f pts[]) const;
    //! returns the minimal up-right rectangle containing the rotated rectangle
    Rect boundingRect() const;
    //! conversion to the old-style CvBox2D structure
    operator CvBox2D() const;

    Point2f center; //< the rectangle mass center
    Size2f size;    //< width and height of the rectangle
    float angle;    //< the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle.
};

    3个成员变量:center(块中心(x,y)), size(宽和高), angle(旋转角: 水平轴和第一边的角);3个构造函数

    另外,这里还需要提一下,结构体类型CvBox2D ,它原型如下:

typedef struct CvBox2D
{
    CvPoint2D32f center;  /* Center of the box.                          */
    CvSize2D32f  size;    /* Box width and length.                       */
    float angle;          /* Angle between the horizontal axis           */
                          /* and the first side (i.e. length) in degrees */
}
CvBox2D;

   这个结构体,有3个成员:center(块中心(x,y)); size(长宽); angle:旋转角。矩阵是直立的(upright),下面的图是来自《learning OpenCV》 P268


   OpenCV在绘制椭圆的时候,有以下函数:

C++: void ellipse(Mat& img, Point center, Size axes, double angle, double startAngle, doubleendAngle, const Scalar& color, int thickness=1, int lineType=8, int shift=0)
C++: void ellipse(Mat& img, const RotatedRect& box, const Scalar& color, int thickness=1, intlineType=8)
C: void cvEllipse(CvArr* img, CvPoint center, CvSize axes, double angle, double startAngle, double endAngle, CvScalar color, int thickness=1, int lineType=8, int shift=0 )
C: void cvEllipseBox(CvArr* img, CvBox2D box, CvScalar color, int thickness=1, intlineType=8, int shift=0 )


  OpenCV中的椭圆拟合事实上就是对Fitzgibbon提出的直接最小二乘拟合算法的实现,这是一种非迭代的椭圆拟合算法,可以参考论文:《Direct least square fitting of ellipses》,它要求拟合的点至少为6个点。


   下面是Opencv安装文件下的一个实例:opencv_source_code/samples/cpp/fitellipse.cpp

// opencv学习笔记-椭圆拟合.cpp : 定义控制台应用程序的入口点。
//

/*
*功能:椭圆拟合
*时间:2014-04-19
*/

#include "stdafx.h"


#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;

int sliderPos = 70;
Mat image;

//函数声明
void processImage(int, void*);

int main( int argc, char** argv )
{
    const char* filename = "stuff.jpg";
	//读取图像
    image = imread(filename, 0);
    if( image.empty() )
    {
        cout << "Couldn't open image " << endl;
        return 0;
    }

    imshow("source", image);
    namedWindow("result", 1);

    // Create toolbars. HighGUI use.
	// 创建一个滑动块
    createTrackbar( "threshold", "result", &sliderPos, 255, processImage );
    processImage(0, 0);

    // Wait for a key stroke; the same function arranges events processing
    waitKey();
    return 0;

}

// Define trackbar callback functon. This function find contours,
// draw it and approximate it by ellipses.
void processImage(int /*h*/, void*)
{
    vector<vector<Point> > contours;
	//这句相当于二值化。这个matlab的那句好像: Iwt = Iw>=threshold;
    Mat bimage = image >= sliderPos;
	//Mat bimage;
	//threshold(image, bimage, sliderPos, 255,CV_THRESH_BINARY);

	//提取轮廓,相当于matlab中连通区域分析
    findContours(bimage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

	//我们将在cimage上面绘图
    Mat cimage = Mat::zeros(bimage.size(), CV_8UC3);

    for(size_t i = 0; i < contours.size(); i++)
    {
		//轮廓的边缘点个数
        size_t count = contours[i].size();
		//Fitzgibbon的椭圆拟合方法,要求至少6个点,文献:Direct Least Squares Fitting of Ellipses[1999]
        if( count < 6 )
            continue;

        Mat pointsf;
		//将轮廓中的点转换为以Mat形式存储的2维点集(x,y)
        Mat(contours[i]).convertTo(pointsf, CV_32F);

		//最小二次拟合(Fitzgibbon的方法)
		//box包含了椭圆的5个参数:(x,y,w,h,theta)
        RotatedRect box = fitEllipse(pointsf);

		//把那些长轴与短轴之比很多的那些椭圆剔除。
        if( MAX(box.size.width, box.size.height) > MIN(box.size.width, box.size.height)*8 )
            continue;
		//绘制轮廓
        drawContours(cimage, contours, (int)i, Scalar::all(255), 1, 8);

		//绘制椭圆
        ellipse(cimage, box, Scalar(0,0,255), 1, CV_AA);
		//绘制椭圆
       // ellipse(cimage, box.center, box.size*0.5f, box.angle, 0, 360, Scalar(0,255,255), 1, CV_AA);

		//绘制矩形框
        Point2f vtx[4];
		//成员函数points 返回 4个矩形的顶点(x,y)
        box.points(vtx);
        for( int j = 0; j < 4; j++ )
            line(cimage, vtx[j], vtx[(j+1)%4], Scalar(0,255,0), 1, CV_AA);
    }

    imshow("result", cimage);
}




参考:

1.opencv官方文档 fitellipse

2.opencv官方文档 RotatedRect 

3.opencv官方文档 ellipse

1.http://blog.sina.com.cn/s/blog_662c785901011i7z.html

2.http://hi.baidu.com/zsb517/item/fd12932d2a82bf0842634a10

3.http://www.cnblogs.com/slysky/archive/2011/10/14/2212227.html

展开阅读全文

没有更多推荐了,返回首页