OpenCvSharp函数:ApproxPolyDP轮廓逼近

ApproxPolyDP轮廓逼近

函数说明:使用道格拉斯-普克算法(Douglas–Peucker algorithm)获取一个小于或等于指定精度(epsilon)的更少坐标集的轮廓(或曲线)。图片来自(道格拉斯普克算法)

//函数原型1
void ApproxPolyDP(InputArray curve,
    OutputArray approxCurve,
    double epsilon,
    bool closed)

//函数原型2
Point[] ApproxPolyDP(IEnumerable<Point> curve,
    double epsilon,
    bool closed)

//函数原型3
Point2f[] ApproxPolyDP(IEnumerable<Point2f> curve,
    double epsilon,
    bool closed)

参数

说明

InputArray curve

IEnumerable<Point> curve

IEnumerable<Point2f> curve

待计算的轮廓(曲线)

double epsilon

近似精度,为逼近结果与原轮廓(曲线)的最大差值

bool closed

轮廓(曲线)是否闭合

返回值OutputArray approxCurve

返回逼近后的轮廓(曲线)坐标集

图像示例

原图

逼近并矫正后结果

通过轮廓发现的轮廓个数是2864(蓝色边框),轮廓逼近后个数只剩4个(红点)

源代码示例

public void Run()
{
    using (var src = Cv2.ImRead(ImagePath.Book, ImreadModes.Color))
    {
        if (src.Empty()) throw new Exception("图像读取有误");
        var srcWinName = "src";

        ResizeWin(srcWinName, src);
        Cv2.ImShow("src", src);                

        using (var srcGray = new Mat())
        {
            Cv2.CvtColor(src, srcGray, ColorConversionCodes.BGR2GRAY);
            //中值模糊
            Cv2.MedianBlur(srcGray, srcGray, 15);
            //Otsu二值化
            Cv2.Threshold(srcGray, srcGray, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.BinaryInv);

            var srcGrayWinName = "srcGray";
            ResizeWin(srcGrayWinName, srcGray);
            Cv2.ImShow(srcGrayWinName, srcGray);

            //轮廓发现
            Cv2.FindContours(srcGray, out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);

            //找到最大轮廓
            var maxIndex = -1;
            double maxContourArea = 0;
            for (int index = 0; index < contours.Length; index++)
            {
                var area = Cv2.ContourArea(contours[index]);
                if (maxContourArea > area) continue;
                maxIndex = index;
                maxContourArea = area;
            }

            if (maxIndex > -1)
            {
                //绘制未逼近前的轮廓
                Cv2.DrawContours(src, new Point[][] { contours[maxIndex] }, -1, Scalar.Blue, 5);

                //轮廓逼近参数
                var epsilon = Cv2.ArcLength(contours[maxIndex], true) * 0.1;
                //轮廓逼近
                var approxContour = Cv2.ApproxPolyDP(contours[maxIndex], epsilon, true);

                //标记逼近后轮廓点
                foreach (var point in approxContour)
                {
                    Cv2.Circle(src, point, 10, Scalar.Red, -1);
                }

                //获取轮廓最小外接矩形(图像中书不是平行四边形,应该用霍夫变换的,但还没研究,先用这个简单处理吧)
                var RotatedRect = Cv2.MinAreaRect(approxContour);

                //获取旋转矩形,Angle为正数时是逆时针
                var rotMat = Cv2.GetRotationMatrix2D(RotatedRect.Center, RotatedRect.Angle, 1);

                //每个通道分开仿射变换
                var splits = Cv2.Split(src);
                for (int i = 0; i < splits.Length; i++)
                {
                    var dst = new Mat();
                    //仿射变换
                    Cv2.WarpAffine(splits[i], dst, rotMat, srcGray.Size());
                    splits[i] = dst;
                }
                Cv2.Merge(splits, src);

                //转化率逼近前后的个数
                Cv2.PutText(src, $"Before ApproxPolyDP Contour count={contours[maxIndex].Length},after ={approxContour.Length}", new Point(50, 50), HersheyFonts.HersheySimplex, 1.5, Scalar.Red,5);

                var srcResult = "ApproxPolyDP";
                ResizeWin(srcResult, src);
                Cv2.ImShow(srcResult, src);
            }                    
        }
    }
    Cv2.WaitKey();
    Cv2.DestroyAllWindows();
}

/// <summary>
/// 缩放窗口
/// </summary>
/// <param name="winName"></param>
/// <param name="mat"></param>
/// <param name="newWidth"></param>
private void ResizeWin(string winName, Mat mat, int newWidth = 600)
{
    Cv2.NamedWindow(winName, WindowFlags.KeepRatio);
    Cv2.ResizeWindow(winName, newWidth, (int)(mat.Height * newWidth / mat.Width));
}

今天是女神节,祝天下女神们节日快乐!

OpenCvSharp函数示例(目录)

参考

https://edu.csdn.net/learn/38286/608280

https://docs.opencv.org/

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图南科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值