我有一个图像,我想将其转换为逻辑图像,包括线条为黑色,背景为白色。当然,使用阈值方法可以做到这一点,但我不想通过这种方式来做到这一点。我想通过使用线跟踪方法或类似的方法来检测它。
关于视网膜血管的检测。我找到了article,但我不知道创建动态搜索窗口的方式。
我该怎么做?
原始图片:
跟踪方式:
我用油漆准备了图像。
答案 0 :(得分:6)
这是一个经典的Breadth First Search (BFS)问题。您可以将您的示例中标记的起点视为进入迷宫的切入点,您的工作将从迷宫中找到出路。 BFS背后的基本驱动力是使用queue。在起点处,将此点添加到队列中。然后,当队列不为空时,将队列中的点出列队列,然后检查其任何邻居,看看你是否有:
如果你有任何满足(1)和(2)的点,你可以通过排队将这些点添加到队列中。一旦你完成了向队列添加点的操作,你就会返回并将另一个点出列并重复该算法,直到你的队列为空。
对于你的线追踪算法,你要做的是,对于你已经出列的每一个点,你会用一种颜色标记图像......让我们说你&#39 ; d用红色标记。一旦您将该点出列,请将您尚未访问的那些点添加到您的队列中,然后返回并出列另一个点,然后重复逻辑。您将继续此操作,直到您的队列为空。关于BFS的好处是,它允许您同时探索多条路径,如果您达到死胡同,我们将停止搜索此路径,并允许我们尚未探索的其他路径继续探索。
这是我写的一些示例代码。为简单起见,我从StackOverflow读取您的图像,将图像转换为黑白图像并对图像进行镂空。遗憾的是,您需要将此转换为逻辑才能使此算法正常工作。我知道你不希望这样,但我假设你将有多个这些痕迹的实例,所以如果你标记一个连续血管内的点,这个算法将标记所有点,属于这艘船。
无论如何,我进行了镂空,使得容器的厚度为1像素,使事情变得更容易。我还创建了镂空图像的彩色版本,以便我们可以在我们用红色探测的像素中进行着色。在此之后代码执行的第一件事是它向您显示骨架化图像,它等待您单击容器中的某个位置。这是通过ginput
完成的。代码将找到与您单击的位置相关的最近点,并将其作为起点。这是通过简单地找到与您在容器中的每个有效点点击的点的最小欧几里德距离来完成的。
一旦我们找到了这个起点,我们将其添加为队列的第一个条目并开始我们的BFS算法。作为奖励,我还编写了代码来保存作为动画GIF的进度。每隔20帧,图像就会写入此动画GIF文件。另外,我向您展示了每20帧线条跟踪的样子。这一直持续到我们用完点或队列为空,然后算法停止。动画GIF也存储在您运行代码的同一目录中。我还写了最终完成的图像看起来像什么,因为当我们停止算法时,它不会发生在20帧的倍数,所以你应该写出最后一帧和最后一帧。文件,应该是完全标记的船只图像。
不用多说,这里是代码:
% // Read in the image from StackOverflow
im = imread('http://i.stack.imgur.com/3t4Dx.png');
%// Skeletonize the image to simplify problem
im = bwmorph(~im2bw(im), 'skel', 'inf');
%// Make a colour version so that we can mark pixels we have visited in
%// red
im_colour = 255*uint8(cat(3,im,im,im));
%// Get a starting point from the user
imshow(im);
[col,row] = ginput(1);
close all;
%// Find the closest point on the vessel where we have clicked and
%// add to the queue as a starting point
[rows,cols] = find(im);
[~,ind] = min((row-rows).^2 + (col-cols).^2);
queue = [rows(ind), cols(ind)];
%// Variable that stores all the locations we have visited so far
mask = false(size(im));
%// To save animated GIF to file
filename = 'linetracing.gif';
figure;
%// Counter that keeps track of how many points we have processed so far
%// This also allows us to write the line tracing algorithm output at
%// certain iteration numbers to output
n = 1;
%// While the queue is not empty
while ~isempty(queue)
%// Dequeue
pt = queue(1,:);
queue(1,:) = [];
%// If this is not a valid vessel point, mark as visited and continue
if im(pt(1),pt(2)) == 0
mask(pt(1),pt(2)) = true;
%// If we have visited this point, continue
elseif mask(pt(1),pt(2))
continue;
else
%// We haven't visited this point yet
%// Mark this as visited
mask(pt(1),pt(2)) = true;
%// Colour the image at this point
im_colour(pt(1),pt(2),:) = [255;0;0];
%// We will write the progress of our line tracing every 20 frames
%// If we are at the first frame, we need to initialize our GIF
%// writing. Loop the GIF animation forever when viewing it
if n == 1
[imind,cm] = rgb2ind(im_colour,256);
imshow(im_colour);
imwrite(imind, cm, filename, 'Loopcount', inf);
%// For every 20th frame, add the progress to our GIF
elseif mod(n,20) == 0
[imind,cm] = rgb2ind(im_colour,256);
imshow(im_colour);
imwrite(imind, cm, filename, 'WriteMode', 'append');
end
%// Increment counter
n = n + 1;
%// Find neighbouring points that surround current point
%// and only select those that we haven't visited
[c,r] = meshgrid(pt(2)-1:pt(2)+1,pt(1)-1:pt(1)+1);
ind = sub2ind(size(im), r, c);
locs = im(ind);
r = r(locs);
c = c(locs);
%// Enqueue
queue = [queue; r(:) c(:)];
end
end
%// Write the very last frame in case we don't get to do that. Only
%//happens if the count is not a multiple of 20.
imshow(im_colour);
[imind,cm] = rgb2ind(im_colour,256);
imwrite(imind, cm, filename, 'WriteMode', 'append');
以下是将此代码作为动画GIF运行的示例。我的起点与您在帖子中标记示例的位置大致相同。
希望这会让你开始。祝你好运!