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

如何在带支撑件的圆柱图像中准确检测并测量圆形半径?

问题描述

我正在开发一款测量圆形半径的应用,将圆柱放置在两个塑料支撑件上。对图像进行阈值化处理后,支撑件会被识别为圆柱的一部分。我尝试使用轮廓检测和最小外接圆来查找最大和第二大对象,但由于支撑件的干扰,外圆始终检测错误。我使用的是C#和EmguCV,形态学操作会损坏圆形边缘导致测量不准确,请问如何正确检测并测量圆形?Python和OpenCV的解决方案也可。

现有代码(C#/EmguCV)

VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(binaryimg, contours, null, RetrType.Tree, ChainApproxMethod.ChainApproxNone);
VectorOfPoint largestContour = null;
VectorOfPoint secondLargestContour = null;
double maxArea = 0;
double secondMaxArea = 0;

if (contours.Size < 2)
{
    Console.WriteLine("Not enough contours found to detect both OD and ID.");
}
      
for (int i = 0; i < contours.Size; i++)
{
    using (VectorOfPoint contour = contours[i])
    {
        double area = CvInvoke.ContourArea(contour);

        if (area > maxArea)
        {
            secondMaxArea = maxArea;
            secondLargestContour = largestContour;
            maxArea = area;
            largestContour = contour;
        }
        else if (area > secondMaxArea)
        {
            secondMaxArea = area;
            secondLargestContour = contour;
        }
    }
}

if (largestContour != null && secondLargestContour != null)
{
    CircleF outerCircle = CvInvoke.MinEnclosingCircle(largestContour);
    CircleF innerCircle = CvInvoke.MinEnclosingCircle(secondLargestContour);
}

图像展示

原始图像

放置在两个塑料支撑件上的圆柱

当前错误输出

外圆检测错误,包含支撑件部分

解决方案

核心思路:放弃单纯的面积排序,通过**圆形度(Circularity)**筛选轮廓,结合精准拟合或霍夫圆检测,避开支撑件干扰。

方案一:C#/EmguCV 优化版

步骤说明

  1. 优化阈值化:用Otsu自动阈值减少支撑件误分割
  2. 筛选圆形轮廓:通过圆形度公式(4 * π * 面积 / (周长²))筛选接近完美圆形的轮廓
  3. 拟合外接圆:对筛选后的轮廓拟合最小外接圆,按半径排序得到内外圆

代码示例

// 1. 替换原阈值步骤,用Otsu自动阈值优化分割
Mat grayImg = new Mat();
CvInvoke.CvtColor(originalImg, grayImg, ColorConversion.Bgr2Gray);
Mat binaryImg = new Mat();
CvInvoke.Threshold(grayImg, binaryImg, 0, 255, ThresholdType.BinaryInv | ThresholdType.Otsu);

// 2. 查找轮廓并筛选圆形特征
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(binaryImg, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple);

List<CircleF> validCircles = new List<CircleF>();
foreach (var contour in contours)
{
    double area = CvInvoke.ContourArea(contour);
    if (area < 100) continue; // 过滤小噪声

    double perimeter = CvInvoke.ArcLength(contour, true);
    if (perimeter == 0) continue;

    // 计算圆形度,值越接近1越接近完美圆形
    double circularity = 4 * Math.PI * area / (perimeter * perimeter);
    if (circularity > 0.8) // 阈值可根据实际图像微调
    {
        CircleF circle = CvInvoke.MinEnclosingCircle(contour);
        validCircles.Add(circle);
    }
}

// 3. 按半径排序得到内外圆
if (validCircles.Count >= 2)
{
    validCircles.Sort((a, b) => b.Radius.CompareTo(a.Radius));
    CircleF outerCircle = validCircles[0];
    CircleF innerCircle = validCircles[1];
    Console.WriteLine($"外圆半径:{outerCircle.Radius:F2},内圆半径:{innerCircle.Radius:F2}");
}
else
{
    Console.WriteLine("未检测到足够的有效圆形轮廓");
}

方案二:Python/OpenCV 实现

步骤说明

  1. 灰度化+Otsu阈值处理
  2. 轮廓检测+圆形度筛选
  3. 可选霍夫圆检测辅助验证

代码示例

import cv2
import numpy as np

# 读取图像
img = cv2.imread("original_image.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 1. Otsu自动阈值化
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 2. 筛选圆形轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
valid_circles = []

for cnt in contours:
    area = cv2.contourArea(cnt)
    if area < 100:
        continue
    perimeter = cv2.arcLength(cnt, True)
    if perimeter == 0:
        continue
    # 计算圆形度
    circularity = 4 * np.pi * area / (perimeter ** 2)
    if circularity > 0.8:
        (x, y), radius = cv2.minEnclosingCircle(cnt)
        valid_circles.append((x, y, radius))

# 3. 按半径排序输出结果
if len(valid_circles) >= 2:
    valid_circles.sort(key=lambda c: c[2], reverse=True)
    outer_x, outer_y, outer_r = valid_circles[0]
    inner_x, inner_y, inner_r = valid_circles[1]
    print(f"外圆半径:{outer_r:.2f},内圆半径:{inner_r:.2f}")
    
    # 可视化结果
    cv2.circle(img, (int(outer_x), int(outer_y)), int(outer_r), (0, 255, 0), 2)
    cv2.circle(img, (int(inner_x), int(inner_y)), int(inner_r), (0, 0, 255), 2)
    cv2.imshow("Result", img)
    cv2.waitKey(0)
else:
    print("未检测到足够的有效圆形轮廓")

可选优化:霍夫圆检测

若轮廓筛选效果不佳,可直接用霍夫圆检测(适合对比度较好的图像):

circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1.2, minDist=50,
                           param1=50, param2=30, minRadius=50, maxRadius=200)
if circles is not None:
    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
    cv2.imshow("Hough Circles", img)
    cv2.waitKey(0)

内容的提问来源于stack exchange,提问作者Interceptor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:34:58