1. 程式人生 > >【視覺-立體視覺】全域性匹配演算法SGBM實現(含動態規劃DP)詳解

【視覺-立體視覺】全域性匹配演算法SGBM實現(含動態規劃DP)詳解

最近一直在學習SGBM演算法,作為一種全域性匹配演算法,立體匹配的效果明顯好於區域性匹配演算法,但是同時複雜度上也要遠遠大於區域性匹配演算法。演算法主要是參考Stereo Processing by Semiglobal Matching and Mutual Information,裡面有講完整的演算法實現。
OpenCV中實際上是提供了SGBM類進行SGBM演算法的實現。
#include <highgui.h>
#include <cv.h>
#include <cxcore.h>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
        
    IplImage * img1 = cvLoadImage(&quot;left.png&quot;,0);
    IplImage * img2 = cvLoadImage(&quot;right.png&quot;,0);
    cv::StereoSGBM sgbm;
        int SADWindowSize = 9;
        sgbm.preFilterCap = 63;
        sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;
        int cn = img1->nChannels;
        int numberOfDisparities=64;
        sgbm.P1 = 8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
        sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
        sgbm.minDisparity = 0;
        sgbm.numberOfDisparities = numberOfDisparities;
        sgbm.uniquenessRatio = 10;
        sgbm.speckleWindowSize = 100;
        sgbm.speckleRange = 32;
        sgbm.disp12MaxDiff = 1;
        Mat disp, disp8;
        int64 t = getTickCount();
        sgbm((Mat)img1, (Mat)img2, disp);
        t = getTickCount() - t;
        cout<<&quot;Time elapsed:&quot;<<t*1000/getTickFrequency()<<endl;
        disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
        
        namedWindow(&quot;left&quot;, 1);
        cvShowImage(&quot;left&quot;, img1);
        namedWindow(&quot;right&quot;, 1);
        cvShowImage(&quot;right&quot;, img2);
        namedWindow(&quot;disparity&quot;, 1);
        imshow(&quot;disparity&quot;, disp8);
        waitKey();
        imwrite(&quot;sgbm_disparity.png&quot;, disp8);   
    cvDestroyAllWindows();
        return 0;
}
貼出效果:


//深度圖

但是僅僅用OpenCV自帶的SGBM類來實現並不能滿足,我還是希望能夠自己實現該演算法,然後最關鍵是移植到FPGA上去。

於是我嘗試自已去寫SGBM的程式碼,論文中提高Dynamic programming演算法,實際上SGBM中也用到了多方向的Dynamic programming,但是我目前只是實現了單方向的DP。

//引入概率公式

//引入CBT的插值方法
//加上相鄰匹配點位置之間的限制
#include <cstdio>
#include <cstring>
#include <iostream>
#include<cv.h>
#include<highgui.h>
#include <cmath>

using namespace std;
const int Width =  1024;
const int Height = 1024;
int Ddynamic[Width][Width];

//使用鐘形曲線作為匹配概率,差值越小則匹配的概率越大,最終的要求是使匹配的概率最大,概率曲線使用matlab生成

//均方差30
//int Probability[256] = {
//   255, 255, 254, 252, 250, 247, 244, 240, 235, 230, 225, 219, 213, 206, 200, 192, 185, 178, 170, 162, 
//   155, 147, 139, 132, 124, 117, 110, 103, 96, 89, 83, 77, 71, 65, 60, 55, 50, 46, 42, 38, 35, 31, 28, 
//   25, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
//};

