使用MATLAB在图像中分离两个重叠的圆 [英] Separate two overlapping circles in an image using MATLAB

查看:562
本文介绍了使用MATLAB在图像中分离两个重叠的圆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用MATLAB将下图中的两个连接圆分开?我尝试过使用 imerode ,但这并没有给出好的结果。腐蚀不起作用,因为为了腐蚀足以分离圆圈,线条会消失或变得严重。在其他起始图片中,圆和线重叠,因此隔离重叠的对象也不起作用。



图像显示由标识的对象bwboundaries ,每个对象涂上不同的颜色。正如你所看到的那样,两个淡蓝色圆圈被连接起来,我想要将它们分开,产生两个独立的圆圈。谢谢



解决方案

我建议您通过确定(X,Y)关于包含我们形状的图像的坐标,以便我可以在每次迭代时在空白图像上绘制一个圆。要做到这一点,你只需要找到相对于每个圆的中心的欧氏距离,并且只有当该位置的距离小于<时才将像素设置为 true code> - [R 。执行此操作后,您将只创建一个圆圈并将其全部过滤掉。然后你会在这个圈子上使用 regionprops ,将它添加到我们的 circles_img 数组中,该数组只包含圆圈,然后继续其余的圈子。



此时,我们将保存所有圈子。这就是 circles_img 到目前为止的结果:





您会注意到绘制的圆圈是干净的,但原始的圆圈是原始圆圈图像有点锯齿状。如果我们尝试使用此干净图像移除圆圈,您将在边框处获得一些残留像素,并且您不会完全删除圆圈本身。为了说明我的意思,如果我尝试用 circles_img 删除圈子,这就是你的图片的样子:





..不好,对吗?



如果你想完全删除圆圈,那么通过 imreconstruct 您可以将此图像用作种子图像,并指定原始图像是我们正在努力的。形态重建的工作基本上是洪水填充。您指定了种子像素和要处理的图像, imreconstruct 的作业来自这些种子,使用白色填充填充,直到我们到达对象的边界为止种子像素位于。因此:

  out_circles = imreconstruct(circles_img,out); 

因此,我们在最终重建的圆圈图片中得到此信息:





大!现在,使用此选项并从原始图像中删除圆圈。完成此操作后,在此最终映像上再次运行 regionprops 并附加到 struct_reg 变量。显然,在执行此操作之前保存原始图像的副本:

  out_copy = out; 
out_copy(out_circles)= false;
struct_reg = [struct_reg; regionprops(out_copy)];

仅仅为了争论,这就是删除了圆圈后图片的样子:





现在,我们已经分析了所有形状。请记住,我做了完整的 regionprops 调用,因为我不知道你在分析中到底想要什么...所以我决定给你一切。






希望这会有所帮助!


How do I separate the two connected circles in the image below, using MATLAB? I have tried using imerode, but this does not give good results. Eroding does not work, because in order to erode enough to separate the circles, the lines disappear or become mangled. In other starting pictures, a circle and a line overlap, so isolating the overlapping objects won't work either.

The image shows objects identified by bwboundaries, each object painted a different color. As you can see, the two light blue circles are joined, and I want to disjoin them, producing two separate circles. Thanks

解决方案

I would recommend you use the Circular Hough Transform through imfindcircles. However, you need version 8 of the Image Processing Toolbox, which was available from version R2012a and onwards. If you don't have this, then unfortunately this won't work :(... but let's go with the assumption that you do have it. However, if you are using something older than R2012a, Dev-iL in his/her comment above linked to some code on MATLAB's File Exchange on an implementation of this, most likely created before the Circular Hough Transform was available: http://www.mathworks.com/matlabcentral/fileexchange/9168-detect-circles-with-various-radii-in-grayscale-image-via-hough-transform/


This is a special case of the Hough Transform where you are trying to find circles in your image rather than lines. The beauty with this is that you are able to find circles even when the circle is partially completed or overlapping.

I'm going to take the image that you provided above and do some post-processing on it. I'm going to convert the image to binary, and remove the border, which is white and contains the title. I'm also going to fill in any holes that result so that all of the objects are filled in with solid white. There is also some residual quantization noise after I do this step, so I'm going to a small opening with a 3 x 3 square element. After, I'm going to close the shapes with a 3 x 3 square element, as I see that there are noticeable gaps in the shapes. Therefore:

Therefore, directly reading in your image from where you've posted it:

im = imread('http://s29.postimg.org/spkab8oef/image.jpg'); %// Read in the image
im_gray = im2double(rgb2gray(im)); %// Convert to grayscale, then [0,1]
out = imclearborder(im_gray > 0.6); %// Threshold using 0.6, then clear the border
out = imfill(out, 'holes'); %// Fill in the holes
out = imopen(out, strel('square', 3));
out = imclose(out, strel('square', 3));

This is the image I get:

Now, apply the Circular Hough Transform. The general syntax for this is:

[centres, radii, metric] = imfindcircles(img, [start_radius, end_radius]);

img would be the binary image that contains your shapes, start_radius and end_radius would be the smallest and largest radius of the circles you want to find. The Circular Hough Transform is performed such that it will find any circles that are within this range (in pixels). The outputs are:

  1. centres: Which returns the (x,y) positions of the centres of each circle detected
  2. radii: The radius of each circle
  3. metric: A measure of purity of the circle. Higher values mean that the shape is more probable to be a circle and vice-versa.

I searched for circles having a radius between 30 and 60 pixels. Therefore:

[centres, radii, metric] = imfindcircles(out, [30, 60]);

We can then demonstrate the detected circles, as well as the radii by a combination of plot and viscircles. Therefore:

imshow(out);
hold on;
plot(centres(:,1), centres(:,2), 'r*'); %// Plot centres
viscircles(centres, radii, 'EdgeColor', 'b'); %// Plot circles - Make edge blue

Here's the result:

As you can see, even with the overlapping circles towards the top, the Circular Hough Transform was able to detect two distinct circles in that shape.


Edit - November 16th, 2014

You wish to ensure that the objects are separated before you do bwboundaries. This is a bit tricky to do. The only way I can see you do this is if you don't even use bwboundaries at all and do this yourself. I'm assuming you'll want to analyze each shape's properties by themselves after all of this, so what I suggest you do is iterate through every circle you have, then place each circle on a new blank image, do a regionprops call on that shape, then append it to a separate array. You can also keep track of all of the circles by having a separate array that adds the circles one at a time to this array.

Once you've finished with all of the circles, you'll have a structure array that contains all of the measured properties for all of the measured circles you have found. You would use the array that contains only the circles from above, then use these and remove them from the original image so you get just the lines. You'd then call one more regionprops on this image to get the information for the lines and append this to your final structure array.

Here's the first part of the procedure I outlined above:

num_circles = numel(radii); %// Get number of circles
struct_reg = []; %// Save the shape analysis per circle / line here

%// For creating our circle in the temporary image
[X,Y] = meshgrid(1:size(out,2), 1:size(out,1));

%// Storing all of our circles in this image
circles_img = false(size(out));

for idx = 1 : num_circles %// For each circle we have...        
    %// Place our circle inside a temporary image    
    r = radii(idx);
    cx = centres(idx,1); cy = centres(idx,2);
    tmp = (X - cx).^2 + (Y - cy).^2 <= r^2;        

    % // Save in master circle image
    circles_img(tmp) = true;

    %// Do regionprops on this image and save    
    struct_reg = [struct_reg; regionprops(tmp)]; 
end


The above code may be a bit hard to swallow, but let's go through it slowly. I first figure out how many circles we have, which is simply looking at how many radii we have detected. I keep a separate array called struct_reg that will append a regionprops struct for each circle and line we have in our image. I use meshgrid to determine the (X,Y) co-ordinates with respect to the image containing our shapes so that I can draw one circle onto a blank image at each iteration. To do this, you simply need to find the Euclidean distance with respect to the centre of each circle, and set the pixels to true only if that location has its distance less than r. After doing this operation, you will have created only one circle and filtered all of them out. You would then use regionprops on this circle, add it to our circles_img array, which will only contain the circles, then continue with the rest of the circles.

At this point, we will have saved all of our circles. This is what circles_img looks like so far:

You'll notice that the circles drawn are clean, but the actual circles in the original image are a bit jagged. If we tried to remove the circles with this clean image, you will get some residual pixels along the border and you won't completely remove the circles themselves. To illustrate what I mean, this is what your image looks like if I tried to remove the circles with circles_img by itself:

... not good, right?

If you want to completely remove the circles, then do a morphological reconstruction through imreconstruct where you can use this image as the seed image, and specify the original image to be what we're working on. The job of morphological reconstruction is essentially a flood fill. You specify seed pixels, and an image you want to work on, and the job of imreconstruct is from these seeds, flood fill with white until we reach the boundaries of the objects that the seed pixels resided in. Therefore:

out_circles = imreconstruct(circles_img, out);

Therefore, we get this for our final reconstructed circles image:

Great! Now, use this and remove the circles from the original image. Once you do this, run regionprops again on this final image and append to your struct_reg variable. Obviously, save a copy of the original image before doing this:

out_copy = out;
out_copy(out_circles) = false;
struct_reg = [struct_reg; regionprops(out_copy)];

Just for sake of argument, this is what the image looks like with the circles removed:

Now, we have analyzed all of our shapes. Bear in mind I did the full regionprops call because I don't know exactly what you want in your analysis... so I just decided to give you everything.


Hope this helps!

这篇关于使用MATLAB在图像中分离两个重叠的圆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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