Сегментация легких с помощью K-means содержит белую границу.

Вопрос или проблема

Я новичок в обработке изображений, я пытаюсь сегментировать КТ изображения легких с помощью Kmeans следующим образом:

import numpy as np
import re
import pandas as pd
from skimage import morphology
from skimage import measure
from PIL import Image
from sklearn.cluster import KMeans
from skimage.transform import resize
from glob import glob
import sys
import os
import cv2
from scipy.ndimage.morphology import binary_dilation,generate_binary_structure
from skimage.morphology import convex_hull_image

def process_mask(mask):
    convex_mask = np.copy(mask)
    for i_layer in range(convex_mask.shape[0]):
        mask1  = np.ascontiguousarray(mask[i_layer])
        if np.sum(mask1)>0:
            mask2 = convex_hull_image(mask1)
            if np.sum(mask2)>2*np.sum(mask1):
                mask2 = mask1
        else:
            mask2 = mask1
        convex_mask[i_layer] = mask2
    struct = generate_binary_structure(3,1)
    dilatedMask = binary_dilation(convex_mask,structure=struct,iterations=10)

    return dilatedMask

def lumTrans(img):
    lungwin = np.array([-1200.,600.])
    newimg = (img-lungwin[0])/(lungwin[1]-lungwin[0])
    newimg[newimg<0]=0
    newimg[newimg>1]=1
    newimg = (newimg*255).astype('uint8')
    return newimg

def lungSeg(imgs_to_process,output,name):

    if os.path.exists(output+"https://datascience.stackexchange.com/"+name+'_clean.npy') : return
    imgs_to_process = Image.open(imgs_to_process)

    img_to_save = imgs_to_process.copy()
    img_to_save = np.asarray(img_to_save).astype('uint8')

    imgs_to_process = lumTrans(imgs_to_process)    
    imgs_to_process = np.expand_dims(imgs_to_process, axis=0)
    x,y,z = imgs_to_process.shape 

    img_array = imgs_to_process.copy()  
    A1 = int(y/(512./100))
    A2 = int(y/(512./400))

    A3 = int(y/(512./475))
    A4 = int(y/(512./40))
    A5 = int(y/(512./470))
    for i in range(len(imgs_to_process)):
        img = imgs_to_process[i]
        print(img.shape)
        x,y = img.shape
        #Стандартизируем значения пикселей
        allmean = np.mean(img)
        allstd = np.std(img)
        img = img-allmean
        img = img/allstd
        # Найдите среднее значение пикселя вблизи легких
        # для перенормализации вымытых изображений
        middle = img[A1:A2,A1:A2] 
        mean = np.mean(middle)  
        max = np.max(img)
        min = np.min(img)

        kmeans = KMeans(n_clusters=2).fit(np.reshape(middle,[np.prod(middle.shape),1]))
        centers = sorted(kmeans.cluster_centers_.flatten())
        threshold = np.mean(centers)
        thresh_img = np.where(img<threshold,1.0,0.0)  # пороговое значение изображения

        eroded = morphology.erosion(thresh_img,np.ones([4,4]))
        dilation = morphology.dilation(eroded,np.ones([10,10]))

        labels = measure.label(dilation)
        label_vals = np.unique(labels)
        regions = measure.regionprops(labels)
        good_labels = []
        for prop in regions:
            B = prop.bbox
            if B[2]-B[0]<A3 and B[3]-B[1]<A3 and B[0]>A4 and B[2]<A5:
                good_labels.append(prop.label)
        mask = np.ndarray([x,y],dtype=np.int8)
        mask[:] = 0

        for N in good_labels:
            mask = mask + np.where(labels==N,1,0)
        mask = morphology.dilation(mask,np.ones([10,10])) # последняя дилатация
        imgs_to_process[i] = mask

    m1 = imgs_to_process

    convex_mask = m1
    dm1 = process_mask(m1)
    dilatedMask = dm1
    Mask = m1
    extramask = dilatedMask ^ Mask
    bone_thresh = 180
    pad_value = 0

    img_array[np.isnan(img_array)]=-2000
    sliceim = img_array
    sliceim = sliceim*dilatedMask+pad_value*(1-dilatedMask).astype('uint8')
    bones = sliceim*extramask>bone_thresh
    sliceim[bones] = pad_value

    x,y,z = sliceim.shape
    if not os.path.exists(output): 
        os.makedirs(output)

    img_to_save[sliceim.squeeze()==0] = 0

    im = Image.fromarray(img_to_save)

    im.save(output + name + '.png', 'PNG')

Метод вызова сегментации легких:

lungSeg(image_path, new_image_path, image_name)

Проблема в том, что сегментированное легкое все еще содержит белые границы, как это:

сегментированное легкое (выход):

segmented lung

несегментированное легкое (вход):

unsegmented lung

Весь код здесь https://colab.research.google.com/drive/1gdZi7dv2bo4MNgR9suuM1ZCMItSWXggl?usp=sharing

Попробуйте использовать Операции эрозии и дилатации для удаления белой области.

Ответ или решение

В вопросе рассматривается задача сегментации легких на КТ-снимках с использованием алгоритма K-средних (KMeans). При текущей реализации возникает проблема: на сегментированном изображении остаются белые границы. Рассмотрим причины этой проблемы и как её можно устранить.

Теория:

Сегментация изображения на основе алгоритма K-средних заключается в делении пикселей на кластеры по их интенсивностям. В данном случае используется два кластера, что позволяет отделить яркие области (предположительно кости) и менее яркие области (возможные легкие). Однако после сегментации могут возникать нежелательные артефакты, например, белые границы, которые могут быть результатом неточного порогового значения или артефактов, возникающих при морфологических операциях.

Пример проблемы:

Как видно на изображении результата, белые границы могут появляться из-за недостаточно точной сегментации, где области, граничащие с легкими, неправильно классифицируются. Это может быть связано с особенностями алгоритма K-средних, который может не в полной мере учитывать контекст изображения, особенно в сложных медицинских снимках.

Применение:

Для устранения белых границ можно использовать морфологические операции, такие как эрозия и дилатация (расширение). Эти операции могут помочь удалить небольшие артефакты, такие как ненужные белые границы.

  1. Эрозия уменьшает белые области в изображении. Это достигается с помощью свертки с ядром (например, матрицей из единиц), которое сканирует изображение и удаляет пиксели на границе объектов, уменьшая их размер.

  2. Дилатация увеличивает области объектов, что может помочь восстановить полезную информацию после применения эрозии.

В Python это можно реализовать с использованием библиотеки OpenCV:

import cv2

def remove_white_borders(image_path):
    # Загрузите изображение
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

    # Примените эрозию для уменьшения белых областей
    kernel = np.ones((5, 5), np.uint8)
    eroded = cv2.erode(img, kernel, iterations=1)

    # Примените дилатацию для восстановления структуры
    dilated = cv2.dilate(eroded, kernel, iterations=1)

    return dilated

Эту функцию можно использовать на этапе постобработки, чтобы улучшить качество сегментации и удалить белые границы.

Таким образом, внедрение правок и корректная настройка параметров морфологических операций могут существенно улучшить результаты сегментации изображения. Рекомендуется также тщательно проверять и модифицировать алгоритм кластеризации и пороговые значения, чтобы оптимально выделять только интересующие области легких.

Оцените материал
Добавить комментарий

Капча загружается...