Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to get boundaries of grains from a microphotograph. I have tried using different methods but because of the texture of background I am not able to get smooth boundaries.


Codes that I've tried are:


      MorphologicalBinarize[Import[""], .5]]]]

This gives output as:

Result 1


        ChanVeseBinarize[Import[""]]], 2000]]]

This gives output as:

enter image description here

However, I am not satisfied with either of the results. Can I use any other way/function to determine a more accurate grain boundaries from this image?

share|improve this question
up vote 11 down vote accepted

One approach is to smooth the image (here I've used the curvature flow filter, which is a nonlinear edge-preserving smoothing filter) and then binarize before doing the edge detection.

img = Import[""]  
curve = CurvatureFlowFilter[img, 40];

enter image description here

Dilating makes it look a bit smoother, but you may (or may not) want to do that, depending on what you are doing with the images.

Dilation[EdgeDetect[FillingTransform[DeleteSmallComponents[Binarize[curve]]]], 1]

enter image description here

share|improve this answer

My high-level strategy would be to use WatershedSegmentation on a gradient image (see this answer for a description of what this function does), starting from a marker image that looks like this:

enter image description here

So WatershedSegmentation can grow the highlighted "seeds" until they touch at the highest gradient border.

So first step: Get the marker image. It doesn't have to follow the grain contours perfectly, so I can use a large blurring filter to smooth out all the high-frequency details:

GaussianFilter[img, 100]

enter image description here

The grains are easily recognizable in this image using any segmentation technique you like, I'll just use Binarize:

binary = Binarize[gaussian];

enter image description here

To get the markers as above, I take the perimeter of that binary image and make it "wider" using Erosion:

markers = 

That's it, now we can pass the whole thing to WatershedSegmentation:

(seg = WatershedComponents[
    ColorConvert[ImageAdd[GradientFilter[img, 5]], "Grayscale"], 
    markers]) // Colorize

(You might want to play with the GradientFilter filter size to improve the result)

enter image description here

You can get the perimeter using

perimeter = Binarize[ColorNegate[Image[seg]]];
HighlightImage[img, perimeter]

enter image description here

To visualize the result, I'll show it filled:

HighlightImage[img, FillingTransform@perimeter]

enter image description here

share|improve this answer
Instructive description! – Anton Antonov Feb 8 at 22:12

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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