图像处理:如何统计二值图像中目标的凸区域数量?

二值图像凸区域计数实现方案
直接基于OpenCV的轮廓分析能力即可实现,不需要复杂的自定义算法,落地步骤如下:
- 图像预处理
先对输入二值图做形态学开运算,消除孤立噪点、边缘细小毛刺,避免将细碎干扰误判为独立区域,参考代码:import cv2 import numpy as np # 读入灰度二值图 bin_img = cv2.imread("target.png", 0) # 3*3卷积核做开运算 kernel = np.ones((3, 3), np.uint8) cleaned_img = cv2.morphologyEx(bin_img, cv2.MORPH_OPEN, kernel) - 提取独立轮廓
调用轮廓提取接口获取所有独立连通域的轮廓,如果只需要统计最外层不嵌套的凸区域,用外轮廓检索模式即可;如果需要统计嵌套在轮廓内部的凸区域,切换为层级检索模式:# RETR_EXTERNAL仅提取最外层轮廓,RETR_TREE会提取所有层级轮廓 contours, hierarchy = cv2.findContours(cleaned_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - 凸性判定计数
逐一对轮廓做凸性校验,支持严格判定和带容错的宽松判定两种模式,适配不同质量的输入图像:- 严格判定:直接调用
cv2.isContourConvex()接口,返回True则判定为标准凸区域,适合边缘光滑无毛刺的标准场景 - 宽松判定:针对边缘带微小锯齿、轻微拍摄/绘制误差的场景,先计算轮廓的凸包,再统计凸包和原轮廓之间的凸缺陷总面积,当凸缺陷总面积占轮廓自身面积的比例低于设定阈值(通常取0.5%~2%)时,依然判定为凸区域
计数逻辑参考代码:
convex_total = 0 # 最小面积阈值,过滤掉尺寸过小的噪点轮廓,根据实际图像分辨率调整 min_area = 15 # 凸缺陷占比阈值,宽松判定用 defect_ratio_thresh = 0.01 for cnt in contours: cnt_area = cv2.contourArea(cnt) # 过滤过小噪点 if cnt_area < min_area: continue # 严格凸判定 if cv2.isContourConvex(cnt): convex_total += 1 continue # 宽松凸判定 hull = cv2.convexHull(cnt, returnPoints=False) defects = cv2.convexityDefects(cnt, hull) # 无凸缺陷直接判定为凸 if defects is None: convex_total += 1 continue # 统计总凸缺陷量 total_defect = 0 for i in range(defects.shape[0]): _, _, _, defect_depth = defects[i, 0] total_defect += defect_depth / 256.0 if total_defect / cnt_area < defect_ratio_thresh: convex_total += 1 print(f"检测到的凸区域总数为:{convex_total}") - 严格判定:直接调用
- 特殊场景适配
- 如果图像中存在凸区域互相粘连的情况,先做分水岭分割将粘连区域拆分为独立连通域,再执行上述流程,否则会把多个粘连凸区域误判为1个
- 如果需要统计嵌套结构内的凸区域,将轮廓检索模式改为
cv2.RETR_TREE后,根据返回的层级信息筛选需要统计的轮廓层级即可 - 最小面积阈值、凸缺陷占比阈值没有通用固定值,需要根据自身图像的分辨率、目标尺寸做适配调整
内容的提问来源于stack exchange,提问作者Paul_Dx
相关产品推荐
相关产品推荐

