块匹配Block Match算法常用于双目立体匹配和帧间距离匹配上,特点是实现步骤简单,这里介绍四种基本的Block Match算法:
1.Sum of Absolute Differencse(sad)公式如下:
C++实现代码:
Mat funcSADR2L(Mat leftImage, Mat rightImage, int windowSize, int dispMin, int dispMax, int STEP = 1)
{
CV_Assert(leftImage.rows == rightImage.rows && leftImage.cols == rightImage.cols);
CV_Assert(windowSize % 2 == 1);
CV_Assert(dispMax > dispMin);
int nrLeft = leftImage.rows - 1;
int ncLeft = leftImage.cols - 1;
int win = (windowSize - 1) / 2;
Mat dispMap = Mat::zeros(nrLeft, ncLeft, CV_8UC1);
for (int i = 0 + win; i <= nrLeft - win; i = i + STEP)
{
for (int j = 0 + win; j <= ncLeft - win - dispMax; j = j+STEP)
{
double prevSAD = 65532;
double temp = 0.0;
int bestMatchSoFar = dispMin;
for (int dispRange = dispMin; dispRange <= dispMax; dispRange++)
{
double sad = 0.0;
for (int a = -win; a <= win; a++)
{
for (int b = -win; b <= win; b++)
{
if (j + b + dispRange <= ncLeft)
{
temp = (double)rightImage.at(i + a, j + b) - (double)leftImage.at(i + a, j + b + dispRange);
if (temp < 0.0)
{
temp = temp*(-1.0);
}
sad = sad + temp;
}
}
}
if (prevSAD > sad)
{
prevSAD = sad;
bestMatchSoFar = dispRange;
}
}
dispMap.at(i, j) = bestMatchSoFar;
}
}
normalize(dispMap, dispMap, 0, 255, CV_MINMAX);
return dispMap;
}
2.Sum of Squared Differences(ssd)公式如下:
C++实现代码:
Mat funcSSDR2L(Mat leftImage, Mat rightImage, int windowSize, int dispMin, int dispMax, int STEP = 1)
{
CV_Assert(leftImage.rows == rightImage.rows && leftImage.cols == rightImage.cols);
CV_Assert(windowSize % 2 == 1);
CV_Assert(dispMax > dispMin);
int nrLeft = leftImage.rows - 1;
int ncLeft = leftImage.cols - 1;
int win = (windowSize - 1) / 2;
Mat dispMap = Mat::zeros(nrLeft, ncLeft, CV_8UC1);
for (int i = 0 + win; i <= nrLeft - win; i = i + STEP)
{
for (int j = 0 + win; j <= ncLeft - win - dispMax; j = j + STEP)
{
double prevSDD = 65532;
double temp = 0.0;
int bestMatchSoFar = dispMin;
for (int dispRange = dispMin; dispRange <= dispMax; dispRange++)
{
double ssd = 0.0;
for (int a = -win; a <= win; a++)
{
for (int b = -win; b <= win; b++)
{
if (j + b + dispRange <= ncLeft)
{
temp = (double)rightImage.at(i + a, j + b) - (double)leftImage.at(i + a, j + b + dispRange);
temp = temp*temp;
ssd = ssd + temp;
}
}
}
if (prevSDD > ssd)
{
prevSDD = ssd;
bestMatchSoFar = dispRange;
}
}
dispMap.at(i, j) = bestMatchSoFar;
}
}
normalize(dispMap, dispMap, 0, 255, CV_MINMAX);
return dispMap;
}
3.Sum of Hamming Distances(shd)公式如下:
bit()的含义是像素转为二进制后含有多少个1,整个公式意思就是两张局部图先异或一下,然后统计所有像素二进制化后1的个数,取最少的那个就行了。
c++实现代码:
Mat funcSHDR2L(Mat leftImage, Mat rightImage, int windowSize, int dispMin, int dispMax,int STEP = 1)
{
CV_Assert(leftImage.rows == rightImage.rows && leftImage.cols == rightImage.cols);
CV_Assert(windowSize % 2 == 1);
CV_Assert(dispMax > dispMin);
int nrLeft = leftImage.rows - 1;
int ncLeft = leftImage.cols - 1;
int win = (windowSize - 1) / 2;
Mat dispMap = Mat::zeros(nrLeft, ncLeft, CV_8UC1);
for (int i = 0 + win; i <= nrLeft - win; i = i + STEP)
{
for (int j = 0 + win; j <= ncLeft - win - dispMax; j = j + STEP)
{
int min = 0;
int position = 0;
Rect rightRect = Rect(j - win, i - win, 2 * win + 1, 2 * win + 1);
Mat rightWindow = rightImage(rightRect);
for (int dispRange = dispMin; dispRange <= dispMax; dispRange++)
{
if (j + win + dispRange <= ncLeft)
{
Rect leftRect = Rect(j - win + dispRange, i - win, 2 * win + 1, 2 * win + 1);
Mat leftWindow = leftImage(leftRect);
Mat bloc3 = Mat::zeros(leftWindow.rows, leftWindow.cols, CV_8UC1);
for (int m = 0; m < leftWindow.rows; m++)
{
for (int n = 0; n < leftWindow.cols; n++)
{
bloc3.at(m, n) = leftWindow.at(m, n) ^ rightWindow.at(m, n);
}
}
int dis = 0;
for (int m = 0; m < leftWindow.rows; m++)
{
for (int n = 0; n < leftWindow.cols; n++)
{
dis += BitCount(bloc3.at(m, n));
}
}
if (dispRange == 0)
min = dis;
else if (min > dis)
{
min = dis;
position = dispRange;
}
}
}
dispMap.at(i, j) = position;
}
}
normalize(dispMap, dispMap, 0, 255, CV_MINMAX);
return dispMap;
}
4.Normalized Cross Correlation(ncc)公式如下:
c++实现代码:
Mat funcNCCR2L(Mat leftImage, Mat rightImage, int windowSize, int dispMin, int dispMax, int STEP = 1)
{
CV_Assert(leftImage.rows == rightImage.rows && leftImage.cols == rightImage.cols);
CV_Assert(windowSize % 2 == 1);
CV_Assert(dispMax > dispMin);
int nrLeft = leftImage.rows - 1;
int ncLeft = leftImage.cols - 1;
int win = (windowSize - 1) / 2;
Mat dispMap = Mat::zeros(nrLeft, ncLeft, CV_8UC1);
for (int i = 0 + win; i <= nrLeft - win; i = i + STEP)
{
for (int j = 0 + win; j <= ncLeft - win - dispMax; j = j + STEP)
{
double prevNCC = 0.0;
int bestMatchSoFar = dispMin;
for (int dispRange = dispMin; dispRange <= dispMax; dispRange++)
{
double ncc = 0.0;
double nccNumberator = 0.0;
double nccDenominator = 0.0;
double nccDenominatorRightWindow = 0.0;
double nccDenominatorLeftWindow = 0.0;
for (int a = -win; a <= win; a++)
{
for (int b = -win; b <= win; b++)
{
nccNumberator += rightImage.at(i + a, j + b)*leftImage.at(i + a, j + b + dispRange);
nccDenominatorRightWindow += rightImage.at(i + a, j + b)*rightImage.at(i + a, j + b);
nccDenominatorLeftWindow += leftImage.at(i + a, j + b + dispRange)*leftImage.at(i + a, j + b + dispRange);
}
}
nccDenominator = sqrt(nccDenominatorRightWindow*nccDenominatorLeftWindow);
ncc = nccNumberator / nccDenominator;
if (prevNCC < ncc)
{
prevNCC = ncc;
bestMatchSoFar = dispRange;
}
}
dispMap.at(i, j) = bestMatchSoFar;
}
}
normalize(dispMap, dispMap, 0, 255, CV_MINMAX);
return dispMap;
}