这个系列的目的是通过对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运行截图
原图 | 效果图 | 参数 |
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++)
注意:
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的角度疑云 》