我从 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()
看起来你已经很接近了!您可能需要调整轮廓函数中的参数才能正确捕获所有肋骨:
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
我想有一种更矢量化/更有效的方法来做到这一点,但我认为这将给你带来你想要的第一遍。