OpenCV3.0 Examples学习笔记(9)-fitellipse.cpp-fitEllipse函数实现椭圆拟合

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

目录
简介
Example运行截图
Example分析
Example代码

简介
本文记录了对OpenCV示例 fitellipse .cpp 的分析。
资料地址: http://docs.opencv.org/3.0.0/de/dc7/fitellipse_8cpp-example.html

这个示例主要演示了如何使用 fitEllipse函数 将二维点集合拟合为椭圆。

示例涉及到
findContours, convertTo, fitEllipse, drawContours, ellipse, RotatedRect等函数的使用。
其中
(1)如果需要了解 findContours,drawContours,可以转至 OpenCV3.0 Examples学习笔记(1)-contours2.cpp
(2)如果需要了解 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运行截图
原图
效果图
参数
sliderPos = 70

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++)

注意:
(1) 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);
}



参考资料:
2.《 fitEllipse函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值