You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义形状图像中圆形检测异常:拟合结果为椭圆如何修正

问题描述

我需要实现图像中的圆形检测功能,运行代码后未检测到预期的圆形,反而返回了椭圆拟合结果。
输入图像:
输入图像
结果图像:
结果图像
现有代码如下:

public Mat Run(string imgPath , int thresholdValue = 150)
{
        var img=Cv2.ImRead(imgPath);
        Bitmap bitmap = MatToBitmap(img);
        pictureBox1.Image = bitmap;

        Mat gray = img.CvtColor(ColorConversionCodes.BGR2GRAY);

        ThresholdImg = gray.Threshold(thresholdValue, 255, ThresholdTypes.Binary);
        Bitmap threshold = MatToBitmap(ThresholdImg);
        pictureBox2.Image = threshold;

        //Cv2.ImShow("Threshold", ThresholdImg);
        Mat gaussImg = ThresholdImg.GaussianBlur(new OpenCvSharp.Size(5, 5), 0.8);

        //Cv2.ImShow("GaussianBlur", gaussImg);
        Mat medianImg = ThresholdImg.MedianBlur(5);

        //Cv2.ImShow("MedianBlur", medianImg);
        Mat kernel = new Mat(15, 15, MatType.CV_8UC1);
        Mat DilateImg = ThresholdImg.Dilate(kernel);
        Mat binary = DilateImg.Erode(kernel);

        //Cv2.ImShow("Dilate & Erode", binary);
        Mat element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(5, 5));
        Mat openImg = ThresholdImg.MorphologyEx(MorphTypes.Open, element);

        //Cv2.ImShow("Dilate & Erode", openImg);
        Rect roi = new Rect(0, 0, bitmap.Width, bitmap.Height);
        Mat ROIimg = new Mat(openImg, roi);
        Cv2.ImShow("ROI Image", ROIimg);
        OpenCvSharp.Point[][] contours;
        HierarchyIndex[] hierachy;
        Cv2.FindContours(ROIimg, out contours, out hierachy, RetrievalModes.List, ContourApproximationModes.ApproxTC89KCOS);

        //根据找到的轮廓点拟合椭圆
        for (int i = 0; i < contours.Length; i++)
        {
            //拟合函数至少需要5个点,少于则不进行拟合
            if (contours[i].Length < 5) continue;
            //椭圆拟合
            var rrt = Cv2.FitEllipse(contours[i]);
        }
  }
圆形检测优化方案

现有代码直接调用FitEllipse对所有轮廓做椭圆拟合,没有圆形校验逻辑,自然会返回所有椭圆结果,你可以选择以下两种方案优化:

方案1:使用霍夫圆变换(推荐,适合新手)

霍夫圆变换是OpenCV内置的专门用于圆形检测的API,不需要手动处理轮廓和拟合逻辑,调整参数即可直接得到圆形结果,修改后的核心代码如下:

public Mat Run(string imgPath , int thresholdValue = 150)
{
    var img = Cv2.ImRead(imgPath);
    Mat gray = img.CvtColor(ColorConversionCodes.BGR2GRAY);
    // 中值滤波抗噪,适配霍夫圆检测
    Mat blurImg = gray.MedianBlur(5);
    CircleSegment[] circles = Cv2.HoughCircles(
        blurImg, 
        HoughMethods.Gradient, 
        dp: 1.2, // 分辨率反比
        minDist: 20, // 两个圆之间的最小距离,根据实际场景调整
        param1: 100, // Canny边缘检测高阈值
        param2: 30, // 累加器阈值,值越高检测到的圆越精准
        minRadius: 5, // 最小检测圆半径
        maxRadius: 200 // 最大检测圆半径
    );
    // 绘制检测到的圆
    foreach (var circle in circles)
    {
        Cv2.Circle(img, (int)circle.Center.X, (int)circle.Center.Y, (int)circle.Radius, Scalar.Red, 2);
    }
    return img;
}

如果检测结果多了误检,就调大param2的值;如果漏检了目标圆,就调小param2的值

方案2:基于现有椭圆拟合逻辑增加圆形校验

如果要保留现有轮廓检测的流程,只需要在拟合椭圆后增加圆形判定规则,过滤非圆形的结果即可:

for (int i = 0; i < contours.Length; i++)
{
    if (contours[i].Length < 5) continue;
    var rrt = Cv2.FitEllipse(contours[i]);
    // 计算椭圆长短轴比值,越接近1越接近圆形
    double axisRatio = rrt.Size.Width / rrt.Size.Height;
    // 比值在0.9~1.1之间判定为圆形,阈值可根据精度要求调整
    if (axisRatio > 0.9 && axisRatio < 1.1)
    {
        // 符合圆形要求,执行后续绘制逻辑
        Cv2.Ellipse(img, rrt, Scalar.Red, 2);
    }
}

另外现有预处理逻辑存在重复冗余的问题,多次形态学操作可能会改变原始圆形的边缘形状,建议仅保留必要的滤波步骤即可,不要同时做多组二值化、开闭操作。


内容的提问来源于stack exchange,提问作者Đàn Ngô

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 01:45:03