前文已经介绍了要学习的Kinectfusion的程序样例,这个样例中ThisApp.cpp和ThisApp.h里是最主要的源程序,所以先从这两个源程序开始学习。
1ThisApp.h
// ThisApp类 本程序的抽象
#pragma once
// ThisApp类
class ThisApp{
// 名字真尼玛长 差评
typedef NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE PROCESSOR_TYPE;//typedef关键字在计算机编程语言中用来为复杂的声明定义简单的别名
public:
// 构造函数
ThisApp();
// 析构函数
~ThisApp();
// 初始化
HRESULT Initialize(HINSTANCE hInstance, int nCmdShow);//声明初始化函数。HRESULT函数返回值,一种简单的数据类型。
// 消息循环
void RunMessageLoop();//声明消息循环函数
// 重置
void ResetReconstruction();//声明重置函数
private:
// 窗口过程函数
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// 初始化Kinect函数
HRESULT init_kinect();
// 检查深度帧函数
void check_depth_frame();
private:
// 窗口句柄
HWND m_hwnd = nullptr;
// Kinect v2 传感器
IKinectSensor* m_pKinect = nullptr;
// 深度帧读取器
IDepthFrameReader* m_pDepthFrameReader = nullptr;
// Kinect Fusion 容积重建
INuiFusionReconstruction* m_pReconstruction = nullptr;
// 深度缓存
UINT16* m_pDepthImagePixelBuffer = nullptr;
// 平滑前的浮点深度帧
NUI_FUSION_IMAGE_FRAME* m_pDepthFloatImage = nullptr;
// 平滑后的浮点深度帧
NUI_FUSION_IMAGE_FRAME* m_pSmoothDepthFloatImage = nullptr;
// 点云 Fusion 图像帧
NUI_FUSION_IMAGE_FRAME* m_pPointCloud = nullptr;
// 表面 Fusion 图像帧
NUI_FUSION_IMAGE_FRAME* m_pSurfaceImageFrame = nullptr;
// 法线 Fusion 图像帧
NUI_FUSION_IMAGE_FRAME* m_pNormalImageFrame = nullptr;
// 映射器
ICoordinateMapper* m_pMapper = nullptr;
// 深度空间点
DepthSpacePoint* m_pDepthDistortionMap = nullptr;
// 深度失真
UINT* m_pDepthDistortionLT = nullptr;
// 彩色临帧事件 不能用nullptr初始化 蛋疼
WAITABLE_HANDLE m_hDepthFrameArrived = 0;
// 坐标映射改变事件
WAITABLE_HANDLE m_coordinateMappingChangedEvent = 0;
// Kinect Fusion 相机转换
Matrix4 m_worldToCameraTransform;
// 默认Kinect Fusion 世界到容积转换
Matrix4 m_defaultWorldToVolumeTransform;
// Kinect Fusion 容积重建参数
NUI_FUSION_RECONSTRUCTION_PARAMETERS m_reconstructionParams;
// Kinect Fusion 相机参数
NUI_FUSION_CAMERA_PARAMETERS m_cameraParameters;
// 渲染器
ImageRenderer m_ImagaRenderer;
// 图像宽度
UINT m_cDepthWidth = NUI_DEPTH_RAW_WIDTH;
// 图像高度
UINT m_cDepthHeight = NUI_DEPTH_RAW_HEIGHT;
// Fusion处理器类型
ThisApp::PROCESSOR_TYPE m_processorType;
// 设备索引 处理设备使用默认的(-1)
int m_deviceIndex = -1;
//
USHORT m_cMaxIntegrationWeight = NUI_FUSION_DEFAULT_INTEGRATION_WEIGHT;
// 保留
USHORT unused = 0;
// 计时器
PrecisionTimer m_timer;
// 深度最低阈值
float m_fMinDepthThreshold = NUI_FUSION_DEFAULT_MINIMUM_DEPTH;
// 深度最远阈值
float m_fMaxDepthThreshold = NUI_FUSION_DEFAULT_MAXIMUM_DEPTH;
};
程序段的注释非常详细,ThisApp类包含一个宏定义和共有函数成员、私有函数成员、私有数据成员三部分。这里需要了解一下c++里面类定义的格式,除了构造函数和析构函数声明没有函数类型名,其他函数声明时都有函数类型名,数据声明时前面都有数据类型名。初学c的时候我们接触的数据类型名主要是int,float,double等这些,但我们发现这里出现了好多数据类型名,之所有有那么多数据类型名,那是因为类和结构体也可以看作是自定义的数据类型,定义了多少类和结构体就会有多少数据类型,在vs2017中可以通过查看定义(选中按F12)来查看该类或结构体(例如IKinectSensor,就是Kinect.h中定义的一个继承结构体)。
2ThisApp.cpp—构造函数和析构函数
头文件是类的声明,具体实现功能还是要继续学习cpp源程序。第一部分源程序定义了ThisApp的构造函数和虚构函数。
#include "stdafx.h"
#include "included.h"
#define TITLE L"Title"
#define WNDWIDTH 1024
#define WNDHEIGHT 768
#define lengthof(a) sizeof(a)/sizeof(*a)
void SetIdentityMatrix(Matrix4 &mat)//构造4×4单位矩阵函数,Matrix4是含有16个浮点型数据的结构体,关于typedef struct见下面注释1
{
mat.M11 = 1.f; mat.M12 = 0.f; mat.M13 = 0.f; mat.M14 = 0.f;
mat.M21 = 0.f; mat.M22 = 1.f; mat.M23 = 0.f; mat.M24 = 0.f;
mat.M31 = 0.f; mat.M32 = 0.f; mat.M33 = 1.f; mat.M34 = 0.f;
mat.M41 = 0.f; mat.M42 = 0.f; mat.M43 = 0.f; mat.M44 = 1.f;
}
// ThisApp类成员函数(重置函数)定义
void ThisApp::ResetReconstruction(){
m_pReconstruction->ResetReconstruction(&m_worldToCameraTransform, &m_defaultWorldToVolumeTransform);//“->”(见注释2)代表指向结构成员,ResetReconstruction是INuiFusionReconstruction类(见注释3)的成员函数
//m_pReconstruction->ResetReconstruction(nullptr, nullptr);
}
// ThisApp构造函数
ThisApp::ThisApp(){
// 重建参数
m_reconstructionParams.voxelsPerMeter = 256.f; //m_reconstructionParams是在ThisApp.h中定义的NUI_FUSION_RECONSTRUCTION_PARAMETERS结构体(见注释4)的对象
m_reconstructionParams.voxelCountX = 384;
m_reconstructionParams.voxelCountY = 384;
m_reconstructionParams.voxelCountZ = 384;
// 使用AMP进行运算
m_processorType = NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE_AMP;//NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE_AMP查看NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE枚举类型(见注释5)
// 设置为单位矩阵
SetIdentityMatrix(m_worldToCameraTransform);
SetIdentityMatrix(m_defaultWorldToVolumeTransform);
// 相机内部参数。m_cameraParameters是在ThisApp.h中定义的NUI_FUSION_CAMERA_PARAMETERS结构体(见注释6)的对象
m_cameraParameters.focalLengthX = NUI_KINECT_DEPTH_NORM_FOCAL_LENGTH_X;//NUI_KINECT_DEPTH_NORM_FOCAL_LENGTH_X是宏定义,用焦点x值/512(深度图像的宽)得到
m_cameraParameters.focalLengthY = NUI_KINECT_DEPTH_NORM_FOCAL_LENGTH_Y;//焦点y值/424(深度图像的高)
m_cameraParameters.principalPointX = NUI_KINECT_DEPTH_NORM_PRINCIPAL_POINT_X;//主点x值/512
m_cameraParameters.principalPointY = NUI_KINECT_DEPTH_NORM_PRINCIPAL_POINT_Y;//主点y值/424
}
// ThisApp析构函数
ThisApp::~ThisApp(){
// 销毁事件
if (m_hDepthFrameArrived && m_pDepthFrameReader){
m_pDepthFrameReader->UnsubscribeFrameArrived(m_hDepthFrameArrived);//取消彩色临帧事件,UnsubscribeFrameArrived(见注释7)是IDepthFrameReader(见注释7)的成员函数
m_hDepthFrameArrived = 0;
}
// 释放DepthFrameReader
SafeRelease(m_pDepthFrameReader);//SafeRelease用来释放指针。查看定义发现模板类的用法template<class Interface>(见注释8)
// 清理Fusion数据
SafeRelease(m_pReconstruction);
SafeRelease(m_pMapper);
// 清理Fusion图像帧
SAFE_FUSION_RELEASE_IMAGE_FRAME(m_pSurfaceImageFrame);//m_pSurfaceImageFrame是在ThisApp.h中定义的NUI_FUSION_IMAGE_FRAME结构体(见注释9)的对象
SAFE_FUSION_RELEASE_IMAGE_FRAME(m_pPointCloud);//SAFE_FUSION_RELEASE_IMAGE_FRAME查看定义是起释放参数的作用
SAFE_FUSION_RELEASE_IMAGE_FRAME(m_pDepthFloatImage);
SAFE_FUSION_RELEASE_IMAGE_FRAME(m_pSmoothDepthFloatImage);
SAFE_FUSION_RELEASE_IMAGE_FRAME(m_pNormalImageFrame);
// 清理缓存
SAFE_DELETE_ARRAY(m_pDepthImagePixelBuffer);//SAFE_DELETE_ARRAY查看定义是起清除的作用
SAFE_DELETE_ARRAY(m_pDepthDistortionMap);//m_pDepthDistortionMap是在ThisApp.h中定义的 DepthSpacePoint结构体(见注释10)的对象
SAFE_DELETE_ARRAY(m_pDepthDistortionLT);
// 优雅地关闭Kinect
if (m_pKinect){
m_pKinect->Close();
}
SafeRelease(m_pKinect);//释放kinect
}
注释1:struct和typedef struct
typedef struct就是给这个结构体取了一个别名
举例:
typedef struct tagMyStruct
{
int iNum;
long lLength;
} MyStruct;
上面的tagMyStruct是标识符,MyStruct是变量类型(相当于(int,char等))。
这语句实际上完成两个操作:
1) 定义一个新的结构类型
struct tagMyStruct
{
int iNum;
long lLength;
};
分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,不论是否有typedefstruct 关键字和tagMyStruct一起,构成了这个结构类型,这个结构都存在。
我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。
2) typedef为这个新的结构起了一个名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;
因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。
注释2:C++中的.和::和:和->的区别
在学习C++的过程中我们经常会用到.和::和:和->,在此整理一下这些常用符号的区别。
1、A.B则A为对象或者结构体;
2、A->B则A为指针,->是成员提取,A->B是提取A中的成员B,A只能是指向类、结构、联合的指针;
3、::是作用域运算符,A::B表示作用域A中的名称B,A可以是名字空间、类、结构;
4、:一般用来表示继承;