在肺部分段区域上拟合抛物线

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

我正在尝试对胸部 X 光图像进行肺部分割

import cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

def margin(img, margin_percent=10):
    h, w = img.shape
    margin_x = int(w * margin_percent / 100)
    margin_y = int(h * margin_percent / 100)
    cropped = img[margin_y:h-margin_y, margin_x:w-margin_x]
    return cropped

def process(img):
    flat_img = img.flatten().reshape(-1, 1)
    kmeans = KMeans(n_clusters=2, n_init=10, random_state=0)
    labels = kmeans.fit_predict(flat_img)
    centers = kmeans.cluster_centers_
    if np.mean(centers[1]) > np.mean(centers[0]):
        labels = 1 - labels
    clustered = np.reshape(labels, img.shape)
    clustered_binary = np.uint8(clustered * 255)
    return clustered_binary

def segment_and_filter(clustered_img):
    ret, thresh = cv2.threshold(clustered_img, 0, 255, cv2.THRESH_BINARY)
    if cv2.__version__[0] > '3':
        contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    else:
        _, contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    max_area = 0
    largest_contour = None
    for contour in contours:
        area = cv2.contourArea(contour)
        if area > max_area:
            max_area = area
            largest_contour = contour
    
    result = np.zeros_like(clustered_img)
    cv2.drawContours(result, [largest_contour], -1, 255, thickness=cv2.FILLED)
    return result, largest_contour

def process_image(image_path):
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    cropped_img = margin(img)
    clustered_img = process(cropped_img)
    filtered_result, largest_contour = segment_and_filter(clustered_img)
    
    combined_image = np.hstack((filtered_result[:, :filtered_result.shape[1] // 2], 
                                cv2.flip(filtered_result[:, :filtered_result.shape[1] // 2], 1)))
    
    return combined_image

image_path = "/kaggle/input/chest-xray-pneumonia/chest_xray/test/NORMAL/IM-0105-0001.jpeg"
result_image = process_image(image_path)

plt.figure(figsize=(9, 3))
plt.imshow(result_image, cmap='gray')
plt.title('Combined Lungs')
plt.axis('on')
plt.show()

上面的代码给出了这个输出 到目前为止一切都很好

现在我想拟合一条覆盖两个肺部区域的抛物线 尝试了多次 但这没有用

你能帮我吗?

尝试过单肺得到这个,但对两个都不起作用

预计

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

希望这对您有帮助。

import cv2
import numpy as np
import matplotlib.pyplot as plt


def preprocess_image(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    equalized = cv2.equalizeHist(gray)
    return equalized


def segment_lungs(image):
    _, binary = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2)
    binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations=2)

    return binary


image_path = "image.png"
image = cv2.imread(image_path)

preprocessed_image = preprocess_image(image)

lung_mask = segment_lungs(preprocessed_image)

if cv2.__version__[0] > '3':
    contours, _ = cv2.findContours(lung_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
else:
    _, contours, _ = cv2.findContours(lung_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

top_points = []
for contour in contours:
    top_point = tuple(contour[contour[:, :, 1].argmin()][0])
    top_points.append(top_point)

top_points = np.array(top_points)

sorted_top_points = top_points[np.argsort(top_points[:, 0])]

x = sorted_top_points[:, 0]
y = sorted_top_points[:, 1]


coefficients = np.polyfit(x, y, 2)
a, b, c = coefficients

x_values = np.linspace(min(x), max(x), 100)
y_values = a * x_values ** 2 + b * x_values + c

plt.imshow(image, cmap='gray')

for contour in contours:
    plt.plot(contour[:, 0, 0], contour[:, 0, 1], 'r', linewidth=2)

plt.plot(x_values, y_values, 'b', linewidth=5)
plt.title('Lung Segmentation with Fitted Parabola')
plt.axis('off')
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.