另一种方法是使用bwdistgeodesic
沿边缘的距离来查找角的顺序。这应该适用于可以检测到连续边缘的任何多边形。
我们首先从 Stack Overflow 加载图像并将其转换为黑白图像,以便更容易找到边缘
A = imread('http://i.stack.imgur.com/dpbpP.jpg');
A_bw = im2bw(A,100/255); %binary image
A_bw1 = imcomplement(A_bw); %inverted binary image
该bwmorph
功能提供了许多用于处理黑白图像的选项。我们将使用该remove
选项来查找多边形的边缘,但如果您愿意,也可以使用另一个边缘检测器。
%Find the edges
A_edges = bwmorph(A_bw, 'remove');
[edge_x, edge_y] = find(A_edges');
让我们可视化我们检测到的边缘
figure; imshow(A_edges);
好的,我们有一个很好的清晰的连续边缘。现在让我们找到角落。我用过corner
,但你可以用你最喜欢的角探测器代替
A_corners = corner(A_bw1, 'QualityLevel',.3);
让我们可视化我们的初始角排序
figure; imshow(A_bw1);
hold on
plot(A_corners(:,1), A_corners(:,2), 'r.', 'MarkerSize', 18)
text(A_corners(:,1), A_corners(:,2), strsplit(num2str(1:length(A_corners))), 'Color', 'g', 'FontSize', 24);
hold off
您可能没有注意到的另一件事是它们并不直接位于边缘。我将首先找到沿边缘到每个角点的最近点,然后将角以红色可视化,将最近的边缘点以绿色可视化。
[~, ind] = min(pdist2(A_corners, [edge_x, edge_y]), [], 2);
A_edge_corners = [edge_x(ind), edge_y(ind)];
figure; imshow(A_edges);
hold on;
plot(A_corners(:,1), A_corners(:,2), 'r.', 'MarkerSize', 18)
plot(A_edge_corners(:,1), A_edge_corners(:,2),'g.', 'MarkerSize', 18)
hold off;
为了计算每个角的边缘周围的距离,我们将使用边缘上的角点近似值A_edge_corners
(绿点)而不是角点本身A_corners
(红点)。
现在我们拥有了我们需要使用的所有部件bwdistgeodesic
。此函数查找黑白图像中每个非零像素到种子点的距离。我们对从初始角到边缘上每个点的距离感兴趣。让我们试试看。
% Calculate distance from seed corner
first_corner = A_edge_corners(1,:);
D = bwdistgeodesic(A_edges, first_corner(1), first_corner(2));
figure; imagesc(D);
我们从最右边的角落开始,远离角落的像素值增加。但这并不是我们想要的。如果我们使用这些值对角进行排序,我们最终会得到与初始点的距离排序。
[~, corner_order] = sort(D(sub2ind(size(D), A_edge_corners(:,2), A_edge_corners(:,1))));
A_corners_reorder1 = A_corners(corner_order, :);
figure; imshow(A_bw1);
hold on
plot(A_corners_reorder1(:,1), A_corners_reorder1(:,2),'r.', 'MarkerSize', 18)
text(A_corners_reorder1(:,1), A_corners_reorder1(:,2), strsplit(num2str(1:length(A_corners))), 'Color', 'g', 'FontSize', 24);
hold off
为了解决这个问题,我们只需要打破边缘,使排序只从初始点朝一个方向进行。如果您对顺时针或逆时针排序感兴趣,则需要根据边缘的方向根据一组规则打破边缘。如果方向无关紧要,您可以简单地找到初始角的相邻像素,并在那里打破边缘。
%Break the edge into one path by removing a pixel adjacent to first corner
%If the corner is near the edge of the image, you would need to check for
%edge conditions
window = A_edges(first_corner(2)-1:first_corner(2)+1, first_corner(1)-1:first_corner(1)+1);
window(2,2) = 0; %Exclude the corner itself
[x, y] = find(window, 1);
A_edges(first_corner(2)+x-2, first_corner(1)+y-2) = 0;
figure; imshow(A_edges);
hold on;
plot(first_corner(1), first_corner(2), 'r.', 'MarkerSize', 18)
hold off;
现在沿边缘到初始点的距离只能走一条路径
%Find order the pixels along edge
D = bwdistgeodesic(A_edges, first_corner(1), first_corner(2));
figure; imagesc(D);
这为我们提供了所需的边缘顺序
[~, corner_order] = sort(D(sub2ind(size(D), A_edge_corners(:,2), A_edge_corners(:,1))));
A_corners = A_corners(corner_order, :);
figure; imshow(A_bw1);
hold on
plot(A_corners(:,1), A_corners(:,2),'r.', 'MarkerSize', 18)
text(A_corners(:,1), A_corners(:,2), strsplit(num2str(1:length(A_corners))), 'Color', 'g', 'FontSize', 24);
hold off
此方法也适用于相对于质心不平衡的多边形,例如第二个演示图像。
为了好玩,我展示了第三张图像,它在质心的另一侧有一个顶点,作为不平衡多边形的更清晰示例。我的方法也正确解析了这个图像。