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

如何优化并自动化椭圆检测代码的参数调整流程?

问题描述

现有一段可较好检测类椭圆结构的代码:针对输入图像1,设置自适应阈值C值为6、形态学闭运算核尺寸为(11,11)时可得到理想分割结果;但针对输入图像2、3,需手动调整C值及核尺寸才能检测到全部5个椭圆。所有待检测输入图像均固定包含5个椭圆,希望编写算法实现参数的自动调整,无需手动修改。请问该如何实现,是否有更优方案?

附现有代码:

import cv2
import numpy as np
import skimage.exposure

# read the input
img = cv2.imread('RedJan20.png')

# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# blur
blur = cv2.GaussianBlur(gray, (0,0), sigmaX=99, sigmaY=99)

# do division normalization
normal = cv2.divide(gray, blur, scale=255)

# stretch to full dynamic range
stretch = skimage.exposure.rescale_intensity(normal, in_range='image', out_range=(0,255)).astype(np.uint8)

# adaptive threshold  
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 25, 6)

# apply morphology close 
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# get external contours
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]


# filter out small contours and fit ellipse
# draw contour on copy of image and also draw ellipse
result1 = img.copy()
result2 = img.copy()
i = 1
count = 0
for cntr in contours:
    area = cv2.contourArea(cntr)
    #if area > 10000:
    if area > 5000:
        ellipse = cv2.fitEllipse(cntr)
        (xc,yc),(d1,d2),angle = ellipse
        print('ellipse #:', i)
        print('center:', xc,yc)
        print('diameters:', d1,d2)
        print('angle:', angle)
        print('')
        cv2.drawContours(result1, [cntr], 0, (0,0,255), 1)
        cv2.ellipse(result2, (int(xc),int(yc)), (int(d1/2),int(d2/2)), angle, 0, 360, (0,0,255), 1)
        i += 1
        count += 1
print(count)

# show results
cv2.imshow('gray', gray)
cv2.imshow('blur', blur)
cv2.imshow('normalized', normal)
cv2.imshow('stretched', stretch)
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('contours', result1)
cv2.imshow('ellipses', result2)
cv2.waitKey(0)

自动参数调整实现方案

核心思路是遍历候选参数组合,以检测到的有效椭圆数量(目标为5个)作为判断标准,找到符合要求的参数:

1. 定义参数搜索范围

基于已知有效参数设定合理区间,覆盖不同图像的亮暗、轮廓大小差异:

  • 自适应阈值C值:[-10, 15](步长1)
  • 形态学核尺寸:[(5,5), (7,7), ..., (15,15)](步长2,保持奇数)

2. 封装检测逻辑为可复用函数

将阈值处理、形态学操作、椭圆计数逻辑封装,方便批量参数测试:

3. 遍历参数筛选最优解

按顺序遍历所有参数组合,找到能检测到5个椭圆的参数后立即停止搜索,提升效率。

修改后的代码示例

import cv2
import numpy as np
import skimage.exposure

def detect_ellipses(gray_img, c_value, kernel_size):
    """封装椭圆检测逻辑,返回有效椭圆数量及中间结果"""
    # 自适应阈值处理
    thresh = cv2.adaptiveThreshold(gray_img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, 
                                  cv2.THRESH_BINARY_INV, 25, c_value)
    # 形态学闭运算
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, kernel_size)
    morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    # 提取外部轮廓
    contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours = contours[0] if len(contours) == 2 else contours[1]
    # 统计有效椭圆数量(轮廓面积达标且点数足够拟合椭圆)
    count = 0
    for cntr in contours:
        if cv2.contourArea(cntr) > 5000 and len(cntr) >= 5:
            count += 1
    return count, thresh, morph, contours

# 图像预处理
img = cv2.imread('RedJan20.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (0,0), sigmaX=99, sigmaY=99)
normal = cv2.divide(gray, blur, scale=255)
stretch = skimage.exposure.rescale_intensity(normal, in_range='image', out_range=(0,255)).astype(np.uint8)

# 参数候选集
c_candidates = range(-10, 16)
kernel_candidates = [(k, k) for k in range(5, 16, 2)]

# 寻找最优参数
best_c = 6
best_kernel = (11,11)
found_flag = False

for c in c_candidates:
    for kernel_size in kernel_candidates:
        ellipse_count, _, _, _ = detect_ellipses(stretch, c, kernel_size)
        if ellipse_count == 5:
            best_c = c
            best_kernel = kernel_size
            found_flag = True
            break
    if found_flag:
        break

# 使用最优参数完成检测与可视化
ellipse_count, thresh, morph, contours = detect_ellipses(stretch, best_c, best_kernel)

result1 = img.copy()
result2 = img.copy()
i = 1
for cntr in contours:
    area = cv2.contourArea(cntr)
    if area > 5000 and len(cntr) >=5:
        ellipse = cv2.fitEllipse(cntr)
        (xc,yc),(d1,d2),angle = ellipse
        print(f'ellipse #: {i}')
        print(f'center: {xc:.2f}, {yc:.2f}')
        print(f'diameters: {d1:.2f}, {d2:.2f}')
        print(f'angle: {angle:.2f}\n')
        cv2.drawContours(result1, [cntr], 0, (0,0,255), 1)
        cv2.ellipse(result2, (int(xc),int(yc)), (int(d1/2),int(d2/2)), angle, 0, 360, (0,0,255), 1)
        i += 1

print(f"检测到椭圆数量: {ellipse_count}")
print(f"最优参数: C={best_c}, 核尺寸={best_kernel}")

# 显示结果
cv2.imshow('stretched', stretch)
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('contours', result1)
cv2.imshow('ellipses', result2)
cv2.waitKey(0)
cv2.destroyAllWindows()

更优方案建议

1. 优化预处理逻辑

原代码中用gray做阈值处理,但已经生成了对比度更均匀的stretch,直接使用stretch做阈值能提升不同图像的适配性。

2. 替换自适应阈值为Otsu自动阈值

若椭圆与背景灰度差异明显,Otsu阈值可自动计算分割阈值,无需调整C值:

_, thresh = cv2.threshold(stretch, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

3. 使用专用椭圆检测算法

skimage的hough_ellipse专门针对椭圆检测,无需依赖轮廓筛选,适配性更强:

from skimage.transform import hough_ellipse
from skimage.draw import ellipse_perimeter

# 图像预处理
img = cv2.imread('RedJan20.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (0,0), sigmaX=99, sigmaY=99)
normal = cv2.divide(gray, blur, scale=255)
stretch = skimage.exposure.rescale_intensity(normal, in_range='image', out_range=(0,255)).astype(np.uint8)
edges = cv2.Canny(stretch, 50, 200)

# 霍夫椭圆检测
ellipses = hough_ellipse(edges, accuracy=20, threshold=250, min_size=100, max_size=500)
ellipses = sorted(ellipses, key=lambda x: x[0], reverse=True)

result = img.copy()
count = 0
for e in ellipses:
    if count >=5:
        break
    yc, xc, a, b, orientation = e[1:]
    cy, cx = ellipse_perimeter(int(yc), int(xc), int(a), int(b), orientation)
    result[cy, cx] = (0, 0, 255)
    count +=1

print(f"检测到椭圆数量: {count}")
cv2.imshow('hough_ellipses', result)
cv2.waitKey(0)

内容的提问来源于stack exchange,提问作者John C Lau

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 23:25:27