//均方差 5
int Probability[256] = {
    255, 250, 235, 213, 185, 155, 124, 96, 71, 50, 35, 23, 14, 9, 5, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

int  main()
{  
  
    IplImage * leftImage = cvLoadImage(&quot;l2.jpg&quot;,0);
    IplImage * rightImage = cvLoadImage(&quot;r2.jpg&quot;,0);

    //IplImage * leftImage = cvLoadImage(&quot;left.bmp&quot;,0);                           
    //IplImage * rightImage = cvLoadImage(&quot;right.bmp&quot;,0);

    int imageWidth = leftImage->width;
    int imageHeight =leftImage->height;

    IplImage * DPImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
    IplImage * effectiveImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
    IplImage * FilterImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);

    unsigned char * pPixel = NULL;
    unsigned char  pixel;
    unsigned char * pPixel2 = NULL;
    unsigned char  pixel2;
    for (int i = 0; i< imageHeight;i++)
    {
        for (int j =0; j < imageWidth;j++ )
        {
            pPixel = (unsigned char *)DPImage->imageData + i*DPImage->widthStep + j;
            *pPixel = 0;
            pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + j;
            *pPixel = 0;
        }
    }



    cvNamedWindow(&quot;Left&quot;,1);
    cvNamedWindow(&quot;Right&quot;,1);
    cvNamedWindow(&quot;Depth&quot;,1);
    cvNamedWindow(&quot;effectiveImage&quot;,1);

    cvShowImage(&quot;Left&quot;,leftImage);
    cvShowImage(&quot;Right&quot;,rightImage);

    int minD = 0;
    int maxD = 31;
    //假設影象是經過矯正的,那麼每次都只是需要搜搜同一行的內容
    int max12Diff = 10;
   
    for (int i = 0;i < imageWidth;i++)
    {
        Ddynamic[0] = 0;
        Ddynamic[0] = 0;
    }

    unsigned char * pLeftPixel  = NULL;
    unsigned char * pRightPixel = NULL;
    unsigned char leftPixel = 0;
    unsigned char leftMax = 0;
    unsigned char leftMin = 0;
    unsigned char tempLeft1 = 0;
    unsigned char tempLeft2 = 0;
    unsigned char rightPixel =0;
    unsigned char difPixel = 0;
    int m,n,l;

    int t1 = clock();
    for (int i = 0 ; i < imageHeight;i++)
    {
        for (int j = 0; j<imageWidth;j++)
        {
            for (int k = j + minD; k <= j + maxD;k++)
            {
                if (k <= 0 || k >= imageWidth -1)
                {

                }else {
                    pLeftPixel = (unsigned char*)leftImage->imageData + i*leftImage->widthStep + k;
                    pRightPixel= (unsigned char*)rightImage->imageData+i*rightImage->widthStep + j;
                    leftPixel  = *pLeftPixel;
                    rightPixel = *pRightPixel;
                    leftPixel  = *pLeftPixel;
                    tempLeft1 = (*pLeftPixel +(*(pLeftPixel -1)))/2;
                    tempLeft2 = (*pLeftPixel +(*(pLeftPixel +1)))/2;

                    leftMax = max(max(tempLeft1,tempLeft2),leftPixel);
                    leftMin = min(min(tempLeft1,tempLeft2),leftPixel);
                    difPixel = max(max(rightPixel - leftMax,leftMin - rightPixel),0);


                    if (difPixel <= max12Diff)
                    {
                        Ddynamic[j + 1][k + 1] = Ddynamic[j][k] + Probability[difPixel]; 
                    }else if (Ddynamic[j][k+1] > Ddynamic[j+1][k])
                    {
                        Ddynamic[j + 1][k + 1] = Ddynamic[j][k+1];
                    }else{
                        Ddynamic[j+1][k+1] = Ddynamic[j+1][k];
                    }
   
                    //cout<<Ddynamic[j +1][k+1]<<&quot;  &quot;;
                }
               
            }
             //cout<<&quot;\n&quot;;
        }
        //逆向搜尋,找出最佳路徑
         m = imageWidth;
         n = imageWidth;
         int m2 = imageWidth, n2 = imageWidth;
         l = Ddynamic[imageWidth][imageWidth];
        while( m >= 1 && n >= 1)
        {
            if ((m2 == m + 1 && n2 >= n +1) || ( m2 > m +1 && n2 == n + 1))
            {
                pPixel = (unsigned char *)DPImage->imageData + i*DPImage->widthStep + m;
                *pPixel = (n-m)*10;
                //標記有效匹配點
                pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + m;
                *pPixel = 255;

                m2 = m;
                n2 = n;

            }
            if (Ddynamic[m-1][n-1] >= Ddynamic[m][n -1] && Ddynamic[m-1][n -1] >= Ddynamic[m-1][n])
            {

                m--; 
                n--;
            }else if (Ddynamic[m-1][n] >= Ddynamic[m][n -1] && Ddynamic[m-1][n] >= Ddynamic[m-1][n -1])
            { 
                m--;
            }
            else
            { 
                n--;
            }
           
        }

       //cvWaitKey(0);
    }
    int t2 = clock();
    cout<<&quot;dt: &quot;<<t2-t1<<endl;

    //顯示Ddynamic最後一行
   /* for (int i = 0 ;i<= imageWidth;i++)
    {
        for (int j= 0; j<= imageWidth;j++)
        {
           cout<<Ddynamic[j]<<&quot;  &quot;;
        }
        cout<<&quot;\n\n&quot;;
    }*/


    //refine the depth image  7*7中值濾波
    //統計未能匹配點的個數
    int count = 0;
    for (int i = 0 ;i< imageHeight;i++)
    {
        for (int j= 0; j< imageWidth;j++)
        {
            pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + j;
            pixel = *pPixel;
            if (pixel == 0)
            {
                count++;
            }
        }
    }
    
    cout<<&quot;Count:  &quot;<<count<<&quot;  &quot;<<(double)count/(imageWidth*imageHeight)<<endl;
    cvShowImage(&quot;Depth&quot;,DPImage);
    cvShowImage(&quot;effectiveImage&quot;,effectiveImage);
   // cvWaitKey(0);


    FilterImage = cvCloneImage(DPImage);

    //7*7中值濾波
    int halfMedianWindowSize = 3;
    int medianWindowSize = 2*halfMedianWindowSize + 1;
    int medianArray[100] = {0};
    count = 0;
    int temp = 0;
    int medianVal = 0;

    for (int i = halfMedianWindowSize + 1 ;i< imageHeight - halfMedianWindowSize;i++)
    {
        for (int j = halfMedianWindowSize; j< imageWidth - halfMedianWindowSize;j++)
        {
            pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + j;
            pixel = *pPixel;
            if (pixel == 0)
            {
                count = 0;
                for (int m = i - halfMedianWindowSize ; m <= i + halfMedianWindowSize ;m++)
                {
                    for (int n = j - halfMedianWindowSize; n <= j + halfMedianWindowSize ;n++)
                    {
                        pPixel2 = (unsigned char *)DPImage->imageData + m*DPImage->widthStep + n;
                        pixel2 = *pPixel2;
                        if (pixel2 != 0)
                        {
                             medianArray[count] = pixel2;
                             count++;
                        }
       
                    }
                    //排序
                    for (int k = 0; k< count;k++)
                    {
                        for (int l = k + 1; l< count;l++)
                        {
                            if (medianArray[l] < medianArray[l-1] )
                            {
                                temp = medianArray[l];
                                medianArray[l] = medianArray[l-1];
                                medianArray[l-1] = temp;
                            }
                        }
                    }
                    medianVal = medianArray[count/2];
                    pPixel = (unsigned char *)FilterImage->imageData + i*DPImage->widthStep + j;
                    *pPixel = medianVal;
                }

            }
        }
    }
    cvShowImage(&quot;Depth&quot;,DPImage);
    cvShowImage(&quot;effectiveImage&quot;,effectiveImage);
    cvShowImage(&quot;Filter&quot;,FilterImage);

    cvSaveImage(&quot;depth.jpg&quot;,DPImage);
    cvSaveImage(&quot;Filter.jpg&quot;,FilterImage);
    cvSaveImage(&quot;effective.jpg&quot;,effectiveImage);

    cvWaitKey(0);
    return 0;
}
//效果

