雙目視覺(五)立體匹配算法之動態規劃全局匹配

           動態規劃全局匹配

全局匹配算法:

全局匹配主要是利用圖像的全局約束信息,通過構建全局能量函數,然後通過優化方法最小化全局能量函數以求得緻密視差圖。目前優化方法主要有:動態規劃(DP)、置信傳播(BP)、模擬退火、圖割法(GC)等。

動態規劃:

動態規劃的思想就是把求解整個過程分解爲若干子過程,逐個求解子過程。例如斐波那契數列,fib(6)分解爲fib(5)和fib(4),而fib(5)分解爲fib(4)和fib(3),fib(4)爲一個重複子問題,而動態規劃就是解決這類問題的方式之一。

這是我學習動態規劃相關知識的鏈接:

https://www.bilibili.com/video/av16544031/?spm_id_from=333.788.videocard.1

https://www.bilibili.com/video/av45990457?from=search&seid=5131266338769155396

在雙目匹配中,動態規劃立體匹配是基於極線約束,通過依次尋找每條極線上匹配點對的最小代價路徑的動態尋優方法求解全局能量最小化,得到匹配視差圖。

步驟大致如下:

  • step1.構建全局能量函數

其中,爲數據項,一般表示爲代價函數;爲視差平滑約束項。

 

  • step2. 代價函數構建

代價函數構建這裏採用的是塊匹配,也就是以第一圖像待匹配點爲中心像素創建一個n*n的窗口,在第二幅圖像中,沿着極線取出與基準點領域同樣大小爲n*n的領域,進行領域內的相似度函數的計算。

說明:代價函數採用的是C++中的繼承構建

  • imageType:判斷左右圖像的信息相似性。比如大小是否一樣大呀。
  • aggregate:這也就是所謂的代價聚合函數,計算左右圖像領域內的相似性度量的。
class CostFunction {
public:
    float lambda;

    cv::Mat left;//左圖像
    cv::Mat right;//右圖像

    int blocksize;//block大小
    int margin;//塊的邊界

    float normCost;
    float normWin;
    //構造函數
    CostFunction( cv::Mat left, cv::Mat right, float lambda)
    {
		lambda = 1.0;
        this->left = left;
        this->right = right;
        imageType(left, right);
        this->lambda = lambda;
    }
    //虛構函數
    virtual bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.size() == right.size());

        return true;
    }
    //代價聚合
    virtual float aggregate(int x1, int x2, int y) = 0;

    float p(float cost) {
        return 1 - exp(-cost / lambda);
    }

    ~CostFunction() {}
};

class RGBCost : public CostFunction {
public:
    RGBCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {}

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_8UC3 && "img type not supported");

        return true;
    }

    // aggregate over a ROI of input images
    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        for (int i = y - margin; i <= y + margin; ++i) {
            cv::Vec3b* lptr = left.ptr<cv::Vec3b>(i);
            cv::Vec3b* rptr = right.ptr<cv::Vec3b>(i);

            for ( int j = -margin; j <= margin; ++j) {
                sum += eukl(lptr[x1 + j], rptr[x2 + j]);      // cost function
            }
        }

        return sum / sqrt(255*255 + 255*255+255*255);      // normalize to winsize*1.0
    }

    float eukl(cv::Vec3b l, cv::Vec3b r) {
        float a = l[0] - r[0];
        float b = l[1] - r[1];
        float c = l[2] - r[2];
        return std::sqrt(a*a + b*b + c*c);
    }

    ~RGBCost() {}
};

class FloatCost : public CostFunction {
public:
    FloatCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {}

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_32F && "img type not supported");

        return true;
    }

    // aggregate over a ROI of input images
    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        for (int i = y - margin; i <= y + margin; ++i) {
            float* lptr = left.ptr<float>(i);
            float* rptr = right.ptr<float>(i);

            for ( int j = -margin ; j <= margin; ++j) {
                sum += abs(lptr[x1 + j] - rptr[x2 + j]);      // cost function
            }
        }

        return sum / (blocksize*blocksize*lambda);
    }
};

