圖像細化(Image Thinning),一般指二值圖像的骨架化(Image Skeletonization) 的一種操作運算。
所謂的細化就是經過一層層的剝離,從原來的圖中去掉一些點,但仍要保持原來的形狀,直到得到圖像的骨架。骨架,可以了解為圖象的中軸。
好的細化算法一定要滿足:
- 收斂性;
- 保證細化後細線的連通性
- 保持原圖的基本形狀
- 減少筆畫相交處的畸變
- 細化結果是原圖像的中心線
- 細化的快速性和疊代次數少
依據是否使用疊代運算可以分為兩類:
- 非疊代算法
- 一次即産生骨架,如基于距離變換的方法。遊程長度編碼細化等。
- 疊代算法
即重複删除圖像邊緣滿足一定條件的像素,最終得到單像素寬帶骨架。
疊代方法依據其檢查像素的方法又可以再分成
- 串行算法
是否删除像素在每次疊代的執行中是固定順序的,它不僅取決于前次疊代的結果,也取決于本次疊代中已處理過像素點分布情況.
- 并行算法
像素點删除與否與像素值圖像中的順序無關,僅取決于前次疊代的結果
細化算法:
- Burning Algorithm
使用疊代的方法去除圖像的邊界, 可使用掃描線法來擷取邊界
- Zhang并行快速細化算法
模闆:
p3 p2 p9 p4 p1 p8 p5 p6 p7 |
第一步,(其中p1為前景點,如果以下四個條件同時滿足,則删除p1,即令p1=0)
1. 2<=N(p1)<=6 // 中心為黑點 2. Z0(p1)=1 // Nz為八鄰域中黑點的數目 3. p2*p8*p6=0 // 避免圖像被打斷( 其反條件時不可删) 4. p4*p8*p6=0 其中,Z0(p1)是以p2,p3,...p8,p9為序時,這些點的值從0->1變化的次數 N(p1)是p1的非0鄰近點的個數 |
被判定為删除的點暫不删除,但要加以記錄。
等所有邊界點都被判斷完後,再一起将所有标記了的點删除,接下來進入第二階段的删除步驟。
第二步,按照如下條件進行第二階段的删除,條件為
1. 2<=N(p1)<=6 // 中心為黑點 2. Z0(p1)=1 // Nz為八鄰域中黑點的數目 3. p2*p4*p6=0 // 避免圖像被打斷( 其反條件時不可删) 4. p2*p4*p8=0 |
同第一步一樣,判定要删除的點隻是加以記錄而暫不删除,等待最後同時删除
對一副圖像反複執行第一步與第二步的算法步驟,知道都沒有可删除的點為止
我的zhang細化代碼如下:
// p3 p2 p1
//**********使用zhang并行快速算法進行細化 p4 p p0
// p5 p6 p7
void ZhangThinning(int w,int h,BYTE *imgBuf)
{
int neighbor[8];
BYTE *mark=new BYTE[w*h];
memset(mark,0,w*h);
BOOL loop=TRUE;
int x,y,k;
int markNum=0;
while(loop)
{
loop=FALSE;
//第一步
markNum=0;
for(y=1;y<h-1;y++)
{
for(x=1;x<w-1;x++)
{
//條件1:p必須是前景點
if(imgBuf[y*w+x]==0 ) continue;
neighbor[0]= imgBuf[y*w+x+1] ;
neighbor[1]= imgBuf[(y-1)*w+x+1];
neighbor[2]= imgBuf[(y-1)*w+x];
neighbor[3]= imgBuf[(y-1)*w+x-1];
neighbor[4]= imgBuf[y*w+x-1];
neighbor[5]= imgBuf[(y+1)*w+x-1];
neighbor[6]= imgBuf[(y+1)*w+x];
neighbor[7]= imgBuf[(y+1)*w+x+1];
//條件2:2<=N(p)<=6
int np=(neighbor[0]+neighbor[1]+neighbor[2]+neighbor[3]+neighbor[4]+neighbor[5]+neighbor[6]+neighbor[7])/255;
if(np<2 || np>6) continue;
//條件3:S(p)=1
int sp=0;
for(int i=1;i<8;i++)
{
if(neighbor[i]-neighbor[i-1]==255)
sp++;
}
if(neighbor[0]-neighbor[7]==255)
sp++;
if(sp!=1) continue;
//條件4:p2*p0*p6=0
if(neighbor[2]&neighbor[0]&neighbor[6]!=0)
continue;
//條件5:p0*p6*p4=0
if(neighbor[0]&neighbor[6]&neighbor[4]!=0)
continue;
//标記删除
mark[w*y+x]=1;
markNum++;
loop=TRUE;
}
}
//将标記删除的點置為背景色
if(markNum>0)
{
for(y=0;y<h;y++)
{
for(x=0;x<w;x++)
{
k=y*w+x;
if(mark[k]==1)
{
imgBuf[k]=0;
}
}
}
}
//第二步
markNum=0;
for(y=1;y<h-1;y++)
{
for(x=1;x<w-1;x++)
{
//條件1:p必須是前景點
if(imgBuf[y*w+x]==0 ) continue;
neighbor[0]= imgBuf[y*w+x+1] ;
neighbor[1]= imgBuf[(y-1)*w+x+1];
neighbor[2]= imgBuf[(y-1)*w+x];
neighbor[3]= imgBuf[(y-1)*w+x-1];
neighbor[4]= imgBuf[y*w+x-1];
neighbor[5]= imgBuf[(y+1)*w+x-1];
neighbor[6]= imgBuf[(y+1)*w+x];
neighbor[7]= imgBuf[(y+1)*w+x+1];
//條件2:<=N(p)<=6
int np=(neighbor[0]+neighbor[1]+neighbor[2]+neighbor[3]+neighbor[4]+neighbor[5]+neighbor[6]+neighbor[7])/255;
if(np<2 || np>6) continue;
//條件3:S(p)=1
int sp=0;
for(int i=1;i<8;i++)
{
if(neighbor[i]-neighbor[i-1]==255)
sp++;
}
if(neighbor[0]-neighbor[7]==255)
sp++;
if(sp!=1) continue;
//條件4:p2*p0*p4==0
if(neighbor[2]&neighbor[0]&neighbor[4]!=0)
continue;
//條件5:p2*p6*p4==0
if(neighbor[2]&neighbor[6]&neighbor[4]!=0)
continue;
//标記删除
mark[w*y+x]=1;
markNum++;
loop=TRUE;
}
}
//将标記删除的點置為背景色
for(y=0;y<h;y++)
{
for(x=0;x<w;x++)
{
k=y*w+x;
if(mark[k]==1)
{
imgBuf[k]=0;
}
}
}
}
}
判斷一個點是否能去掉, 要根據它的八個相鄰點的情況來判斷。(中間的點)

