自定义形状图像中圆形检测异常:拟合结果为椭圆如何修正
问题描述
我需要实现图像中的圆形检测功能,运行代码后未检测到预期的圆形,反而返回了椭圆拟合结果。
输入图像:
结果图像:
现有代码如下:
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ô
相关产品推荐
相关产品推荐