class CondHistCost : public CostFunction {
public:
    cv::Mat nuLeft, nuRight;
    CondHistCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {
        cv::Mat histl = condHist(left, 3);
        nuLeft = switchColors(left, histl);
        cv::Mat histr = condHist(right, 3);
        nuRight = switchColors(right, histr);
    }

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_32F && "img type not supported");

        return true;
    }

    // aggregate over a ROI of input images
    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        for (int i = y - margin; i <= y + margin; ++i) {
            float* lptr = nuLeft.ptr<float>(i);
            float* rptr = nuRight.ptr<float>(i);

            for ( int j = -margin ; j <= margin; ++j) {
                sum += abs(lptr[x1 + j] - rptr[x2 + j]);      // cost function
            }
        }

        return sum / (blocksize*blocksize*lambda);
    }
};


class GrayCost : public CostFunction {
public:
    GrayCost(cv::Mat left, cv::Mat right, float lambda) : CostFunction(left, right, lambda) {}

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_8UC1 && "img type not supported");

        return true;
    }

    // aggregate over a ROI of input images
    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        for (int i = y - margin; i <= y + margin; ++i) {
            uchar* lptr = left.ptr<uchar>(i);
            uchar* rptr = right.ptr<uchar>(i);

            for ( int j = -margin; j <= margin; ++j) {
                sum += abs(lptr[x1 + j] - rptr[x2 + j]);      // cost function
            }
        }

        return sum / (blocksize*blocksize*255.0);
    }
};

class GradientCost : public CostFunction {
public:
    cv::Mat l_grad;   // 3 channel float
    cv::Mat r_grad;   // 3 channel float

    GradientCost(const cv::Mat left, const cv::Mat right, float lambda) : CostFunction(left, right, lambda) {
        l_grad = getRGBGradientAngle(left);
        r_grad = getRGBGradientAngle(right);

        //displayGradientPic(l_grad);
        //displayGradientPic(r_grad);
    }

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_8UC3 && "img type not supported");

        return true;
    }

    // aggregate over a ROI of input images
    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        for (int i = y - margin; i <= y + margin; ++i) {
            cv::Vec3f* lptr = l_grad.ptr<cv::Vec3f>(i);
            cv::Vec3f* rptr = r_grad.ptr<cv::Vec3f>(i);

            for ( int j = -margin; j <= margin; ++j) {
                sum += eukl(lptr[x1 + j], rptr[x2 + j]);      // cost function
            }
        }

        return sum / sqrt(255*255 + 255*255 + 255*255);      // normalize to winSize * 1.0
    }

    float eukl(cv::Vec3f l, cv::Vec3f r) {
        float a = l[0] - r[0];
        float b = l[1] - r[1];
        float c = l[2] - r[2];
        return std::sqrt(a*a + b*b + c*c);
    }

    ~GradientCost() {
        l_grad.release();
        r_grad.release();
    }
};

class CensusCost : public CostFunction {
public:
    int censusWindow;
    int censusMargin;
    CensusCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
        // census.... nimmt einen Block
        this->censusWindow = censusWindow;
        this->censusMargin = censusWindow / 2;

        this->normWin = censusWindow * censusWindow;
        // nimmt einen Block
    }

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_8UC1 && "img type not supported");

        return true;
    }

    unsigned int census(int x1, int x2, int y, uchar c1, uchar c2) {
        unsigned int diff = 0;

        for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
            uchar* lptr = left.ptr<uchar>(i);
            uchar* rptr = right.ptr<uchar>(i);

            for(int j = -censusMargin; j <= censusMargin; ++j) {
                bool t1 = (c1 < lptr[x1 + j]);
                bool t2 = (c2 < rptr[x2 + j]);

                if(t1 != t2) diff++;
            }
        }

        return diff; /// (censusWindow*censusWindow);
    }

    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        /*for(int i = y - margin; i <= y + margin; ++i) {
            uchar *lptr = left.ptr<uchar>(i);
            uchar *rptr = right.ptr<uchar>(i);

            for(int j = -margin; j <= margin; ++j)
                sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
        }*/
        uchar *lptr = left.ptr<uchar>(y);
        uchar *rptr = right.ptr<uchar>(y);
        sum = census(x1, x2, y, lptr[x1], rptr[x2]);
        return sum / normWin;
    }
};

