使用MATLAB进行线跟踪 [英] Line tracking with MATLAB

查看:135
本文介绍了使用MATLAB进行线跟踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个图像,我想将其转换为逻辑图像,包括线条为黑色,背景为白色。当然,可以使用阈值方法来实现,但我不想通过这种方式来实现。我想通过使用线跟踪方法或类似的方法来检测它。



它是关于视网膜血管检测。我发现了问题。您可以将您示例中标记的起点视为进入迷宫的切入点,您的工作将从迷宫中找到出路。 BFS背后的基本驱动力是它使用 队列 。在起点,您将此点添加到队列中。然后,当队列不为空时,将队列中的点出列,然后检查其任何邻居,看看你是否有:


  1. 之前没有访问过它们。

  2. 如果它们是迷宫中的路径点......或者在这种情况下,这些是在其中的船只点line。

如果您有任何满足(1)和(2)的点,您可以将这些点添加到队列中排队他们。一旦你完成了向队列添加点数,你就会返回并取出另一个点并重复算法,直到你的队列为空。






对于你的线追踪算法,你会做的是,对于你已经出列的每一个点,你会用一种颜色标记图像...让我们说你要在红。一旦你将该点出列,将那些你没有访问过的点和有效的船只点添加到你的队列然后返回并将另一个点出列,然后重复逻辑。您将继续此操作,直到您的队列为空。关于BFS的好处是,它允许您同时探索多条路径,如果您达到死胡同,我们将停止搜索此路径,并允许我们尚未探索的其他路径继续被探索。



这是我写的一些示例代码。为简单起见,我从StackOverflow读取您的图像,将图像转换为黑白图像并对图像进行镂空。遗憾的是,您需要将此转换为逻辑才能使此算法正常工作。我知道你不希望这样,但我假设你会有这些痕迹的多个实例,所以如果你标记一个连续血管内的点,这个算法将标记属于这个血管的所有点。



无论如何,我进行了镂空,以便容器的厚度为1像素,以便于操作。我还创建了镂空图像的彩色版本,以便我们可以在我们用红色探测的像素中着色。在此之后代码执行的第一件事是它向您显示骨架化图像,它等待您单击容器中的某个位置。这是通过 ginput 。代码将找到与您单击的位置相关的最近点,并将其作为起点。这是通过简单地找到与您在容器中的每个有效点点击的点的最小欧几里德距离来完成的。



一旦找到这个起点,我们添加这个作为我们队列中的第一个进入并开始我们的BFS算法。作为奖励,我还编写了代码来保存作为动画GIF的进度。每隔20帧,图像就会写入此动画GIF文件。另外,我向您展示每20帧线条跟踪的样子。这一直持续到我们用完点或队列为空,然后算法停止。动画GIF也存储在您运行代码的同一目录中。我还写了最终完成的图像看起来像什么,因为当我们停止算法时,它不会发生在20帧的倍数,所以你应该写出最后一帧和最后一帧文件,这应该是完全标记的船只图像。



没有进一步的麻烦,这里是代码:

 %//从StackOverflow中读取图片
im = imread('http://i.stack.imgur.com/3t4Dx.png');

%//歪曲图像以简化问题
im = bwmorph(~im2bw(im),'skel','inf');

%//制作一个彩色版本,以便我们可以在
%中标记我们访问过的像素//红色
im_colour = 255 * uint8(cat(3,im,im) ,IM));

%//从用户那里获得一个起点
imshow(im);
[col,row] = ginput(1);
全部收盘;

%//找到我们点击的船只上的最近点和
%//添加到队列作为起点
[rows,cols] = find( IM);
[〜,ind] = min((行 - 行)。^ 2 +(col-cols)。^ 2);
queue = [rows(ind),cols(ind)];

%//存储到目前为止我们访问过的所有位置的变量
mask = false(size(im));

%//将动画GIF保存到文件
filename ='linetracing.gif';
数字;

%//跟踪我们到目前为止处理的点数的计数器
%//这也允许我们以
%//编写线追踪算法输出某些迭代数输出
n = 1;

%//队列不为空时
而〜isempty(队列)

%//出队
pt =队列(1,: );
queue(1,:) = [];

%//如果这不是有效的船只点,请标记为已访问并继续
如果im(pt(1),pt(2))== 0
掩码(pt(1),pt(2))= true;

%//如果我们已经访问过这一点,继续
elseif mask(pt(1),pt(2))
继续;
else
%//我们还没有访问过这一点
%//将此标记为已访问
mask(pt(1),pt(2))= true;

