zoukankan      html  css  js  c++  java
  • 立体视觉算法SGBM(一)

    最近一直在学习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("left.png",0);
    IplImage * img2 = cvLoadImage("right.png",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<<"Time elapsed:"<<t*1000/getTickFrequency()<<endl;
    disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));

    namedWindow("left", 1);
    cvShowImage("left", img1);
    namedWindow("right", 1);
    cvShowImage("right", img2);
    namedWindow("disparity", 1);
    imshow("disparity", disp8);
    waitKey();
    imwrite("sgbm_disparity.png", 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("l2.jpg",0);
    IplImage * rightImage = cvLoadImage("r2.jpg",0);

    //IplImage * leftImage = cvLoadImage("left.bmp",0); 
    //IplImage * rightImage = cvLoadImage("right.bmp",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("Left",1);
    cvNamedWindow("Right",1);
    cvNamedWindow("Depth",1);
    cvNamedWindow("effectiveImage",1);

    cvShowImage("Left",leftImage);
    cvShowImage("Right",rightImage);

    int minD = 0;
    int maxD = 31;
    //假设图像是经过矫正的,那么每次都只是需要搜搜同一行的内容
    int max12Diff = 10;

    for (int i = 0;i < imageWidth;i++)
    {
    Ddynamic[0][i] = 0;
    Ddynamic[i][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]<<" ";
    }

    }
    //cout<<"\n";
    }
    //逆向搜索,找出最佳路径
    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<<"dt: "<<t2-t1<<endl;

    //显示Ddynamic最后一行
    /* for (int i = 0 ;i<= imageWidth;i++)
    {
    for (int j= 0; j<= imageWidth;j++)
    {
    cout<<Ddynamic[i][j]<<" ";
    }
    cout<<"\n\n";
    }*/


    //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<<"Count: "<<count<<" "<<(double)count/(imageWidth*imageHeight)<<endl;
    cvShowImage("Depth",DPImage);
    cvShowImage("effectiveImage",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("Depth",DPImage);
    cvShowImage("effectiveImage",effectiveImage);
    cvShowImage("Filter",FilterImage);

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

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





    论文中的多方向的DP暂时还没有实现,等实现时候再贴出来。

    (未完待续)

  • 相关阅读:
    django-based blog- mezzanine
    echo "hello" | nc -4t -w1 localhost 8001
    boost静态链接的问题 -lgcc_s
    Vim 新用法
    解决docker中DNS查询的问题
    centos 升级GCC/G++
    enable c++11 in autoconf in fucking gnu auto tools
    Fucking "pkg-config not found"
    在CentOS 6.X 上面安装 Python 2.7.X
    redis sentinel 配置
  • 原文地址:https://www.cnblogs.com/libing64/p/2878713.html
Copyright © 2011-2022 走看看