Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing ridge detection

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.

like image 360
Jesse Beder Avatar asked Feb 25 '09 08:02

Jesse Beder


2 Answers

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.

like image 159
Ian Hopkinson Avatar answered Oct 16 '22 12:10

Ian Hopkinson


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);
like image 2
mpen Avatar answered Oct 16 '22 12:10

mpen