问题:
给定这样的凸四边形二进制掩码BW
,确定四个角的最有效方法是什么?
例如。,
迄今为止最好的解决方案:
使用edge
查找边界线,使用Hough变换在边缘图像中找到4条线,然后找到这4条线的交点,或在边缘图像上使用拐角检测器。似乎很复杂,我不禁感到这里有一个更简单的解决方案。
顺便说一句,convhull
并不总是返回4点(也许有人可以建议使用qhull
选项来防止这种情况发生):它也会沿边缘返回一些点。
编辑:
Amro's answer看起来非常优雅高效。但是,由于每个峰都不是唯一的,因此在每个实际拐角处可能会有多个“拐角”。我可以根据θ将它们聚类,然后将“角”平均在一个真实的角上,但是主要问题是使用order(1:10)
。10
是否足以解决所有拐角问题,还是会排除实际拐角处的“拐角”?
最佳答案
这有点类似于@AndyL的建议。但是我在极坐标而不是切线中使用边界签名。
请注意,我首先提取边缘,获取边界,然后将其转换为签名。最后,我们找到边界上距质心最远的点,这些点构成了找到的角。 (或者,我们也可以检测出拐角处的特征峰)。
以下是一个完整的实现:
I = imread('oxyjj.png');
if ndims(I)==3
I = rgb2gray(I);
end
subplot(221), imshow(I), title('org')
%%# Process Image
%# edge detection
BW = edge(I, 'sobel');
subplot(222), imshow(BW), title('edge')
%# dilation-erosion
se = strel('disk', 2);
BW = imdilate(BW,se);
BW = imerode(BW,se);
subplot(223), imshow(BW), title('dilation-erosion')
%# fill holes
BW = imfill(BW, 'holes');
subplot(224), imshow(BW), title('fill')
%# get boundary
B = bwboundaries(BW, 8, 'noholes');
B = B{1};
%%# boudary signature
%# convert boundary from cartesian to ploar coordinates
objB = bsxfun(@minus, B, mean(B));
[theta, rho] = cart2pol(objB(:,2), objB(:,1));
%# find corners
%#corners = find( diff(diff(rho)>0) < 0 ); %# find peaks
[~,order] = sort(rho, 'descend');
corners = order(1:10);
%# plot boundary signature + corners
figure, plot(theta, rho, '.'), hold on
plot(theta(corners), rho(corners), 'ro'), hold off
xlim([-pi pi]), title('Boundary Signature'), xlabel('\theta'), ylabel('\rho')
%# plot image + corners
figure, imshow(BW), hold on
plot(B(corners,2), B(corners,1), 's', 'MarkerSize',10, 'MarkerFaceColor','r')
hold off, title('Corners')
编辑:
为了回应Jacob的评论,我应该解释一下,我首先尝试使用一阶/二阶导数查找签名中的峰,但最终获得了最远的N点。 10只是一个临时值,很难一概而论(我尝试将4个与拐角数量相同,但并未涵盖所有拐角)。我认为将它们聚类以删除重复项的想法值得研究。
据我所知,第一种方法的问题在于,如果在不考虑
rho
的情况下绘制θ
,您将得到不同的形状(不相同的峰),因为我们跟踪边界的速度不同,并且取决于曲率。如果我们能弄清楚如何标准化该效果,则可以使用导数获得更准确的结果。