这个系列的目的是通过对OpenCV示例,进一步了解OpenCV函数的使用,不涉及具体原理。





目录



简介



Example运行截图



Example分析



Example代码





简介


本文记录了对OpenCV示例 fitellipse .cpp 的分析。

资料地址: http://docs.opencv.org/3.0.0/de/dc7/fitellipse_8cpp-example.html






fitEllipse函数 将二维点集合拟合为椭圆。





示例涉及到



convertTo, fitEllipse, drawContours, ellipse, RotatedRect等函数的使用。



其中



findContours,drawContours,可以转至 OpenCV3.0 Examples学习笔记(1)-contours2.cpp



convertTo,可以转至 OpenCV3.0 Examples学习笔记(4)-demhist.cpp


(3)fitEllipse,ellipse函数定义如下:



fitEllipse




将二维点集合拟合为椭圆。





函数原型:




RotatedRect fitEllipse( InputArray points );






参数说明:



points :可采用vector<Point>二维点集合



                或者使用输入Mat对象,测试证明需使用 CV_32F类型,一般可以将检测出的单个轮廓



                转换为M at后使用,如




                 Mat(contours[i]).convertTo(pointsf, CV_32F);



                 RotatedRect box = fitEllipse(pointsf);







返回值说明:



RotatedRect :包含 中心center、大小size以及角度angle信息。







ellipse



绘制椭圆形状。





函数原型:



ellipse由两个函数原型




void ellipse(InputOutputArray img, const RotatedRect& box, const Scalar& color,



                        int thickness = 1, int lineType = LINE_8);







void ellipse(InputOutputArray img, Point center, Size axes,



                        double angle, double startAngle, double endAngle,



                        const Scalar& color, int thickness = 1,



                        int lineType = LINE_8, int shift = 0);






参数说明:



InputOutputArray  img:需要绘制的目标图像;



const RotatedRect& box:代表椭圆区域的RotatedRect对象;



const Scalar& color:颜色;



int thickness = 1:线的粗细(-1为实心);



int lineType = LINE_8:线的类型;






Point center:椭圆圆心;



Size axes:轴长;



double angle:圆的偏移角度;



double startAngle:圆弧起始角度;



double endAngle:圆弧终止角度;



 int shift:圆心坐标和轴长的进度,默认都取0。






PS:显然,第二个原型更加灵活,通过设置startAngle,endAngle可以绘制出椭圆的一部分






Example运行截图



原图

效果图

参数



opencv python拟合平面 opencv拟合椭圆_opencv



opencv python拟合平面 opencv拟合椭圆_opencv_02


sliderPos = 70





opencv python拟合平面 opencv拟合椭圆_opencv python拟合平面_03

sliderPos = 90

Example分析

1.声明代码所需的变量和图像处理函数

int sliderPos = 70;

Mat image;

void processImage(int, void*);



2.从命令行参数中加载图像并显示


const char* filename = argc == 2 ? argv[1] : (char*)"../data/stuff.jpg"; 
 
 
 

       image = imread(filename, 0); 
 
 
 

       if( image.empty() ) 
 
 
 

       { 
 
 
 

           cout << "Couldn't open image " << filename << "\nUsage: fitellipse <image_name>\n"; 
 
 
 

           return 0; 
 
 
 

       } 
 
 
 
 
  
 
 

       imshow("source", image);

3.声明处理图像预览窗口

    namedWindow("result", 1);

4.创建滑动条,设置 sliderPos 阈值 , 并使用 processImage作为图像处理函数

createTrackbar( "threshold", "result", &sliderPos, 255, processImage );

5.逐步分析processImage函数

5.1声明存储轮廓的集合

vector<vector<Point> > contours;

5.2根据阈值对图像进行二值化操作

Mat bimage = image >= sliderPos;

5.3获取轮廓

findContours(bimage, contours, RETR_LIST, CHAIN_APPROX_NONE);

5.4创建目标图像用于显示结果

Mat cimage = Mat::zeros(bimage.size(), CV_8UC3);

注意:

(1)背景为黑色

5.5遍历轮廓

