# Boundary identification

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:

1)

EdgeDetect[
DeleteSmallComponents[
FillingTransform[
MorphologicalBinarize[Import["http://imgur.com/o7OF9jG.jpg"], .5]]]]


This gives output as:

2)

EdgeDetect[
FillingTransform[
DeleteSmallComponents[
ColorNegate[
ChanVeseBinarize[Import["http://imgur.com/o7OF9jG.jpg"]]], 2000]]]


This gives output as:

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?

-

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["http://i.stack.imgur.com/TIiTZ.jpg"]
curve = CurvatureFlowFilter[img, 40];
EdgeDetect[FillingTransform[DeleteSmallComponents[Binarize[curve]]]]


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]


-

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:

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]


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

binary = Binarize[gaussian];


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

markers =
Erosion[ColorNegate[MorphologicalPerimeter[binary]],
DiskMatrix[50]];


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

(seg = WatershedComponents[
markers]) // Colorize


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

You can get the perimeter using

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


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

HighlightImage[img, FillingTransform@perimeter]


-
Instructive description! – Anton Antonov Feb 8 at 22:12