簡體   English   中英

以順時針順序檢測非凸多邊形的角坐標MATLAB

[英]Detect corner coordinates of a non-convex polygon in clockwise order MATLAB

我有一些圖像,包括凸多邊形和非凸多邊形。 每個圖像只包含一個多邊形。 我需要檢測角坐標,並需要按順時針或逆時針順序對它們進行排序。 對於凸多邊形,我使用Harris角點檢測來檢測角點和凸包線以對點進行排序。 但我對如何排序非凸多邊形沒有任何想法。 由於我的輸入是圖像,我認為一些圖像處理技術可能有助於通過沿多邊形邊緣移動來對它們進行排序。 有沒有辦法最簡單?

示例圖片:

我隨機命名了角落。

在此輸入圖像描述

預期產量:

我希望角坐標按此順序為1 3 5 9 4 2 8 7 6 101 10 6 7 8 2 4 9 5 3 你可以從任何一點開始,不一定是1

編輯1:

在對所有凸多邊形以及一些非凸多邊形起作用的rayryeng解之后,有一些非凸多邊形與他的算法不相符

這是一個例子

在此輸入圖像描述

另一種方法是使用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);

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);

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

角落從第1點重新排序

為了解決這個問題,我們只需要打破邊緣,這樣排序只能從初始點開始向一個方向發展。 如果您對順時針或逆時針順序感興趣,則需要根據一組規則打破邊緣,具體取決於邊緣的方向。 如果方向無關緊要,您可以簡單地找到初始角落的相鄰像素,並在那里打破邊緣。

%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);

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

正確的訂購

此方法也適用於相對於質心不平衡的多邊形,例如第二個演示圖像。

第二個演示圖像

為了好玩,我提出了第三個圖像,它在質心的另一側有一個頂點,作為不平衡多邊形的一個更清晰的例子。 我的方法也正確地解析了這個圖像。

這是圖像處理中的常見問題。 典型的答案是找到形狀的質心,並找到質心和每個角點之間的角度。 您將確保表示角度,使其范圍在[0,360)度之間。 完成此操作后,您可以角度進行排序 ,然后使用結果順序來確定點的順序。

您呈現的圖像需要一些預處理,以便我可以開始處理它。 我直接從StackOverflow讀取圖像,然后我反轉圖像,使黑色星星變成白色。 我還需要刪除數字,所以我使用bwareaopen刪除任何小區域的文本。 完成后,我通過corner對此圖像執行角點檢測,並將QualityFactor設置為0.3,這樣我就可以檢測到10個角點。 非常具體:

%// Read image from StackOverflow
im = rgb2gray(imread('http://i.stack.imgur.com/dpbpP.jpg'));

%// Threshold the image and area open it
im_thresh = im <= 100;
im_open = bwareaopen(im_thresh, 50);

%// Detect corner points
out = corner(im_open, 'QualityLevel', 0.3);

%// Show the image with the corner points
imshow(im_open);
hold on
plot(out(:,1), out(:,2), 'r.')

im_open包含我們最終處理的圖像。 這就是我得到的:

在此輸入圖像描述


現在,讓我們找到質心。 這可以通過找到非零位置的坐標,並找到每個維度的平均值來完成:

[rows, cols] = find(im_open);
cenX = mean(cols);
cenY = mean(rows);

cenXcenY包含圖像質心的(x,y)位置。 只是為了確保我們做對了:

imshow(im_open);
hold on;
plot(cenX, cenY, 'r.', 'MarkerSize', 18);

我們得到:

在此輸入圖像描述

非常好。 現在, out在前面的代碼包含(x,y)的角點的點。 您所要做的就是確定從質心到每個角點的角度,然后對角度進行排序。 您可以使用此排序順序重新排列角點,以便為您提供排列的點數。 如果需要順時針 ,則需要按升序對值進行排序。 如果你想要逆時針 ,你需要按降序排序。 我會根據你想要的決定把這個留給你,但是我會編寫代碼來讓你做到這兩點。 因此,只需這樣做:

%// Determine angles (in degrees)
angles = atan2d(out(:,2) - cenY, out(:,1) - cenX);

%// Any negative angles, add 360 degrees to convert to positive
angles(angles < 0) = 360 + angles(angles < 0);

%// Sort the angles
[~,ind] = sort(angles); %// clockwise
%[~,ind] = sort(angles, 'descend'); %// counter-clockwise

%// Re-arrange the corner points to respect the order
out_reorder = out(ind,:);

現在最后的測試是繪制這些點,並在每個點旁邊繪制一個數字,看看我們是否正確。 這可以通過以下方式完成:

%// Show image
imshow(im_open);
hold on;
%// Show points
plot(out_reorder(:,1), out_reorder(:,2), 'r.', 'MarkerSize', 18);

%// Place a textbox at each point and show a sequence number
for idx = 1 : size(out_reorder,1)
    text(out_reorder(idx,1), out_reorder(idx,2), num2str(idx), 'FontSize', 24, 'Color', 'green');
end

我們得到:

在此輸入圖像描述

對我來說看上去很好! 因此, out_reorder為您提供角點,使它們遵循順時針順序或逆時針順序。 您連續遇到的每一行都會為您提供下一個自然遵循您尋求的順時針或逆時針順序的點。

還要注意編號的開始位置。 角度0由水平線定義,該水平線相對於質心指向東方。 因此,當我們以升序開始時,最接近0的位置是您看到數字1的位置。在1之后,您會看到它以順時針順序掃過,直到我們用完了角點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM