采用Matlab标定箱对kinect2.0标定。
1.生成标定板,有标定板的自动忽略这一步。
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
int main() {
//单位转换
int dot_per_inch = 96;
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);
return 0;
}
2.数据采集
调用Kinect摄像头对标定板进行拍摄,并保存为大小相同的图片。
#include "kinect.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2\opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
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<BYTE>(depthData[i] % 256);
// reinterpret_cast<BYTE*>(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));
// 显示
char key_board = waitKey(10);
//imshow("rgb", i_rgb_resize);
//if (key_board == 'w')
// break; //彩色图像
//imshow("i_src_depth", i_src_depth);
//if (waitKey(1) == VK_ESCAPE)
// break; //深度图像
imshow("ir", i_ir);
if (key_board == 'w')
// break; //红外图像
imwrite("D:\\Document\\biaoding\\infrared15.png", 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;
}
3.打开Matlab(2020a),在APP中找到camera calibrator
4.将拍摄的图像添加到matlab中。
输入棋盘格大小
在添加图片后会自动进行角点检测
5.点击calibrate进行标定
6.标定结果分析
横坐标是每张图像,纵坐标是重投影误差(不理解的可以自行百度~),在标定中普遍认为重投影误差小于0.5时,证明标定精度高。由上图可知,15张图平均误差为0.22
7.点击export camera parameters,输出内外参数
8.上面各个参数都代表什么意思就不一一写了,可以参考博客
(https://blog.csdn.net/JennyBi/article/details/100155519)
9.个人学习,并不商用。有很多东西也是之前从博客里看到的,现在已经找不到出处了,所以记录下来方便自己学习。如有侵权,立即删除。