本文分三部分:
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 |
上面的表中还有一项i_Offset表示的是Block处理结果的有效内容的起始位置,在写入图像时,要从Block的此位置开始读取内容并写入原始图像从i_Write开始的内存中。
3. 立体匹配中的图像重叠分块的方法介绍
立体匹配中使用分块处理的方法和一般的图像处理的分块方法不同,因为Block之间的对应需要一个初始的视差来驱动,否则可能导致图像块之间没有很好的重叠(如图3所示)。
图 3. 无初始视差驱动的航空影像分块处理
所以,如果有初始视差图来驱动,就可以很好地实现影像分块,而且这时不仅可以解除内存限制或者实现并行处理,还可以减小每个图像块的视差搜索范围,因此最终还有可能减少误匹配率。
基于此方法,立体匹配的分块处理方法框架如下:
[cpp] view plain copy
- 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;
-
- }
- 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);
- }
- }
- }