class CensusFloatCost : public CostFunction {
public:
    int censusWindow;
    int censusMargin;

    CensusFloatCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
        // census.... nimmt einen Block
        this->censusWindow = censusWindow;
        this->censusMargin = censusWindow / 2;
    }

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_32F && "img type not supported");

        return true;
    }

    unsigned int census(int x1, int x2, int y, float c1, float c2) {
        unsigned int diff = 0;

        for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
            float* lptr = left.ptr<float>(i);
            float* rptr = right.ptr<float>(i);

            for(int j = -censusMargin; j <= censusMargin; ++j) {
                bool t1 = (c1 < lptr[x1 + j]);
                bool t2 = (c2 < rptr[x2 + j]);

                if(t1 != t2) diff++;
            }
        }

        return diff;
    }

    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        for(int i = y - margin; i <= y + margin; ++i) {
            float *lptr = left.ptr<float>(i);
            float *rptr = right.ptr<float>(i);

            for(int j = -margin; j <= margin; ++j)
                sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
        }
        float *lptr = left.ptr<float>(y);
        float *rptr = right.ptr<float>(y);
        //sum = census(x1, x2, y, lptr[x1], rptr[x2]);
        return sum / (censusWindow*censusWindow*lambda);
    }
};

class RGBCensusCost : public CostFunction {
public:
    int censusWindow;
    int censusMargin;

    RGBCensusCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
        // census.... nimmt einen Block
        this->censusWindow = censusWindow;
        this->censusMargin = censusWindow / 2;
        normCost = censusWindow*censusWindow*3;
        // nimmt einen Block
    }

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_8UC3 && "img type not supported");

        return true;
    }

    unsigned int census(int x1, int x2, int y, cv::Vec3b c1, cv::Vec3b c2) {
        unsigned int diff = 0;

        for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
            cv::Vec3b* lptr = left.ptr<cv::Vec3b>(i);
            cv::Vec3b* rptr = right.ptr<cv::Vec3b>(i);

            for(int j = -censusMargin; j <= censusMargin; ++j) {
                cv::Vec3b cl = lptr[x1 + j];
                cv::Vec3b cr = rptr[x2 + j];

                for(int ch = 0; ch < 3; ++ch) {
                    bool t1 = (c1[ch] < cl[ch]);
                    bool t2 = (c2[ch] < cr[ch]);

                    if(t1 != t2) diff++;
                }
            }
        }

        return diff;
    }

    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        for(int i = y - margin; i <= y + margin; ++i) {
            cv::Vec3b *lptr = left.ptr<cv::Vec3b>(i);
            cv::Vec3b *rptr = right.ptr<cv::Vec3b>(i);

            for(int j = -margin; j <= margin; ++j)
                sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
        }
        //cv::Vec3b *lptr = left.ptr<cv::Vec3b>(y);
        //cv::Vec3b *rptr = right.ptr<cv::Vec3b>(y);

        return sum / normCost;
    }
};

class RGBGradCensusCost : public CostFunction {
public:
    int censusWindow;
    int censusMargin;

    float normCost;
    float normWin;

    cv::Mat l_grad;
    cv::Mat r_grad;

    RGBGradCensusCost(cv::Mat left, cv::Mat right, int censusWindow, float lambda) : CostFunction(left, right, lambda) {
        // census.... nimmt einen Block
        this->censusWindow = censusWindow;
        this->censusMargin = censusWindow / 2;
        normWin = censusWindow*censusWindow*3;
        // nimmt einen Block
        l_grad = getRGBGradientAngle(left);
        r_grad = getRGBGradientAngle(right);
    }

    bool imageType(cv::Mat left, cv::Mat right) {
        assert(left.type() == right.type() && "imgL imgR types not equal");
        assert(left.type() == CV_8UC3 && "img type not supported");

        return true;
    }

