如何使用OpenCV查找含大于180°角和内凹白色椭圆形的形状
带刻入式凹圆形的形状筛选需求
仅用文字较难描述目标特征,以下为示例图片对照表:
| 原始形状 | 标注后形状 |
|---|---|
| (5组OpenCV检测到的原始形状示例图) | (对应标注了尖角和内凹椭圆区域的示例图) |
左侧是使用OpenCV的findContours函数检测到的示例形状,右侧用红色标注了部分尖角/锐边(大角度)以及绝大多数椭圆形“刻入”区域。内凹椭圆形结构是核心筛选特征,和误检测的噪声区分度极高。
筛选条件
基于OpenCV检测到的轮廓,目标形状需同时满足以下两个条件:
- 边缘处存在背景色的内凹雕刻结构
- 至少四分之一的内凹结构处存在大于180°的向内夹角
受保密协议限制无法提供原始图像,上述示例已获得授权,满足条件即可筛选出目标形状。
现有代码基础
已实现轮廓提取的基础代码如下:
import numpy as np import cv2 img = np.asarray(image) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度图二值化 _, threshold = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for i, contour in enumerate(contours): # 后续筛选逻辑补充处 pass
已尝试未生效的方案
cv2.approxPolyDP:可输出近似多边形,但无法直接基于输出结果识别凹形cv2.boundingRect:可通过坐标重叠定位特征候选区域,但无法区分尖角和平滑圆形,漏检率高
实现方案
步骤1:快速筛选非凸轮廓,提取内凹区域
先用cv2.isContourConvex()排除全凸轮廓,减少计算量。对非凸轮廓计算凸缺陷识别所有内凹区域:
# 计算轮廓凸包,returnPoints设为False才能获取索引用于凸缺陷计算 hull = cv2.convexHull(contour, returnPoints=False) defects = cv2.convexityDefects(contour, hull) # 凸缺陷返回值格式:[起点索引, 终点索引, 最远点索引, 最远点到凸包的距离]
步骤2:统计内凹区域角度占比
对每个凸缺陷的三个关联点,用向量点积计算内凹顶点的内角,统计大于180°的夹角占比:
def calculate_angle(p1, p2, p3): # p2为夹角顶点 v1 = p1 - p2 v2 = p3 - p2 dot_product = np.dot(v1, v2) cos_angle = dot_product / (np.linalg.norm(v1) * np.linalg.norm(v2)) # 限制取值范围避免浮点计算误差 cos_angle = np.clip(cos_angle, -1.0, 1.0) return np.arccos(cos_angle) * 180 / np.pi valid_defect_count = 0 if defects is not None: for defect in defects: s, e, f, d = defect[0] start = tuple(contour[s][0]) end = tuple(contour[e][0]) far = tuple(contour[f][0]) angle = calculate_angle(np.array(start), np.array(far), np.array(end)) if angle > 180: valid_defect_count += 1 # 判断是否满足四分之一占比要求 if valid_defect_count / len(defects) >= 0.25: pass # 进入下一步椭圆判定
步骤3:判定内凹区域是否为椭圆形刻入结构
提取内凹区域的轮廓点,用cv2.fitEllipse()做椭圆拟合,计算拟合残差,残差低于阈值即可判定为目标椭圆形刻入结构,排除不规则噪声凹痕。
内容的提问来源于stack exchange,提问作者brunoais
相关产品推荐
相关产品推荐

