46
$\begingroup$

I have done a lot of research and found out methods like adaptive thresholding , watershed etc that can be used of detecting veins in leaves . However thresholding isn't good as it introduces a lot of noise

All my images are gray image please could anyone suggest what approaches to adopt while considering this problem in urgent need of help

EDIT:My original image

enter image description here

After thresholding

enter image description here

As suggested by the answer i have tried the following edge detection

  1. Canny

Too much noise and unwanted disturbances

enter image description here

  1. Sobel

enter image description here

  1. Roberts

enter image description here

EDIT: Tried one more operation i get the following result its better than what i tried with canny and adaptive What do you feel?

enter image description here

$\endgroup$
  • $\begingroup$ Could you please show us some images? $\endgroup$ – Jonas Mar 14 '12 at 16:11
  • $\begingroup$ I have added images $\endgroup$ – vini Mar 14 '12 at 16:22
  • $\begingroup$ @vini Are you currently doing this as a pre-processing step in order to get a good template match later on? Also, how did you get the second image, through simple thresholding? $\endgroup$ – Spacey Mar 14 '12 at 17:19
  • $\begingroup$ My aim is to get the best possible result in segmenting the veins so that my output doesnt contain stray artifacts ,i have used Adaptive thresholding to get the second image $\endgroup$ – vini Mar 14 '12 at 17:26
  • $\begingroup$ From the images you have given, it looks like you are using (various) filters on a thresholded image. This will give extremely poor results. You should use the filters on the original image, then threshold their output. $\endgroup$ – Benjohn Jan 26 '16 at 11:06
56
$\begingroup$

You're not looking for edges (=borders between extended areas of high and low gray value), you're looking for ridges (thin lines darker or brighter than their neighborhood), so edge filters might not be ideal: An edge filter will give you two flanks (one on each side of the line) and a low response in the middle of the line:

filter samples

ADD: If've been asked to explain the difference between an edge detector and a ridge detector more clearly. I apologize in advance if this answer is getting very long.

An edge detector is (usually) a first derivative operator: If you imagine the input image as a 3D landscape, an edge detector measures the steepness of the slope at each point of that landscape:

enter image description here

If you want to detect the border of an extended bright or dark region, this is just fine. But for the veins in the OP's image it will give you just the same: the outlines left and right of each vein:

enter image description here

That also explains the "double line pattern" in the Canny edge detector results:

enter image description here

So, how do you detect these thin lines (i.e. ridges), then? The idea is that the pixel values can be (locally) approximated by a 2nd order polynomial, i.e. if the image function is $g$, then for small values of $x$ and $y$:

$g(x,y)\approx \frac{1}{2} x^2 \frac{\partial ^2g}{\partial x^2}+x y \frac{\partial ^2g}{\partial x\, \partial y}+\frac{1}{2} y^2 \frac{\partial ^2g}{\partial y\, ^2}+x \frac{\partial g}{\partial x}+y \frac{\partial g}{\partial y}+g(0,0)$

or, in matrix form:

$g(x,y)\approx \frac{1}{2} \left( \begin{array}{c} x \\ y \end{array} \right).\left( \begin{array}{cc} \frac{\partial ^2g}{\partial x^2} & \frac{\partial ^2g}{\partial x\, \partial y} \\ \frac{\partial ^2g}{\partial x\, \partial y} & \frac{\partial ^2g}{\partial y\, ^2} \end{array} \right).\left( \begin{array}{cc} x & y \end{array} \right)+\left( \begin{array}{c} x \\ y \end{array} \right).\left( \begin{array}{cc} \frac{\partial g}{\partial x} & \frac{\partial g}{\partial y} \end{array} \right)+g(0,0)$

The second order derivative matrix $\left( \begin{array}{cc} \frac{\partial ^2g}{\partial x^2} & \frac{\partial ^2g}{\partial x\, \partial y} \\ \frac{\partial ^2g}{\partial x\, \partial y} & \frac{\partial ^2g}{\partial y\, ^2} \end{array} \right)$ is called the "Hessian matrix". It describes the 2nd order structure we're interested in.

