You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 18:24:54