当我们查找到一个轮廓进行形状分析时,通常需要使用多边形来逼近一个轮廓,使得顶点数变少,OpenCV的approxPolyDP函数就可以实现这个功能。
approxPolyDP函数使用了Douglas-Peucker算法:
1、先从轮廓中找出两个最远的点,将两点相连,即b-c;
2、在原来的轮廓上查找一个离线段距离最远的点,将该点加入逼近后的新轮廓中,即c-d;
3、然后重复前面的算法,不断迭代,将最远的点添加进来,直到所有的点到多边形的最短距离小于指定的精度。
函数原型
void approxPolyDP( InputArray curve,OutputArray approxCurve,double epsilon, bool closed );
参数解析:
- curve:存储在std :: vector或Mat中的2D点的输入向量,一般是轮廓点的集合。
- approxCurve:输出拟合的多边形点集, 类型应与输入曲线的类型相同。
- epsilon:指定近似精度的参数, 这是原始曲线和它的近似之间最大距离。
- closed:如果为true,则闭合近似曲线(其第一个和最后一个顶点为连接的);否则,不闭合。
关键代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
//定义颜色常量
const cv::Scalar RED = cv::Scalar(0, 0, 255); //红色
const cv::Scalar PINK = cv::Scalar(230, 130, 255); //粉色
const cv::Scalar BLUE = cv::Scalar(255, 0, 0); //蓝色
const cv::Scalar LIGHTBLUE = cv::Scalar(255, 255, 160); //亮蓝色
const cv::Scalar GREEN = cv::Scalar(0, 255, 0); //绿色
const cv::Scalar YELLOW = cv::Scalar(175, 255, 255); //黄色
const cv::Scalar DEEP_SKYBLUE = cv::Scalar(0, 191, 255); //深天空蓝
const cv::Scalar ORCHID = cv::Scalar(218, 112, 214); //兰花
const cv::Scalar WHITE = cv::Scalar(255, 255, 255); //白色
int main()
{
Mat srcImage, grayImage, binaryImage;
srcImage = imread("OpenCV.jpg",1);
resize(srcImage, srcImage,Size(srcImage.cols/2,srcImage.rows/2));
Mat dstImage_3(srcImage.size(), CV_8UC3, Scalar::all(0));
Mat dstImage_5(srcImage.size(), CV_8UC3, Scalar::all(0));
Mat dstImage_8(srcImage.size(), CV_8UC3, Scalar::all(0));
cvtColor(srcImage, grayImage,COLOR_RGB2GRAY);
imshow("grayImage", grayImage);
threshold(grayImage, binaryImage,200,255, THRESH_BINARY_INV);
imshow("binaryImage", binaryImage);
vector<vector<Point>> contours;
findContours(binaryImage, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
vector<vector<Point>> contours_ploy(contours.size());
for (int i=0;i<contours.size();i++)
{
drawContours(srcImage, contours, i, Scalar(230, 130, 255), 1, CV_AA);
//epsilon==3
approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);
drawContours(dstImage_3, contours_ploy, i, PINK, 1, CV_AA);
//epsilon==5
approxPolyDP(Mat(contours[i]), contours_ploy[i], 5, true);
drawContours(dstImage_5, contours_ploy, i, LIGHTBLUE, 1, CV_AA);
//epsilon==8
approxPolyDP(Mat(contours[i]), contours_ploy[i], 8, true);
drawContours(dstImage_8, contours_ploy, i, YELLOW, 1, CV_AA);
}
imshow("srcImage", srcImage);
imshow("dstImage_3", dstImage_3);
imshow("dstImage_5", dstImage_5);
imshow("dstImage_8", dstImage_8);
waitKey(0);
destroyAllWindows();
return 0;
}
从以上结果可以看出,设置的精度越小,多边形越拟合。