但是論文中多方向的DP卻看了好幾天都沒有頭緒該怎麼寫?因此這裡貼出進展,希望各位大俠能夠幫幫忙,共同學習。

 

 

 

 

 

opencvSGBM半全域性立體匹配演算法的研究

 

轉載請說明出處:http://blog.csdn.net/zhubaohua_bupt/article/details/51866700

 

自己在stereosgbm.cpp的最後加了一個把灰度影象顯示成偽彩色影象的函式,為的是更好的觀察視差圖。

 

[html] view plain copy

  1. myStereoSGBM::GenerateFalseMap(cv::Mat &src, cv::Mat &disp)  

下面分別給出 main.cpp、stereosgbm.h(從calib3d.hpp裡面提取出來,opencv版本2.4.9)、stereosgbm.cpp。配置完opencv環境後即可使用。有興趣的朋友可以研究一下程式碼。

 

main.cpp

 

[html] view plain copy

  1. #include"sgbm.h"  
  2. int main()  
  3. {  
  4.       
  5.     Mat img111 =  imread("E:/matchpic/testbanch_data/raindeer_left.pgm", 0);  
  6.     Mat img222 = imread("E:/matchpic/testbanch_data/raindeer_right.pgm", 0);      
  7.     imshow("left",img111);  
  8.     waitKey(10);  
  9.   
  10. cv::myStereoSGBM sgbm;  
  11.       
  12. int SADWindowSize = 5;  
  13. sgbm.preFilterCap = 63 ;   
  14. sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;  
  15. int cn = img111.channels();  
  16. int numberOfDisparities=128;  
  17. sgbm.P1 = 8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;  
  18. sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;   
  19. sgbm.minDisparity = 0;  
  20. sgbm.numberOfDisparities = numberOfDisparities;  
  21. sgbm.uniquenessRatio = 10;  
  22. sgbm.speckleWindowSize =100;  
  23. sgbm.speckleRange = 10;  
  24. sgbm.disp12MaxDiff = 1;  
  25. Mat disp;  
  26. sgbm( img111, img222,disp );//disp經過處理輸出的是short型別  
  27. Mat disp8,color(disp.size(),CV_8UC3);  
  28.  disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));//轉化成uchar顯示  
  29.   
  30. sgbm.GenerateFalseMap(disp8,color);  
  31. imshow("",color);  
  32. imshow("",disp8);  
  33. waitKey(10);  
  34. }   


 

 

