如何只看到外边缘才能找到圆心?

时间:2013-11-20 14:56:35

标签: image-processing matlab

使用matlab,我需要以编程方式找到圆的中心,而我只能看到圆的外边缘。

以下是我正在尝试处理的测试图片:

忽略外缘周围的黑色。我把相机放在一个示波器后面,这就是为什么你只能在中间看到一个小的放大圆圈。这些黑色圆圈实际上是一个目标,因此有多个环互相嵌套。 Image to process

使用imfindcircles()

的脚本

在下面的matlab脚本中,我使用了imfindcircles()。 imfindcircles()有两个问题。  1.每次通话大约需要2-3秒,这对我的申请来说会很慢。  2.它无法预测上面示例图像中的圆心。它需要首先看到更多的圆圈。

Rmin = 40; %7 and 12 for small circle
Rmax = 100;

% Create video input object.
vid = videoinput('winvideo',1);

% Set video input object properties for this application.
% Note that example uses both SET method and dot notation method.
set(vid,'TriggerRepeat',100);
vid.FrameGrabInterval = 5;


vid = videoinput('winvideo', 1, 'MJPG_1280x720');
%src = getselectedsource(vid);

%number of frames to get each time the camera is triggered
vid.FramesPerTrigger = 1;

%return grayscale for one less thing to process
vid.ReturnedColorspace = 'grayscale';

%make the trigger type manual. This allows use to grab one frame at a time
triggerconfig(vid, 'manual');

% allow us to capture unlimited frames, with only starting the video once
vid.TriggerRepeat = Inf;

%preview(vid);

%start(vid);

%trigger(vid);

%stoppreview(vid);

% Create a figure window.
%figure;

% Start acquiring frames.
start(vid);

while(true)

    trigger(vid);

    %get a single image frame
    image = getdata(vid);

    %draw the image on screen
    imshow(image);
    drawnow;     % update figure window

    %set the center of the image. This is used as an additional way to
    %calibrate the score, camera, and laser. You can change where the "center" of
    %the camera image is by adjusting these values.
    % [x, y]
    imageCenter = [500, 500];
    viscircles(imageCenter, 5,'EdgeColor','r');

    %find circles (the target) in the image and draw a circle around it
    [centers, radii, metric] = imfindcircles(image,[Rmin Rmax], 'ObjectPolarity', 'dark');

    %make sure a circle on screen was found
    if(centers)
        %draw circle found on screen
        viscircles(centers, radii,'EdgeColor','b');

        %calculate distance from center of the image and the center of the circle
        %x minus x; y minus y; then calc hypotenuse
        circleCenterX = centers(1,1);
        circleCenterY = centers(1,2);

        imageCenterX = imageCenter(1,1);
        imageCenterY = imageCenter(1,2);

        %calculate the di
        distanceX = circleCenterX - imageCenterX;  
        distanceY = circleCenterY - imageCenterY ;

        %calculate the hypotenuse (b^2 + b^2 = c^2)
        hypotenuse = sqrt(distanceX^2 + distanceY^2);

        %create sound based on distance from the center of the image
        a=sin(2*pi*hypotenuse*(0:0.000125:0.05));
        sound(a);

        disp(hypotenuse);

        %if you are withing X pixel of the center make a beeping noise
        if(hypotenuse <= 15)
            a=sin(2*pi*400*(0:0.000125:0.05));
            sound(a);
            sound(a);
            sound(a);
        end

        %show a measuring line to verfiy results
        %h = imdistline;
    end

    %clear memory after each frame to avoid memory leak
    flushdata(vid, 'triggers');

end

%doesnät get run but use these commands to clean up before running the
%script again
imaqreset();
%stop(vid);
%delete(vid);
%clear;
%close(gcf);

脚本试图替换imfindcircles()

为了加快处理速度,我抛出了我们的imfindcircles()并试图创建自己的函数来做类似的事情。该脚本将图像转换为二进制图像,然后使用regionprops查找白色对象的中心。您还会注意到在代码中检测中心的基本想法。它还试图找到这样一个想法的中心:当两个或多个完美的圆圈放在彼此内部时,它们都将具有相同的中心......但在我上面的图片示例中,这个简单的概念无法工作,因为它甚至不能检测单个圆圈,更不用说其中的其他圆圈了。

