kinect 2的数据获取与深度相机的标定

我需要通过kinect 2获取深度信息 ,进而转化为点云进行点云预处理实现实时三维重构,获取深度相机的内参有利于提高三维重建的精度。要想获取kinect深度相机的内参,首先必须获取深度相机拍摄的图像,由深度相机拍摄的图像有深度图和红外图两种,深度图难以识别,所以我需要过去kinect的红外数据。(kinect 2里面有两个摄像头,一个是彩色相机,一个是深度相机,由于我只需要深度数据所以我只标定深度相机。)

标定原理:张正友标定法原理
标定工具:Matlab

1 Kinect数据获取

数据获取我参考了一位博主的代码,原博客链接:https://blog.csdn.net/jiaojialulu/article/details/53087988
该博客写得非常详细,代码完整,可以直接运行(为了能够保存红外图片,程序我在原基础上加了一行)。

1.1六种数据源

Kinect Data Sources – 6种数据源

  1. ColorFrameSource
    彩色图
  2. InfraredFrameSource
    红外图(16-bit)
  3. DepthFrameSource
    深度图(16-bit,单位:mm)
    kinect采的深度数据是short型,即每个像素深度占2个字节,但是16位中只有12位是有用的,2^12 = 4096,单位是毫米,所以范围是4m
  4. BodyIndexFrameSource
    人物索引图(用一个字节代表人体,最多支持6个人体)
  5. BodyFrameSource
    人体关节图
  6. AudioSource
    声音

1.2完整代码

#include "kinect.h"
#include 
#include   
#include 
#include   
using namespace cv;
using namespace std;

// 安全释放指针
template<class Interface>
inline void SafeRelease(Interface *& pInterfaceToRelease)
{
	if (pInterfaceToRelease != NULL)
	{
		pInterfaceToRelease->Release();
		pInterfaceToRelease = NULL;
	}
}

int main()
{
	// 获取Kinect设备
	IKinectSensor* m_pKinectSensor;
	HRESULT hr;
	hr = GetDefaultKinectSensor(&m_pKinectSensor);
	if (FAILED(hr))
	{
		return hr;
	}

	IMultiSourceFrameReader* m_pMultiFrameReader;
	if (m_pKinectSensor)
	{
		hr = m_pKinectSensor->Open();
		if (SUCCEEDED(hr))
		{
			// 获取多数据源到读取器  
			hr = m_pKinectSensor->OpenMultiSourceFrameReader(
				FrameSourceTypes::FrameSourceTypes_Color |
				FrameSourceTypes::FrameSourceTypes_Infrared |
				FrameSourceTypes::FrameSourceTypes_Depth,
				&m_pMultiFrameReader);
		}
	}

	if (!m_pKinectSensor || FAILED(hr))
	{
		return E_FAIL;
	}
	// 三个数据帧及引用
	IDepthFrameReference* m_pDepthFrameReference;
	IColorFrameReference* m_pColorFrameReference;
	IInfraredFrameReference* m_pInfraredFrameReference;
	IInfraredFrame* m_pInfraredFrame;
	IDepthFrame* m_pDepthFrame;
	IColorFrame* m_pColorFrame;
	// 三个图片格式
	Mat i_rgb(1080, 1920, CV_8UC4);      //注意:这里必须为4通道的图,Kinect的数据只能以Bgra格式传出
	Mat i_depth(424, 512, CV_8UC1);
	Mat i_src_depth(424, 512, CV_16UC1);
	Mat i_ir(424, 512, CV_16UC1);

	UINT16 *depthData = new UINT16[424 * 512];
	IMultiSourceFrame* m_pMultiFrame = nullptr;
	while (true)
	{
		// 获取新的一个多源数据帧
		hr = m_pMultiFrameReader->AcquireLatestFrame(&m_pMultiFrame);
		if (FAILED(hr) || !m_pMultiFrame)
		{
			//cout << "!!!" << endl;
			continue;
		}

		// 从多源数据帧中分离出彩色数据,深度数据和红外数据
		if (SUCCEEDED(hr))
			hr = m_pMultiFrame->get_ColorFrameReference(&m_pColorFrameReference);
		if (SUCCEEDED(hr))
			hr = m_pColorFrameReference->AcquireFrame(&m_pColorFrame);
		if (SUCCEEDED(hr))
			hr = m_pMultiFrame->get_DepthFrameReference(&m_pDepthFrameReference);
		if (SUCCEEDED(hr))
			hr = m_pDepthFrameReference->AcquireFrame(&m_pDepthFrame);
		if (SUCCEEDED(hr))
			hr = m_pMultiFrame->get_InfraredFrameReference(&m_pInfraredFrameReference);
		if (SUCCEEDED(hr))
			hr = m_pInfraredFrameReference->AcquireFrame(&m_pInfraredFrame);

		// color拷贝到图片中
		UINT nColorBufferSize = 1920 * 1080 * 4;
		if (SUCCEEDED(hr))
			hr = m_pColorFrame->CopyConvertedFrameDataToArray(nColorBufferSize, reinterpret_cast<BYTE*>(i_rgb.data), ColorImageFormat::ColorImageFormat_Bgra);

		// depth拷贝到图片中
		if (SUCCEEDED(hr))
		{
			hr = m_pDepthFrame->CopyFrameDataToArray(424 * 512, depthData);
			//for (int i = 0; i < 512 * 424; i++)
			//{
			//  // 0-255深度图,为了显示明显,只取深度数据的低8位
			//  BYTE intensity = static_cast(depthData[i] % 256);
			//  reinterpret_cast(i_depth.data)[i] = intensity;
			//}

			// 实际是16位unsigned int数据
			hr = m_pDepthFrame->CopyFrameDataToArray(424 * 512, reinterpret_cast<UINT16*>(i_src_depth.data));
		}

		// infrared拷贝到图片中
		if (SUCCEEDED(hr))
		{
			hr = m_pInfraredFrame->CopyFrameDataToArray(424 * 512, reinterpret_cast<UINT16*>(i_ir.data));
		}

		Mat i_rgb_resize = i_rgb.clone();       // 缩小方便看
		cv::resize(i_rgb_resize, i_rgb_resize, Size(512, 424));
		// 显示
		imshow("rgb", i_rgb_resize);
		if (waitKey(1) == VK_ESCAPE)
			break;
		imshow("i_src_depth", i_src_depth);
		if (waitKey(1) == VK_ESCAPE)
			break;
		imshow("ir", i_ir);
		if (waitKey(1) == VK_ESCAPE)
			break;
		imwrite("D:\\Document\\biaoding\\infrared20.tif", i_ir);//红外图保存路径吗,这个写入图片需要自己拍一张更改一下图片序号

		// 释放资源
		SafeRelease(m_pColorFrame);
		SafeRelease(m_pDepthFrame);
		SafeRelease(m_pInfraredFrame);
		SafeRelease(m_pColorFrameReference);
		SafeRelease(m_pDepthFrameReference);
		SafeRelease(m_pInfraredFrameReference);
		SafeRelease(m_pMultiFrame);
	}
	// 关闭窗口,设备
	cv::destroyAllWindows();
	m_pKinectSensor->Close();
	std::system("pause");
	return 0;

}

