胸部X光图像肺区域分割优化请求(不使用预训练模型)
问题描述
我导入了一个包含大量X光图像的Kaggle数据集,目标是检测肺区域并将肋骨笼外部区域置黑。最初尝试以覆盖肺部的最亮连通区域——肋骨笼为轮廓进行分割,但数据集图像侧边带有L/R标注文本干扰。我裁剪了10%的边缘以规避文本后运行算法,未得到理想输出。需要改进算法或提供其他分割双肺的方案,偏好不使用预训练模型。
现有代码
import cv2 import numpy as np import matplotlib.pyplot as plt def crop_xray(image_path, margin_percentage=10): image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) height, width = image.shape margin_x = int(width * margin_percentage / 100) margin_y = int(height * margin_percentage / 100) cropped_image = image[margin_y:height-margin_y, margin_x:width-margin_x] return cropped_image, image def add_outline(image): blurred = cv2.GaussianBlur(image, (5, 5), 0) edges = cv2.Canny(blurred, 30, 150) kernel = np.ones((5, 5), np.uint8) closed_edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel) dilated = cv2.dilate(closed_edges, kernel, iterations=3) dilated = cv2.bitwise_not(dilated) _, mask = cv2.threshold(dilated, 0, 255, cv2.THRESH_BINARY) outlined_image = cv2.bitwise_and(image, image, mask=mask) return outlined_image xray_image_path = "/kaggle/input/chest-xray-pneumonia/chest_xray/test/NORMAL/IM-0075-0001.jpeg" cropped_image, original_image = crop_xray(xray_image_path) outlined_image = add_outline(cropped_image) plt.figure(figsize=(15, 5)) # Original image plt.subplot(1, 3, 1) plt.imshow(original_image, cmap='gray') plt.title('Original Image') plt.axis('on') # Cropped image plt.subplot(1, 3, 2) plt.imshow(cropped_image, cmap='gray') plt.title('Cropped Image with 10% Margin') plt.axis('on') # Outlined image plt.subplot(1, 3, 3) plt.imshow(outlined_image, cmap='gray') plt.title('Outlined Image') plt.axis('on') plt.show()
当前输出

期望输出

改进方案
核心流程
采用自动阈值分割+连通区域筛选+形态学修复的组合方案,无需裁剪边缘即可规避文本干扰,精准定位双肺:
- 用大津法(Otsu)自动计算阈值,分离X光中的高亮组织区域(含肺部、肋骨)
- 筛选连通区域,保留面积符合双肺范围的区域,排除文本这类小面积干扰
- 用形态学闭操作填补掩码漏洞,开操作清除残留噪点
- 将掩码与原图结合,得到仅保留肺区域的结果
改进后代码
import cv2 import numpy as np import matplotlib.pyplot as plt def segment_lung(image_path): # 读取灰度X光图像 image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 1. 大津法自动阈值分割,分离高亮区域 _, thresh_img = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # 2. 提取并筛选连通区域 num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(thresh_img, connectivity=8) img_area = image.shape[0] * image.shape[1] # 设定面积阈值:保留图像面积10%到50%之间的区域(适配双肺尺寸) min_valid_area = img_area * 0.1 max_valid_area = img_area * 0.5 # 生成初始掩码 lung_mask = np.zeros_like(image) for label_idx in range(1, num_labels): # 跳过背景(索引0) area = stats[label_idx, cv2.CC_STAT_AREA] if min_valid_area < area < max_valid_area: lung_mask[labels == label_idx] = 255 # 3. 形态学操作修复掩码 # 椭圆核比矩形核更贴合肺部轮廓 morph_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15)) # 闭操作填补小漏洞 lung_mask = cv2.morphologyEx(lung_mask, cv2.MORPH_CLOSE, morph_kernel) # 开操作清除残留小噪点 lung_mask = cv2.morphologyEx(lung_mask, cv2.MORPH_OPEN, morph_kernel) # 4. 应用掩码得到分割结果 segmented_image = cv2.bitwise_and(image, image, mask=lung_mask) return image, segmented_image # 测试执行 xray_path = "/kaggle/input/chest-xray-pneumonia/chest_xray/test/NORMAL/IM-0075-0001.jpeg" original_img, result_img = segment_lung(xray_path) # 可视化结果 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.imshow(original_img, cmap='gray') plt.title('原始X光图像') plt.axis('off') plt.subplot(1, 2, 2) plt.imshow(result_img, cmap='gray') plt.title('肺区域分割结果') plt.axis('off') plt.tight_layout() plt.show()
方案特点
- 无需裁剪边缘,避免丢失肺边缘的有效信息
- 自动适配不同X光的亮度差异,阈值无需手动调整
- 通过面积筛选精准排除文本、小噪点等干扰元素
- 椭圆形态学核更贴合肺部自然轮廓,分割结果更准确
内容的提问来源于stack exchange,提问作者Subhadeep98Ares
相关产品推荐
相关产品推荐