    unsigned int census(int x1, int x2, int y, cv::Vec3f c1, cv::Vec3f c2) {
        unsigned int diff = 0;

        for(int i = y - censusMargin; i <= y + censusMargin; ++i) {
            cv::Vec3f* lptr = l_grad.ptr<cv::Vec3f>(i);
            cv::Vec3f* rptr = r_grad.ptr<cv::Vec3f>(i);

            for(int j = -censusMargin; j <= censusMargin; ++j) {
                cv::Vec3f cl = lptr[x1 + j];
                cv::Vec3f cr = rptr[x2 + j];

                for(int ch = 0; ch < 3; ++ch) {
                    bool t1 = (c1[ch] < cl[ch]);
                    bool t2 = (c2[ch] < cr[ch]);

                    if(t1 != t2) diff++;
                }
            }
        }

        return diff;
    }

    float aggregate(int x1, int x2, int y) {
        float sum = 0;
        /*for(int i = y - margin; i <= y + margin; ++i) {
            cv::Vec3f *lptr = l_grad.ptr<cv::Vec3f>(i);
            cv::Vec3f *rptr = r_grad.ptr<cv::Vec3f>(i);

            for(int j = -margin; j <= margin; ++j)
                sum += census(x1 + j, x2 + j, i, lptr[x1 + j], rptr[x2 + j]);
        }*/
        cv::Vec3f *lptr = l_grad.ptr<cv::Vec3f>(y);
        cv::Vec3f *rptr = r_grad.ptr<cv::Vec3f>(y);

        sum = census(x1, x2, y, lptr[x1], rptr[x2]);
        return sum / normWin;
    }
};

step3.視差空間的構建

DSI(Disparity Space Image)視差空間圖像爲一個三維矩陣,主要由橫軸x,縱軸y,視差搜索範圍d構成,傳統的DP方法一般就是爲了在某固定的Y(也就是某極線上)尋找一條從最左段到最右段的最小代價路徑,每條路徑的代價爲

  • 視差空間的構建

輸入參數:

  • imageSize:圖像的大小
  • blocksize:塊的大小
  • y:某條極線

輸出參數:

  • map:某極線上左右圖像兩兩領域相互的代價值
  • 左範圍:[margin,imageSize.width - margin]
  • 右範圍:[margin,imageSize.width - margin]
cv::Mat BlockMatching::disparitySpace(Size imageSize, int blocksize, int y)
{
    int margin = blocksize / 2;
    int start = margin;
    int stopW = imageSize.width - margin;
    int workSpace = stopW - start;

    // leave out the borders
    //Mat map = Mat(workSpace, workSpace, CV_32F);        // not preinitialized.. // numeric_limits<float>::max());
    Mat map = Mat(workSpace, workSpace, CV_32F, numeric_limits<float>::max());

    //int dmax = 101;
    for(int x1 = start; x1 < stopW; x1++) {
        float* ptr = map.ptr<float>(x1 - margin);       // [x1 - margin, x2 - margin]

        //ptr[max(x1 - 1, start) - margin] = numeric_limits<float>::max();              // fast borders
        //ptr[min(x1 + dmax, stopW - 1) - margin] = numeric_limits<float>::max();
        //for(int x2 = x1; x2 < min(x1 + dmax, stopW); x2++) {
        for(int x2 = start; x2 < stopW; x2++) {

            // combine costs
            float cost = 0;
            for(size_t i = 0; i < functions.size(); ++i) {
                float val = functions[i]->aggregate(x1, x2, y);
                mins[i] = min(mins[i], val);                        // debug
                maxs[i] = max(maxs[i], val);                        // debug
                cost += val;
            }

            // x1, x2. Das heißt x1 sind die Zeilen. Wir gehen jedes Mal die Zeilen runter.
            // geht nur von 0 - workspace, deshalb margin abziehen
            //map.at<float>(x1 - margin, x2 - margin) = greySad(leftRoi, rightRoi);
            ptr[x2 - margin] = cost;
        }
    }
    return map;
}

step4:動態規劃

