views:

1291

answers:

3

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:



and run the Canny Algorithm to get:



(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.

+2  A: 

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
+2  A: 

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);
Mark
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
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.
Mark
A: 

Hi I am also working on a similar project. The way I am thinking of is, Step1. Gaussian Smooth Step2. Use a CUT-OFF Threshold to mark all those points under it as NO-EDGE, up it as POSSIBLE-EDGE Step3. Two ways I am thinking of, not decide which one to go yet a. find an operator which can mark the Local Max points within those POSSIBLE-EDGE b. Get first order derivative, find all Zero-Crossing points within those POSSIBLE-EDGE Connect those marked points will form the final single pixel edge. -Justin

Justin