基于Python OpenCV的圆环内圈检测失败问题求助
圆环内圈检测问题及解决建议
问题描述
我开发了一个程序,用于读取含圆环的图像,识别圆环的外圈和内圈,并以类似声呐的方式扫描内圈检测缺陷。但目前程序无法检测到圆环的内圈,已尝试调整多个参数但均无效,恳请提供解决建议。
测试图像:
现有代码
import cv2 import numpy as np def detect_annulus(image): # Convert to grayscale gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Denoise the image denoised = cv2.fastNlMeansDenoising(gray, None, 10, 10, 7) # Perform Canny edge detection edges = cv2.Canny(denoised, 50, 100) # Detect circles using Hough Circle Transform circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=50, param2=25, minRadius=220, maxRadius=1000) # Check if circles are found if circles is not None: # Convert the circle parameters to integers circles = np.round(circles[0, :]).astype(int) # Filter circles based on size, aspect ratio, or position if needed # Sort circles by radius in descending order circles = sorted(circles, key=lambda x: x[2], reverse=True) # Extract the annulus circle (outer circle) x, y, r_outer = circles[0] # Extract the inside circle (smaller circle) x_inner, y_inner, r_inner = circles[1] # Calculate the radius inside the annulus r_final = r_outer - r_inner # Draw the circles on the image cv2.circle(image, (x, y), r_outer, (0, 255, 0), 2) cv2.circle(image, (x_inner, y_inner), r_inner, (0, 0, 255), 2) # Display the image with circles cv2.imshow('Circles', image) cv2.waitKey(0) cv2.destroyAllWindows() return r_final else: print("No circles detected.") return None def scan_circle_for_imperfections(image, center_x, center_y, radius, step_size): # Initialize variables to store imperfections imperfections = [] # Convert to grayscale gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Calculate the number of iterations based on step size num_iterations = int(360 / step_size) # Initialize variables to store the largest and smallest r_final values largest_r_final = None smallest_r_final = None # Iterate over angles around the circle for i in range(num_iterations): # Compute the current angle angle = i * step_size # Compute the coordinates of the point on the circle x = int(center_x + radius * np.cos(np.radians(angle))) y = int(center_y + radius * np.sin(np.radians(angle))) # Get the pixel intensity at the point intensity = gray[y, x] # Calculate the r_final value at the current point r_final = intensity / 255.0 * radius # Update the largest and smallest r_final values if largest_r_final is None or r_final > largest_r_final: largest_r_final = r_final if smallest_r_final is None or r_final < smallest_r_final: smallest_r_final = r_final # Calculate the threshold for detecting imperfections threshold = 0.5 # Adjust this value based on your requirements # Iterate over angles again to find imperfections for i in range(num_iterations): # Compute the current angle angle = i * step_size # Compute the coordinates of the point on the circle x = int(center_x + radius * np.cos(np.radians(angle))) y = int(center_y + radius * np.sin(np.radians(angle))) # Get the pixel intensity at the point intensity = gray[y, x] # Calculate the r_final value at the current point r_final = intensity / 255.0 * radius # Check if the r_final value is significantly larger than others if r_final - smallest_r_final > threshold * (largest_r_final - smallest_r_final): imperfections.append((x, y)) return imperfections def main(): # Load the input image image = cv2.imread('Images/1.jpg') # Detect the annulus and calculate the inside and outside radii r_final = detect_annulus(image) if r_final is not None: # Find the center coordinates of the annulus center_x = int(image.shape[1] / 2) center_y = int(image.shape[0] / 2) # Define the scanning radius from the center scan_radius = int(r_final * 1.2) # Define the step size for scanning step_size = 5 # Scan the circle for imperfections imperfections = scan_circle_for_imperfections(image, center_x, center_y, scan_radius, step_size) # Print the imperfections if imperfections: print(f"Imperfections found: {len(imperfections)}") for imperfection in imperfections: print(f"Coordinate: {imperfection}") else: print("No imperfections found.") else: print("Failed to detect the annulus.") if __name__ == '__main__': main()
解决建议
1. 优化HoughCircles参数适配内圈
测试图像中内圈边缘对比度弱于外圈,当前参数对弱边缘小半径圆不友好,建议调整:
- param2:降低至15-20,该值是圆心累加器阈值,越小越容易检测弱边缘圆
- minRadius/maxRadius:缩小范围匹配内圈尺寸,比如设
minRadius=100,maxRadius=200 - minDist:内外圈圆心基本重合,调小至10,允许近距离圆心的圆被检测
调整后的调用示例:
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, dp=1, minDist=10, param1=50, param2=18, minRadius=100, maxRadius=200)
2. 改进预处理强化内圈边缘
- 替换降噪方式:fastNlMeansDenoising易模糊内圈边缘,改用
cv2.GaussianBlur(gray, (5,5), 0),降噪同时保留更多边缘 - 调整Canny阈值:降低下限至30,保留弱边缘:
edges = cv2.Canny(denoised, 30, 80)
3. 增加圆心一致性校验
圆环内外圈圆心应重合,检测到多个圆后过滤偏差过大的圆:
# 过滤与外圈圆心偏差≤5像素的圆 outer_center = (x, y) valid_inner_circles = [] for circle in circles: cx, cy, cr = circle distance = np.sqrt((cx - outer_center[0])**2 + (cy - outer_center[1])**2) if distance < 5: valid_inner_circles.append(circle) # 从有效圆中选半径第二大的作为内圈 if len(valid_inner_circles) >=2: valid_inner_circles = sorted(valid_inner_circles, key=lambda x: x[2], reverse=True) x_inner, y_inner, r_inner = valid_inner_circles[1] else: print("No valid inner circle found") return None
4. 轮廓检测替代方案
若Hough变换仍无效,改用轮廓提取:
- 二值化分离圆环区域
- 提取轮廓并筛选近似圆形的轮廓
- 按面积大小区分内外圈
示例代码片段:
# 二值化处理 _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) # 提取轮廓 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选圆形轮廓 circular_contours = [] for cnt in contours: perimeter = cv2.arcLength(cnt, True) area = cv2.contourArea(cnt) if perimeter ==0: continue circularity = 4 * np.pi * area / (perimeter **2) # 圆形度0.8-1.2视为圆形 if 0.8 < circularity < 1.2: circular_contours.append(cnt) # 按面积排序,大的为外圈,小的为内圈 circular_contours.sort(key=lambda x: cv2.contourArea(x), reverse=True) if len(circular_contours)>=2: (x_outer, y_outer), r_outer = cv2.minEnclosingCircle(circular_contours[0]) (x_inner, y_inner), r_inner = cv2.minEnclosingCircle(circular_contours[1])
内容的提问来源于stack exchange,提问作者Nisipeanu Ionut
相关产品推荐
相关产品推荐