stereosgbm.h

 

[html] view plain copy

  1. <pre name="code" class="html"><pre name="code" class="html">#include"opencv2/opencv.hpp"  
  2. #include<iostream>  
  3. using namespace cv;  
  4. using namespace std;  
  5. namespace cv  
  6. {   
  7. class myStereoSGBM  
  8. {  
  9. public:  
  10.     myStereoSGBM( int _minDisparity=0, int _numDisparities=0, int _SADWindowSize=0,  
  11. int _P1=0, int _P2=0, int _disp12MaxDiff=0, int _preFilterCap=0,   
  12. int _uniquenessRatio=0, int _speckleWindowSize=0, int _speckleRange=0,   
  13. bool _fullDP=false ) ;  
  14. //  myStereoSGBM();  
  15.     virtual void operator()(cv::InputArray _left, InputArray _right, OutputArray _disp ) ;  
  16.     void GenerateFalseMap(cv::Mat &src, cv::Mat &disp);  
  17.     ~myStereoSGBM() ;  
  18.   
  19.     enum{DISP_SHIFT=4,DISP_SCALE=(1<<DISP_SHIFT)};  
  20.     int minDisparity;  
  21.     int numberOfDisparities;  
  22.     int SADWindowSize;   
  23. int P1; int P2;  
  24. int disp12MaxDiff;  
  25. int preFilterCap;  
  26.   
  27. int uniquenessRatio;  
  28. int speckleWindowSize;  
  29. int speckleRange;  
  30. bool fullDP ;  
  31. protected :  
  32.     Mat buffer;  
  33. };  
  34. void filterSpeckles( InputOutputArray _img, double _newval, int maxSpeckleSize, double _maxDiff, InputOutputArray __buf ) ;  
  35. void validateDisparity( InputOutputArray _disp, InputArray _cost, int minDisparity, int numberOfDisparities, int disp12MaxDiff ) ;  
  36. CvRect cvGetValidDisparityROI( CvRect roi1, CvRect roi2, int minDisparity, int numberOfDisparities, int SADWindowSize ) ;  
  37. //void cvValidateDisparity( CvArr* _disp, const CvArr* _cost, int minDisparity, int numberOfDisparities, int disp12MaxDiff ) ;  
  38. }  


 

 

 
 

 

stereosgbm.cpp

 