主要分爲四步:

  1. 設置初始位置的值(已知的值,這裏設置的最後一行,最後一列的點爲初始值)
  2. 計算邊界上的代價(最後一行、最後一列)
  3. 從三個方向(向上、向左、斜向上)計算代價
  4. 記錄每一步的方向
  5. 第一行的最小值即爲視差點

 這裏不容易理解,其實它和Leetcode的最短路徑的題是相似的

題目:給定一個矩陣,從左上角開始每次只能向右或者向下移動,最後到達右下角的位置,路徑上的所有的數字累加起來作爲這條路徑的路勁和。要求返回所有路徑和中的最小路徑和

1 3 1
1 5 1
4 2 1

路徑1,3,1,1,1,1是所有路徑中路徑和最小的,所以返回其和7。

  • 第一步:起始點1
  • 第二步:如果一直向下或者向右:
1 4 5
2 5 1
6 2 1
  • 第三步:計算第二行第二列的值,比較第一行第二列和第二行第一列的數誰小就選誰,依次類推。
1 4 5
2 7  
6    
1 4 5
2 7 6
6 8  
1 4 5
2 7 6
6 8 7
  •   最小路徑和的代碼

int minPathSum1(int matrix[][col], int dp[][col], int path[][col])
{
    if(matrix == NULL)
    {
        return 0;
    }
 
    dp[0][0] = matrix[0][0];
 
    //計算第一列的值
    for(int i = 1; i < row; i ++)
    {
        dp[i][0] = dp[i - 1][0] + matrix[i][0];
 
        path[i][0] = 0;
    }
 
    //計算第一行的值
    for(int j = 1; j < col; j++)
    {
        dp[0][j] = dp[0][j- 1] + matrix[0][j];
 
        path[0][j] = 1;
    }
 
    //計算其它的值
    for(int i = 1; i < row; i++)
    {
        for(int j = 1; j < col; j++)
        {
            int direction = dp[i][j-1] < dp[i-1][j] ? 1 : 0;
            dp[i][j] = (direction ?  dp[i][j-1] : dp[i-1][j]) + matrix[i][j];
            path[i][j] = direction;
        }
    }//for
 
 
    return dp[row - 1][col - 1];
}

 

  •  dp視差空間代碼
