在立体视觉中,常常用到Census变换,Census变换是一种非参数局部变换,其将周围像素的强度映射到一个比特穿,从而捕获图像的结构。同时使用Census变换可以减少由相机增益和偏置引起变化的影响。在立体匹配过程中,将图像做Census变换后,计算像素点之间的明式距离进行匹配,可以得到较好的效果。
这篇博客主要介绍介绍实现Census变换,由于使用OpenCV的容器和接口,所以直接使用OpenCV调用比较方便。
一、Census变换原理
先给个链接,这个可以看这个链接中的内容。。
二、Census变换OpenCV实现
先贴上代码
// _Tp为数据类型,根据自己比特串的长度选取 template<typename _Tp> void ImageCensus(Mat& gray, Mat& census, int cw, int ch){ for (int y = ch; y < rows - 1 - ch; y++){ const uchar *pcur = gray.ptr<uchar>(y); for (int x = cw; x < cols - 1 - cw; x++){ const uchar cur = pcur[x]; _Tp mask = 1; _Tp val = 0; for (int i = -ch; i <= ch; ++i){ const uchar *psur = gray.ptr<uchar>(y + i); for (int j = -cw; j <= cw; ++j){ if (i == 0 && j == 0){ continue; } const uchar sur = psur[x + j]; if (cur < sur){ val |= mask; } mask <<= 1; } } census.ptr<_Tp>(y)[x] = val; } } }
解释一下函数的参数
Mat& gray:CV_8UC1的灰度图像,如果你的图像不是灰度图像,那么只需要在gray.ptr<uchar>,改掉uchar就可以了,由于大家大多使用灰度图像做输入,这部分就没有用泛型写。
Mat& census:输出的Census图像,类型需要和泛型参数<_Tp>对应,表示了census图像每个点的长度。 如果你使用的是3*3窗格,那么使用uchar类型就可以了,除去中心像素只有8个位,如果是5*5窗格,就是24位,必须用int32,如果使用更大的窗口,那么久需要长的结构__int64或者__m128 __m256等,要是更长就要自己定义联合体或者新类型了。
cw:窗口的宽度,ch:窗口的高度
下面,选取1*1窗口,用uchar8位来看看效果
Census变换之后的结构,是不是和LBP有相似之处呢?
OK,See You Next Chapter!