[html] view plain copy

  1. <pre name="code" class="html">   
  2.   
  3. /*M/////////////////////////////////////////////////////////////////////////////////  
  4.   
  5. //////   
  6. //   
  7. // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.   
  8. //   
  9. // By downloading, copying, installing or using the software you agree to this   
  10.   
  11. license.   
  12. // If you do not agree to this license, do not download, install,   
  13. // copy or use the software.   
  14. //   
  15. //   
  16. // License Agreement   
  17. // For Open Source Computer Vision Library   
  18. //   
  19. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.   
  20. // Copyright (C) 2009, Willow Garage Inc., all rights reserved.   
  21. // Third party copyrights are property of their respective owners.   
  22. //   
  23. // Redistribution and use in source and binary forms, with or without modification,   
  24. // are permitted provided that the following conditions are met:   
  25. //   
  26. // * Redistribution's of source code must retain the above copyright notice,   
  27. // this list of conditions and the following disclaimer.   
  28. //   
  29. // * Redistribution's in binary form must reproduce the above copyright notice,   
  30. // this list of conditions and the following disclaimer in the documentation   
  31. // and/or other materials provided with the distribution.   
  32. //   
  33. // * The name of the copyright holders may not be used to endorse or promote   
  34.   
  35. products   
  36. // derived from this software without specific prior written permission.   
  37. //   
  38. // This software is provided by the copyright holders and contributors "as is" and   
  39. // any express or implied warranties, including, but not limited to, the implied   
  40. // warranties of merchantability and fitness for a particular purpose are   
  41.   
  42. disclaimed.   
  43. // In no event shall the Intel Corporation or contributors be liable for any direct,   
  44. // indirect, incidental, special, exemplary, or consequential damages   
  45. // (including, but not limited to, procurement of substitute goods or services;   
  46. // loss of use, data, or profits; or business interruption) however caused   
  47. // and on any theory of liability, whether in contract, strict liability,   
  48. // or tort (including negligence or otherwise) arising in any way out of   
  49. // the use of this software, even if advised of the possibility of such damage.   
  50. //   
  51. //M*/   
  52. /*   
  53. This is a variation of   
  54. "Stereo Processing by Semiglobal Matching and Mutual Information"   
  55. by Heiko Hirschmuller.   
  56. We match blocks rather than individual pixels, thus the algorithm is called   
  57. SGBM (Semi-global block matching)   
  58. */   
  59. //#include "precomp.hpp"   
  60.   
  61. #include <limits.h>   
  62. #include"sgbm.h"  
  63. #include<fstream>  
  64. namespace cv   
  65. {   
  66. typedef unsigned char PixType;   
  67. typedef short CostType;   
  68. typedef short DispType;   
  69. enum { NR = 16 , NR2 = NR/2 }; //NR=16  
  70. //myStereoSGBM::myStereoSGBM()   
  71. //{   
  72. //minDisparity = numberOfDisparities = 0;   
  73. //SADWindowSize = 0;   
  74. //P1 = P2 = 0;   
  75. //disp12MaxDiff = 0;   
  76. //preFilterCap = 0;   
  77. //uniquenessRatio = 0;   
  78. //speckleWindowSize = 0;   
  79. //speckleRange = 0;   
  80. //fullDP = false;   
  81. //}   
  82. myStereoSGBM::myStereoSGBM( int _minDisparity, int _numDisparities, int _SADWindowSize, int _P1, int _P2, int _disp12MaxDiff,  
  83.                        int _preFilterCap, int _uniquenessRatio, int _speckleWindowSize, int _speckleRange, bool _fullDP )  
  84.   
  85. {   
  86. minDisparity = _minDisparity;   
  87. numberOfDisparities = _numDisparities;   
  88. SADWindowSize = _SADWindowSize;   
  89. P1 = _P1;   
  90. P2 = _P2;   
  91. disp12MaxDiff = _disp12MaxDiff;   
  92. preFilterCap = _preFilterCap;   
  93. uniquenessRatio = _uniquenessRatio;   
  94. speckleWindowSize = _speckleWindowSize;   
  95. speckleRange = _speckleRange;   
  96. fullDP = _fullDP;   
  97. }   
  98. myStereoSGBM::~myStereoSGBM()   
  99. {   
  100. }   
  101. /*   
  102. For each pixel row1[x], max(-maxD, 0) <= minX <= x < maxX <= width - max(0, -minD),   
  103. and for each disparity minD<=d<maxD the function   
  104. computes the cost (cost[(x-minX)*(maxD - minD) + (d - minD)]), depending on the   
  105. difference between row1[x] and row2[x-d]. The subpixel algorithm from   
  106. "Depth Discontinuities by Pixel-to-Pixel Stereo" by Stan Birchfield and C. Tomasi //亞畫素插值  
  107. is used, hence the suffix BT.   
  108. the temporary buffer should contain width2*2 elements   
  109. */   
  110. static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y, int minD, int maxD, CostType* cost,   
  111.                             PixType* buffer, const PixType* tab, int tabOfs, int )   
  112.                               
  113. {   
  114.       
  115. int x, c, width = img1.cols, cn = img1.channels();   
  116. int minX1 = max(-maxD, 0), maxX1 = width + min(minD, 0);   
  117. int minX2 = max(minX1 - maxD, 0), maxX2 = min(maxX1 - minD, width);   
  118. int D = maxD - minD, width1 = maxX1 - minX1, width2 = maxX2 - minX2;   
  119. const PixType *row1 = img1.ptr<PixType>(y), *row2 = img2.ptr<PixType>(y);   
  120. PixType *prow1 = buffer + width2*2, *prow2 = prow1 + width*cn*2;   
  121. tab += tabOfs;   
  122. for( c = 0; c < cn*2; c++ )   
  123. {   
  124. prow1[width*c] = prow1[width*c + width-1] = prow2[width*c] = prow2[width*c + width-1] = tab[0];   
  125. }   
  126. int n1 = y > 0 ? -(int)img1.step : 0, s1 = y < img1.rows-1 ? (int)img1.step : 0;   
  127. int n2 = y > 0 ? -(int)img2.step : 0, s2 = y < img2.rows-1 ? (int)img2.step : 0;   
  128. if( cn == 1 )   
  129.     {   
  130.           
  131.         for( x = 1; x < width-1; x++ )   
  132.         {   
  133.           prow1[x] = tab[(row1[x+1] - row1[x-1])*2 + row1[x+n1+1] - row1[x+n1-1] + row1[x+s1+1] - row1[x+s1-1]];   
  134.            
  135.           prow2[width-1-x] = tab[(row2[x+1] - row2[x-1])*2 + row2[x+n2+1] - row2[x+n2-1] +  row2[x+s2+1] - row2[x+s2-1]];   
  136.            prow1[x+width] = row1[x];   
  137.            prow2[width-1-x+width] = row2[x];   
  138.         }   
  139.     }   
  140. else   
  141. {   
  142.     for( x = 1; x < width-1; x++ )   
  143.     {   
  144.     prow1[x] = tab[(row1[x*3+3] - row1[x*3-3])*2 + row1[x*3+n1+3] - row1[x*3+n1-3] + row1[x*3+s1+3] - row1[x*3+s1-3]];   
  145.     prow1[x+width] = tab[(row1[x*3+4] - row1[x*3-2])*2 + row1[x*3+n1+4] - row1[x*3+n1-2] + row1[x*3+s1+4] - row1[x*3+s1-2]];   
  146.     prow1[x+width*2] = tab[(row1[x*3+5] - row1[x*3-1])*2 + row1[x*3+n1+5] - row1[x*3+n1-1] + row1[x*3+s1+5] - row1[x*3+s1-1]];   
  147.     prow2[width-1-x] = tab[(row2[x*3+3] - row2[x*3-3])*2 + row2[x*3+n2+3] - row2[x*3+n2-3] + row2[x*3+s2+3] - row2[x*3+s2-3]];   
  148.     prow2[width-1-x+width] = tab[(row2[x*3+4] - row2[x*3-2])*2 + row2[x*3+n2+4] - row2[x*3+n2-2] + row2[x*3+s2+4] - row2[x*3+s2-2]];   
  149.     prow2[width-1-x+width*2] = tab[(row2[x*3+5] - row2[x*3-1])*2 + row2[x*3+n2+5] - row2[x*3+n2-1] + row2[x*3+s2+5] - row2[x*3+s2-1]];   
  150.   
  151.     prow1[x+width*3] = row1[x*3];   
  152.     prow1[x+width*4] = row1[x*3+1];   
  153.     prow1[x+width*5] = row1[x*3+2];   
  154.    
  155.     prow2[width-1-x+width*3] = row2[x*3];   
  156.     prow2[width-1-x+width*4] = row2[x*3+1];   
  157.     prow2[width-1-x+width*5] = row2[x*3+2];   
  158.     }   
  159. }   
  160. memset( cost, 0, width1*D*sizeof(cost[0]) );   
  161.   
  162. buffer -= minX2;   
  163. cost -= minX1*D + minD; // simplify the cost indices inside the loop   
  164.   
  165. /*#if CV_SSE2   
  166. volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE2);   
  167. #endif*/   
  168. #if 1   
  169. for( c = 0; c < cn*2; c++, prow1 += width, prow2 += width )   
  170. {   
  171. int diff_scale = c < cn ? 0 : 2; //對預處理之後的影象和原影象生成的代價加權相加        C=Cpreprocess+1/4*C原圖  
  172. // precompute   
  173. // v0 = min(row2[x-1/2], row2[x], row2[x+1/2]) and   
  174. // v1 = max(row2[x-1/2], row2[x], row2[x+1/2]) and   
  175. for( x = minX2; x < maxX2; x++ )   
  176.         {   
  177.             int v = prow2[x];   
  178.             int vl = x > 0 ? (v + prow2[x-1])/2 : v;   
  179.             int vr = x < width-1 ? (v + prow2[x+1])/2 : v;   
  180.             int v0 = min(vl, vr); v0 = min(v0, v);   
  181.             int v1 = max(vl, vr); v1 = max(v1, v);   
  182.             buffer[x] = (PixType)v0;   
  183.             buffer[x + width2] = (PixType)v1;   
  184.         }   
  185.   
  186. for( x = minX1; x < maxX1; x++ )   
  187.   {   
  188.             int u = prow1[x];   
  189.             int ul = x > 0 ? (u + prow1[x-1])/2 : u;   
  190.             int ur = x < width-1 ? (u + prow1[x+1])/2 : u;   
  191.             int u0 = min(ul, ur); u0 = min(u0, u);   
  192.             int u1 = max(ul, ur); u1 = max(u1, u);   
  193. //#if CV_SSE2   
  194. //if( useSIMD )   
  195. //{   
  196. //__m128i _u = _mm_set1_epi8((char)u), _u0 = _mm_set1_epi8((char)u0);   
  197. //__m128i _u1 = _mm_set1_epi8((char)u1), z = _mm_setzero_si128();   
  198. //__m128i ds = _mm_cvtsi32_si128(diff_scale);   
  199. //for( int d = minD; d < maxD; d += 16 )   
  200. //{   
  201. //__m128i _v = _mm_loadu_si128((const __m128i*)(prow2 + width-x-1 + d));   
  202. //__m128i _v0 = _mm_loadu_si128((const __m128i*)(buffer + width-x-1 + d));   
  203. //__m128i _v1 = _mm_loadu_si128((const __m128i*)(buffer + width-x-1 + d + width2));   
  204. //__m128i c0 = _mm_max_epu8(_mm_subs_epu8(_u, _v1), _mm_subs_epu8(_v0, _u));   
  205. //__m128i c1 = _mm_max_epu8(_mm_subs_epu8(_v, _u1), _mm_subs_epu8(_u0, _v));   
  206. //__m128i diff = _mm_min_epu8(c0, c1);   
  207. //c0 = _mm_load_si128((__m128i*)(cost + x*D + d));   
  208. //c1 = _mm_load_si128((__m128i*)(cost + x*D + d + 8));   
  209. //_mm_store_si128((__m128i*)(cost + x*D + d), _mm_adds_epi16(c0, _mm_srl_epi16  
  210. //  
  211. //(_mm_unpacklo_epi8(diff,z), ds)));   
  212. //_mm_store_si128((__m128i*)(cost + x*D + d + 8), _mm_adds_epi16(c1, _mm_srl_epi16  
  213. //  
  214. //(_mm_unpackhi_epi8(diff,z), ds)));   
  215. //}   
  216. //}   
  217. //else   
  218. //#endif   
  219.         {   
  220.                     for( int d = minD; d < maxD; d++ )   
  221.                     {   
  222.                     int v = prow2[width-x-1 + d];   
  223.                     int v0 = buffer[width-x-1 + d];   
  224.                     int v1 = buffer[width-x-1 + d + width2];   
  225.                     int c0 = max(0, u - v1); c0 = max(c0, v0 - u);   
  226.                     int c1 = max(0, v - u1); c1 = max(c1, u0 - v);   
  227.                                                                                     //cout<<cost[x*D + d]<<endl;  
  228.                     cost[x*D + d] = (CostType)(cost[x*D+d] + (min(c0, c1) >> diff_scale)); //代價由預處理後的影象和原圖兩部分共同組成  
  229.                     //if(c==0) continue;  
  230.                     //else                                                    
  231.                     //cost[x*D + d] = (CostType)( (min(c0, c1) >> diff_scale));   
  232.                     //  cout<<"  +="<<cost[x*D + d]<<endl;  
  233.                                                                   
  234.                     }   
  235.                       
  236.         }   
  237.     }   
  238.   
  239. }   
  240. #else   
  241. for( c = 0; c < cn*2; c++, prow1 += width, prow2 += width )   
  242. {   
  243. for( x = minX1; x < maxX1; x++ )   
  244. {   
  245. int u = prow1[x];   
  246. #if CV_SSE2   
  247. if( useSIMD )   
  248. {   
  249. __m128i _u = _mm_set1_epi8(u), z = _mm_setzero_si128();   
  250. for( int d = minD; d < maxD; d += 16 )   
  251. {   
  252. __m128i _v = _mm_loadu_si128((const __m128i*)(prow2 + width-1-x + d));   
  253. __m128i diff = _mm_adds_epu8(_mm_subs_epu8(_u,_v), _mm_subs_epu8(_v,_u));   
  254. __m128i c0 = _mm_load_si128((__m128i*)(cost + x*D + d));   
  255. __m128i c1 = _mm_load_si128((__m128i*)(cost + x*D + d + 8));   
  256. _mm_store_si128((__m128i*)(cost + x*D + d), _mm_adds_epi16(c0, _mm_unpacklo_epi8  
  257.   
  258. (diff,z)));   
  259. _mm_store_si128((__m128i*)(cost + x*D + d + 8), _mm_adds_epi16(c1,   
  260.   
  261. _mm_unpackhi_epi8(diff,z)));   
  262. }   
  263. }   
  264. else   
  265. #endif   
  266. {   
  267. for( int d = minD; d < maxD; d++ )   
  268. {   
  269. int v = prow2[width-1-x + d];   
  270. cost[x*D + d] = (CostType)(cost[x*D + d] + (CostType)std::abs(u - v));   
  271. }   
  272. }   
  273. }   
  274. }   
  275. #endif   
  276. }   
  277. /*   
  278. computes disparity for "roi" in img1 w.r.t. img2 and write it to disp1buf.   
  279. that is, disp1buf(x, y)=d means that img1(x+roi.x, y+roi.y) ~ img2(x+roi.x-d, y+roi.y).   
  280. minD <= d < maxD.   
  281. disp2full is the reverse disparity map, that is:   
  282. disp2full(x+roi.x,y+roi.y)=d means that img2(x+roi.x, y+roi.y) ~ img1(x+roi.x+d, y+roi.y)   
  283. note that disp1buf will have the same size as the roi and   
  284. disp2full will have the same size as img1 (or img2).   
  285. On exit disp2buf is not the final disparity, it is an intermediate result that   
  286.   
  287. becomes   
  288. final after all the tiles are processed.   
  289. the disparity in disp1buf is written with sub-pixel accuracy   
  290. (4 fractional bits, see CvmyStereoSGBM::DISP_SCALE),   
  291. using quadratic interpolation, while the disparity in disp2buf   
  292. is written as is, without interpolation.   
  293. disp2cost also has the same size as img1 (or img2).   
  294. It contains the minimum current cost, used to find the best disparity, corresponding   
  295.   
  296. to the minimal cost.   
  297. */   
  298. static void computeDisparitySGBM( const Mat& img1, const Mat& img2, Mat& disp1, const myStereoSGBM& params, Mat& buffer )   
  299. {   
  300. //#if CV_SSE2/*   
  301. //      static const uchar LSBTab[] =   
  302. //      {   
  303. //      0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,   
  304. //  
  305. //      2, 0, 1, 0,   
  306. //      5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,   
  307. //  
  308. //      2, 0, 1, 0,   
  309. //      6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,   
  310. //  
  311. //      2, 0, 1, 0,   
  312. //      5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,   
  313. //  
  314. //      2, 0, 1, 0,   
  315. //      7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,   
  316. //  
  317. //      2, 0, 1, 0,   
  318. //      5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,   
  319. //  
  320. //      2, 0, 1, 0,   
  321. //      6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,   
  322. //  
  323. //  &