15
$\begingroup$

I have a microscope image of some animal tissue and wish to get the contours for all the cells that are present in the image. the cells are connected to the neighbouring cells via these contours. At the bottom of the image the signal intensity is faint but the human eye can still detect some contours.

I have tried a bunch of techniques including the use of ClusteringComponents and MorphologicalBinarize, LaplacianGaussianFilter and GradientFilter but have been unsuccessful in my approaches. The particular problem I am facing is the inability to get rid of the noisy signal (grains/granules whatever you may wish to call them) inside the contours during segmentation.

Can anyone kindly help me for my research problem. Thanks in advance.

enter image description here

the closest i have are the following approaches but they do not prove satisfactory:

KuwaharaFilter[CommonestFilter[GaussianFilter[
Binarize[img, 0.2, Method -> "MinimumError"], 3], 3],3]

enter image description here

Using SkeletonTransform after KuwaharaFilter and application of other filters

KuwaharaFilter[CommonestFilter[GaussianFilter[
Binarize[img, 0.18, Method -> "MinimumError"], 3],3], 3] //
Binarize[#, 0.6] & // SkeletonTransform

enter image description here

Using DistanceTransform in conjunction with KuwaharaFilter and a bunch of filters

KuwaharaFilter[CommonestFilter[GaussianFilter[
Binarize[img, 0.18, Method -> "MinimumError"], 3],3], 3] //
Binarize[#, 0.55] & //DistanceTransform // ImageAdjust

enter image description here

$\endgroup$
  • 3
    $\begingroup$ It is always good idea to provide a link to a duplicate question on the Wolfram Community. It can help both current answerers and future visitors of the site. $\endgroup$ – Alexey Popkov Oct 13 '16 at 17:06
  • 4
    $\begingroup$ For reference, Shadi Ashnai provided an answer here. $\endgroup$ – J. M. will be back soon Oct 14 '16 at 21:34
17
$\begingroup$
img = Import["https://i.stack.imgur.com/YsIVf.png"];

img2 = Pruning @ Thinning @ Closing[#, 10]& @ DeleteSmallComponents[#, 25000]& @ 
 LocalAdaptiveBinarize[#, 50]& @ GaussianFilter[#, 10]& @ img

enter image description here

HighlightImage[img, img2]

enter image description here

$\endgroup$
  • $\begingroup$ thanks. nice job ! but do you see the large region at the bottom right. there is still some segmentation that can be done there. somehow its missing that $\endgroup$ – Ali Hashmi Oct 13 '16 at 11:50
  • $\begingroup$ and also i see two more places where segmentation is missing $\endgroup$ – Ali Hashmi Oct 13 '16 at 11:52
  • 4
    $\begingroup$ Citing nikie: "If you start with noisy data, you should always expect somewhat noisy results". The upper right part of the image is the sharpest. Image processing algorithms tend to treat an image as a whole - if they work well on a part that is sharp, they usually fail where the quality is lower. You can, e.g., apply ImageAdjust to img first, change the parameter in GaussianFilter from 10 to 12, but is that really a better result?... $\endgroup$ – corey979 Oct 13 '16 at 13:20
  • $\begingroup$ ...You could also divide the image in two parts and process them separately. $\endgroup$ – corey979 Oct 13 '16 at 13:20
13
$\begingroup$

I have somewhat mixed corey's and nikie's approach (check their posts) to arrive at a somewhat reasonable segmentation. Kudos to them.

img2 =  ImageAdjust@RidgeFilter[img, 5] // GaussianFilter[#, 8] & // 
   LocalAdaptiveBinarize[#, 50] & // 
  DeleteSmallComponents[#, 25000] & // Closing[#, 10] & // 
Thinning // Pruning;

HighlightImage[img, img2]

enter image description here

$\endgroup$
12
$\begingroup$

Your image contains thin, line-like structures, so a RidgeFilter seems like a good idea:

img = Import["https://i.stack.imgur.com/YsIVf.png"]
ridges = ImageAdjust[RidgeFilter[img, 5]]

enter image description here

Die ridges have large brightness variance, but MorphologicalBinarize works well enough:

bin = MorphologicalBinarize[ridges, {.1, .5}]

enter image description here

To segment the individual cells, I need markers for each cell center. The maxima of a distance transform usually give good markers:

dist = DistanceTransform[ColorNegate@bin];    
maxMarkers = MaxDetect[dist, 2];    
HighlightImage[bin, maxMarkers]

enter image description here

Now I can use those markers as starting points for a watershed segmentation:

watersheds = WatershedComponents[ridges, maxMarkers];
Colorize[watersheds]

enter image description here

These are segmentation borders highlighted in the original image:

HighlightImage[img, ColorNegate[Binarize[Image[watersheds]]]]

enter image description here

$\endgroup$
  • $\begingroup$ great. there are some extraneous cells (extra) that are formed as a result of this $\endgroup$ – Ali Hashmi Oct 13 '16 at 11:54
  • $\begingroup$ Yes. Cleaning those up is left as an exercise to the reader ;-) $\endgroup$ – Niki Estner Oct 13 '16 at 12:22
  • $\begingroup$ haha .. just saying that there should be no need to clean up. Because cleaning could change the topology of the mask. Removing something that was not there to begin with and is shared between three bodies can change topology in three different ways ! $\endgroup$ – Ali Hashmi Oct 13 '16 at 12:27
  • 2
    $\begingroup$ @AliHashmi: If you start with noisy data, you should always expect somewhat noisy results. Regarding extra segments: WatershedComponents (actually, all segmentation algorithms) try to segment the whole image. There is not enough data in your image to do that, so the visible borders are "extrapolated" to the border of the image. If you don't want that, use DeleteBorderComponents on the segmentation result. For the interior areas, you might want to clean up the markers image - but that's really something you have to do yourself, as you're the one who knows what you're looking for $\endgroup$ – Niki Estner Oct 13 '16 at 12:40
4
$\begingroup$

I provide a method don't include DeleteSmallComponents

pic = Import["https://i.stack.imgur.com/YsIVf.png"]

HighlightImage[pic, 
 ColorNegate@
  Image[WatershedComponents[GradientFilter[MeanFilter[pic, 5], 2], 
    MaxDetect[
     ImageAdjust@
      DistanceTransform[
       ColorNegate[Binarize[MeanFilter[pic, 8], .2]]], .1]]]]

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.