OpenCV中K-Means二聚类分割后如何提取目标区域二值掩码
问题根源
调用cv2.kmeans时使用cv2.KMEANS_RANDOM_CENTERS参数会随机选择初始聚类中心,每次运行后标签0、1对应的前景/背景类别会随机互换,没有固定对应关系,因此无法稳定提取目标区域。
实现逻辑
要稳定生成可用于面积计算的左心耳掩码,按以下流程处理即可:
- 聚类完成后匹配目标类别:原始图像中左心耳腔体区域亮度显著低于周围亮背景,将两个BGR格式的聚类中心转为灰度值,灰度值更小的类别即为左心耳区域。如果要降低聚类结果的随机波动,可将初始化参数替换为
cv2.KMEANS_PP_CENTERS,使用kmeans++算法选择初始中心,结果一致性更好。 - 生成标准二值掩码:将聚类得到的标签数组与目标类别值做相等判断,生成的布尔数组转为
uint8格式,目标区域赋值255、背景赋值0,即可得到单通道二值掩码。 - 面积计算:直接统计掩码中非零像素的数量,即可得到左心耳的像素面积;如果需要实际物理面积,乘以DICOM文件中存储的像素间距参数即可。
完整实现代码
import numpy as np import cv2 # 读取原始图像 img = cv2.imread('1_LA.jpg') pixel_values = np.float32(img.reshape((-1, 3))) # 设置K-means聚类参数 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) K = 2 # 若要更稳定的聚类结果,可将下面的cv2.KMEANS_RANDOM_CENTERS替换为cv2.KMEANS_PP_CENTERS _, labels, centers = cv2.kmeans(pixel_values, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) labels = labels.reshape(img.shape[:-1]) # 匹配暗区域(左心耳)对应的标签 center_gray = [] for c in centers: # 将BGR格式的聚类中心转为灰度值 gray_val = cv2.cvtColor(np.uint8([[c]]), cv2.COLOR_BGR2GRAY)[0][0] center_gray.append(gray_val) target_label = np.argmin(center_gray) # 生成二值掩码 mask = np.uint8(labels == target_label) * 255 # 计算像素面积 area_pixel = cv2.countNonZero(mask) print(f"左心耳像素面积:{area_pixel}") # 保存掩码文件 cv2.imwrite('laa_mask.png', mask) # 可选:生成分割叠图验证效果 mask_3channel = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) overlay = cv2.addWeighted(img, 0.7, mask_3channel, 0.3, 0) cv2.imwrite('segmentation_verify.jpg', overlay)
结果说明
运行代码后生成的laa_mask.png为单通道二值掩码,目标区域值为255、背景值为0,和需求的目标掩码格式完全一致,可直接用于后续面积计算、形态学操作等任务。
如果后续测试的图像中目标区域为高亮度区域,只需将代码中np.argmin替换为np.argmax即可正确匹配目标类别。
内容的提问来源于stack exchange,提问作者TseHsien
相关产品推荐
相关产品推荐

