區域填充之掃瞄線演算法

2021-06-05 17:51:48 字數 4524 閱讀 6603

區域的填充可以根據區域的填充,採用不同的填充演算法,而其中有掃瞄線類演算法和種子填充演算法。這裡,先介紹掃瞄線類演算法之有序邊表的掃瞄線演算法。其他什麼種子填充、邊界標誌演算法、4連通區域的遞迴演算法、8連通區域的遞迴演算法、掃瞄線種子填充演算法比較簡單。

其實有序邊表其實領會了也好理解,關鍵是將思想轉化為**。

先介紹演算法思想:

1.根據給出的多邊形頂點座標,建立et表(同時計算ymax和ymin)

2.初始化aet表,使之為空

3.使用掃瞄線yi值作為迴圈變數,使之初始值為ymin

重複做以下操作:

(1)如果et表中yi桶非空,則合併到aet中

(2)對aet表中記錄按x值從小到大排序

(3)依次取出表中記錄,兩兩配對填充

(4)如果aet表中某記錄的ymax=yi,則刪除該記錄

(5)對仍在aet中的記錄,修改x值,x=x+1/m (m為斜率)

現在,關鍵要細節的處理與**實現。

1.頂點座標,由於無法確定頂點數,所以我們用乙個陣列儲存。建立乙個填充函式

void regionfill(hdc hdc,point1 *p,int len,int ymin,int ymax)  

我們需要建立edgetable類,通過分析,這個結構很像我們資料結構的圖(鄰接表表示)

**如下:

/*

*author qyl

*date 2012/4/7

*purpose 邊表結構

*version 1.1

*/#include"llist.h"

#include"point1.h"

class edge

edge(float x0,float incr,float y0)

friend bool operator

class edgetable

~edgetable()

llist* getvalue(int pos)

return l;

} void setedge(int pos,edge e)

numberedge++;

vertex[pos]->insert(e);

} void deledge(int pos,edge e)

}} void deleteall(int pos)

void createtableedge(point1 * p,int len,int ymin,int ymax)

else

break;

case 2:

if((*(flag+len-1))!=1 && (*(flag+len-1))!=3)

else

if((*(flag+j+1))!=1 && (*(flag+j+1)!=1)!=3)

else

break;

case 3:

if((*(flag+j+1))!=1 && (*(flag+j+1))!=3)

else

break;

default: break;}}

else

else

break;

case 2:

if((*(flag+(j+1)%len))!=1 && (*(flag+(j+1)%len))!=3)

else

if((*(flag+j-1))!=1 && (*(flag+j-1))!=3)

else

break;

case 3:

if((*(flag+(j+1)%len))!=1 && (*(flag+(j+1)%len))!=3)

else

break;

default: break;}}

}}} */

/*for(int i=ymin;i<=ymax;i++)

//非極值點 ymax-1

else if(p[1].gety()>p[0].gety() && p[len-1].gety()insert(*e);

}//非極值點 ymax-1

else if(p[1].gety()p[0].gety())

}else

//非極值點 ymax-1

else if(p[(j+1)%len].gety()>p[j].gety() && p[(j-1)%len].gety()insert(*e);

}//非極值點 ymax-1

else if(p[(j+1)%len].gety()p[j].gety())}}

} */

/*for(int j=0;jp[0].gety() && p[len-1].gety()>p[0].gety())

//非極值點 ymax-1

else if(p[1].gety()>p[0].gety() && p[len-1].gety()insert(*e);

}//非極值點 ymax-1

else if(p[1].gety()p[0].gety())

}else

//非極值點 ymax-1

else if(p[(j+1)%len].gety()>p[j].gety() && p[(j-1)%len].gety()insert(*e);

}//非極值點 ymax-1

else if(p[(j+1)%len].gety()p[j].gety())

}} */

for(int i=ymin;i<=ymax;i++)

else

if(p[len-2].gety()>p[len-1].gety())

