7

I'm trying to write a ridge detection algorithm, and all of the sources I've found seem to conflate edge detection with ridge detection. Right now, I've implemented the Canny edge detection algorithm, but it's not what I want: for example, given a single line in the image, it will effectively translate it to a double line of edges (since it will record both sides of the line) - I just want it to read the one line.

The wikipedia article about ridge detection has a bunch of math, but this kind of this doesn't help me as a programmer (not that I'm averse to math, but it's not my field, and I don't understand how to translate their differential equations into code). Is there a good source for actually implementing this? Or, for that matter, is there a good open source implementation?

Edit: here's the simple example. We start with a simple line:

http://img24.imageshack.us/img24/8112/linez.th.png

and run the Canny Algorithm to get:

http://img12.imageshack.us/img12/1317/canny.th.png

(you can see that it's thicker here - if you click on the image, you'll see that it really is two adjacent lines with a blank in between)

Also, I'm writing in C++, but that shouldn't really matter. But I want to code the algorithm, not just write SomePackage::findRidges() and be done with it.

Jesse Beder
  • 33,081
  • 21
  • 109
  • 146
  • what language are you writing in? Matlab has functions that handle just that. I'd be surprised if R doesn't have that too. – Nathan Fellman Feb 25 '09 at 08:32
  • C++, but I'm looking for the algorithm! – Jesse Beder Feb 26 '09 at 02:25
  • I think you've got a thresholding problem, rather than a ridge finding problem. – Ian Hopkinson Feb 26 '09 at 06:25
  • You can recover a single line from your double line generated using the Canny filter using one dilate operation followed by 3 erodes (I tried it out in ImageJ) - this should also remove any edges. – Ian Hopkinson Feb 26 '09 at 08:21
  • @Ian, thanks, this seems to work. If you edit your post to mention this, I'll upvote it. – Jesse Beder Feb 27 '09 at 20:09
  • 1
    However, it's still hackish, and it's not *exactly* what I want. – Jesse Beder Feb 27 '09 at 20:10
  • @Jesse - it's done. I agree it's a bit hackish - but that's image analysis for you ;-) Depending on precise nature of your original image you might be able to dispense with the Canny filter step – Ian Hopkinson Feb 28 '09 at 07:20
  • 1
    Look at phase congruency for better edge detection. – Autonomous Mar 12 '13 at 20:46
  • Funny that nobody has mentioned second order derivatives. Canny uses first order derivatives, and finds edges. A ridge is a line along which the second order derivative, perpendicular to the line, is maximal or minimal. You can get this using the eigenvalues if the Hessian matrix. – Cris Luengo Nov 27 '18 at 02:19
  • Read here: https://dsp.stackexchange.com/a/1735/33605 – Cris Luengo Nov 27 '18 at 02:28

3 Answers3

5

Maybe you need to think in terms of cleaning up the line you already have, rather than a Canny-like edge detection. It feels like you should be able to do something with image morphology, in particular I'm thinking of the skeletonize and ultimate eroded points type operations. Used appropriately these should remove from your image any features which are not 'lines' - I believe they're implemented in Intel's OpenCV library.

You can recover a single line from your double line generated using the Canny filter using one dilate operation followed by 3 erodes (I tried it out in ImageJ) - this should also remove any edges.

Ian Hopkinson
  • 3,412
  • 4
  • 24
  • 28
2

I was going to suggest cleaning up your lines like Ian said, but if you don't want to do that, you might also look into doing some variant of a hough transform.

http://en.wikipedia.org/wiki/Hough_transform

You should be able to get the actual equation for the line from this, so you can make it as thin or as thick as you like. The only tricky part is figuring out where the line ends.

Here's the code I wrote for a hough transform a few years ago, written in MATLAB. I'm not sure how well it works anymore, but it should give you a general idea. It will find all the lines (not segments) in an image

im = imread('cube.tif');
[bin1,bin2,bin3] = canny(im);

%% define constants
binary = bin1;
distStep = 10; % in pixels
angStep = 6; % in degrees
thresh = 50;

%% vote
maxDist = sqrt((size(binary,1))^2+(size(binary,2))^2);
angLoop = 0:angStep*pi/180:pi;
origin = size(binary)/2;
accum = zeros(ceil(maxDist/distStep)+1,ceil(360/angStep)+1);

for y=1:size(binary,2)
    for x=1:size(binary,1)
    if binary(x,y)
        for t = angLoop
        dx = x-origin(1);
        dy = y-origin(2);
        r = x*cos(t)+y*sin(t);
        if r < 0
            r = -r;
            t = t + pi;
        end
        ri = round(r/distStep)+1;
        ti = round(t*180/pi/angStep)+1;
        accum(ri,ti) = accum(ri,ti)+1;
        end
    end
    end
end
imagesc(accum);

%% find local maxima in accumulator
accumThresh = accum - thresh;
accumThresh(logical(accumThresh<0)) = 0;
accumMax = imregionalmax(accumThresh);
imagesc(accumMax);

%% calculate radius & angle of lines
dist = [];
ang = [];
for t=1:size(accumMax,2)
    for r=1:size(accumMax,1)
    if accumMax(r,t)
        ang = [ang;(t-1)*angStep/180*pi];
        dist = [dist;(r-1)*distStep];
    end
    end
end
scatter(ang,dist);
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • I'm already doing this - the problem is that the Canny algorithm gives double edges, as I've described. So I need a better Step #1 :) – Jesse Beder Feb 26 '09 at 15:59
  • Well, if all your images look like that, you can skip step 1. Otherwise, if you're using an actual image, you shouldn't have thin lines like that, and canny shouldn't give you any problems, no? Just a thought. – mpen Feb 28 '09 at 19:32
  • I believe Jesse's problem is how to *mark* the ridge line, after that of course you can apply the Hough transform to obtain the line's parameters but that is not his point here. – jasxun Aug 17 '11 at 21:18
1

If anyone is still interested in this, here is an implementation of the ridges/valleys algorithm: C++ source code. Look for a function called get_ridges_or_valleys(). This implementation is a 3D version of the algorithm proposed by Linderhed (2009). See page 8 of the paper for the ridges/valleys algorithm.

Paulo Carvalho
  • 554
  • 5
  • 10