文章目录
- 一、什么叫轮廓的多边形近似拟合
- 二、轮廓的多边形近似拟合函数
- 三、简单应用
- 1.原始素材
- 2.代码
- 3.运行结果
一、什么叫轮廓的多边形近似拟合
轮廓一般都是光滑的曲线,多边形近似拟合的意思就是,利用少量的点组成的折线,近似逼近原始多边形,这样可以减少轮廓的点集数量,或者说减少后续计算量。
比如原始轮廓是这样的:
这个轮廓可能会有几百个点组成,其实我们可以用四个点,就能近似的表示出这个轮廓来,如下图:
一共四个绿色的点,他们连成的直线,和原始的轮廓基本非常相似了。如果变成像下图一样的7个点,连成的折现就更像原始轮廓了,也就是说点越多,精度越高,这就是轮廓的多边形近似拟合。
二、轮廓的多边形近似拟合函数
public static void ApproxPolyDP(
IInputArray curve, // 输入的轮廓
IOutputArray approxCurve, // 拟合后的点集
double epsilon, // 精度,原始曲线与近似曲线之间的最大距离。
bool closed // 是否闭合
)
函数的输出结果 IOutputArray approxCurve ,是近似拟合点的集合。
三、简单应用
1.原始素材
原始素材srcMat如下图:
这是一张米奇老鼠的照片,下面我们对其身体的每个部位进行拟合。
2.代码
代码如下:
Mat tempMat = srcMat.Clone();
Mat dstMat = srcMat.Clone();
Mat gray = new Mat();
int threshold = 40;
int epsilon = 20;
// 转成灰度图再二值化
CvInvoke.CvtColor(tempMat, gray, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(gray, gray, threshold, 255, ThresholdType.Binary);
CvInvoke.Imshow("Gray and threshold", gray);
// 定义轮廓集合
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
VectorOfRect hierarchy = new VectorOfRect();
CvInvoke.FindContours(gray, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxNone);
// 在一张黑色图中画出所有轮廓
Mat allContours = new Mat(new System.Drawing.Size(gray.Cols, gray.Rows), DepthType.Cv8U, 1);
allContours.SetTo(new MCvScalar(0, 0, 0));
CvInvoke.DrawContours(allContours, contours, -1, new MCvScalar(255, 255, 255), 1);
// 按照面积筛选,太小的轮廓不计算
Dictionary<int, double> dict = new Dictionary<int, double>();
if (contours.Size > 0)
{
for (int i = 0; i < contours.Size; i++)
{
double area = CvInvoke.ContourArea(contours[i]);
Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);
if (rect.Width > 20 && rect.Height > 20 && area < 3000000)
{
dict.Add(i, area);
}
}
}
var item = dict.OrderByDescending(v => v.Value); // v.Value就代表面积,是降序排列
// 开始拟合
foreach (var it in item)
{
int key = it.Key;
VectorOfPoint approxPoly = new VectorOfPoint();
Mat approxPolyResultMat = new Mat(new System.Drawing.Size(gray.Cols, gray.Rows), DepthType.Cv8U, 3);
CvInvoke.ApproxPolyDP(contours[key], approxPoly, epsilon, true); // 多边形轮廓拟合
CvInvoke.Polylines(dstMat, approxPoly, true, new MCvScalar(0, 0, 255), 1); // 画出红色的拟合多边形
}
CvInvoke.Imshow("All contours, " + dict.Count(), allContours);
CvInvoke.Imshow("Final result image, " + dstMat.Size.ToString(), dstMat);
3.运行结果
如下所示:
因为精度是20,也就是拟合的直线举例原始轮廓最远距离是20像素,因此拟合的精度不是很高,如果epsilon = 2,结果如下:
拟合精度提高了很多,进本上等于原始轮廓形状了,但是输出的拟合点集数量也增加了很多,因此在实际使用过程中,需要选择合适的epsilon精度参数。
原创不易,请勿抄袭。共同进步,相互学习。