3
$\begingroup$

I have a large dataset of SEM micrographs I am trying to binarily segment via ClusteringComponents, and it has seemed to be the most accurate method compared to the other binarization functions, e.g. Morphological Binarize.

However, while the clusters are accurate, it assigns the dark or light pixel groups in essentially random order. However I suspect that it occurs when the contrast is low.

I am able to reproduce this problem with example images. On the first image, the dark pixels are assigned 0, while on the second image, the light pixels are assigned 0.

test=ExampleData[{"TestImage","Man"}]

enter image description here

clustered=ClusteringComponents[test,2,PerformanceGoal->"Quality"];
Image[clustered - 1, "Bit"]

enter image description here

test2=ExampleData[{"TestImage","Tank2"}]

enter image description here

clustered2=ClusteringComponents[test2,2,PerformanceGoal->"Quality"]

enter image description here

How can I get it so it consistently assigns the dark pixel components to either 0 or 1??

$\endgroup$
3
  • $\begingroup$ JK the effect does not change if I increase contrast $\endgroup$ Commented Aug 26, 2020 at 22:14
  • $\begingroup$ The only hack-solution I can think of now, is use the clustered image to mask over the original and run ImageMeasurements of the original's average pixel intensity in the masked region. Then conditionally ColorNegate the clustered image if the average intensity is above (or below) a given threshold. $\endgroup$ Commented Aug 26, 2020 at 22:45
  • 1
    $\begingroup$ I like your jerry-rigged solution. From the properties & relations section in the documentation, we can see that, at least for many types of data, it is based on FindClusters, which itself doesn't offer a way to order clusters. $\endgroup$
    – C. E.
    Commented Aug 27, 2020 at 7:44

1 Answer 1

1
$\begingroup$

OK so I'm gonna post my jerry-rigged solution so far:

  1. Use the binarized cluster image to generate a mask of the original image

  2. Testing the mean pixel intensity of the masked area vs global mean to check if the black clusters match up with the dark areas

  3. Conditionally ColorNegate the values that don't match

    clusterColorTestFunction[testImage_] := 
    Module[{clustered,mask,globalMean,maskedMean},
    
    clustered=ClusteringComponents[testImage,2,PerformanceGoal->"Quality"];
    mask=Image[clustered - 1, "Bit"];
    
    globalMean=ImageMeasurements[testImage,"Mean"];
    maskedMean=ImageMeasurements[testImage,"Mean",Masking->mask];
    
    Which[globalMean>maskedMean,ColorNegate[mask],globalMean <maskedMean,mask]
    ];
    
    clusterColorTestFunction[#]&/@{test,test2}
    

enter image description here

However, if there is a solution within the Clustering functionality I would love to hear it

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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