zoukankan      html  css  js  c++  java
  • 立体视觉-opencv中立体匹配相关代码

    三种匹配算法比较

    BM算法:

    该算法代码:

    view plaincopy to clipboardprint?

    1. CvStereoBMState *BMState = cvCreateStereoBMState();  
    2. int SADWindowSize=15;   
    3. BMState->SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 9;  
    4. BMState->minDisparity = 0;  
    5. BMState->numberOfDisparities = 32;  
    6. BMState->textureThreshold = 10;  
    7. BMState->uniquenessRatio = 15;  
    8. BMState->speckleWindowSize = 100;  
    9. BMState->speckleRange = 32;  
    10. BMState->disp12MaxDiff = 1;  
    11. cvFindStereoCorrespondenceBM( left, right, left_disp_,BMState);  
    12.    cvNormalize( left_disp_, left_vdisp, 0, 256, CV_MINMAX ); 

    其中minDisparity是控制匹配搜索的第一个参数,代表了匹配搜苏从哪里开始,numberOfDisparities表示最大搜索视差数uniquenessRatio表示匹配功能函数,这三个参数比较重要,可以根据实验给予参数值。

    该方法速度最快,一副320*240的灰度图匹配时间为31ms,视差图如下。

    clip_image001

    这图是解释BM(bidirectional matching)算法的很好的例子。进行双向匹配,首先通过匹配代价在右图中计算得出匹配点。然后相同的原理及计算在左图中的匹配点。比较找到的左匹配点和源匹配点是否一致,如果你是,则匹配成功。

    image

    第二种方法是SGBM方法这是OpenCV的一种新算法:

    view plaincopy to clipboardprint?

    1. cv::StereoSGBM sgbm;  
    2.         sgbm.preFilterCap = 63;  
    3.         int SADWindowSize=11;   
    4.         int cn = 1;  
    5.         sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;  
    6.         sgbm.P1 = 4*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;  
    7.         sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;  
    8.         sgbm.minDisparity = 0;  
    9.         sgbm.numberOfDisparities = 32;  
    10.         sgbm.uniquenessRatio = 10;  
    11.         sgbm.speckleWindowSize = 100;  
    12.         sgbm.speckleRange = 32;  
    13.         sgbm.disp12MaxDiff = 1;  
    14.         sgbm(left , right , left_disp_);  
    15.         sgbm(right, left  , right_disp_); 

    各参数设置如BM方法,速度比较快,320*240的灰度图匹配时间为78ms,视差效果如下图。

    clip_image002

    第三种为GC方法:

    view plaincopy to clipboardprint?

    1. CvStereoGCState* state = cvCreateStereoGCState( 16, 2 );  
    2. left_disp_  =cvCreateMat( left->height,left->width, CV_32F );  
    3. right_disp_ =cvCreateMat( right->height,right->width,CV_32F );  
    4. cvFindStereoCorrespondenceGC( left, right, left_disp_, right_disp_, state, 0 );  
    5. cvReleaseStereoGCState( &state ); 

    该方法速度超慢,但效果超好。

    clip_image003

    各方法理论可以参考文献。

    函数解释

    参数注释

    1StereoBMState

    // 预处理滤波参数

    • preFilterType:预处理滤波器的类型,主要是用于降低亮度失真(photometric distortions)、消除噪声和增强纹理等, 有两种可选类型:CV_STEREO_BM_NORMALIZED_RESPONSE(归一化响应) 或者 CV_STEREO_BM_XSOBEL(水平方向Sobel算子,默认类型), 该参数为 int 型;
    • preFilterSize:预处理滤波器窗口大小,容许范围是[5,255],一般应该在 5x5..21x21 之间,参数必须为奇数值, int 型
    • preFilterCap:预处理滤波器的截断值,预处理的输出值仅保留[-preFilterCap, preFilterCap]范围内的值,参数范围:1 - 31(文档中是31,但代码中是 63, int

    // SAD 参数

    • SADWindowSize:SAD窗口大小,容许范围是[5,255],一般应该在 5x5 至 21x21 之间,参数必须是奇数,int 型
    • minDisparity:最小视差默认值为 0, 可以是负值,int 型
    • numberOfDisparities:视差窗口,即最大视差值与最小视差值之差, 窗口大小必须是 16 的整数倍,int 型

    // 后处理参数

    • textureThreshold:低纹理区域的判断阈值。如果当前SAD窗口内所有邻居像素点的x导数绝对值之和小于指定阈值,则该窗口对应的像素点的视差值为 0(That is, if the sum of absolute values of x-derivatives computed over SADWindowSize by SADWindowSize pixel neighborhood is smaller than the parameter, no disparity is computed at the pixel),该参数不能为负值,int 型
    • uniquenessRatio:视差唯一性百分比, 视差窗口范围内最低代价是次低代价的(1 + uniquenessRatio/100)倍时,最低代价对应的视差值才是该像素点的视差,否则该像素点的视差为 0 (the minimum margin in percents between the best (minimum) cost function value and the second best value to accept the computed disparity, that is, accept the computed disparity d^ only if SAD(d) >= SAD(d^) x (1 + uniquenessRatio/100.) for any d != d*+/-1 within the search range ),该参数不能为负值,一般5-15左右的值比较合适,int 型
    • speckleWindowSize:检查视差连通区域变化度的窗口大小, 值为 0 时取消 speckle 检查,int 型
    • speckleRange:视差变化阈值,当窗口内视差变化大于阈值时,该窗口内的视差清零,int 型

    // OpenCV2.1 新增的状态参数

    • roi1, roi2:左右视图的有效像素区域,一般由双目校正阶段的 cvStereoRectify 函数传递,也可以自行设定。一旦在状态参数中设定了 roi1 和 roi2,OpenCV 会通过cvGetValidDisparityROI 函数计算出视差图的有效区域,在有效区域外的视差值将被清零。
    • disp12MaxDiff:左视差图(直接计算得出)和右视差图(通过cvValidateDisparity计算得出)之间的最大容许差异。超过该阈值的视差值将被清零。该参数默认为 -1,即不执行左右视差检查。int 型。注意在程序调试阶段最好保持该值为 -1,以便查看不同视差窗口生成的视差效果。具体请参见《使用OpenGL动态显示双目视觉三维重构效果示例》一文中的讨论。

    在上述参数中,对视差生成效果影响较大的主要参数是 SADWindowSize、numberOfDisparities 和 uniquenessRatio 三个,一般只需对这三个参数进行调整,其余参数按默认设置即可

    在OpenCV2.1中,BM算法有C和C++ 两种实现模块。

    2StereoSGBMState

    SGBM算法的状态参数大部分与BM算法的一致,下面只解释不同的部分:

    • SADWindowSize:SAD窗口大小,容许范围是[1,11],一般应该在 3x3 至 11x11 之间,参数必须是奇数,int 型
    • P1, P2:控制视差变化平滑性的参数。P1、P2的值越大,视差越平滑。P1是相邻像素点视差增/减 1 时的惩罚系数;P2是相邻像素点视差变化值大于1时的惩罚系数。P2必须大于P1。OpenCV2.1提供的例程 stereo_match.cpp 给出了 P1 和 P2 比较合适的数值
    • fullDP:布尔值,当设置为 TRUE 时,运行双通道动态编程算法(full-scale 2-pass dynamic programming algorithm),会占用O(W*H*numDisparities)个字节,对于高分辨率图像将占用较大的内存空间。一般设置为 FALSE

    注意OpenCV2.1的SGBM算法是用C++ 语言编写的,没有C实现模块。与H. Hirschmuller提出的原算法相比,主要有如下变化:

    1. 算法默认运行单通道DP算法,只用了5个方向,而fullDP使能时则使用8个方向(可能需要占用大量内存)。
    2. 算法在计算匹配代价函数时,采用块匹配方法而非像素匹配(不过SADWindowSize=1时就等于像素匹配了)。
    3. 匹配代价的计算采用BT算法("Depth Discontinuities by Pixel-to-Pixel Stereo" by S. Birchfield and C. Tomasi),并没有实现基于互熵信息的匹配代价计算。
    4. 增加了一些BM算法中的预处理和后处理程序。

    3StereoGCState

    GC算法的状态参数只有两个:numberOfDisparities 和 maxIters ,并且只能通过 cvCreateStereoGCState 在创建算法状态结构体时一次性确定,不能在循环中更新状态信息。GC算法并不是一种实时算法,但可以得到物体轮廓清晰准确的视差图,适用于静态环境物体的深度重构。

    注意GC算法只能在C语言模式下运行,并且不能对视差图进行预先的边界延拓,左右视图和左右视差矩阵的大小必须一致。

    原理解释

    目前立体匹配算法是计算机视觉中的一个难点和热点,算法很多,但是一般的步骤是:

    A、匹配代价计算

    匹配代价计算是整个立体匹配算法的基础,实际是对不同视差下进行灰度相似性测量。常见的方法有灰度差的平方SD(squared intensity differences),灰度差的绝对值AD(absolute intensity differences)等。另外,在求原始匹配代价时可以设定一个上限值,来减弱叠加过程中的误匹配的影响。以AD法求匹配代价为例,可用下式进行计算,其中T为设定的阈值。

    这就是在参数设置中阈值的作用,在视差图中经常有黑色区域,就是和阈值的设置关。

    B、 匹配代价叠加

    一般来说,全局算法基于原始匹配代价进行后续算法计算。而区域算法则需要通过窗口叠加来增强匹配代价的可靠性,根据原始匹配代价不同,可分为:

    此图是核心算法的解释,就是计算区域内像素差值,可以为单个像素也可以为一定区域内,主要看SAD的窗口大小的设置,同时SAD设置决定误匹配的多少和运算效率问题,所以大小设置一定要很慎重。

    C、 视差获取

    对于区域算法来说,在完成匹配代价的叠加以后,视差的获取就很容易了,只需在一定范围内选取叠加匹配代价最优的点(SAD和SSD取最小值,NCC取最大值)作为对应匹配点,如胜者为王算法WTA(Winner-take-all)。而全局算法则直接对原始匹配代价进行处理,一般会先给出一个能量评价函数,然后通过不同的优化算法来求得能量的最小值,同时每个点的视差值也就计算出来了。

    D、视差细化(亚像素级)

    大多数立体匹配算法计算出来的视差都是一些离散的特定整数值,可满足一般应用的精度要求。但在一些精度要求比较高的场合,如精确的三维重构中,就需要在初始视差获取后采用一些措施对视差进行细化,如匹配代价的曲线拟合、图像滤波、图像分割等。

    亚像素级的处理就是涉及到BMState参数设置后后续参数的设置了。

    有关立体匹配的介绍和常见匹配算法的比较,推荐大家看看Stefano Mattoccia 的讲义 Stereo Vision: algorithms and applications,190页的ppt,讲解得非常形象详尽。

    1. opencv2.1opencv2.0在做stereo vision方面有什么区别了?

    2.1版增强了Stereo Vision方面的功能:

    (1) 新增了 SGBM 立体匹配算法(源自Heiko Hirschmuller的《Stereo Processing by Semi-global Matching and Mutual Information》),可以获得比 BM 算法物体轮廓更清晰的视差图(但低纹理区域容易出现横/斜纹路,在 GCstate->fullDP 选项使能时可消减这种异常纹路,但对应区域视差变为0,且运行速度会有所下降),速度比 BM 稍慢, 352*288的帧处理速度大约是 5 帧/秒;

    (2) 视差效果:BM < SGBM < GC;处理速度:BM > SGBM > GC ;

    (3) BM 算法比2.0版性能有所提升,其状态参数新增了对左右视图感兴趣区域 ROI 的支持(roi1 和 roi2,由stereoRectify函数产生);

    (4) BM 算法和 GC 算法的核心代码改动不大,主要是面向多线程运算方面的(由 OpenMP 转向 Intel TBB);

    (5) cvFindStereoCorrespondenceBM 函数的disparity参数的数据格式新增了 CV_32F 的支持,这种格式的数据给出实际视差,而 2.0 版只支持 CV_16S,需要除以 16.0 才能得到实际的视差数值。

    2. 用于立体匹配的图像可以是彩色的吗?

    在OpenCV2.1中,BM和GC算法只能对8位灰度图像计算视差,SGBM算法则可以处理24位(8bits*3)彩色图像。所以在读入图像时,应该根据采用的算法来处理图像:

    int color_mode = alg == STEREO_SGBM ? 1 : 0;
    //////////////////////////////////////////////////////////////////////////
    // 载入图像
    cvGrabFrame( lfCam );
    cvGrabFrame( riCam );
    frame1 = cvRetrieveFrame( lfCam );
    frame2 = cvRetrieveFrame( riCam );
    if(frame1.empty()) break;
    resize(frame1, img1, img_size, 0, 0);
    resize(frame2, img2, img_size, 0, 0);
    // 选择彩色或灰度格式作为双目匹配的处理图像
    if (!color_mode && cn>1)
    {
    cvtColor(img1, img1gray, CV_BGR2GRAY);
    cvtColor(img2, img2gray, CV_BGR2GRAY);
    img1p = img1gray;
    img2p = img2gray;
    }
    else
    {
    img1p = img1;
    img2p = img2;
    }

    3. 怎样获取与原图像有效像素区域相同的视差图?

    OpenCV2.0及以前的版本中,所获取的视差图总是在左侧和右侧有明显的黑色区域,这些区域没有有效的视差数据。视差图有效像素区域与视差窗口(ndisp,一般取正值且能被16整除)和最小视差值(mindisp,一般取0或负值)相关,视差窗口越大,视差图左侧的黑色区域越大,最小视差值越小,视差图右侧的黑色区域越大。其原因是为了保证参考图像(一般是左视图)的像素点能在目标图像(右视图)中按照设定的视差匹配窗口匹配对应点,OpenCV 只从参考图像的第 (ndisp - 1 + mindisp) 列开始向右计算视差,第 0 列到第 (ndisp - 1 + mindisp) 列的区域视差统一设置为 (mindisp - 1) *16;视差计算到第 width + mindisp 列时停止,余下的右侧区域视差值也统一设置为 (mindisp - 1) *16。 

     static const int DISPARITY_SHIFT = 4;
    …
     int ndisp = state->numberOfDisparities;
        int mindisp = state->minDisparity;
         int lofs = MAX(ndisp - 1 + mindisp, 0);
        int rofs = -MIN(ndisp - 1 + mindisp, 0);
         int width = left->cols, height = left->rows;
        int width1 = width - rofs - ndisp + 1;
         short FILTERED = (short)((mindisp - 1) << DISPARITY_SHIFT);
       initialize the left and right borders of the disparity map
         for( y = 0; y < height; y++ )
        {
            for( x = 0; x < lofs; x++ )
                 dptr[y*dstep + x] = FILTERED;
             for( x = lofs + width1; x < width; x++ )
                 dptr[y*dstep + x] = FILTERED;
         }
         dptr += lofs;
        for( x = 0; x < width1; x++, dptr++ )
    
    

    这样的设置很明显是不符合实际应用的需求的,它相当于把摄像头的视场范围缩窄了。因此,OpenCV2.1 做了明显的改进,不再要求左右视图和视差图的大小(size)一致,允许对视差图进行左右边界延拓,这样,虽然计算视差时还是按上面的代码思路来处理左右边界,但是视差图的边界得到延拓后,有效视差的范围就能够与对应视图完全对应。具体的实现代码范例如下:

    //////////////////////////////////////////////////////////////////////////
    // 对左右视图的左边进行边界延拓,以获取与原始视图相同大小的有效视差区域
    copyMakeBorder(img1r, img1b, 0, 0, m_nMaxDisp, 0, IPL_BORDER_REPLICATE);
    copyMakeBorder(img2r, img2b, 0, 0, m_nMaxDisp, 0, IPL_BORDER_REPLICATE);
    
    //////////////////////////////////////////////////////////////////////////
    // 计算视差
    if( alg == STEREO_BM )
    {
    	bm(img1b, img2b, dispb);
    	// 截取与原始画面对应的视差区域(舍去加宽的部分)
    	displf = dispb.colRange(m_nMaxDisp, img1b.cols);	
    }
    else if(alg == STEREO_SGBM)
    {
    	sgbm(img1b, img2b, dispb);
    	displf = dispb.colRange(m_nMaxDisp, img1b.cols);
    }
    

    4. cvFindStereoCorrespondenceBM的输出结果好像不是以像素点为单位的视差?

    @scyscyao:在OpenCV2.0中,BM函数得出的结果是以16位符号数的形式的存储的,出于精度需要,所有的视差在输出时都扩大了16倍(2^4)。其具体代码表示如下:

    dptr[y*dstep] = (short)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*128/d : 0) + 15) >> 4);

    可以看到,原始视差在左移8位(256)并且加上一个修正值之后又右移了4位,最终的结果就是左移4位。

    因此,在实际求距离时,cvReprojectTo3D出来的X/W,Y/W,Z/W都要乘以16 (也就是W除以16),才能得到正确的三维坐标信息。”

    OpenCV2.1中,BM算法可以用 CV_16S 或者 CV_32F 的方式输出视差数据,使用32位float格式可以得到真实的视差值,而CV_16S 格式得到的视差矩阵则需要 除以16 才能得到正确的视差。另外,OpenCV2.1另外两种立体匹配算法 SGBM 和 GC 只支持 CV_16S 格式的 disparity 矩阵

    5. 如何设置BMSGBMGC算法的状态参数?

     

    6. 如何实现视差图的伪彩色显示?

    首先要将16位符号整形的视差矩阵转换为8位无符号整形矩阵,然后按照一定的变换关系进行伪彩色处理。我的实现代码如下:

    // 转换为 CV_8U 格式,彩色显示
    dispLfcv = displf, dispRicv = dispri, disp8cv = disp8;
    if (alg == STEREO_GC)
    {
    	cvNormalize( &dispLfcv, &disp8cv, 0, 256, CV_MINMAX );
    } 
    else
    {
    	displf.convertTo(disp8, CV_8U, 255/(m_nMaxDisp*16.));
    }
    F_Gray2Color(&disp8cv, vdispRGB);
    

    灰度图转伪彩色图的代码,主要功能是使灰度图中 亮度越高的像素点,在伪彩色图中对应的点越趋向于 红色;亮度越低,则对应的伪彩色越趋向于 蓝色;总体上按照灰度值高低,由红渐变至蓝,中间色为绿色。其对应关系如下图所示:

    图20

    void F_Gray2Color(CvMat* gray_mat, CvMat* color_mat)
    {
    	if(color_mat)
    		cvZero(color_mat);
    		
    	int stype = CV_MAT_TYPE(gray_mat->type), dtype = CV_MAT_TYPE(color_mat->type);
    	int rows = gray_mat->rows, cols = gray_mat->cols;
    
    	// 判断输入的灰度图和输出的伪彩色图是否大小相同、格式是否符合要求
    	if (CV_ARE_SIZES_EQ(gray_mat, color_mat) && stype == CV_8UC1 && dtype == CV_8UC3)
    	{
    		CvMat* red = cvCreateMat(gray_mat->rows, gray_mat->cols, CV_8U);
    		CvMat* green = cvCreateMat(gray_mat->rows, gray_mat->cols, CV_8U);
    		CvMat* blue = cvCreateMat(gray_mat->rows, gray_mat->cols, CV_8U);
    		CvMat* mask = cvCreateMat(gray_mat->rows, gray_mat->cols, CV_8U);
    
    		// 计算各彩色通道的像素值
    		cvSubRS(gray_mat, cvScalar(255), blue);	// blue(I) = 255 - gray(I)
    		cvCopy(gray_mat, red);			// red(I) = gray(I)
    		cvCopy(gray_mat, green);			// green(I) = gray(I),if gray(I) < 128
    		cvCmpS(green, 128, mask, CV_CMP_GE );	// green(I) = 255 - gray(I), if gray(I) >= 128
    		cvSubRS(green, cvScalar(255), green, mask);
    		cvConvertScale(green, green, 2.0, 0.0);
    
    		// 合成伪彩色图
    		cvMerge(blue, green, red, NULL, color_mat);
    
    		cvReleaseMat( &red );
    		cvReleaseMat( &green );
    		cvReleaseMat( &blue );
    		cvReleaseMat( &mask );
    	}
    }
    

    7. 如何将视差数据保存为 txt 数据文件以便在 Matlab 中读取分析?

    由于OpenCV本身只支持 xml、yml 的数据文件读写功能,并且其xml文件与构建网页数据所用的xml文件格式不一致,在Matlab中无法读取。我们可以通过以下方式将视差数据保存为txt文件,再导入到Matlab中。

    void saveDisp(const char* filename, const Mat& mat)		
    {
    	FILE* fp = fopen(filename, "wt");
    	fprintf(fp, "%02d/n", mat.rows);
    	fprintf(fp, "%02d/n", mat.cols);
    	for(int y = 0; y < mat.rows; y++)
    	{
    		for(int x = 0; x < mat.cols; x++)
    		{
    			short disp = mat.at<short>(y, x); // 这里视差矩阵是CV_16S 格式的,故用 short 类型读取
    			fprintf(fp, "%d/n", disp); // 若视差矩阵是 CV_32F 格式,则用 float 类型读取
    		}
    	}
    	fclose(fp);
    }
    

    相应的Matlab代码为:

    function img = txt2img(filename)
    data = importdata(filename);
    r = data(1);    % 行数
    c = data(2);    % 列数
    disp = data(3:end); % 视差
    vmin = min(disp);
    vmax = max(disp);
    disp = reshape(disp, [c,r])'; % 将列向量形式的 disp 重构为 矩阵形式
    %  OpenCV 是行扫描存储图像,Matlab 是列扫描存储图像
    %  故对 disp 的重新排列是首先变成 c 行 r 列的矩阵,然后再转置回 r 行 c 列
    img = uint8( 255 * ( disp - vmin ) / ( vmax - vmin ) );
    mesh(disp);
    set(gca,'YDir','reverse');  % 通过 mesh 方式绘图时,需倒置 Y 轴方向
    axis tight; % 使坐标轴显示范围与数据范围相贴合,去除空白显示区
    

    显示效果如下:

     

    SGBM算法原理

    emi-global matching(缩写SGM)是一种用于计算双目视觉中disparity的半全局匹配算法。在OpenCV中的实现为semi-global block matching(SGBM)。

    SGBM的思路是:

    通过选取每个像素点的disparity,组成一个disparity map,设置一个和disparity map相关的全局能量函数,使这个能量函数最小化,以达到求解每个像素最优disparity的目的。

    能量函数形式如下:

    D指disparity map。E(D)是该disparity map对应的能量函数。

    p, q代表图像中的某个像素

    Np 指像素p的相邻像素点(一般认为8连通)

    C(p, Dp)指当前像素点disparity为Dp时,该像素点的cost

    P1 是一个惩罚系数,它适用于像素p相邻像素中dsparity值与p的dsparity值相差1的那些像素。

    P2 是一个惩罚系数,它适用于像素p相邻像素中dsparity值与p的dsparity值相差大于1的那些像素。

    I[.]函数返回1如果函数中的参数为真,否则返回0

    利用上述函数在一个二维图像中寻找最优解是一个NP-complete问题,耗时过于巨大,因此该问题被近似分解为多个一维问题,即线性问题。而且每个一维问题都可以用动态规划来解决。因为1个像素有8个相邻像素,因此一般分解为8个一维问题。

    考虑从左到右这一方向,如下图所示:

    则每个像素的disparity只和其左边的像素相关,有如下公式:

    r指某个指向当前像素p的方向,在此可以理解为像素p左边的相邻像素。
    Lr(p, d) 表示沿着当前方向(即从左向右),当目前像素p的disparity取值为d时,其最小cost值。

    这个最小值是从4种可能的候选值中选取的最小值:

    1.前一个像素(左相邻像素)disparity取值为d时,其最小的cost值。

    2.前一个像素(左相邻像素)disparity取值为d-1时,其最小的cost值+惩罚系数P1。

    3.前一个像素(左相邻像素)disparity取值为d+1时,其最小的cost值+惩罚系数P1。

    4.前一个像素(左相邻像素)disparity取值为其他时,其最小的cost值+惩罚系数P2。

    另外,当前像素p的cost值还需要减去前一个像素取不同disparity值时最小的cost。这是因为Lr(p, d)是会随着当前像素的右移不停增长的,为了防止数值溢出,所以要让它维持在一个较小的数值。

    C(p, d)的计算很简单,由如下两个公式计算:

    即,当前像素p和移动d之后的像素q之间,经过半个像素插值后,寻找两个像素点灰度或者RGB差值的最小值,作为C(p, d)的值。

    具体来说:设像素p的灰度/RGB值为I(p),先从I(p),(I(p)+I(p-1))/2,(I(p)+I(p+1))/2三个值中选择出和I(q)差值最小的,即

    d(p,p-d)。然后再从I(q),(I(q)+I(q-1))/2,(I(q)+I(q+1))/2三个值中选择出和I(p)差值最小的,即d(p-d,p)。最后从两个值中选取最小值,就是C(p, d)

    上面是从一个方向(从左至右)计算出的像素在取值为某一disparity值时的最小cost值。但是一个像素有8个邻域,所以一共要从8个方向计算(左右,右左,上下,下上,左上右下,右下左上,右上左下,左下右上)这个cost值。

    然后把八个方向上的cost值累加,选取累加cost值最小的disparity值作为该像素的最终disparity值。对于每个像素进行该操作后,就形成了整个图像的disparity map。公式表达如下:

    SGBM算法遍历每个像素,针对每个像素的操作和disparity的范围有关,故时间复杂度为:

    经典算法例子解释

    opencv中关于模板匹配的例子说明

  • 相关阅读:
    leetcode Super Ugly Number
    leetcode Find Median from Data Stream
    leetcode Remove Invalid Parentheses
    leetcode Range Sum Query
    leetcode Range Sum Query
    leetcode Minimum Height Trees
    hdu 3836 Equivalent Sets
    hdu 1269 迷宫城堡
    hud 2586 How far away ?
    poj 1330 Nearest Common Ancestors
  • 原文地址:https://www.cnblogs.com/polly333/p/5130375.html
Copyright © 2011-2022 走看看