14

I have a segmentation image of CT scan (only 1 and 0 values). I use the function "label" from skimage.measure to get a ndarray of the connected component. Now I need to get only the largest connected component from the "label" output (ndarray). Do you have any idea how can I do it?

My code looks like this:

from skimage.measure import label    

def getLargestCC(segmentation):
    labels = label(segmentation)
    // now I need to get only the largest connected component and return it
return largestCC

Thanks a lot!

Vipasana
  • 503
  • 1
  • 4
  • 13
  • Could you post the content of `segmentation` for testing? – Tiger-222 Nov 28 '17 at 22:11
  • It's a bit of a problem because it's an image and I don't know how can I add this kind of a file in the posts here. It's actually an image file which I did segmentation for it, so every pixels with value between 2 values are 1 and all the others are 0. – Vipasana Nov 30 '17 at 16:21

6 Answers6

23

The answer of Gilly is interesting but wrong if the background (label=0) is larger than CC researched. The Alaleh Rz solution deals with the background but is very slow. Adapting the solution proposed by Gilly and removing the background problem:

import numpy as np
from skimage.measure import label   

def getLargestCC(segmentation):
    labels = label(segmentation)
    assert( labels.max() != 0 ) # assume at least 1 CC
    largestCC = labels == np.argmax(np.bincount(labels.flat)[1:])+1
    return largestCC
Vincent Agnus
  • 1,263
  • 11
  • 11
6

I am not sure what you want as the output, a mask?

import numpy as np
from skimage.measure import label   

def getLargestCC(segmentation):
    labels = label(segmentation)
    largestCC = labels == np.argmax(np.bincount(labels.flat))
    return largestCC

Numpy's bincount will count for each label the number of occurrences, and argmax will tell you which of these was the largest.

Gilly
  • 1,739
  • 22
  • 30
6

The OP's input segmentation data is binary where the background is 0. So, we can use Vincent Agnus' np.bincount approach but simplify the background rejection logic by using np.bincount's weights argument. Set weights=segmentation.flat to zero out the background sum.

import numpy as np
from skimage.measure import label   

def getLargestCC(segmentation):
    labels = label(segmentation)
    largestCC = labels == np.argmax(np.bincount(labels.flat, weights=segmentation.flat))
    return largestCC
P Tate
  • 61
  • 1
  • 2
4

The following function gives the largest connected segmentation which is not backgroud. The shape of input and output is the same which could be 2D or 3D images.

import numpy as np
from skimage.measure import label

def getLargestCC(segmentation):
    labels = label(segmentation)
    unique, counts = np.unique(labels, return_counts=True)
    list_seg=list(zip(unique, counts))[1:] # the 0 label is by default background so take the rest
    largest=max(list_seg, key=lambda x:x[1])[0]
    labels_max=(labels == largest).astype(int)
    return labels_max
Alaleh Rz
  • 415
  • 6
  • 8
4

I was trying to figure out how to stop skimage.measure.label counting background as separate region. It was that I almost started digging skimage.measure.regionprops docs until I came upon P Tate's elegant solution. Here is a quick figure which shows how using suggested weights parameter of numpy.bincount can save some lines of code.

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

img_bw = img_as_bool(img)
labels = skimage.measure.label(img_bw, return_num=False)

maxCC_withbcg = labels == np.argmax(np.bincount(labels.flat))
maxCC_nobcg = labels == np.argmax(np.bincount(labels.flat, weights=img_bw.flat))

fig, ax = plt.subplots(1, 2)
ax[0].imshow(maxCC_withbcg), ax[0].set_title('counts bcg')
ax[1].imshow(maxCC_nobcg), ax[1].set_title('not counts bcg')
[axi.set_axis_off() for axi in ax.ravel()]

enter image description here

San Askaruly
  • 311
  • 1
  • 10
0

Based on P Tate's solution and assuming that the binary segmentation mask is of type bool one could also use that mask to only input the foreground pixels into np.bincount by indexing/masking with segmentation:

import numpy as np
from skimage.measure import label   

def largest_connected_component(segmentation):
    labels = label(segmentation)
    largest_cc = labels == np.argmax(np.bincount(labels[segmentation]))
    return largest_cc