12
$\begingroup$

I picked up the following leaf today while going for a walk. enter image description here

And wanted then to run the same analysis that @Vitaly Kaurov did for rivers under this posting

Measuring Fractal Dimensions of natural objects from digital images

and then also proceed to measure the length of branches and angles of the ribs and veins of the leaf as shown in this other posting.

how-to-measure-segment-length-and-branch-angle

The final objective would be to collect different leaves from different species and prepare some sort of visualization of the different species.

I played around with different ImageProcessing functions, the best I could do was the following.

leaf = ImageRotate[Import["http://i.stack.imgur.com/cnvC4.jpg"], \[Pi]/2];
leafBW = ColorSeparate[leaf, "RGB"][[3]];
ribs = ImageAdd[MinDetect[leafBW, 0.27], MaxDetect[leafBW, 0.27]]

Processed Leaf

The questions are:

  1. Is there a better way to process the image to maximize the details of ribs and secondary veins?
  2. How can we eliminate the edge of the leaf from the image?
$\endgroup$
8
  • $\begingroup$ Is this good enough? $\endgroup$
    – rm -rf
    Jul 27, 2013 at 17:52
  • $\begingroup$ Looks great @rm-rf. Is there any way to remove the border of the leaf too? $\endgroup$
    – Zviovich
    Jul 27, 2013 at 18:03
  • $\begingroup$ Hmmm... I'm not satisfied with the result. While it seems to capture a lot of the smaller cells, a good number of them are spurious, as you can see from the overlay image. Perhaps nikie/Matthias or others might have better suggestions (I used a RidgeFilter followed by Binarize and played with the thresholds). Yours is more accurate than mine. $\endgroup$
    – rm -rf
    Jul 27, 2013 at 18:20
  • 2
    $\begingroup$ I noticed that the picture was a bit blurred in places. If you could press it between two sheets of glass it could provide more detail... $\endgroup$
    – cormullion
    Jul 27, 2013 at 19:56
  • $\begingroup$ @cormullion Your comment is OT :) $\endgroup$ Jul 28, 2013 at 2:47

1 Answer 1

10
$\begingroup$

I fiddled around a bit with the image you provided. First of all: image quality suffers greatly from (i) bad imaging conditions, especially image blur resulting from not pressing the leaf evenly onto the scanner, and (ii) the JPEG compression artifacts.

Initially we cut out the interesting part of the image

leaf = ImageTake[ImageRotate[Import["http://i.stack.imgur.com/cnvC4.jpg"], \[Pi]/2], {50,620}, {10, 1120}]

Mathematica graphics

and convert it to grayscale

leafg = ColorConvert[leaf, "Grayscale"]

Mathematica graphics

then we sharpen it to get more detail in the heavily blurred image areas (this is a sledge-hammer approach).

leafs = Sharpen[leafg, 20]

Mathematica graphics

In order to get the mask for eliminating the edge of the leaf from the image we binarize the image, clear the image of small components and dilate the mask inwardly.

mask = Dilation[DeleteSmallComponents[Binarize[leafg], Method -> "Cluster"], 10]

Mathematica graphics

Now we have a choice: are we interested in the major ribs and secondary veins (A) or do we want to get all possible veins (B).

(A): To get major ribs and secondary veins only we apply a ridge filter with a width of 3 pixels

rfp = ImageAdjust[RidgeFilter[leafs, 3]]

Mathematica graphics

and binarize the resulting image.

rf = Binarize[rfp, FindThreshold[rfp, Method -> "Mean"]]

Mathematica graphics

Then we skeletonize the segmentation

skelimg1 = Thinning[rf]

Mathematica graphics

and remove the edge of the leaf using our generated mask.

res1 = ImageSubtract[skelimg1, mask]

Mathematica graphics

This is the result of (A):

ImageAdd[leaf, res1]

Mathematica graphics

(B): To get all veins we apply a ridge filter with a width of 1.5 pixels

rf1p = ImageAdjust[RidgeFilter[leafs, 1.5]]

Mathematica graphics

and binarize the resulting image.

rf1 = Binarize[rf1p, FindThreshold[rf1p, Method -> "Mean"]]

Mathematica graphics

As one can see there are some areas in the middle of the stem that were not segmented correctly. These artifacts are the result of the ridge filter operation: 1.5 pixels are suitable for the enhancement of fine veins but do not work for thick ribs. Thinning of this segmentation would produce loops on the stem. To counter this effect we generate a second segmentation with a ridge filter of width 3.5 (the threshold requires some manual adaption because of the bad image quality)

rf2 = Binarize[ImageAdjust[RidgeFilter[leafs, 3.5]], 0.17]

Mathematica graphics

and add the two images. As we see, the blurred areas cannot be properly segmented.

ridgeimg = ImageAdd[rf1, rf2]

Mathematica graphics

Then we skeletonize the segmentation

skelimg2 = Thinning[ridgeimg]

Mathematica graphics

and remove the edge of the leaf using our generated mask.

res2 = ImageSubtract[skelimg2, mask]

Mathematica graphics

This is the result of (B):

ImageAdd[leaf, res2]

Mathematica graphics

For analysis you should remove all separate components to get the true connected skeleton. And, of course, please do optimize the imaging conditions ;).

$\endgroup$
1
  • 7
    $\begingroup$ +1 nice answer. Leaves nothing for anyone else to do... :) $\endgroup$
    – cormullion
    Dec 4, 2013 at 10:17

Your Answer

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

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