Search code examples
pythonopencvmachine-learningimage-processingk-means

Lung Segmentation from CT grey sale image using K means clustering Error


Input CT imageI tried to run below code for segmenting lung alone, but resulting image is as attached[Result image gettingInput CT image. Please help.

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

X= cv2.imread('0070.png',0)
pixel_values = np.float32(X)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
k = 3
ret, labels, (centers) = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
centers = np.uint8(centers)
labelss = labels.flatten()
print(labelss)
segmented_image = centers[labelss]
segmented_image = segmented_image.reshape((X.shape))
plt.imshow(segmented_image)
plt.show()

Solution

  • Here is a revised version that gets only the lungs and makes all the rest black using Python/OpenCV. After the kmeans processing, we only have 3 gray levels and the one we want is the middle one. So we threshold to extract that. Then we get the contour and areas and keep only the largest two contours by area.

    Input:

    enter image description here

    from skimage import io
    from sklearn import cluster
    import matplotlib.pyplot as plt
    import cv2
    import numpy as np
    
    # read input and convert to range 0-1
    image = io.imread('lung.png',as_gray=True)/255.0
    h, w = image.shape
    
    # reshape to 1D array
    image_2d = image.reshape(h*w,1)
    
    # set number of colors
    numcolors = 3
    
    # do kmeans processing
    kmeans_cluster = cluster.KMeans(n_clusters=int(numcolors))
    kmeans_cluster.fit(image_2d)
    cluster_centers = kmeans_cluster.cluster_centers_
    cluster_labels = kmeans_cluster.labels_
    
    # need to scale result back to range 0-255
    newimage = cluster_centers[cluster_labels].reshape(h, w)*255.0
    newimage = newimage.astype('uint8')
    
    # threshold to keep only middle gray values
    lower = (100)
    upper = (200)
    thresh = cv2.inRange(newimage, lower, upper)
    
    # get contours and corresponding areas and indices
    cntrs_info = []
    contours = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    contours = contours[0] if len(contours) == 2 else contours[1]
    index=0
    for cntr in contours:
        area = cv2.contourArea(cntr)
        cntrs_info.append((index,area))
        index = index + 1
    
    # sort contours by area
    def takeSecond(elem):
        return elem[1]
    cntrs_info.sort(key=takeSecond, reverse=True)
    
    # draw two largest contours as white filled on black background
    result = np.zeros_like(newimage)
    index_first = cntrs_info[0][0]
    cv2.drawContours(result,[contours[index_first]],0,(255),-1)
    index_second = cntrs_info[1][0]
    cv2.drawContours(result,[contours[index_second]],0,(255),-1)
    
    # display result
    io.imshow(newimage)
    io.show()
    io.imshow(thresh)
    io.show()
    io.imshow(result)
    io.show()
    
    # save kmeans clustered image and layer 3
    io.imsave('lung_kmeans.gif', newimage)
    io.imsave('lung_kmeans_thresh.gif', thresh)
    io.imsave('lung_kmeans_lungs.gif', result)
    

    Kmeans result:

    enter image description here

    Threshold result:

    enter image description here

    Two largest areas:

    enter image description here