Kinect 2.0去除(彩色点云)或(彩色图像和深度图像对齐后彩色图像)的重影

参考:kinect 2.0 SDK学习笔记(四)–深度图与彩色图对齐
主要是在这个程序里面,加了点语句,因为原理是根据深度图像像素坐标计算出来对应的原始RGB图像像素坐标,出现重影的地方可能是因为这一部分是彩色相机的盲区,没有颜色,而深度相机有像素,根据像素坐标计算出来对应到彩色图像坐标会有重复。所以只要判断每次计算出来彩色图像的坐标,是否和之前计算的重复即可。
每次计算出来彩色图像的坐标后,标记为1,下一次计算出来这个坐标发现标记为1了,说明之前已经提取过了,那么这个深度像素点很有可能就是彩色图像的盲区,把这个像素设置为黑色,就去掉重影了。
但是处理完了之后还是有重影,不知道是我对齐的部分对齐的不太好,还是我这种去除重影的方法有问题,先这样吧。

/*
功能:将深度图映射到彩色图上,生成和深度图匹配的对齐彩色图
参考:https://blog.csdn.net/jiaojialulu/article/details/53154045
https://blog.csdn.net/jiaojialulu/article/details/53154045?locationNum=8&fps=1
日志:
2020.7.23 可用!
2021.4.28 加了去除重影的部分,成功!但是不知道是不太严谨还是因为自己对齐的不太好,有些地方的重影还是存在。但是已经去除很多啦!
*/
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <fstream>
#include <iostream>
#include <sstream>
#include <Eigen/Core>
#include <Eigen/LU>
#include <thread>

using namespace cv;
using namespace std;

struct KinectParm
{
	float fx_rgb;
	float fy_rgb;
	float cx_rgb;
	float cy_rgb;

	float fx_ir;
	float fy_ir;
	float cx_ir;
	float cy_ir;

	Eigen::Matrix3f R_ir2rgb;
	Eigen::Vector3f T_ir2rgb;
};

