能否使用OpenCV去除角膜内皮细胞二值掩码中的内部轮廓?
角膜内皮细胞二值掩码内部杂散边缘清理方案
问题背景
我正在开发一个输出角膜内皮细胞二值掩码的网络,初始掩码如下:
目标是仅保留边缘完全闭合的完整细胞,去除所有杂散边缘。经过CV2和scikit后处理,得到了部分清理后的掩码:
已通过cv2.RETR_EXTERNAL去除了所有外部杂散边缘,但图像中仍存在无法清除的内部杂散边缘,示例如下:
目前用于清理骨架化后外部杂散边缘的代码:
import cv2 import numpy as np # Load the binary mask image mask = cv2.imread('pruned_result.png', cv2.IMREAD_GRAYSCALE) # Find contours in the opened image contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Create a mask for valid cells filtered_mask = np.zeros_like(mask) cv2.drawContours(filtered_mask, contours, -1, 255, thickness=cv2.FILLED) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) # Perform morphological opening to remove small stray edges opened = cv2.morphologyEx(filtered_mask, cv2.MORPH_OPEN, kernel) # Perform morphological closing to fill in any holes closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel) cutout_image = cv2.bitwise_and(mask, closed) # Save the resulting image with stray edges removed cv2.imwrite('filtered_mask.png', cutout_image)
针对性解决方法
1. 轮廓特征筛选
内部杂散边缘多对应极小或形状异常的轮廓,可在提取轮廓时增加面积、圆度筛选:
import cv2 import numpy as np mask = cv2.imread('pruned_result.png', cv2.IMREAD_GRAYSCALE) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) filtered_mask = np.zeros_like(mask) for cnt in contours: area = cv2.contourArea(cnt) # 过滤面积过小的轮廓(阈值根据实际图像调整) if area < 50: continue # 筛选近似圆形的细胞轮廓(圆度阈值按需调整) perimeter = cv2.arcLength(cnt, True) if perimeter == 0: continue circularity = 4 * np.pi * (area / (perimeter ** 2)) if circularity > 0.5: cv2.drawContours(filtered_mask, [cnt], -1, 255, cv2.FILLED) # 后续形态学操作可保留或调整 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) opened = cv2.morphologyEx(filtered_mask, cv2.MORPH_OPEN, kernel) cv2.imwrite('filtered_mask.png', opened)
2. 孔洞填充+反向提取
先填充细胞区域内的微小孔洞,再提取完整闭合细胞:
import cv2 import numpy as np mask = cv2.imread('pruned_result.png', cv2.IMREAD_GRAYSCALE) h, w = mask.shape # 填充所有孔洞 filled_mask = mask.copy() flood_mask = np.zeros((h+2, w+2), np.uint8) cv2.floodFill(filled_mask, flood_mask, (0,0), 255) holes = cv2.bitwise_not(filled_mask) filled_mask = mask | holes # 提取填充后的外部轮廓,过滤小区域 contours, _ = cv2.findContours(filled_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cleaned_mask = np.zeros_like(mask) for cnt in contours: if cv2.contourArea(cnt) > 50: cv2.drawContours(cleaned_mask, [cnt], -1, 255, cv2.FILLED) cv2.imwrite('filtered_mask.png', cleaned_mask)
3. 结合scikit-image区域分析
通过区域属性(实心度、面积)过滤杂散边缘:
import cv2 import numpy as np from skimage.measure import label, regionprops mask = cv2.imread('pruned_result.png', cv2.IMREAD_GRAYSCALE) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) filtered_mask = np.zeros_like(mask) cv2.drawContours(filtered_mask, contours, -1, 255, cv2.FILLED) # 标记连通区域并筛选 label_img = label(filtered_mask) cleaned_mask = np.zeros_like(filtered_mask) for region in regionprops(label_img): # 实心度接近1表示区域完整无孔洞 if region.area > 50 and region.solidity > 0.8: cleaned_mask[label_img == region.label] = 255 cv2.imwrite('filtered_mask.png', cleaned_mask)
内容的提问来源于stack exchange,提问作者vss61
相关产品推荐
相关产品推荐

