从 X 射线图像中检测肺部区域

问题描述 投票:0回答:1

我从 Kaggle 导入了一个包含大量 X 射线图像的数据集。我的目标是检测肺部区域和胸腔的外部,我想将其变黑。最初,我尝试了一种方法来勾勒出胸腔的轮廓,因为它是覆盖肺部的最亮的连接部分。然而,数据集图像存在在侧面标记 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()

我得到的输出

所需的输出[有点这样,可以不同,但应该检测肺部区域]

python opencv machine-learning image-processing computer-vision
1个回答
0
投票

看起来你已经很接近了!您可能需要调整轮廓函数中的参数才能正确捕获所有肋骨:

def add_outline(image, kernel_size=(5,5), dilations=3, canny_low=30, canny_high=150):
    
    blurred = cv2.GaussianBlur(image, kernel_size, 0)
    edges = cv2.Canny(blurred, canny_low, canny_high)
    kernel = np.ones(kernel_size, np.uint8)
    closed_edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
    dilated = cv2.dilate(closed_edges, kernel, iterations=dilations)
    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

我想你可以通过一些实验来弄清楚。

要创建所需的蒙版,您可以蒙版边缘左侧和右侧的所有像素:

def segment_image(image, outlines):
    # image: your input image
    # outlines: just the `mask` from your `add_outline` function
    new_mask = np.zeros_like(image) # assuming your image is grayscaled i.e. no color channel, this should be a 2D array
    for i,(img_row, outline_row) in enumerate(zip(image, outlines)):
        bounds = np.where(outline_row > 0)[0] # find the indices of the edges
        new_mask[i, bounds.min():bounds.max()] = 1 # fill-in the new mask
    return image * new_mask

我想有一种更矢量化/更有效的方法来做到这一点,但我认为这将给你带来你想要的第一遍。

© www.soinside.com 2019 - 2024. All rights reserved.