如何使用OpenCV裁剪二值图像中最大的1-3个Blob
嘿,这问题我太熟了!用OpenCV处理这种二值图像里的Blob裁剪其实没那么复杂,我给你一步步拆解清楚怎么做:
步骤分解:
1. 读取图像并提取轮廓
首先咱们得把二值图像读进来,然后提取出所有的Blob轮廓。这里推荐用RETR_EXTERNAL模式只找最外层轮廓,避免嵌套轮廓干扰;CHAIN_APPROX_SIMPLE可以压缩轮廓点,节省内存:
import cv2 import numpy as np # 读取二值图像(灰度模式) img = cv2.imread('your_binary_image.png', cv2.IMREAD_GRAYSCALE) # 提取所有外层轮廓 contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
2. 按面积排序,选中目标Blob
接下来把所有轮廓按面积从大到小排序,这样就能轻松拿到最大的几个Blob。你可以选最大的1个,或者前3个,全看需求:
# 按轮廓面积降序排序 contours_sorted = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True) # 选择要保留的Blob数量,比如前3个(改成1就是只取最大的) top_n = 3 selected_contours = contours_sorted[:top_n]
3. 提取目标区域(两种方式可选)
这里有两种常用的处理方式,你可以根据需求选:
方式A:保留原图尺寸,只显示选中的Blob
这种方式会生成一张和原图一样大的图像,只保留你选中的Blob,其余区域还是黑色:
# 创建和原图一样大的黑色掩码 mask = np.zeros_like(img) # 在掩码上填充选中的轮廓(白色) cv2.drawContours(mask, selected_contours, -1, 255, thickness=cv2.FILLED) # 用掩码提取目标区域 result = cv2.bitwise_and(img, mask) # 保存或查看结果 cv2.imwrite('selected_blobs.png', result) cv2.imshow('Selected Blobs', result) cv2.waitKey(0) cv2.destroyAllWindows()
方式B:单独裁剪每个Blob的最小包围框
如果需要把每个大Blob单独切出来保存,就遍历选中的轮廓,用boundingRect找到每个Blob的边界框,然后裁剪:
# 遍历选中的轮廓,逐个裁剪 for idx, cnt in enumerate(selected_contours): # 获取当前Blob的边界框坐标(x,y)和宽高(w,h) x, y, w, h = cv2.boundingRect(cnt) # 裁剪出Blob区域 cropped_blob = img[y:y+h, x:x+w] # 保存裁剪后的图像 cv2.imwrite(f'cropped_blob_{idx+1}.png', cropped_blob) # 显示结果 cv2.imshow(f'Cropped Blob {idx+1}', cropped_blob) cv2.waitKey(0) cv2.destroyAllWindows()
一些实用小提示
- 如果你的图像里有零星的小噪声白点,建议先做个开运算清理一下,避免噪声干扰排序结果:
# 用3x3的核做开运算,去除小噪声 kernel = np.ones((3,3), np.uint8) img_cleaned = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 之后用清理后的图像提取轮廓即可
- 要是你的二值图像是黑色Blob、白色背景,记得先用
cv2.bitwise_not(img)反转一下,确保目标是白色的,这样后续步骤才会正常工作。
内容的提问来源于stack exchange,提问作者kaptsea