(1)不能删,因為它是個内部點,我們要求的是骨架,如果連内部點也删了,骨架也會被掏空的;
(2)不能删,和(1)是同樣的道理;
(3)可以删,這樣的點不是骨架;
(4)不能删,因為删掉後,原來相連的部分斷開了;
(5)可以删,這樣的點不是骨架;
(6)不能删,因為它是直線的端點,如果這樣的點删了,那麼最後整個直線也被删了,剩不下什麼;
總結:
(1)内部點不能删除;
(2)孤立點不能删除;
(3)直線端點不能删除;
(4)如果P是邊界點,去掉P後,如果連通分量不增加,則P可以删除。
- Hilditch、Pavlidis、Rosenfeld細化算法
這類算法則是在程式中直接運算,根據運算結果來判定是否可以删除點的算法,差别在于不同算法的判定條件不同。
Hilditch算法使用于二值圖像,比較普通,是一般的算法;
Pavlidis算法通過并行和串行混合處理來實作,用位運算進行特定模式的比對,所得的骨架是8連接配接的,使用于0-1二值圖像;
Rosenfeld算法是一種并行細化算法,所得的骨架形态是8-連接配接的,使用于0-1二值圖像。
(後兩種算法的效果要更好一些,但是處理某些圖像時效果一般,第一種算法使用性強些。)
- 索引表細化算法
經過預處理後得到待細化的圖像是0、1二值圖像。像素值為1的是需要細化的部分,像素值為0的是背景區域。基于索引表的算法就是依據一定的判斷依據,所做出的一張表,然後根據魔鬼要細化的點的八個鄰域的情況查詢,若表中元素是1,若表中元素是1,則删除該點(改為背景),若是0則保留。因為一個像素的8個鄰域共有256中可能情況,是以,索引表的大小一般為256。
查找表為二值圖像處理提供了簡潔而有效的方法。考慮一個像素的3乘3鄰域。由于在這個鄰域範圍有9個像素,每個像素有兩個狀态(二值圖像,取0,1),那麼整個鄰域不同狀态的總數量為2^9=512 .這樣,我們可以相對不同的情況(512種),來安排對應的輸出值,而這512種可能是事先預知的,給每一個單元(一共9個單元)分别安排不同的權值,
1 8 64
2 16 128
4 32 256
也就是2的不同幂次,0,1,2,3。。。 8次幂
那麼,某種狀态數值就是權重值的和。
比如,
下面一種鄰域組合:
0 1 0
1 1 0
0 0 1
它的值=2+8+16+256=282
這樣的話,我們通過一個數值,就可以表達一種3乘3鄰域的一種空間分布狀态。