当我们绘制一个多边形或进行形状分析时,通常需要使用多边形逼近一个轮廓,使顶点数变少。Opencv实现了其中两种逼近方法:
1.函数CV::approxPolyDP()进行多边形逼近
void cv::approxPolyDP(
cv::InputArray curve, //Array or vector of 2-dimensional points
cv::outputArray approxCurve, //Result ,type is same as ‘curve’
double epsilon, //max distance from ‘curve’ to ‘approxCurve’
bool closed //if true, assume link from last to first vertex
参数epsilon是要求的逼近准确度。含义是,你允许在原多边形和最终拟合的多边形之间存在的最大偏差。最后一个参数closed 指明curve中的一些列点是否是一个闭合的多边形。若设为true,则认为曲线是闭合的。
这个函数基于Douglas-Peucker algorithm(道格拉斯-普克算法).该算法首先从轮廓中挑出两个最远的点,将两点相连,然后在原来的轮廓上寻找一个离线段距离最远的点,将该点加入逼近后的新轮廓中.算法反复迭代,不断将最远的点添加到结果中,直到所有点到多边形的最短小于parameter参数指定的精度。从这里可以看出,将精度设置为为轮廓周长或外包矩形周长 等表示轮廓总长度的值的几分之一比较合适。
(其它常用的方法包括Rosenfeld-Johnson算法和Teh-Chin算法,Teh-Chin算法在Opencv中并不用于缩减顶点,而是在提取多边形时使用,见cv::findContours())
轮廓处理中经常遇到的另一个任务是计算一些轮廓变化的概括特性。这可能包括长度或其它一些反映轮廓整体大小的量度 arcLength()函数。
基于了解了通过阈值分割提取图像中的目标物体、通过边缘检测提取目标物体的轮廓,使用这两种方法基本能够确定物体的边缘或者前景。接下来,我们通常需要做的是拟合这些边缘和前景,如确定边缘是否满足某种几何形状,如直线、圆、椭圆等,或者拟合出包含前景或者边缘像素点的最小外包矩形、圆、凸包等几何形状,为计算它们的面积或者模版匹配等操作打下坚实的基础。
点集是指坐标点的集。已知二维笛卡尔坐标系中的很多坐标点,需要直到包围这些坐标点的最小外包四边形或者圆,在这里最小指的是最小面积。
1.最小外包直立矩形:
Rect boundingRect(InputArray points)
来实现点集的最小外包直立(up-right)矩形
2.最小外包旋转矩形
需要三个要素确定一个旋转矩形,它们是中心坐标尺寸、(宽、高)和旋转角度。
RotatedRect minAreaRect(InputArray points)
旋转矩形4个顶点
void boxPoints(RotatedRect box, OutputArray points)
3.最小外包圆
点集的最小外包圆
minEnclosingCircle(InputArray points,Point2f& center, float& radius)
4.最小凸包
给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中的所有点。
void convexHull(InputArray points,OututArray hull,bool clockwise=false,bool returnPoints=true)
points:输入点集是Vector或者Mat类型
hull:构成凸包的点,类型为vector、vector
clockwise:hull中的点是按顺时针还是逆时针排列的
returnPoints:值为true时,hull存储的是坐标点;值为false时,存储的是这些坐标点的点集中的索引。
利用该函数求出的凸包,坐标点的顺序不是随机排列的,而是按照某顺序排列的。
5.最小外包三角形
求点集的最小外包三角形
double minEnclosingTriangle(InputArray points,CV_OUT OutputArray triangle)
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <math.h>
#include "deque"
#include "algorithm"
#include "stack"
#include "queue"
#include "list"
#include "set"
using namespace cv;
using namespace std;
int main()
{
//奌集
Mat points = (Mat_<float>(5, 2) << 1, 1, 5, 1, 1, 10, 5, 10, 2, 5);
//Mat points = (Mat_<Vec2f>(5, 1) << Vec2f(1, 1), Vec2f(5, 1), Vec2f(1, 10), Vec2f(5, 10), Vec2f(2, 5));
//最小外包直立矩形
Rect rect = boundingRect(points);
cout << "最小外包直立矩形:" << rect << endl;
//最小外包旋转矩形
RotatedRect rRect = minAreaRect(points);
cout << "旋转矩形的角度:" << rRect.angle << endl;
cout << "旋转矩形的中心:" << rRect.center << endl;
cout << "旋转矩形的尺寸:" << rRect.size << endl;
//计算点集的最小外包旋转矩形
Point2f center;
float radius;
minEnclosingCircle(points, center, radius);
cout << "圆心::" << center << endl;
cout << "半径" << radius << endl;
//凸多边形
vector<Point2f> hull;
convexHull(points, hull);
for (int i = 0; i < hull.size(); i++)
{
cout << hull[i] << ",";
}
//最小外包三角形
vector<Point> triangle;
double area = minEnclosingTriangle(points, triangle);
cout << "三角形的三个顶点:";
for (int i = 0; i < 3; i++)
{
cout << triangle[i] << ",";
}
cout << "最小外包三角形的面积" << area << endl;
system("pause");
return 0;
}