Census算法的C++实现

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;
}

大家可以留言改进。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值