census算法的c++实现
这个代码是在(48条消息) 双目立体匹配 Census_MisTimee的博客-CSDN博客
基础上改的,添加了一些代码理解内容,由于本身对c++没有很熟悉(c++小白)所以代码的改进后不知道是不是更好,反正理解是更好理解了hhh。如果理解有错误的地方,麻烦在下方留言再改进。
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//先定义census对图像进行编码//
//首先定义一个窗口的大小
int hWind = 1;
//相当于利用窗口遍历整个图像,并且将8位的数字给每次窗口的中心点。
Mat ProcessImg(Mat& Img);
//定义一个左图像和右图像,还是在Mat类下面,这个是要用来分别获得将左右图像传递给ProcessImg后,得到的图像
Mat LeftCensus, RightCensus;
//通过下面这个类的成员函数获得视差图
Mat getDisparity(Mat& left, Mat& right);
//对视差图进行优化
Mat ProcessDisparity(Mat& disImg);
//先定义汉明距离//
int GetHammingWeight(uchar value);
//下面就是接受的返回值用自己定义的变量来接受
int ImgHeight, ImgWeight;
Mat LeftImg, RightImg;
Mat DisparityImg(ImgHeight,ImgWeight,CV_8UC1,Scalar::all(0));
Mat DisparityImg_Processed(ImgHeight, ImgWeight, CV_8UC1, Scalar::all(0));
int main()
{
LeftImg = imread("E:/vs_qt_code/2.ppm", 0);//0是加载灰度图像//
RightImg = imread("E:/vs_qt_code/3.ppm", 0);
ImgHeight = LeftImg.rows;//获得行数也就是图像的高度//
ImgWeight = LeftImg.cols;//获得列数//
LeftCensus = ProcessImg(LeftImg);
namedWindow("Left_census", 1);
imshow("Left_census", LeftCensus);
waitKey(500);
RightCensus = ProcessImg(RightImg);
namedWindow("Right_census", 1);
imshow("Right_census", RightCensus);
waitKey(500);
DisparityImg = getDisparity(LeftCensus, RightCensus);
namedWindow("Disparity", 1);
imshow("Disparity", DisparityImg);
// imwrite(save_dir + "disparity.jpg", DisparityImg);
waitKey(500);
DisparityImg_Processed = ProcessDisparity(DisparityImg);
namedWindow("shichayouhua", 1);
imshow("shichayouhua", DisparityImg_Processed);
waitKey();
return 0;
}
Mat ProcessImg(Mat& Img)
{
Mat Img_census = Mat(Img.rows, Img.cols, CV_8UC1, Scalar::all(0));//创建一个单通道灰度图像,由于经过下面的操作每个中心点都变为census 序列也就是二进制的数串,
uchar center = 0;
for (int i = 0; i < ImgHeight - hWind-1; i++)
{
for (int j = 0; j < ImgWeight - hWind-1; j++)
{
center = Img.at<uchar>(i + hWind, j + hWind);//当遍历图像时获取每次的中心点,因为是3*3的矩阵这也是为什么要i < ImgHeight - hWind-1,j < ImgWeight - hWind-1
uchar neighbor = 0;
uchar census = 0;
for (int p = i; p <= i + 2 * hWind; p++)
{
for (int q = j; q <= j + 2 * hWind; q++)
{
if (p >= 0 && p < ImgHeight && q >= 0 && q < ImgWeight)
{
if (!(p == i + hWind && q == j + hWind))
{
neighbor = Img.at<uchar>(p, q);
if (neighbor > center)
{
census = census * 2;//这里*2的意思就是左移,这里应该是把大于的取为0,小于的取为1了,但是由于这样取最后hamming操作的结果是一样的
}
else
{
census = census * 2 + 1;
}
}
}
}
}
Img_census.at<uchar>(i + hWind, j + hWind) = census;//将census序列赋给每次便利的中心点
}
}
return Img_census;
}
int GetHammingWeight(uchar value)
{
int num = 0;
if (value == 0)
return 0;
while(value)
{
++num;
value = (value - 1) & value;
}
return num;
}
//用来获得视差图
Mat getDisparity(Mat& left, Mat& right)
{
int DSR_min = 0;
int DSR_max = 16;
Mat disparity(ImgHeight, ImgWeight, CV_8UC1);
Mat Dif(1, DSR_max - DSR_min, CV_8UC1);//定义一个1维的单通道矩阵
for (int i = 0; i < ImgHeight; i++)
{
for (int j = 0; j < ImgWeight; j++)
{
uchar R;
uchar L;
uchar diff;
int count = 0;
L = left.at<uchar>(i, j);
for (int k = DSR_min; k < DSR_max; k++)
{
int y = j - k;//这里为什么用j-k,是因为左眼看到的视图会比右眼看到的偏右,因此以左眼为参考的话,确定右图的视差,则是要往左在0-16范围内寻找一样的点,由于往往是在一条线上的所以直接找不同位置的像素纵坐标就好。
if (y < 0)
{
Dif.at<uchar>(k) = 0;
}
if(y>=0)
{
R = right.at<uchar>(i, y);//将右视图的这几个像素都取出来//
diff = L ^ R;
diff = GetHammingWeight(diff);
Dif.at<uchar>(k) = diff;
}
}
Point minLoc;
minMaxLoc(Dif, NULL, NULL, &minLoc, NULL);
int loc = minLoc.x;//这里的x指的是列 矩阵和坐标刚好相反
disparity.at<uchar>(i, j) = (loc + 1) * 16 - 1;//这里就刚好改到0-255像素内
}
}
return disparity;
}
//视差优化 大白话就是将像素低于125的变为0,大于125的存储到ProcessDisImg
Mat ProcessDisparity(Mat& disImg)
{
Mat ProcessDisImg(ImgHeight, ImgWeight, CV_8UC1); //用来存储图像的,里面的参数就是多大多高,单通道的灰度图像
for (int i = 0; i < ImgHeight; i++)
{
for (int j = 0; j < ImgWeight; j++)
{
uchar pixel = disImg.at<uchar>(i, j);
if (pixel < 100)
{
pixel = 0;
}
ProcessDisImg.at<uchar>(i, j) = pixel;
}
}
return ProcessDisImg;
}
大家可以留言改进。