これは、 @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')
編集:
ジェイコブのコメントに応えて、私は最初に一次/二次導関数を使用して署名のピークを見つけようとしましたが、最終的に最も遠いNポイントを取得したことを説明する必要があります。10は単なるアドホックな値であり、一般化するのは難しいでしょう(コーナーの数と同じ4を試してみましたが、すべてをカバーしていませんでした)。それらをクラスタリングして重複を削除するというアイデアは、検討する価値があると思います。
私が見る限り、最初のアプローチの問題は、境界をトレースする速度が異なり、依存するため、考慮rho
せずにプロットすると、異なる形状(同じピークではない)が得られることでした。曲率。その効果を正規化する方法を理解できれば、導関数を使用してより正確な結果を得ることができます。θ