bool loadParm(KinectParm* kinectParm)
{
	// 加载参数
	ifstream parm("registration_me_modification_T.txt");
	string stringLine;
	if (parm.is_open())
	{
		// rgb相机参数:fx,fy,cx,cy
		getline(parm, stringLine);
		stringstream lin(stringLine);
		string s1, s2, s3, s4, s5, s6, s7, s8, s9;
		lin >> s1 >> s2 >> s3 >> s4;
		kinectParm->fx_rgb = atof(s1.c_str());
		kinectParm->fy_rgb = atof(s2.c_str());
		kinectParm->cx_rgb = atof(s3.c_str());
		kinectParm->cy_rgb = atof(s4.c_str());
		stringLine.clear();
		// ir相机参数:fx,fy,cx,cy
		getline(parm, stringLine);
		stringstream lin2(stringLine);
		lin2 << stringLine;
		lin2 >> s1 >> s2 >> s3 >> s4;
		kinectParm->fx_ir = atof(s1.c_str());
		kinectParm->fy_ir = atof(s2.c_str());
		kinectParm->cx_ir = atof(s3.c_str());
		kinectParm->cy_ir = atof(s4.c_str());
		stringLine.clear();

		// R_ir2rgb
		getline(parm, stringLine);
		stringstream lin3(stringLine);
		lin3 << stringLine;
		lin3 >> s1 >> s2 >> s3 >> s4 >> s5 >> s6 >> s7 >> s8 >> s9;
		kinectParm->R_ir2rgb <<
			atof(s1.c_str()), atof(s2.c_str()), atof(s3.c_str()),
			atof(s4.c_str()), atof(s5.c_str()), atof(s6.c_str()),
			atof(s7.c_str()), atof(s8.c_str()), atof(s9.c_str());
		stringLine.clear();

		// T_ir2rgb
		getline(parm, stringLine);
		stringstream lin4(stringLine);
		lin4 << stringLine;
		lin4 >> s1 >> s2 >> s3;
		kinectParm->T_ir2rgb << atof(s1.c_str()), atof(s2.c_str()), atof(s3.c_str());
	}
	else
	{
		cout << "parm.txt not right!!!";
		return false;
	}
	cout << "******************************************" << endl;

	cout << "fx_rgb:    " << kinectParm->fx_rgb << endl;
	cout << "fy_rgb:    " << kinectParm->fy_rgb << endl;
	cout << "cx_rgb:    " << kinectParm->cx_rgb << endl;
	cout << "cy_rgb:    " << kinectParm->cy_rgb << endl;
	cout << "******************************************" << endl;
	cout << "fx_ir:     " << kinectParm->fx_ir << endl;
	cout << "fy_ir:     " << kinectParm->fy_ir << endl;
	cout << "cx_ir:     " << kinectParm->cx_ir << endl;
	cout << "cy_ir:     " << kinectParm->cy_ir << endl;
	cout << "******************************************" << endl;
	cout << "R_ir2rgb:" << endl << kinectParm->R_ir2rgb << endl;
	cout << "******************************************" << endl;
	cout << "T_ir2rgb:" << endl << kinectParm->T_ir2rgb << endl;
	cout << "******************************************" << endl;
	return true;
}
int main()
{
	// 1. 读取参数
	KinectParm *parm = new KinectParm();
	if (!loadParm(parm))
		return 0;
	// 2. 载入rgb图片和深度图并显示
	Mat bgr(1080, 1920, CV_8UC4);
	bgr = imread("2020-12- 3-20-12- 5-rgb.png");
	Mat depth(424, 512, CV_16UC1);
	depth = imread("2020-12- 3-20-12- 5-depth.png", IMREAD_ANYDEPTH);   // 图片读入后的格式不一定和定义时候的一样,比如这里读入后的格式就是8UC3
	//Mat depth2rgb = imread("2019- 4-13-19-46-35-depth.png");
	// 3. 显示
	thread th = std::thread([&]{
		while (true)
		{
			imshow("原始彩色图", bgr);
			waitKey(1);
			imshow("原始深度图", depth);
			waitKey(1);
			/*imshow("原始投影图", depth2rgb);
			waitKey(1);*/
		}
	});
	// 4. 变换

	// 4.1 计算各个矩阵
#pragma region  非齐次
	Eigen::Matrix3f K_ir;           // ir内参矩阵
	K_ir <<
		parm->fx_ir, 0, parm->cx_ir,
		0, parm->fy_ir, parm->cy_ir,
		0, 0, 1;
	Eigen::Matrix3f K_rgb;          // rgb内参矩阵
	K_rgb <<
		parm->fx_rgb, 0, parm->cx_rgb,
		0, parm->fy_rgb, parm->cy_rgb,
		0, 0, 1;

	Eigen::Matrix3f R;
	Eigen::Vector3f T;
	Eigen::Vector3f T_me;//2020.6.23 自己手动平移一下
	R = K_rgb*parm->R_ir2rgb*K_ir.inverse();
	T = K_rgb*parm->T_ir2rgb;
	T_me << 10000, 0, 0;//2020.6.23 加是颜色往左移动

	cout << "K_rgb:\n" << K_rgb << endl;
	cout << "K_ir:\n" << K_ir << endl;
	cout << "R:\n" << R << endl;
	cout << "T:\n" << T << endl;

	cout << depth.type() << endl;


	// 4.2 计算投影
	Mat result(424, 512, CV_8UC3);
	int i = 0,x;
	Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> matrix_NN;//创建动态矩阵,不能创建静态矩阵,因为维数太高——Eigen::Matrix<double, 1920, 1080> matrix_NN;
	matrix_NN = Eigen::MatrixXd::Zero(1920, 1080);//用零矩阵初始化

	for (int row = 0; row < 424; row++)
	{
		for (int col = 0; col < 512; col++)
		{
			unsigned short* p = (unsigned short*)depth.data;
			unsigned short depthValue = p[row * 512 + col];//16位
			//cout << "depthValue       " << depthValue << endl;
			if (depthValue != -std::numeric_limits<unsigned short>::infinity() && depthValue != -std::numeric_limits<unsigned short>::infinity() && depthValue != 0 && depthValue != 65535)
			{
				// 投影到彩色图上的坐标
				Eigen::Vector3f uv_depth(col, row, 1.0f);                            // !!!p_ir
				//Eigen::Vector3f uv_color = depthValue / 1000.f*R*uv_depth + T / 1000;   // !!!Z_rgb*p_rgb=R*Z_ir*p_ir+T; (除以1000,是为了从毫米变米)
				Eigen::Vector3f uv_color = depthValue / 1000.f*R*uv_depth + (T + T_me) / 1000;//2020.6.23//公式含义:已知深度某一像素坐标及对应深度值,求彩色图对应像素坐标及其彩色值

				int X = static_cast<int>(uv_color[0] / uv_color[2]);                // !!!Z_rgb*p_rgb -> p_rgb,这里为深度图某一像素坐标(col,row)对应的彩色图像素坐标(X,Y)(这里说的彩色图为原始彩色图:1920×1080)
				int Y = static_cast<int>(uv_color[1] / uv_color[2]);                // !!!Z_rgb*p_rgb -> p_rgb
				
			

				//cout << "X:       " << X << "     Y:      " << Y << endl;
				if ((X >= 0 && X < 1920) && (Y >= 0 && Y < 1080))
				{
					if (matrix_NN(X, Y) == 1)//2021.4.28 去除重影程序,计算出来的XY为原大小的RGB图像,只要第二次计算出来和之前计算出的坐标一样就把这个点置零,而不是赋上颜色
					{
						result.data[i * 3] = 0;
						result.data[i * 3 + 1] = 0;
						result.data[i * 3 + 2] = 0;
					}
					else
					{
						matrix_NN(X, Y) = 1;
						//cout << "X:       " << X << "     Y:      " << Y << endl;
						result.data[i * 3] = bgr.data[3 * (Y * 1920 + X)];//1920*1080个点顺次排列,再加上rgb分开来,每个像素三个值,一共1920*1080*3个数字,上面求得深度图坐标(col,row)这个点对应在彩色图中的坐标为(X,Y)通过这3个公式,就能找到这个坐标对应的rgb值
						result.data[i * 3 + 1] = bgr.data[3 * (Y * 1920 + X) + 1];//因为对于深度图col,row是顺序遍历的,所以保存到对齐后的彩色图,直接顺序保存即可
						result.data[i * 3 + 2] = bgr.data[3 * (Y * 1920 + X) + 2];
						//cout << "b:       " << result.data[i * 3] << "     g:      " << result.data[i * 3 + 1] << endl;
					}
				}
				else
				{
					result.data[i * 3] = 0;
					result.data[i * 3 + 1] = 0;
					result.data[i * 3 + 2] = 0;
				}
			}
			else
			{
				result.data[i * 3] = 0;
				result.data[i * 3 + 1] = 0;
				result.data[i * 3 + 2] = 0;
			}
			i++;
			//cout << "i=" << i << endl;
		}
	}
	imwrite("2020-12- 3-20-12- 5-result.png", result);
	thread th2 = std::thread([&]{
		while (true)
		{
			imshow("结果图", result);
			waitKey(1);
		}
	});

	th.join();
	th2.join();
#pragma endregion


	system("pause");
	return 0;
}

原始彩色图像:
请添加图片描述
对齐后的彩色图像:
请添加图片描述

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值