Python OpenCV形状识别代码异常:为何检测结果不符合预期?
问题分析与解决
核心逻辑错误
你的代码完全没有实现「形状种类数统计」的功能——当前输出的是检测到的轮廓数量(也就是形状实例的个数),和你预期的「形状种类数」(比如10个圆形就输出1)完全不匹配,这是结果不符合预期的根本原因。
为什么输出为1?
如果实际图像中存在多个形状但代码输出1,可能是以下具体问题:
- 二值化阈值不合理:你用了固定阈值
127做二值化,如果图像亮度不均匀,多个形状会被合并成一个连续的白色区域,findContours只能检测到一个轮廓。 - 轮廓过滤条件过严:
cv2.contourArea(cnt) > 100的过滤规则把大部分小形状的轮廓都过滤掉了,最终只剩一个符合面积要求的轮廓。 - 轮廓检测模式限制:
cv2.RETR_EXTERNAL只检测最外层轮廓,如果形状存在嵌套(比如一个形状在另一个内部),内部形状的轮廓会被直接忽略。
修正后的代码(实现形状种类统计)
要实现「统计形状种类数」的需求,需要先对每个轮廓做形状判断,再统计不同形状的数量:
import cv2 import numpy as np # 输入处理 num_shapes = int(input("Enter the number of shapes in the image: ")) image_path = input("Enter the path to the image: ") # 图像读取与预处理 image = cv2.imread(image_path) if image is None: print("Error: Could not read the image.") exit() gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 改用自适应阈值,应对亮度不均的情况 binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 检测所有层级的轮廓,避免遗漏嵌套形状 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 过滤小轮廓,保留有效形状 filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 50] # 形状判断函数:通过轮廓近似多边形的顶点数区分形状 def get_shape(cnt): peri = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, 0.04 * peri, True) vertices = len(approx) if vertices == 3: return "triangle" elif vertices == 4: x, y, w, h = cv2.boundingRect(approx) aspect_ratio = float(w) / h if 0.95 <= aspect_ratio <= 1.05: return "square" else: return "rectangle" elif vertices > 6: return "circle" else: return "unknown" # 统计形状种类:用集合自动去重 shape_types = set() for cnt in filtered_contours: shape = get_shape(cnt) shape_types.add(shape) # 输出结果 print("Number of shape types:", len(shape_types))
关键改进点
- 改用自适应阈值二值化,避免固定阈值导致的形状合并问题。
- 改用
cv2.RETR_TREE检测所有层级的轮廓,不会遗漏嵌套形状。 - 添加了形状判断逻辑,通过轮廓近似多边形的顶点数区分不同形状。
- 用集合
shape_types自动去重,准确统计不同形状的种类数。
内容的提问来源于stack exchange,提问作者Ilia Kh
相关产品推荐
相关产品推荐

