这有点类似于@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
不考虑的情况下进行绘图θ
,你会得到不同的形状(不是相同的峰),因为我们追踪边界的速度不同并且取决于曲率。如果我们能弄清楚如何规范化这种影响,我们就可以使用导数得到更准确的结果。