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

胸部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()

当前输出

当前输出图像

期望输出

期望输出图像

改进方案

核心流程

采用自动阈值分割+连通区域筛选+形态学修复的组合方案,无需裁剪边缘即可规避文本干扰,精准定位双肺:

  1. 用大津法(Otsu)自动计算阈值,分离X光中的高亮组织区域(含肺部、肋骨)
  2. 筛选连通区域,保留面积符合双肺范围的区域,排除文本这类小面积干扰
  3. 用形态学闭操作填补掩码漏洞,开操作清除残留噪点
  4. 将掩码与原图结合,得到仅保留肺区域的结果

改进后代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:25:59