使用matlab,我需要以编程方式找到圆的中心,而我只能看到圆的外边缘。
以下是我正在尝试处理的测试图片:
忽略外缘周围的黑色。我把相机放在一个示波器后面,这就是为什么你只能在中间看到一个小的放大圆圈。这些黑色圆圈实际上是一个目标,因此有多个环互相嵌套。
在下面的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()并试图创建自己的函数来做类似的事情。该脚本将图像转换为二进制图像,然后使用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
答案 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.