// (1) set last entry sink in matrix (last value)
// (2-3) Initializ Edges
//    (2) initialize travelpath for last col (only south direction)
//    (3) initialize travelpath for last row (only east direction)
// (4) calculate paths till last sink (last entry) till xLast - 1, yLast - 1
// (-) save all (chosen) directions along the way
void DPmat::preCalc(Mat &matrix, Mat &sum, Mat &dirs) {
    float occlusion_south = 1.0f;
    float occlusion_east = 1.0f;
    sum = Mat::zeros(matrix.rows, matrix.cols, matrix.type());         // not initialized with zero, should not be a problem,
    dirs = Mat::zeros(matrix.rows, matrix.cols, CV_16U);               // because traversion is pre initialized with borders

    // dirs = (1, south), (2, south-east), (3, east)

    int rowLast = matrix.rows - 1;           // last index inclusive
    int colLast = matrix.cols - 1;           // last index inclusive

    // (1) initialize sink (last Entry/ terminal point/ matrix exit value)
    sum.at<float>(rowLast, colLast) = matrix.at<float>(rowLast, colLast);

    // (2-3) Initialize Edges

    // (2) calculate all last row entries down to exit value | only downward directions (so upward pre calculation)
    for(int y = rowLast - 1; y >= 0; --y) {
        // sum[y,x] = M[y,x] * occlusion_south + sum[y+1,x]
        sum.at<float>(y, colLast) = matrix.at<float>(y, colLast) * occlusion_south + sum.at<float>(y + 1, colLast);   // add current value + successor min(value)
        dirs.at<ushort>(y, colLast) = 1;    // south
    }

    // (3) initialize last
    for(int x = colLast - 1; x >= 0; --x) {
        // sum[y,x] = M[y,x] * occlusion_east + sum[y+1,x]
        sum.at<float>(rowLast, x) = matrix.at<float>(rowLast, x) * occlusion_east + sum.at<float>(rowLast, x + 1);   // add current value + successor min(value)
        dirs.at<ushort>(rowLast, x) = 3;    // east
    }

    // (4) Main calculation (3 way [south(s), east(e), south-east(se)])
    for(int y = rowLast - 1; y >= 0; --y) {
        float* sum_ptr = sum.ptr<float>(y);
        float* sum_south_ptr = sum.ptr<float>(y+1);
        float* mat_ptr = matrix.ptr<float>(y);
        ushort* dirs_ptr = dirs.ptr<ushort>(y);

        for(int x = colLast - 1; x >= 0; --x) {
            // dirs
            //float s = sum.at<float>(y + 1, x);
            //float se = sum.at<float>(y + 1, x + 1);
            //float e = sum.at<float>(y, x + 1);
            float s = sum_south_ptr[x] * occlusion_south;        // (y+1,x)     occlusion dir
            float se = sum_south_ptr[x + 1];                     // (y+1,x+1)
            float e = sum_ptr[x + 1] * occlusion_east;           // (y, x+1)    occlusion dir

            // lowest cost till current point
            float p = min(s, min(se, e));

            //sum.at<float>(y, x) = p + matrix.at<float>(y, x);   // sum till current (cost + lowest path)
            sum_ptr[x] = p + mat_ptr[x];        // sum[y,x] = p + mat[y, x]

            // selection for traversion direction
            //if(p == s) dirs.at<ushort>(y, x) = 1;   // occlusion
            //if(p == se) dirs.at<ushort>(y, x) = 2;   // math
            //if(p == e) dirs.at<ushort>(y, x) = 3;   // occlusion

            if(p == s) dirs_ptr[x] = 1;   // occlusion
            if(p == se) dirs_ptr[x] = 2;   // math
            if(p == e) dirs_ptr[x] = 3;   // occlusion
        }
    }
}
void DPmat::disparityFromDirs(Mat &sum, Mat &dirs, Mat &disp, int line, int offset) {
    assert(dirs.type() == CV_16U);

    // wir bekommen jetzt einen index x, y
    int rowLast = dirs.rows - 1;
    int colLast = dirs.cols - 1;

    int lastval = -1;
    int x1 = 0;
    int x2 = 0;

    float minVal = numeric_limits<float>::max();
    int minIndex = 0;
    // seek top entry
    for(x2 = 0; x2 < sum.cols; ++x2) {
        float val = sum.at<float>(x1, x2);
        if(val > minVal) {
            minIndex = x2;
            minVal = val;
        }
    }

    x2 = minIndex;

    // safe x1, x2 as disparity match
    ushort disparity = abs(x2 - x1);
    ushort* disp_ptr = disp.ptr<ushort>(line);

    disp_ptr[x1 + offset] = disparity;

    while(x1 < rowLast && x2 < colLast) {
        ushort d = dirs.at<ushort>(x1, x2);

        if(d == 1) {    // 1 = down, skipping left index, left got occloded (occlusion from right)
            x1++;
            if(lastval >= 0) disp_ptr[x1 + offset] = lastval;   // dips[line, x1 + offset] = lastval
            //disp_ptr[x1 + offset] = 0;
        }
        if(d == 2) { // match
            // next entry will be match
            x1++;
            x2++;
            disparity = abs(x2 - x1);

            disp_ptr[x1 + offset] = disparity;
            lastval = disparity;
        }
        if(d == 3) { // 2 = right, skipping right index, occlusion don't care..
            x2++;
            if(lastval >= 0) disp_ptr[x1 + offset] = lastval;   // dips[line, x1 + offset] = lastval
            //disp_ptr[x1 + offset]= 0;
        }
    }
}

原圖像:

視差圖像:


結論:

這種只考慮了圖像左右相鄰像素的視差約束,而忽略了上下領域像素之間的視差約束,這種方法得到的解因此也稱爲掃描線最優解,不能稱爲嚴格意義上的最優解,視差圖像也出現了明顯的橫向條紋瑕疵。而且其計算時間也比較慢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章