基于OpenCV的Python同心圆检测及圆度、偏移方向分析需求
低质量投影同心光圈的圆形识别与分析方案
需求说明
识别投影形成的低质量同心光圈中的圆形,输出量化圆度指标,并判断圆形是否存在特定方向的偏移。待识别图像存在亮度不均、边缘模糊、噪声干扰等问题。
原始代码问题
原代码结合霍夫圆变换与轮廓检测,但未针对低对比度、噪声多的投影图像做针对性预处理,且轮廓筛选逻辑过于严格,导致识别效果不佳。
改进方案与代码
核心优化方向
- 采用自适应阈值适配局部亮度差异,替代固定阈值
- 使用形态学闭运算增强光圈边缘,填补间隙抑制噪声
- 优化轮廓筛选逻辑,放宽圆度阈值适配非完美圆形
- 通过椭圆拟合判断定向偏移,同时计算圆度指标
import cv2 import numpy as np import matplotlib.pyplot as plt # 加载图像 image_path = '/mnt/data/IMG_1.JPG' img = cv2.imread(image_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) output = img.copy() # -------------------------- 预处理优化 -------------------------- # 自适应阈值处理,适配局部亮度差异 adaptive_thresh = cv2.adaptiveThreshold( gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) # 形态学闭运算,填补光圈边缘间隙 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) processed = cv2.morphologyEx(adaptive_thresh, cv2.MORPH_CLOSE, kernel) # -------------------------- 轮廓检测与筛选 -------------------------- contours, _ = cv2.findContours(processed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 圆度计算与轮廓分析函数 def analyze_contour(contour): area = cv2.contourArea(contour) if area < 1000: # 过滤过小噪声轮廓 return None perimeter = cv2.arcLength(contour, True) # 圆度公式:4π×面积/周长²,完美圆为1 circularity = (4 * np.pi * area) / (perimeter ** 2) if perimeter > 0 else 0 # 最小外接圆参数 (x, y), radius = cv2.minEnclosingCircle(contour) center = (int(x), int(y)) radius = int(radius) # 椭圆拟合判断偏移 if len(contour) >= 5: ellipse = cv2.fitEllipse(contour) (ell_center, (major_axis, minor_axis), angle) = ellipse axis_ratio = major_axis / minor_axis if minor_axis > 0 else 0 else: axis_ratio = 1.0 angle = 0.0 return { "center": center, "radius": radius, "circularity": round(circularity, 3), "axis_ratio": round(axis_ratio, 3), "offset_angle": round(angle, 1) } # 筛选符合条件的圆形轮廓 detected_circles = [] for cnt in contours: result = analyze_contour(cnt) # 放宽圆度阈值适配低质量图像 if result and 0.6 < result["circularity"] < 1.4: detected_circles.append(result) # 按半径排序,区分同心光圈层级 detected_circles.sort(key=lambda x: x["radius"]) # -------------------------- 可视化与结果输出 -------------------------- # 绘制识别结果 for circle in detected_circles: cv2.circle(output, circle["center"], circle["radius"], (0, 255, 0), 2) cv2.circle(output, circle["center"], 3, (0, 0, 255), -1) # 标注圆度与偏移信息 text1 = f"圆度: {circle['circularity']}" text2 = f"偏移比: {circle['axis_ratio']}" y_pos = circle["center"][1] + circle["radius"] + 20 cv2.putText(output, text1, (circle["center"][0]-60, y_pos), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1) cv2.putText(output, text2, (circle["center"][0]-60, y_pos+20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1) # 展示原始图像与识别结果 plt.figure(figsize=(12,8)) plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("原始图像") plt.axis('off') plt.subplot(122), plt.imshow(cv2.cvtColor(output, cv2.COLOR_BGR2RGB)), plt.title("识别结果") plt.axis('off') plt.show() # 输出量化指标与偏移判断 print("识别到的圆形量化指标:") for i, circle in enumerate(detected_circles, 1): print(f"\n第{i}个圆:") print(f" 圆心坐标: {circle['center']}") print(f" 半径: {circle['radius']}") print(f" 圆度: {circle['circularity']}") print(f" 长轴/短轴比: {circle['axis_ratio']}") print(f" 偏移方向角度: {circle['offset_angle']}°") # 偏移判断阈值:轴比>1.1视为存在定向偏移 if circle["axis_ratio"] > 1.1: print(f" 结论: 存在定向偏移,方向为{circle['offset_angle']}°") else: print(f" 结论: 无明显定向偏移")
指标说明
- 圆度(Circularity):取值范围为01,越接近1表示轮廓越接近完美圆形。低质量图像中0.61.4的范围可有效筛选光圈圆。
- 长轴/短轴比:大于1.1时判断为存在定向偏移,比值越大偏移程度越明显;偏移角度为椭圆长轴与水平方向的夹角。
内容的提问来源于stack exchange,提问作者Ross
相关产品推荐
相关产品推荐