else

}//非極值點 ymax-1

else if(p[1].gety()>p[0].gety() && p[len-1].gety()p[1].gety())

else

}//非極值點 ymax-1

else if(p[1].gety()p[0].gety())

else}}

else

else

if(j==1)

else

}else

else}}

//非極值點 ymax-1

else if(p[(j+1)%len].gety()>p[j].gety() && p[(j-1)%len].gety()p[(j+1)%len].gety())

else

}//非極值點 ymax-1

else if(p[(j+1)%len].gety()p[j].gety())

else

}else

else}}

}}} }};

**有些凌亂, 但有些錯誤的我並沒有刪去,只是展示如何一步一步改進的,以及發現的錯誤,改了之後好像有些注釋也為修改.

這個表結構成了話,其實其他的就簡單了

這個函式就是掃瞄線演算法啦。

void regionfill(hdc hdc,point1 *p,int len,int ymin,int ymax)

l->removeall();

} //在aet表中按從小到大排序

edge curr;

edge temp;

edge min;

ptr=l=aet.getvalue(i);

/*aet.deleteall(i);

int count=0;

for(l->setstart();l->getvalue(curr);l->next())

count++;

aet.setedge(i,min);

} */

//依次取出aet表中掃瞄線y桶中記錄,兩兩配對填充

for(l->setstart();l->getvalue(curr);l->next())

//在aet表中的每個記錄 對x進行修改

ptr->removeall();

ptr=aet.getvalue(i);

for(ptr->setstart();ptr->getvalue(curr);ptr->next())

//填充完後 刪除aet當前掃瞄線及l,ptr

aet.deleteall(i);

l->removeall();

ptr->removeall();

}}

最後,談談細節問題。就是掃瞄線與頂點相交,必須正確的進行交點個數的計算,否則會出錯。這個我已經包含到edgetable類中了,上面給出了兩種思路,但其中一種由於時間問題為全部完成,已被注釋掉了,有興趣可以修改哈,**共享哈。由於頂點前後連線構成環,而我用的陣列,所以對一些特殊情況要注意,當然也可以用迴圈鍊錶。

對於求最大最小值,也可以建乙個函式求解,這裡為了簡便,採用手動輸入。還有指標一定要小心。可能上面我說要排序,但我沒有排序,那是我插入記錄就是按排序插入的。

因為乙個大括號而多了100多的錯誤,因為乙個變數折騰到凌晨一點……

最後的最後,我只想說,調bug是件考驗毅力耐力的活!!!

掃瞄線演算法

給出幾個矩形對角端點座標,求這些矩形整體覆蓋的面積。基本思想如下圖 先離散化。掃瞄線 是一根想象中的虛線,從左往右掃瞄,遇到 矩形 則成為 事件 遇到 起始邊 則update相應區間的 厚度 或者 覆蓋次數 covercnt 1。遇到 結束邊 則update相應區間的 厚度 covercnt 1。用...

寒江雪 區域填充演算法 掃瞄線

區域填充遞迴演算法已經領教過了。記憶體消耗大,時間效率低,經典的深搜思想。為了解決這個問題,於是有人提出了種子填充掃瞄線演算法。其實就是深搜不行,換寬搜 bfs 該演算法假設已知其中乙個畫素點,然後從這個畫素點出發,去尋找周圍可以著色的點。這個已知點,我們稱其為種子點。每一輪著色之後,記錄下著色的區...

X 掃瞄線演算法

多邊形有兩種重要的表示方法 頂點表示和點陣表示 頂點表示是用多邊形的頂點序列來表示多邊形。這種表示直觀 幾何意義強 佔記憶體少,易於進行幾何變換。但由於它沒有明確指出哪些象素在多邊形內,故不能直接用於面著色 點陣表示是用位於多邊形內的象素集合來刻畫多邊形。這種表示丟失了許多幾何資訊 如邊界 頂點等 ...