影像之結構化特徵 廣度優先搜尋模板題
阿新 • • 發佈:2018-12-02
影像之結構化特徵
Problem Description
在影像比對中,有一種方法是利用影像中的邊緣(edge)資訊,計算每個邊緣資訊中具有代表性的結構化特徵,以作為比對兩張影像是否相似的判斷標準。Water-filling方法是從每個邊緣圖的一個端點開始,繞著相連的邊緣點走並依序編號。若走到某一步時,遇到一個以上不同的連線點,則分成不同路徑同時繼續走,直到沒有任何連線點為止。如果一個點和另一個點為上下左右相鄰,就稱為連線。
例如,在圖的影像中包含三個邊緣圖,每個邊緣圖由一些互相連線的邊緣點構成。圖中以黑色的方塊代表邊緣點,白色的方塊代表背景。在Water-filling方法中,首先,從第一列(row)開始,由上至下,由左至右,先找到第一個黑點並編號為1。接著,找1的下一個尚未編號的連線點並編號為2。依此方法繼續往下一個點前進依次編號。在編號6的點之後有兩個尚未編號的連線點,此時,則分為兩條路線,並同時編號為7繼續往下走。當走到沒有任何的相連點時,則結束現有邊緣圖的編號,並繼續對影像中的其它邊緣圖編號。走完圖1所有邊緣圖後所得到的編號如圖2所示。所以,走完這三個邊緣圖所需要的步數分別為12、7及3;所以,12、7及3可以作為代表此張影像的結構化特徵。請注意:位於斜對角上的兩點不能算做連線,如:
請寫一個程式計算每個影像中,以Water-filling方法走完其中所有的邊緣圖後,將每個邊緣圖需走的步數依走訪的順序列出。
Input
輸入檔案包含一個正方形的影像。每組影像以圖的寬度n開頭(l≤n≤1000)。接下來的n行代表影像的內容:0表示背景的白點,1表示黑色的邊緣點。
Output
對每一個輸入的影像,以Water-filling方法走完所有的邊緣圖後,先印出此張影像中共有幾個邊緣圖。接著,將每個邊緣圖需走的步數按升序列出。
Sample
10
0000000000
0011110000
0000010000
0011111000
0010110100
0010010110
0011110010
0100010010
0100000110
0100000000
樣例輸出
3
3
7
12
觀察本題,我們很容易知道,本題要求我們對於一個圖,其大小為n*n,從上到下,從左到右,進行搜尋。對於搜尋到其值為1的點,我們需要從這個點開始進行廣搜,搜尋完與其相連成一塊的所有點,並且每次搜尋完與其相連的點後,記錄下其距離開始搜尋點最遠的點的搜尋距離。最後,對於所有這樣的值進行排序並且順序輸出。
很顯然,我們只需要按題目所說,搜尋完所有點,並且保證每個聯通的點集僅搜尋一遍且搜尋初始點是其中最左、最上的點。
所以,得到如下程式碼:
#include <cstdio> using namespace std; int n,head=1,tail,num,t,maxn; struct node{ int x,y; }q[1020010]; int ber[1020010]; node move[5]={0,0,1,0,0,1,-1,0,0,-1}; bool bo[1010][1010]; int ans[500010]; inline void read() { for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { char c=getchar(); while ((c!='0')&&(c!='1')) c=getchar(); if (c=='1') bo[i][j]=true; } return ; } void sort(int ,int ); int main() { scanf("%d",&n); read(); for (int j=1;j<=n;j++) for (int i=1;i<=n;i++) { if (bo[i][j]) { maxn=1; q[++tail].x=i; q[tail].y=j; ber[tail]=1; bo[i][j]=false; while (head<=tail) { node now; t=head; if (ber[t]>maxn) maxn=ber[t]; now=q[head++]; for (int k=1;k<=4;k++) if (bo[now.x+move[k].x][now.y+move[k].y]) { bo[now.x+move[k].x][now.y+move[k].y]=false; q[++tail].x=now.x+move[k].x; q[tail].y=now.y+move[k].y; ber[tail]=ber[t]+1; } } ans[++num]=maxn; } } sort(1,num); printf("%d\n",num); for (int i=1;i<=num;i++) printf("%d\n",ans[i]); return 0; } void sort(int l,int r) { int a=l,b=r; int mid=ans[(a+b)>>1]; while (a<=b) { while (ans[a]<mid) a++; while (ans[b]>mid) b--; if (a<=b) { int f=ans[a]; ans[a]=ans[b]; ans[b]=f; a++;b--; } } if (l<b) sort(l,b); if (a<r) sort(a,r); return ; }