%//此时为图像着色
im_colour(pt(1),pt(2),:) = [255; 0; 0];

%//我们将每隔20帧编写一次线跟踪进度
%//如果我们处于第一帧,我们需要初始化我们的GIF
%/ / 写作。查看它时永远循环GIF动画
如果n == 1
[imind,cm] = rgb2ind(im_colour,256);
imshow(im_colour);
imwrite(imind,cm,filename,'Loopcount',inf);
%//每20帧,将进度添加到我们的GIF
elseif mod(n,20)== 0
[imind,cm] = rgb2ind(im_colour,256);
imshow(im_colour);
imwrite(imind,cm,filename,'WriteMode','append');
结束
%//增量计数器
n = n + 1;

%//查找当前点周围的邻近点
%//并且只选择那些我们没有访问过的点
[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);

%//入队
queue = [queue; r(:) c(:)];
end
end

%//写下最后一帧,以防我们不这样做。如果计数不是20的倍数,则只发生
%//
imshow(im_colour);
[imind,cm] = rgb2ind(im_colour,256);
imwrite(imind,cm,filename,'WriteMode','append');






以下是此代码作为动画的示例运行GIF。我的起点与您在帖子中标记示例的位置大致相同。








希望这会让你入门。祝你好运!


I have an image and I want to covert it to logical image includes the line is black and background is white. Of course, it is possible to make that with using threshold method but I don't want to do that by using this way. I want to detect it by using a line tracking method or sometihing like that.

It is about retina vessels detection. I found an article about it but I don't know the way of creating a Dynamic search window.

How can I do that?

Original image:

Tracking way:

I prepared images with paint.

解决方案

This is a classic Breadth First Search (BFS) problem. You can think of your starting point marked in your example as an entry point into a maze where your job is find a way out of the maze. The basic driving force behind BFS is that it uses a queue. At the starting point, you add this point to queue. Then, while the queue is not empty, dequeue the point off the queue, then check any of its neighbours to see if you have:

  1. Not visited them before.
  2. If they are points that are paths in your maze.... or in this case, these are vessel points that are within the line.

Should you have any points that have satisfied both (1) and (2), you add these points to the queue by enqueueing them. Once you're finished adding points to the queue, you go back and dequeue another point and repeat the algorithm until your queue is empty.


For your line tracing algorithm, what you would do is that for each point that you have dequeued, you would mark the image in a colour... let's say you'd mark this in red. Once you dequeue the point, add those points that you haven't visited and that are valid vessel points to your queue then go back and dequeue another point, then repeat the logic. You'd continue with this until your queue is empty. The good thing about BFS is that it allows you to explore multiple paths at the same time and should you reach a dead end, we stop searching this path and allow the other paths we haven't explored to continue being explored.

Here's some sample code that I wrote. To make things simple, I read your image from StackOverflow, converted the image to black and white and skeletonized the image. You unfortunately need to convert this into logical for this algorithm to work. I understand that you don't desire this, but I'm assuming that you will have multiple instances of these traces, and so if you mark a point that is within one continuous vessel, this algorithm will mark all points that belong to this vessel.

In any case, I skeletonized so that the thickness of the vessel is 1 pixel thick to make things easier. I have also created a colour version of the skeletonized image so that we can colour in the pixels we have explored in red. The first thing that the code does after this is that it shows you the skeletonized image, and it waits for you to click somewhere along the vessel. This is done with ginput. The code will find the closest point with respect to where you have clicked, and it makes this the starting point. This is done by simply finding the minimum Euclidean distance with the point you clicked with every valid point that is in the vessel.

Once we find this starting point, we add this as the first entry into our queue and begin our BFS algorithm. As a bonus, I also wrote code to save the progress as an animated GIF. Every 20 frames, an image gets written to this animated GIF file. In addition, I show you what the line tracing looks like at every 20 frames. This continues until we run out of points, or when the queue is empty, and then the algorithm stops. The animated GIF also gets stored in the same directory where you ran the code. I also wrote what the final completed image looks like as it will inevitably be the case where when we stop the algorithm, it doesn't happen at a multiple of 20 frames, and so you should definitely write the last and final frame to file, which should be the completely marked vessel image.

Without further ado, here's the code:

% // 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');


Here's an example run of this code as an animated GIF. I made the starting point around the same as where you have marked your example in your post.


Hopefully this will get you started. Good luck!

这篇关于使用MATLAB进行线跟踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