一、什么是孔洞检测孔洞Hole是目标内部被背景包围的区域。在工业视觉中孔洞通常代表产品结构特征或缺陷。典型应用通孔检测铸件气孔检测注塑件缺料检测密封圈破损检测锂电极片缺陷检测二、孔洞检测原理常见方法轮廓层级HierarchyFloodFill 填充法连通域分析形态学填充面积差法推荐已知外轮廓Hierarchy二值图检测FloodFill统计ConnectedComponents三、方法一FloodFill孔洞检测思路二值图 ↓ 边界FloodFill ↓ 反色 ↓ 与原图OR ↓ 孔洞位置importcv2importnumpyasnpdefdetect_holes(image_path):# 1. 读取图像并转为灰度图imgcv2.imread(image_path)ifimgisNone:print(错误无法读取图像请检查路径。)returngraycv2.cvtColor(img,cv2.COLOR_BGR2GRAY)# 2. Otsu 自动二值化_,binarycv2.threshold(gray,0,255,cv2.THRESH_BINARYcv2.THRESH_OTSU)# 【关键】确保背景是黑色(0)目标前景是白色(255)# 如果图像左上角(0,0)是白色说明前景背景反了需要反转ifbinary[0,0]255:binarycv2.bitwise_not(binary)# # 方法一FloodFill (漫水填充法) 提取孔洞# fillbinary.copy()# mask 的长宽必须比原图各多 2 个像素masknp.zeros((fill.shape[0]2,fill.shape[1]2),np.uint8)# 从 (0,0) 开始填充外部背景为白色cv2.floodFill(fill,mask,(0,0),255)# 反色后与原图合并得到“实心目标”holes_filledcv2.bitwise_or(binary,cv2.bitwise_not(fill))# 用“实心目标”减去“原图”剩下的就是纯粹的孔洞real_holes_floodcv2.subtract(holes_filled,binary)# # 方法二轮廓层级法 (Hierarchy) 提取孔洞 (工业推荐)# 优点不受孔洞是否连通边缘的影响更精准# # RETR_CCOMP 会建立两层层级外层轮廓和内层孔洞contours,hierarchycv2.findContours(binary,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)real_holes_hierarchynp.zeros_like(binary)ifhierarchyisnotNone:fori,hinenumerate(hierarchy[0]):# h[3] 代表父轮廓索引。如果不为 -1说明它是被包围的内部孔洞ifh[3]!-1:cv2.drawContours(real_holes_hierarchy,contours,i,255,-1)# # 3. 在原图上绘制检测结果 (以轮廓层级法为例)# result_imgimg.copy()defect_count0# 在孔洞掩膜上寻找轮廓方便计算面积并过滤噪声hole_cnts,_cv2.findContours(real_holes_hierarchy,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)forcntinhole_cnts:areacv2.contourArea(cnt)# 过滤掉面积小于 20 像素的微小噪点ifarea20:continuedefect_count1x,y,w,hcv2.boundingRect(cnt)# 绘制红色矩形框cv2.rectangle(result_img,(x,y),(xw,yh),(0,0,255),2)# 标注面积cv2.putText(result_img,fArea:{area:.0f},(x,y-5),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,0,255),1)print(f检测到的孔洞/缺陷数量:{defect_count})# 4. 可视化展示cv2.imshow(1. Original Binary,binary)cv2.imshow(2. FloodFill Holes,real_holes_flood)cv2.imshow(3. Hierarchy Holes (Recommended),real_holes_hierarchy)cv2.imshow(4. Final Detection Result,result_img)cv2.waitKey(0)cv2.destroyAllWindows()if__name____main__:detect_holes(test.png)优点简单速度快不依赖轮廓四、方法二轮廓层级检测孔洞contours,hierarchycv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)fori,hinenumerate(hierarchy[0]):parenth[3]ifparent!-1:cv2.drawContours(img,contours,i,(0,0,255),2)说明parent -1外轮廓parent 0孔洞适合孔检测。五、方法三连通域分析num,labels,stats,centerscv2.connectedComponentsWithStats(binary)foriinrange(1,num):areastats[i,cv2.CC_STAT_AREA]ifarea100:continue可用于缺陷数量统计Blob分析异物检测六、方法四形态学检测利用闭运算填充孔洞。kernelcv2.getStructuringElement(cv2.MORPH_ELLIPSE,(9,9))closecv2.morphologyEx(binary,cv2.MORPH_CLOSE,kernel)holescv2.subtract(close,binary)适合小孔检测。七、缺陷分析检测完成后可分析areacv2.contourArea(cnt)lengthcv2.arcLength(cnt,True)x,y,w,hcv2.boundingRect(cnt)ratiow/h常用指标面积长宽比圆度外接矩形数量八、工业案例孔检测统计所有孔数量。铸件气孔过滤面积小于20像素噪声。密封圈检测内部是否断裂。Connector检测定位孔是否存在。九、完整案例importcv2importnumpyasnp imgcv2.imread(part.png)graycv2.cvtColor(img,cv2.COLOR_BGR2GRAY)_,binarycv2.threshold(gray,0,255,cv2.THRESH_BINARYcv2.THRESH_OTSU)fillbinary.copy()masknp.zeros((fill.shape[0]2,fill.shape[1]2),np.uint8)cv2.floodFill(fill,mask,(0,0),255)holescv2.bitwise_not(fill)cnts,_cv2.findContours(holes,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)forcincnts:ifcv2.contourArea(c)30:continuex,y,w,hcv2.boundingRect(c)cv2.rectangle(img,(x,y),(xw,yh),(0,0,255),2)cv2.imshow(result,img)cv2.waitKey()十、常见问题Q为什么检测不到孔洞二值化错误前景背景反色孔洞与边界连通Q为什么孔洞很多噪声未去除阈值不合理建议增加开运算、面积过滤。十一、总结方法优点场景FloodFill简单快速通用Hierarchy最准确Connector连通域统计方便空洞检测形态学小孔检测缺陷检测建议工业视觉中采用二值化 形态学 FloodFill/Hierarchy 面积过滤组合可获得稳定的孔洞检测效果。
Python OpenCV 孔洞检测与缺陷分析详解与实战
发布时间:2026/7/16 14:07:42
一、什么是孔洞检测孔洞Hole是目标内部被背景包围的区域。在工业视觉中孔洞通常代表产品结构特征或缺陷。典型应用通孔检测铸件气孔检测注塑件缺料检测密封圈破损检测锂电极片缺陷检测二、孔洞检测原理常见方法轮廓层级HierarchyFloodFill 填充法连通域分析形态学填充面积差法推荐已知外轮廓Hierarchy二值图检测FloodFill统计ConnectedComponents三、方法一FloodFill孔洞检测思路二值图 ↓ 边界FloodFill ↓ 反色 ↓ 与原图OR ↓ 孔洞位置importcv2importnumpyasnpdefdetect_holes(image_path):# 1. 读取图像并转为灰度图imgcv2.imread(image_path)ifimgisNone:print(错误无法读取图像请检查路径。)returngraycv2.cvtColor(img,cv2.COLOR_BGR2GRAY)# 2. Otsu 自动二值化_,binarycv2.threshold(gray,0,255,cv2.THRESH_BINARYcv2.THRESH_OTSU)# 【关键】确保背景是黑色(0)目标前景是白色(255)# 如果图像左上角(0,0)是白色说明前景背景反了需要反转ifbinary[0,0]255:binarycv2.bitwise_not(binary)# # 方法一FloodFill (漫水填充法) 提取孔洞# fillbinary.copy()# mask 的长宽必须比原图各多 2 个像素masknp.zeros((fill.shape[0]2,fill.shape[1]2),np.uint8)# 从 (0,0) 开始填充外部背景为白色cv2.floodFill(fill,mask,(0,0),255)# 反色后与原图合并得到“实心目标”holes_filledcv2.bitwise_or(binary,cv2.bitwise_not(fill))# 用“实心目标”减去“原图”剩下的就是纯粹的孔洞real_holes_floodcv2.subtract(holes_filled,binary)# # 方法二轮廓层级法 (Hierarchy) 提取孔洞 (工业推荐)# 优点不受孔洞是否连通边缘的影响更精准# # RETR_CCOMP 会建立两层层级外层轮廓和内层孔洞contours,hierarchycv2.findContours(binary,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)real_holes_hierarchynp.zeros_like(binary)ifhierarchyisnotNone:fori,hinenumerate(hierarchy[0]):# h[3] 代表父轮廓索引。如果不为 -1说明它是被包围的内部孔洞ifh[3]!-1:cv2.drawContours(real_holes_hierarchy,contours,i,255,-1)# # 3. 在原图上绘制检测结果 (以轮廓层级法为例)# result_imgimg.copy()defect_count0# 在孔洞掩膜上寻找轮廓方便计算面积并过滤噪声hole_cnts,_cv2.findContours(real_holes_hierarchy,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)forcntinhole_cnts:areacv2.contourArea(cnt)# 过滤掉面积小于 20 像素的微小噪点ifarea20:continuedefect_count1x,y,w,hcv2.boundingRect(cnt)# 绘制红色矩形框cv2.rectangle(result_img,(x,y),(xw,yh),(0,0,255),2)# 标注面积cv2.putText(result_img,fArea:{area:.0f},(x,y-5),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,0,255),1)print(f检测到的孔洞/缺陷数量:{defect_count})# 4. 可视化展示cv2.imshow(1. Original Binary,binary)cv2.imshow(2. FloodFill Holes,real_holes_flood)cv2.imshow(3. Hierarchy Holes (Recommended),real_holes_hierarchy)cv2.imshow(4. Final Detection Result,result_img)cv2.waitKey(0)cv2.destroyAllWindows()if__name____main__:detect_holes(test.png)优点简单速度快不依赖轮廓四、方法二轮廓层级检测孔洞contours,hierarchycv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)fori,hinenumerate(hierarchy[0]):parenth[3]ifparent!-1:cv2.drawContours(img,contours,i,(0,0,255),2)说明parent -1外轮廓parent 0孔洞适合孔检测。五、方法三连通域分析num,labels,stats,centerscv2.connectedComponentsWithStats(binary)foriinrange(1,num):areastats[i,cv2.CC_STAT_AREA]ifarea100:continue可用于缺陷数量统计Blob分析异物检测六、方法四形态学检测利用闭运算填充孔洞。kernelcv2.getStructuringElement(cv2.MORPH_ELLIPSE,(9,9))closecv2.morphologyEx(binary,cv2.MORPH_CLOSE,kernel)holescv2.subtract(close,binary)适合小孔检测。七、缺陷分析检测完成后可分析areacv2.contourArea(cnt)lengthcv2.arcLength(cnt,True)x,y,w,hcv2.boundingRect(cnt)ratiow/h常用指标面积长宽比圆度外接矩形数量八、工业案例孔检测统计所有孔数量。铸件气孔过滤面积小于20像素噪声。密封圈检测内部是否断裂。Connector检测定位孔是否存在。九、完整案例importcv2importnumpyasnp imgcv2.imread(part.png)graycv2.cvtColor(img,cv2.COLOR_BGR2GRAY)_,binarycv2.threshold(gray,0,255,cv2.THRESH_BINARYcv2.THRESH_OTSU)fillbinary.copy()masknp.zeros((fill.shape[0]2,fill.shape[1]2),np.uint8)cv2.floodFill(fill,mask,(0,0),255)holescv2.bitwise_not(fill)cnts,_cv2.findContours(holes,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)forcincnts:ifcv2.contourArea(c)30:continuex,y,w,hcv2.boundingRect(c)cv2.rectangle(img,(x,y),(xw,yh),(0,0,255),2)cv2.imshow(result,img)cv2.waitKey()十、常见问题Q为什么检测不到孔洞二值化错误前景背景反色孔洞与边界连通Q为什么孔洞很多噪声未去除阈值不合理建议增加开运算、面积过滤。十一、总结方法优点场景FloodFill简单快速通用Hierarchy最准确Connector连通域统计方便空洞检测形态学小孔检测缺陷检测建议工业视觉中采用二值化 形态学 FloodFill/Hierarchy 面积过滤组合可获得稳定的孔洞检测效果。