function circleCenter = findCircleCenter(image, drawOnImage, toGray)
    %in order to find the center, find the center of all objects in an image.
    %Once we have the centers, we find the shortest distance between these
    %objects. Our image has multiple circle, each inside the other. The center
    %of all these cirlces are the same. By finding the shortest distance
    %between the objects, we can safely assume we found the center of our
    %target when we find two points are very close to each other. 

    %Adjust the number of pixels between the two points of the circle.
    %Explained in details above.
    minCenterPixelDist = 8;
    %the minimum amount of pixels needed in a region to be considered an
    %object for measurement
    minPixelArea = 100;

    if(toGray == 1)
        %convert to grayscale
        image = rgb2gray(image);
        %figure, imshow(image);
    end

    %find the two closest points
    %see if they are less than 8 pixels apart, this is the center

    %threshold the image to make a binary image
    BW = image > 100; %100
    %figure, imshow(BW);

    %http://www.mathworks.de/de/help/images/ref/imdilate.html
    %se = strel('line',11,90);
    %I2 = imdilate(BW,se);
    %imshow(BW), title('Original')
    %figure, imshow(I2), title('Dilated')

    originalBW = BW;  
    se = strel('disk',2);        
    erodedBW = imerode(originalBW,se);
    %imshow(originalBW), figure, imshow(erodedBW)

    %find regions in binary image
    regionImage = erodedBW;
    s = regionprops(regionImage, image, {'Centroid','WeightedCentroid','Area','FilledImage'});

    %draw the regions found on screen.
    if(drawOnImage == 1)
        %figure, imshow(regionImage);
        title('Weighted (red) and Unweighted (blue) Centroid Locations');
        hold on
        numObj = numel(s);
        for k = 1 : numObj

            %only display regions that are bigger than X number of pixels
            if(s(k).Area > minPixelArea)
                plot(s(k).WeightedCentroid(1), s(k).WeightedCentroid(2), 'r*');
                plot(s(k).Centroid(1), s(k).Centroid(2), 'bo');
                text(s(k).Centroid(1),s(k).Centroid(2), sprintf('%2.1f', s(k).Centroid(1)), 'EdgeColor','b','Color','r');
            end
        end
        hold off
    end

    shortestDist = 100; %stores the current shortest distance found, default to somethign massive so it gets overwriten easily
    shortestDistIndex = 0;%stores the index of the point with the shortest distance

    for idx = 1:numel(s)

        %make sure the current element has more than X number of pixels
        %before processing it
        if(s(idx).Area > minPixelArea)
            %get the x and y of the current element
            currentX = s(idx).Centroid(1);
            currentY = s(idx).Centroid(1);

            %get the x and y of the next element
            try
                nextX = s(idx + 1).Centroid(1);
                nextY = s(idx + 1).Centroid(1);
            catch
                %if we are on the last element, the try statement will fail, and
                %this will end the for loop
                break;
            end

            %calculate the distance between the current centroid and the next one
            distanceX = nextX - currentX;  
            distanceY = nextY - currentY;

            %calculate the hypotenuse (b^2 + b^2 = c^2)
            hypotenuse = sqrt(distanceX^2 + distanceY^2);

            %if the distance is less than the current "shortest distance",
            %overwrite the variable
            if(hypotenuse <= shortestDist)
                shortestDist = hypotenuse;
                shortestDistIndex = idx;
            end
        end
    end

    %if the closest points are within a certain number of pixels, we can
    %assume the are the centers of two circles 
    %also make sure the area of this shortest distance is greater than
    %minPixel area
    if(shortestDist < minCenterPixelDist)
         %get the x and y of our shortest distance centroids
         centerOneX = s(shortestDistIndex).Centroid(1);
         centerOneY = s(shortestDistIndex).Centroid(2);

         centerTwoX = s(shortestDistIndex + 1).Centroid(1);
         centerTwoY = s(shortestDistIndex + 1).Centroid(2);

         %calculate the average between the two closest points
         circleCenterX = (centerOneX + centerTwoX)/2;
         circleCenterY = (centerOneY + centerTwoY)/2;

         circleCenter = [circleCenterX, circleCenterY];

         disp(circleCenter);
    else
        circleCenter = [];
    end
end

3 个答案:

答案 0 :(得分:1)

您可以尝试Hough Transform进行圆圈检测。 See here

答案 1 :(得分:1)

如果圆圈上有3个点(A,B,C),则可以计算它。 外接圆的中心可以在AB,AC或BC段上任意两个垂直平分线的交点处找到。有关更多详细信息,请查看维基百科上的circumscribed circle文章。

答案 2 :(得分:0)

我的解决方案

我写了一篇关于如何解决问题的简短教程,并将我的所有代码发布到github。 See the tutorial and code.本教程是在项目README.md文件中编写的,因此当您查看github页面并向下滚动时,它应该出现。 I used the math @vadim123 suggested here.