如何用OpenCV和Python精准检测白色实体内部首个黑色圆圈?
优化OpenCV检测白色实体内部黑色圆圈的方案
原代码存在的问题
- 拼写错误:
imporrt cv2应为import cv2 - 函数
eroded_image使用了self参数,但并非类成员方法,调用时会报错 - 处理流程冗余:用Canny+膨胀腐蚀+自适应阈值的组合,没有针对性利用黑色圆圈的特征,容易引入干扰
优化思路
针对白色实体内部的黑色圆圈这一特征,简化处理流程:
- 直接通过灰度二值化提取黑色区域
- 利用轮廓的面积、圆形度筛选目标,或使用霍夫圆检测(更适配圆形目标)
- 优先定位白色实体内部的第一个符合条件的圆圈
优化后的代码
import cv2 import numpy as np def detect_inner_black_circle(image_path): # 读取图像 image = cv2.imread(image_path, cv2.IMREAD_COLOR) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 1. 二值化提取黑色区域:反转阈值,将黑色圆圈转为白色前景 _, binary = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY_INV) # 2. 去除小干扰噪点 kernel = np.ones((3, 3), np.uint8) binary_clean = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=1) # 3. 查找轮廓并筛选目标(利用层级关系判断内部轮廓) contours, hierarchy = cv2.findContours(binary_clean, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) target_contour = None for i, cnt in enumerate(contours): # hierarchy[0][i][3] != -1 表示当前轮廓是外层轮廓(白色实体)的子轮廓 if hierarchy[0][i][3] != -1: # 计算圆形度:值越接近1,轮廓越接近圆形 area = cv2.contourArea(cnt) perimeter = cv2.arcLength(cnt, True) if perimeter == 0: continue circularity = 4 * np.pi * (area / (perimeter ** 2)) # 筛选圆形度达标的轮廓(可根据实际场景调整阈值) if circularity > 0.8: target_contour = cnt break # 取第一个符合条件的内部黑色圆圈 # 绘制检测结果 if target_contour is not None: cv2.drawContours(image, [target_contour], -1, (0, 0, 255), 3) # 绘制圆心与最小外接圆 (x, y), radius = cv2.minEnclosingCircle(target_contour) center = (int(x), int(y)) radius = int(radius) cv2.circle(image, center, radius, (255, 0, 0), 2) cv2.circle(image, center, 2, (0, 255, 0), 3) return image # 调用示例 result_image = detect_inner_black_circle('image231.jpg') cv2.imshow('Detected Circle', result_image) cv2.waitKey(0) cv2.destroyAllWindows()
代码说明
- 二值化处理:通过反转阈值,将黑色圆圈转为白色前景,便于轮廓识别
- 形态学开运算:先腐蚀后膨胀,消除小噪点对检测的干扰
- 轮廓层级筛选:使用
RETR_CCOMP获取轮廓层级,确保检测的是白色实体内部的轮廓 - 圆形度筛选:通过计算轮廓的圆形度,排除非圆形的黑色干扰区域
- 结果可视化:绘制轮廓、圆心和外接圆,直观验证检测效果
可选方案:霍夫圆检测
若目标圆圈边缘清晰,可直接使用霍夫圆检测,代码片段如下:
# 在灰度图预处理后添加 blur = cv2.GaussianBlur(gray, (5, 5), 0) # 调整参数适配实际图像:minDist为圆心最小距离,param1/param2为检测阈值,minRadius/maxRadius限制半径范围 circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=10, maxRadius=50) if circles is not None: circles = np.uint16(np.around(circles)) # 取第一个检测到的圆圈 for i in circles[0, :1]: cv2.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2) cv2.circle(image, (i[0], i[1]), 2, (0, 0, 255), 3)
内容的提问来源于stack exchange,提问作者Muhammad Zeeshan Babar
相关产品推荐
相关产品推荐