The 2nd order part of this function can be transformed into the sum of two parabolas $\lambda _1 x^2 + \lambda _2 y^2$ rotated by some angle, by decomposing the Hessian matrix above to a rotation times a diagonal matrix of it's eigenvalues (Matrix decomposition). We don't care about the rotation (we want to detect ridges in any orientation), so we're only interested in $\lambda _1$ and $\lambda _2$

What kind of shapes can this function approximation have? Actually, not that many:

enter image description here

To detect ridges, we want to find areas in the image that look like the last of the plots above, so we're looking for areas where the major eigenvalue of the Hessian is large (compared to the minor eigenvalue). The simplest way to detect that is just to calculate the major eigenvalue at each pixel - and that's what the ridge filter below does.


A ridge filter will probably give better results. I've tried Mathematica's built in RidgeFilter (which calculates the major eigenvalue of the Hessian matrix at each pixel) on your image:

ridge filter

As you can see, there's only a single peak for every thin dark line. Binarizing and skeletonizing yields:

enter image description here

After pruning the skeleton and removing small components (noise) from the image, I get this final skeleton:

enter image description here

Full Mathematica code:

ridges = RidgeFilter[ColorNegate@src];
skeleton = SkeletonTransform[Binarize[ridges, 0.007]];
DeleteSmallComponents[Pruning[skeleton, 50], 50]

ADD:

I'm not a Matlab expert, I don't know if it has a built in ridge filter, but I can show you how to implement it "by hand" (again, using Matematica). As I said, the ridge filter is the major eigenvalue of the Hessian matrix. I can calculate that eigenvalue symbolically in Mathematica:

$\text{eigenvalue}=\text{Last}\left[\text{Eigenvalues}\left[\left( \begin{array}{cc} H_{\text{xx}} & H_{\text{xy}} \\ H_{\text{xy}} & H_{\text{yy}} \end{array} \right)\right]\right]$

=> $\frac{1}{2} \left(H_{\text{xx}}+H_{\text{yy}}+\sqrt{H_{\text{xx}}^2+4 H_{\text{xy}}^2-2 H_{\text{xx}} H_{\text{yy}}+H_{\text{yy}}^2}\right)$

So what you have to do is calculate the second derivatives $H_{\text{xx}}$, $H_{\text{xy}}$, $H_{\text{yy}}$ (using a sobel or derivative of gaussian filter) and insert them into the expression above, and you've got your ridge filter.

$\endgroup$
  • $\begingroup$ Yes thats exactly what i want however i am doing it in matlab and finding an equivalent of the ridge filter has become difficult $\endgroup$ – vini Mar 16 '12 at 1:50
  • 1
    $\begingroup$ @nikie Very nice answer - question - can you please elaborate on the difference between an edge detector and ridge detector for us non-image processing people? Thanks again $\endgroup$ – Spacey Mar 17 '12 at 0:05
  • $\begingroup$ @Mohammad: I've tried, I hope I made it a little clearer now, despite the math $\endgroup$ – Niki Estner Mar 17 '12 at 12:46
  • $\begingroup$ i tried ridge filter doesn't give satisfactory results $\endgroup$ – vini Mar 18 '12 at 17:26
  • 2
    $\begingroup$ @vini: "doesn't give satisfactory results" doesn't really tell me much. Do you get the same result image as the one I posted? What is "not satisfactory"? $\endgroup$ – Niki Estner Mar 19 '12 at 11:32
6
$\begingroup$

When using Canny edge detection (in Halcon), with alpha being 1, and the low threshold 8 and the high threshold 13 (on a scale of 1-255), I get the following result:

Canny edge detection leaf

With tweaking of the parameters, the result you got from Canny can be much more improved. Using this image, you can skip the short edges to remove the noise, and connect the long edges for the final result.

BTW: a different color indicates a different edge.

I can get a fairly similar result using this online Canny edge detector:

  • Choose picture I9Pxl.png
  • Sigma 1.2
  • T-low 0.04
  • T-high 0.07
  • Other settings default
  • Click update view for result
