几何形状(轮廓)的检测和拟合

当我们绘制一个多边形或进行形状分析时,通常需要使用多边形逼近一个轮廓,使顶点数变少。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;
}

猜你喜欢

转载自blog.csdn.net/weixin_42104289/article/details/84316123