上面这个程序能获取彩色图、深度图和红外图三个种数据类型,我只保存红外图。

2 用openCV自制标定板

参考博客:https://blog.csdn.net/weixin_43053387/article/details/84957042
该博主生成的标定板没达到一边奇数一边偶数的要求(一边奇数一边偶数才能定位准确),我做了简单的修改,代码如下。


#include 
#include 
#include 

using namespace std;
using namespace cv;

int main() {
	//单位转换
	int dot_per_inch = 96;  //我的电脑是96DPI(dot per inch)
	double cm_to_inch = 0.3937; //1cm=0.3937inch
	double inch_to_cm = 2.54;   //1inch = 2.54cm
	double inch_per_dot = 1.0 / 96.0;

	//自定义标定板
	double blockSize_cm = 2.5; //方格尺寸:边长2.5cm的正方形
	int blockNum = 8; 


	int blockSize = (int)(blockSize_cm / inch_to_cm * dot_per_inch);
	cout << blockSize << endl;

	int imageSizeW = blockSize * blockNum;
	int imageSizeH = blockSize * (blockNum-1);//棋盘8×7

	cout << imageSizeW << endl;
	Mat chessBoard(imageSizeW, imageSizeH, CV_8UC3, Scalar::all(0));
	unsigned char color = 0;

	for (int i = 0; i < imageSizeH; i = i + blockSize) {
		color = ~color;
		for (int j = 0; j < imageSizeW; j = j + blockSize) {
			Mat ROI = chessBoard(Rect(i, j, blockSize, blockSize));
			ROI.setTo(Scalar::all(color));
			color = ~color;
		}
	}
	imshow("Chess board", chessBoard);
	imwrite("D:\\Document\\chessBoard2.jpg", chessBoard);
	cvWaitKey(3000);
	return 0;
}

kinect 2的数据获取与深度相机的标定_第1张图片

3 用matlab标定

(1)用上面程序获得20张不同角度不同距离的红外照片
kinect 2的数据获取与深度相机的标定_第2张图片
(2)打开matlab,app>>camera calibrator
kinect 2的数据获取与深度相机的标定_第3张图片
(3)将你获得的图片导入matlab中去
kinect 2的数据获取与深度相机的标定_第4张图片
kinect 2的数据获取与深度相机的标定_第5张图片
这步可能会出现自动删除失真严重的图片,确认就行。
(4)确定每个格子的边长,单位;我的时25mm。
kinect 2的数据获取与深度相机的标定_第6张图片
(5)选择三个径向畸变量和切向基变量,如下图所示,再点击校准。
kinect 2的数据获取与深度相机的标定_第7张图片
(6)计算
kinect 2的数据获取与深度相机的标定_第8张图片
(7)得到焦距(单位:像素)、主点(单位:像素)、畸变系数(无量纲)等多个参数
kinect 2的数据获取与深度相机的标定_第9张图片

你可能感兴趣的:(Kinect,for,Windows,SDK,2.0学习)