for(size_t i = 0; i < contours.size(); i++)

注意:

size_t 定义如下

#ifdef  _WIN64

typedef unsigned __int64    size_t;

#else

typedef _W64 unsigned int   size_t;

#endif

5.6判断轮廓中包含的点的数量,如果小于6则没有讨论意义

size_t count = contours[i].size();

        if( count < 6 )

            continue;

5.7将轮廓转换为32F的Mat

Mat pointsf;

        Mat(contours[i]).convertTo(pointsf, CV_32F);

5.8调用fitEllipse对点集合进行椭圆拟合

RotatedRect box = fitEllipse(pointsf);

注意

    (1)虽然此处采用32F的Mat,但实际使用vector<Point>也可以

5.9对拟合出的椭圆进行尺寸过滤

if( MAX(box.size.width, box.size.height) > MIN(box.size.width, box.size.height)*30 )

            continue;

5.10绘制轮廓

drawContours(cimage, contours, (int)i, Scalar::all(255), 1, 8);

5.11使用两种方式绘制椭圆

ellipse(cimage, box, Scalar(0,0,255), 1, LINE_AA);

ellipse(cimage, box.center, box.size*0.5f, box.angle, 0, 360, Scalar(0,255,255), 1, LINE_AA);

注意:

(1)因为绘制的是同一个椭圆,因此第一次用红色绘制的椭圆是看不到的。

5.12绘制RotatedRect 的边缘

Point2f vtx[4];

        box.points(vtx);

        for( int j = 0; j < 4; j++ )

            line(cimage, vtx[j], vtx[(j+1)%4], Scalar(0,255,0), 1, LINE_AA);


Example代码

/********************************************************************************
*
*
*  This program is demonstration for ellipse fitting. Program finds
*  contours and approximate it by ellipses.
*
*  Trackbar specify threshold parametr.
*
*  White lines is contours. Red lines is fitting ellipses.
*
*
*  Autor:  Denis Burenkov.
*
*
*
********************************************************************************/
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;

// static void help()
// {
//     cout <<
//             "\nThis program is demonstration for ellipse fitting. The program finds\n"
//             "contours and approximate it by ellipses.\n"
//             "Call:\n"
//             "./fitellipse [image_name -- Default ../data/stuff.jpg]\n" << endl;
// }

int sliderPos = 70;

Mat image;

void processImage(int, void*);

int main( int argc, char** argv )
{
    const char* filename = argc == 2 ? argv[1] : (char*)"../data/stuff.jpg";
    image = imread(filename, 0);
    if( image.empty() )
    {
        cout << "Couldn't open image " << filename << "\nUsage: fitellipse <image_name>\n";
        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;
    Mat bimage = image >= sliderPos;

    findContours(bimage, contours, RETR_LIST, CHAIN_APPROX_NONE);

    Mat cimage = Mat::zeros(bimage.size(), CV_8UC3);

    for(size_t i = 0; i < contours.size(); i++)
    {
        size_t count = contours[i].size();
        if( count < 6 )
            continue;

        Mat pointsf;
        Mat(contours[i]).convertTo(pointsf, CV_32F);
        RotatedRect box = fitEllipse(pointsf);

        if( MAX(box.size.width, box.size.height) > MIN(box.size.width, box.size.height)*30 )
            continue;
        drawContours(cimage, contours, (int)i, Scalar::all(255), 1, 8);

        ellipse(cimage, box, Scalar(0,0,255), 1, LINE_AA);
        ellipse(cimage, box.center, box.size*0.5f, box.angle, 0, 360, Scalar(0,255,255), 1, LINE_AA);
        Point2f vtx[4];
        box.points(vtx);
        for( int j = 0; j < 4; j++ )
            line(cimage, vtx[j], vtx[(j+1)%4], Scalar(0,255,0), 1, LINE_AA);
    }

    imshow("result", cimage);
}


参考资料:


OpenCV3.0 Examples学习笔记(1)-contours2.cpp


2.《 fitEllipse函数


3.《 opencv学习笔记:RotatedRect和CvBox2D的角度疑云


Opencv的Ellipse函数