Cross-Scale Cost Aggregation for Stereo Matching立体匹配算法介绍

本文深入解析CVPR2014上的一种基于多尺度代价聚合的立体匹配算法,介绍了匹配代价计算(包括CEN、CG、GRD方法)及代价聚合过程(如双边滤波、引导滤波、分割树方法)。通过多尺度思想,结合经典方法,实现高效且精确的视差计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近,研究了下CVPR2014上的一篇基于多尺度代价聚合的立体匹配算法,这个作者提供了原代码,运行了下,发现效果真心不错,不开后端处理的话,时间在0.4s左右。这个算法比较牛逼的有两点:
1:结合多尺度思想,对原始图像进行下采样,然后在每层图像上计算匹配代价,进行代价聚合,然后多尺度得到的视差进行结合,作为最终的代价聚合值。
2:提供了一个框架,里面包含立体匹配很多常用的经典的方法,可以在每一步使用不同的方式完成。
参考一篇博客:http://blog.youkuaiyun.com/wsj998689aa/article/details/44411215

本文结合源码,对这个算法的流程进行详细分析。

首先进行匹配代价计算:
源码里有三种方法,CEN(就是census),CG(Census + TAD + 梯度),GRD(梯度+TAD) ,这三种方式几乎是当下进行第一步匹配代价计算的常用方式。
1:CEN:选定一个窗口,对窗口中每一个像素与中心像素进行比较,大于中心像素即为0,否则为1。从而得到一个二进制系列,分别对左图和右图进行计算每个像素的匹配代价。并得到初步的代价聚合,计算每个像素在视差范围内每个可能视差的代价聚合值。左右匹配,即两个二进制系列相似值,每个对应位是否相等。

void CenCC::buildCV( const Mat& lImg, const Mat& rImg, const int maxDis, Mat* costVol )
{
    // for TAD + Grd input image must be CV_64FC3//输入的图像必须是64FC3
    CV_Assert( lImg.type() == CV_64FC3 && rImg.type() == CV_64FC3 );

    int hei = lImg.rows;//图像宽高
    int wid = lImg.cols;
    Mat lGray, rGray;
    Mat tmp;
    lImg.convertTo( tmp, CV_32F );//64FC3图像数据转化成32F
    cvtColor( tmp, lGray, CV_RGB2GRAY );//灰度化
    lGray.convertTo( lGray, CV_8U, 255 );//灰度图像转换成8U数据格式,并把开始除的255乘回来
    rImg.convertTo( tmp, CV_32F );
    cvtColor( tmp, rGray, CV_RGB2GRAY );
    rGray.convertTo( rGray, CV_8U, 255 );
    // prepare binary code 
    int H_WD = CENCUS_WND / 2;
    bitset<CENCUS_BIT>* lCode = new bitset<CENCUS_BIT>[ wid * hei ];
    bitset<CENCUS_BIT>* rCode = new bitset<CENCUS_BIT>[ wid * hei ];
    bitset<CENCUS_BIT>* pLCode = lCode;
    bitset<CENCUS_BIT>* pRCode = rCode;
    for( int y = 0; y < hei; y ++ ) { //求得中心像素的CENSUS码
        uchar* pLData = ( uchar* ) ( lGray.ptr<uchar>( y ) );
        uchar* pRData = ( uchar* ) ( rGray.ptr<uchar>( y ) );
        for( int x = 0; x < wid; x ++ ) {
            int bitCnt = 0;
            for( int wy = - H_WD; wy <= H_WD; wy ++ ) {
                int qy = ( y + wy + hei ) % hei;
                uchar* qLData = ( uchar* ) ( lGray.ptr<uchar>( qy ) );
                uchar* qRData = ( uchar* ) ( rGray.ptr<uchar>( qy ) );
                for( int wx = - H_WD; wx <= H_WD; wx ++ ) {
                    if( wy != 0 || wx != 0 ) {
                        int qx = ( x + wx + wid ) % wid;
                        ( *pLCode )[ bitCnt ] = ( pLData[ x ] > qLData[ qx ] );//这里是对窗口内的每个像素与中心像素比较,小于则为1,大于则为0
                        ( *pRCode )[ bitCnt ] = ( pRData[ x ] > qRData[ qx ] );
                        bitCnt ++;
                    }

                }
            }
            pLCode ++;
            pRCode ++;
        }
    }
    // build cost volume 初始代价聚合
    bitset<CENCUS_BIT> lB;
    bitset<CENCUS_BIT> rB;
    pLCode = lCode;
    for( int y = 0; y < hei; y ++ ) {
        int index = y * wid;
        for( int x = 0; x < wid; x ++ ) {
            lB = *pLCode;
            for( int d = 0; d < maxDis; d ++ ) {
                double* cost   = ( double* ) costVol[ d ].ptr<double>( y );//costVol是视差为d时的匹配代价Mat集合
                cost[ x ] = CENCUS_BIT;
                if( x - d >= 0 ) {
                    rB = rCode[ index + x - d ];
                    cost[ x ] = ( lB ^ rB ).count();//这里是求左右图的census值的相似性,作为视差为d时,当前像素的匹配代价。
                }

            }
            pLCode ++;
        }
    }
    delete [] lCode;
    delete [] rCode;
}

下面是从右向左进行匹配的,就是在寻找视差方向上时不同而已

// build cost volume
    bitset<CENCUS_BIT> lB;
    bitset<CENCUS_BIT> rB;
    pRCode = rCode;
    for( int y = 0; y < hei; y ++ ) {
        int index = y * wid;
        for( int x = 0; x < wid; x ++ ) {
            rB = *pRCode;
            for( 
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值