使用OpenCV从左到右扫描图像时,如何提取首个闭合圆形ROI?
问题描述
目标图像:
尝试用OpenCV从左到右扫描图像,仅提取其中第一个闭合圆形区域,但现有代码选中的是字符的整个外边缘,而非目标ROI。现有代码如下:
import cv2 import numpy as np import matplotlib.pyplot as plt def find_closed_round_areas(image_path): # Load the image image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # Apply binary thresholding _, thresh = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY_INV) # Find contours contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Create a color version of the original image color_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # Filter and highlight closed round contours highlighted_image = color_image.copy() for contour in contours: if cv2.contourArea(contour) > 100: # Filter out small contours perimeter = cv2.arcLength(contour, True) circularity = 4 * np.pi * cv2.contourArea(contour) / (perimeter ** 2) if circularity > 0.7: # Filter based on circularity cv2.drawContours(highlighted_image, [contour], -1, (0, 255, 0), thickness=2) # Green color in BGR # Display the original and highlighted images plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1) plt.title('Original Image') plt.imshow(cv2.cvtColor(color_image, cv2.COLOR_BGR2RGB)) plt.subplot(1, 2, 2) plt.title('Highlighted Closed Round Areas') plt.imshow(cv2.cvtColor(highlighted_image, cv2.COLOR_BGR2RGB)) plt.show() # Path to the image image_path = '/mnt/data/ROI_65.png' # Find and highlight the closed round areas find_closed_round_areas(image_path)
修改方案
问题核心原因:
- 原代码用
cv2.RETR_EXTERNAL仅提取最外层轮廓,无法获取字符内部的圆形轮廓 - 未按从左到右的顺序筛选轮廓,也没有限制只保留第一个目标
针对性修改步骤:
- 更换轮廓检索模式为
cv2.RETR_TREE,提取所有层级的轮廓(包括内部圆形) - 通过轮廓的外接矩形x坐标排序,实现从左到右的查找顺序
- 增加层级判断过滤最外层大轮廓,同时用面积、圆形度筛选目标,找到第一个符合条件的区域后立即停止遍历
修改后的完整代码
import cv2 import numpy as np import matplotlib.pyplot as plt def find_first_left_closed_round_area(image_path): # 加载灰度图像 image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 二值化处理(反转后黑色为前景) _, thresh = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY_INV) # 提取所有层级的轮廓及层级信息 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 创建彩色图像用于可视化 color_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) highlighted_image = color_image.copy() # 筛选符合条件的圆形轮廓 valid_contours = [] for idx, contour in enumerate(contours): area = cv2.contourArea(contour) # 过滤过小/过大轮廓,且通过层级判断排除最外层轮廓(hierarchy[0][idx][3] != -1表示有父轮廓) if 50 < area < 500 and hierarchy[0][idx][3] != -1: perimeter = cv2.arcLength(contour, True) circularity = 4 * np.pi * area / (perimeter ** 2) # 圆形度阈值可根据实际图像调整 if circularity > 0.8: # 获取轮廓外接矩形的x坐标,用于排序 x, _, _, _ = cv2.boundingRect(contour) valid_contours.append((x, contour)) # 按x坐标从小到大排序,确保从左到右查找 valid_contours.sort(key=lambda item: item[0]) # 标记并提取第一个目标ROI if valid_contours: _, target_contour = valid_contours[0] cv2.drawContours(highlighted_image, [target_contour], -1, (0, 255, 0), thickness=2) # 获取ROI坐标并提取 x, y, w, h = cv2.boundingRect(target_contour) roi = image[y:y+h, x:x+w] # 展示结果 plt.figure(figsize=(12, 6)) plt.subplot(1, 3, 1) plt.title('原始图像') plt.imshow(cv2.cvtColor(color_image, cv2.COLOR_BGR2RGB)) plt.subplot(1, 3, 2) plt.title('标记后的目标区域') plt.imshow(cv2.cvtColor(highlighted_image, cv2.COLOR_BGR2RGB)) plt.subplot(1, 3, 3) plt.title('提取的ROI') plt.imshow(roi, cmap='gray') plt.show() else: print("未找到符合条件的闭合圆形区域") # 图像路径 image_path = '/mnt/data/ROI_65.png' # 执行查找与提取 find_first_left_closed_round_area(image_path)
内容的提问来源于stack exchange,提问作者Ayyoob areacode
相关产品推荐
相关产品推荐

