实施脊线检测

发布于 2024-07-14 02:38:25 字数 880 浏览 15 评论 0原文

我正在尝试编写一个脊检测算法,并且我发现的所有来源似乎都将边缘检测与脊检测混为一谈。 现在,我已经实现了 Canny 边缘检测算法,但这不是我想要的:例如,给定图像中的一条线,它将有效地将其转换为双线边缘(因为它将记录 该行的两侧) - 我只想让它读取一行。

关于山脊检测的 wikipedia 文章 有很多数学知识,但是这种没有帮助我作为一名程序员(并不是说我不喜欢数学,而是这不是我的领域,而且我不明白如何将他们的微分方程转化为代码)。 是否有实际实施此功能的良好来源? 或者,就此而言,是否有一个好的开源实现?

编辑:这是一个简单的例子。 我们从简单的一行开始:

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

并运行Canny算法得到:

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

(你可以看到这里更厚 - 如果你点击图片,你会发现它确实是两个相邻的行,中间有一个空格)

另外,我正在用 C++ 编写,但这并不重要。 但我想编写算法,而不仅仅是编写SomePackage::findRidges()并完成它。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

此岸叶落 2024-07-21 02:38:26

也许您需要考虑清理已有的线路,而不是像 Canny 那样的边缘检测。 感觉你应该能够使用图像形态学做一些事情,特别是我正在考虑骨架化和最终侵蚀点类型操作。 正确使用这些应该从您的图像中删除任何非“线条”的特征 - 我相信它们是在英特尔的 OpenCV 库中实现的。

您可以从使用 Canny 过滤器生成的双线中恢复单线,使用一次扩张操作,然后进行 3 次侵蚀(我在 ImageJ 中尝试过) - 这也应该删除任何边缘。

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.

寂寞花火° 2024-07-21 02:38:26

我本来建议像 Ian 所说的那样清理你的线条,但如果你不想这样做,你也可以考虑做一些霍夫变换的变体。

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

您应该能够获得这条线的实际方程,因此您可以根据需要将其设置为细或粗。 唯一棘手的部分是弄清楚线的终点在哪里。

这是我几年前用 MATLAB 编写的霍夫变换代码。 我不确定它的效果如何,但它应该给你一个总体的想法。 它将找到图像中的所有线条(不是线段)

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);

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);
慢慢从新开始 2024-07-21 02:38:26

如果有人仍然对此感兴趣,这里是脊/谷算法的实现: C++ 源代码。 查找名为 get_ridges_or_valleys() 的函数。 此实现是 Linderhed (2009) 提出的算法的 3D 版本。 有关脊/谷算法,请参阅论文第 8 页。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文