本文分三部分:
1. 圖像直接分塊的問題;
2. 圖像重疊分塊的實現原理介紹;
3. 立體匹配中的圖像重疊分塊的方法介紹;
1. 圖像直接分塊的問題
由於內存的限制或爲了實現並行處理,對圖像進行分塊處理是必要的。如果僅僅對圖像進行分塊處理,然後把處理的圖像塊進行簡單的拼接,容易導致界邊處縫的問題(如下圖所示)。所以,需要在圖像分塊時使得相鄰圖像塊有一定的重疊,然後選擇最優的處理結果填充重疊區域,從而消除接邊縫。
圖 1. 左圖爲直接分塊處理結果,右圖爲重疊分塊處理結果
2. 圖像重疊分塊的實現原理介紹
圖 2. 圖像分塊原理示意圖
如上圖所示,圖像重疊分塊時,有三個Block,三個Position和一個Principle:
三個Block是:起始Block,中間Block和邊緣Block;
三個Position是:Block在原始圖像的讀取和寫入位置,處理結果有效內容在Block自身的位置;
一個 Principle是:各個Block處理結果的有效部分應該保持保持無縫連接;
基於以上思路,我們列出圖像分塊時的幾個關鍵參數:
圖像縱向塊數:m_Tile = (height-BLOCKOVERLAP_Y-1)/(BLOCKHEIGHT-2*BLOCKOVERLAP_Y)+1
圖像橫向塊數:nTile = (width-BLOCKOVERLAP_X-1)/(BLOCKWIDTH-2*BLOCKOVERLAP_X)+1
其中,width和height爲原始圖像的寬高,BLOCKWIDTH和BLOCKHEIGHT爲圖像塊的寬高,BLOCKOVERLAP_X和BLOCKOVERLAP_Y爲圖像塊橫向和縱向的重疊尺寸。因爲橫向和縱向的公式是完全類似的,爲了簡便起見,下面我們用size,BLOCK,OVERLAP來相應代替上面的三個量。
i_Read | i_Write | i_Offset | |
---|---|---|---|
1st | 0 | 0 | 0 |
Middle | i*(BLOCK-2*OVERLAP) | i_Read+OVERLAP | OVERLAP |
Last | size-BLOCK | (i+1)*BLOCK-(2*i-1)*OVERLAP-size | (i+1)*BLOCK-(2*i-1)*OVERLAP-size |
3. 立體匹配中的圖像重疊分塊的方法介紹
立體匹配中使用分塊處理的方法和一般的圖像處理的分塊方法不同,因爲Block之間的對應需要一個初始的視差來驅動,否則可能導致圖像塊之間沒有很好的重疊(如圖3所示)。
圖 3. 無初始視差驅動的航空影像分塊處理
所以,如果有初始視差圖來驅動,就可以很好地實現影像分塊,而且這時不僅可以解除內存限制或者實現並行處理,還可以減小每個圖像塊的視差搜索範圍,因此最終還有可能減少誤匹配率。
基於此方法,立體匹配的分塊處理方法框架如下:
int mTile = (height-BLOCKOVERLAP_Y-1)/(BLOCKHEIGHT-2*BLOCKOVERLAP_Y)+1;
int nTile = (width-BLOCKOVERLAP_X-1)/(BLOCKWIDTH-2*BLOCKOVERLAP_X)+1;
for (int m=0;m<mTile;m++)
{
int m_index= m*(BLOCKHEIGHT-2*BLOCKOVERLAP_Y);
int m_offset = BLOCKOVERLAP_Y;
int m_write = m_index+BLOCKOVERLAP_Y;
if (m==0)
{
m_offset = 0;
m_write = 0;
}
else if (m == mTile-1)
{
m_index = height-BLOCKHEIGHT;
m_offset = (m+1)*BLOCKHEIGHT-(2*m-1)*BLOCKOVERLAP_Y-height;
m_write = m*BLOCKHEIGHT-(2*m-1)*BLOCKOVERLAP_Y;
}
for (int n=0;n<nTile;n++)
{
int n_index = n*(BLOCKWIDTH-2*BLOCKOVERLAP_X);
int n_offset=BLOCKOVERLAP_X;
int n_write = n_index+BLOCKOVERLAP_X;
if (n==0)
{
n_offset = 0;
n_write = 0;
}
else if (n == nTile-1)
{
n_index = width-BLOCKWIDTH;
n_offset = (n+1)*BLOCKWIDTH-(2*n-1)*BLOCKOVERLAP_X-width;
n_write = n*BLOCKWIDTH-(2*n-1)*BLOCKOVERLAP_X;
}
CopyImgData(n_index,m_index,width,height,0,0,BLOCKWIDTH,BLOCKHEIGHT);
//計算整體視差平移量
int AvgBlockDisp = 0;
int num_disp = BLOCKWIDTH*BLOCKHEIGHT;
for (int i=0;i<num_disp;i++)
{
AvgBlockDisp += dm->disparity[i];
}
AvgBlockDisp /= num_disp;
int n_index_refer = n_index+AvgBlockDisp;
CopyImgData(bufl_block,bufl,n_index_refer,m_index,width,height,0,0,BLOCKWIDTH,BLOCKHEIGHT);
CopyImgData(bufr_block,bufr,n_index,m_index,width,height,0,0,BLOCKWIDTH,BLOCKHEIGHT);
Match();
//還原到原始視差範圍
for (int i=0;i<BLOCKHEIGHT;i++)
{
for (int j=0;j<BLOCKWIDTH;j++)
{
dm->disparity[i*BLOCKWIDTH+j] += AvgBlockDisp;
}
}
//寫入到內存
CopyImgData(n_offset,m_offset,BLOCKWIDTH,BLOCKHEIGHT,n_write,m_write,width,height);
CopyImgData(n_offset,m_offset,BLOCKWIDTH,BLOCKHEIGHT,n_write,m_write,width,height);
}
}