$\endgroup$
  • $\begingroup$ Thanks :) I guess Canny is just the best ;) Btw, applying Canny on your result might yield even better results.. $\endgroup$ – Geerten Mar 15 '12 at 10:49
  • $\begingroup$ BTW: If you haven't noticed: What are the limitations of a Canny edge detector? You can give your views here! $\endgroup$ – Dipan Mehta Mar 15 '12 at 12:18
  • $\begingroup$ If you're telling me: I already gave my view at your question..If you're giving a comment in general: I'll delete this comment. $\endgroup$ – Geerten Mar 15 '12 at 12:24
  • $\begingroup$ Oh yes, - i didn't realize this! $\endgroup$ – Dipan Mehta Mar 15 '12 at 12:28
  • $\begingroup$ Thanks for your answer however canny doesnt preserve fine details of veins in leaves which aren't detected as you showed... $\endgroup$ – vini Mar 15 '12 at 16:18
6
$\begingroup$

Following on from the above excellent answer, here is how to do it in python using scikit funcitons.

from skimage.feature import hessian_matrix, hessian_matrix_eigvals

#assume you have an image img

hxx, hxy, hyy = hessian_matrix(img, sigma=3)
i1, i2 = hessian_matrix_eigvals(hxx, hxy, hyy)

#i2 is the variable you want.

#Visualise the result
import matplotlib.pyplot as plt
plt.imshow(i2)
$\endgroup$
  • $\begingroup$ What img should be? I have a png file and it does not work. $\endgroup$ – Sigur Oct 17 '16 at 23:54
  • $\begingroup$ img should be an 2d numpy array. $\endgroup$ – Matthew Shun-Shin Nov 14 '16 at 1:58
  • $\begingroup$ Actually, i1 is the larger of the eigenvalues, so you should use that one. $\endgroup$ – Rob Feb 27 '17 at 14:29
  • $\begingroup$ This is the clearest explanation I have ever seen! $\endgroup$ – Eureka May 3 at 9:16
3
$\begingroup$

Instead of thresholding, i have applied simple edge detection.

Used GIMP with Difference of Gaussian - Radious Outer:3.0 and Inner:1.0.

Here it is how it looks like.

enter image description here

You can further apply a median filter or erosion/dilation so that you can remove some of the grainy noise.

Here is the page that explains gimp's implementation.

You should refer to different techniques like Laplacian of Gaussian or Difference of Gaussin etc. See this: http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm#7

And this answer How is the Laplacian used for Unsharp Mask?

$\endgroup$
  • $\begingroup$ GIMP ? is which edge detector? $\endgroup$ – vini Mar 14 '12 at 17:51
  • 1
    $\begingroup$ No - it's a image editing package. It was a quick check - just to put a point forward.- use edge detection as opposed to thresholding. $\endgroup$ – Dipan Mehta Mar 14 '12 at 17:54
  • $\begingroup$ What edge detector does GIMP use? i am sorry have very little knowledge of it $\endgroup$ – vini Mar 14 '12 at 18:04
  • $\begingroup$ @vini added reference. $\endgroup$ – Dipan Mehta Mar 14 '12 at 18:26
3
$\begingroup$

This topic has always attracted a lot of interest, and yet no real consensus exists on the topic. Therefore I decided to drop a few words.

My answers to previously asked similar questions on stackexchange (Q1 and Q2) involved a subpixel curvilinear structure extraction algorithm by Steger. This method performed reasonably well in many cases and luckily, including this one. Therefore I post the output image here: enter image description here and here with a different parameter setting, and without connected-ness coloring: enter image description here For the details and proper references please see the stackexchange posts I have referred to.

$\endgroup$
0
$\begingroup$

As part of my last year of engineering studies assignment, I had to study segmentation methods for blood vessels in eye fundus images. I found this tree reconstruction method (by Cohen, Laurent D. and Mille, Julien particularly interesting to use along with Fast-Marching Methods.

Other papers you might want to look into :

  • Geodesic Active Contours
  • On the implementation of fast marching methods for 3D lattices
  • Multistencils FMM : a highly accurate solution to the Eikonal Equation on Cartesian Domains

Useful links : - Front propagation in 2D and 3D

I hope this helps a bit, though it's not exactly state of the art.

$\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.