4

I have a binary image of cells. I want to use python to separate these cells individually. Each cell will save in an image. For example, I have 1000 cells, then the output will be 1000 images, each image contains 1 cell. Currently, I am using two ways to obtain it but the output is wrong

from skimage.morphology import watershed
from skimage.feature import peak_local_max
from skimage import morphology
import numpy as np
import cv2
from scipy import ndimage
from skimage import segmentation

image=cv2.imread('/home/toanhoi/Downloads/nuclei/9261_500_f00020_mask.png',0)
image=image[300:600,600:900]
# First way: peak_local_max
distance = ndimage.distance_transform_edt(image)
local_maxi = peak_local_max(distance, indices=False, footprint=np.ones((3, 3)), labels=image)
markers = morphology.label(local_maxi)
labels_ws = watershed(-distance, markers, mask=image)
markers[~image] = -1
labels_rw = segmentation.random_walker(image, markers)
cv2.imshow('watershed',labels_rw)
cv2.waitKey(5000)
# Second way way: using contour
_,contours,heirarchy=cv2.findContours(image,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image,contours,-1,(125,125,0),1)

cv2.imshow('contours',image)
cv2.waitKey(5000)

enter image description here

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Jame
  • 3,746
  • 6
  • 52
  • 101

2 Answers2

5

One can do the same with scikit-image morphology's label() function by finding the connected components in the binary image. Number of cells found is 421 though. Morphologial operations such as erosion / dilation / closing / opening can also be used for pre-processing the input image and to get the desired output.

from skimage import morphology as morph
from skimage.io import imread, imsave
from skimage.color import rgb2gray
import numpy as np
import matplotlib.pyplot as plt

im = rgb2gray(imread('sLUel.png'))
#im = (im > 0).astype(np.uint8)

#labeled = morph.label(morph.binary_opening(im, selem=morph.disk(radius=2)), connectivity=2)
labeled = morph.label(im, connectivity=2)

print(len(np.unique(labeled)))
for i in np.unique(labeled)[1:]: # skip the first component since it's the background
    im_obj = np.zeros(im.shape) 
    im_obj[labeled == i] = 1
    imsave('sLUel_{:03d}.png'.format(i), im_obj)

plt.figure(figsize=(20,10))
plt.subplot(121), plt.imshow(im), plt.axis('off'), plt.title('original binary image', size=15)
plt.subplot(122), plt.imshow(labeled, cmap='spectral'), plt.axis('off'), plt.title('connected components (radius 2)', size=15)
plt.show()

with the following output

enter image description here

Here are the cells identified and separated:

enter image description here

RuaidhrĂ­ Primrose
  • 1,250
  • 1
  • 17
  • 22
Sandipan Dey
  • 21,482
  • 2
  • 51
  • 63
2

one way to do it is,

import numpy as np
import cv2

img = cv2.imread('sLUel.png')       # image provided in question
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
mask = np.zeros(img.shape[:2],np.uint8)

_,contours,hierarchy = cv2.findContours(img,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
count = 0

for i, c in enumerate(contours):
    if hierarchy[0,i,3] != -1:
        continue

    mask_copy = mask.copy()

    cv2.drawContours(mask_copy,c,-1,(255,255,255),-1)
    cv2.floodFill(mask_copy,None,(0,0),255)
    mask_inv=cv2.bitwise_not(mask_copy)

    cv2.imwrite(str(count)+'.png', mask_inv)
    count+=1

there are 420 cells in the image.

Aniket Navlur
  • 962
  • 1
  • 11
  • 22