基于Kinect 2.0深度摄像头的三维重建

刚今天验收的实验,记录一下。

是比较基础的三维重建内容。

算是三维重建入门。

系统:windows

环境:visual studio 2013

语言:c++

相关:OpenCV 2、Kinect SDK 2.0、PCL库

内容:

  使用Kinect 2.0拍摄获取深度图,将彩色图与深度图配准生成点云;

  然后每次拍摄得到的点云用ICP算法进行融合,形成完整点云(每次拍摄仅做微小偏移);

  之后稍微对点云做了些许处理;

  还添加了回档的功能;

声明:

  有挺多借鉴博客与参考资料的,太多懒得写,假装忘了~

原理:(以下不对变量作用作解释,具体可参照变量名猜测,完整代码最后给出)

  流程图如下

 

  1.关于彩色图与深度图的配准,官方文档给出了如下3个坐标系:

  Kinect中总共有着3种坐标空间:

    1.相机空间(Camera space):拥有三个坐标轴,假设kinect面朝正前方,那么X轴向左递增,Y轴向上递增,Z轴向前递增。

    2.深度空间(Depth space):拥有三个坐标轴,其中x、y分别是深度图中像素的位置,z轴为像素的深度值。

    3.色彩空间(Color space):拥有两个坐标轴,其中x、y分别是彩色图像中像素的位置。

  由此,如果知道参数其实自己也能算,但是kinect事实上已经给出了函数。如下图所示

 

  下图为单次生成的点云:

 

  2.关于ICP算法点云配准:

  它的本质思路如下:

    1.计算两个点云之间的匹配关系;

    2.计算旋转平移矩阵;

    3.旋转平移源点云。

    4.如果误差达到要求或者迭代次数够了,则退出,否则回到第一步。

  具体实现可以参照原论文。

  这里使用的是PCL库里自带的实现

  接下来几幅图是点云融合过程(两个点云,慢慢融合)

融合效果:

 

  3.点云处理,都是水水的实验性的处理,

    1.第一种是简单的按照y轴进行颜色变换

    2.第二种是根据高度生成水面

    3.第三种是三角网格化

    详情见代码

代码:

 

#ifndef KINECT_FXXL_H
#define KINECT_FXXL_H

#include <Kinect.h>

#endif
KinectFxxL.h
#include <Kinect.h>
#include "KinectFxxL.h"
KinectFxxL.cpp
#ifndef TEST_FXXL_H
#define TEST_FXXL_H

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/opencv.hpp>  

using namespace std;
using namespace cv;

typedef unsigned short UINT16;

void showImage(Mat tmpMat, string windowName = "tmpImage");

Mat convertDepthToMat(const UINT16* pBuffer, int width, int height);

string convertIntToString(int num);

#endif
OpenCVFxxL.h
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/opencv.hpp>  

#include "OpenCVFxxL.h"

#define pause system("pause")

typedef unsigned short UINT16;

using namespace std;
using namespace cv;

void showImage(Mat tmpMat, string windowName)
{
    imshow(windowName, tmpMat);
    if (cvWaitKey(0) == 27)        //ESC键值为27
        return;
}

Mat convertDepthToMat(const UINT16* pBuffer, int width, int height)
{
    Mat ret;
    uchar* pMat;
    ret = Mat(height, width, CV_8UC1);
    pMat = ret.data;    //uchar类型的指针,指向Mat数据矩阵的首地址
    for (int i = 0; i < width*height; i++)
        *(pMat + i) = *(pBuffer + i);
    return ret;
}

string convertIntToString(int num)
{
    string ret = "";
    if (num < 0) return puts("the function only fits positive int number"), "";
    while (num) ret += (num % 10) + '0', num /= 10;
    reverse(ret.begin(), ret.end());
    if (ret.size() == 0) ret += "0";
    return ret;
}
OpenCVFxxL.cpp
#ifndef PCL_FXXL_H
#define PCL_FXXL_H

#include <time.h>
#include <stdlib.h>
#include <map>
#include <time.h>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <thread>
#include <mutex>
#include <queue>
#include <boost/make_shared.hpp>                //boost指针相关头文件
#include <pcl/io/io.h>  
#include <pcl/visualization/cloud_viewer.h>  
#include <pcl/point_types.h>                    //点类型定义头文件
#include <pcl/point_cloud.h>                    //点云类定义头文件
#include <pcl/point_representation.h>            //点表示相关的头文件
#include <pcl/io/pcd_io.h>                        //PCD文件打开存储类头文件
#include <pcl/filters/voxel_grid.h>                //用于体素网格化的滤波类头文件 
#include <pcl/filters/filter.h>                    //滤波相关头文件
#include <pcl/features/normal_3d.h>                //法线特征头文件
#include <pcl/registration/icp.h>                //ICP类相关头文件
#include <pcl/registration/icp_nl.h>            //非线性ICP 相关头文件
#include <pcl/registration/transforms.h>        //变换矩阵类头文件
#include <pcl/visualization/pcl_visualizer.h>    //可视化类头文件
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/surface/gp3.h>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/opencv.hpp>
#include <cv.h>
#include "OpenCVFxxL.h"

#define shapeCloud(x) x->width=1,x->height=x->size()
#define GAP_NORMAL 0.001
#define GAP_TRANSPARENT 0.005
#define random(x) (rand()%x)

using namespace cv;
using namespace std;
using namespace pcl;
using pcl::visualization::PointCloudColorHandlerGenericField;
using pcl::visualization::PointCloudColorHandlerCustom;

typedef PointXYZRGBA PointT;
typedef PointCloud<PointT> PointCloudT;
typedef PointXYZ PointX;
typedef PointCloud<PointX> PointCloudX;
typedef PointCloud<PointNormal> PointCloudWithNormals;

extern boost::shared_ptr<pcl::visualization::PCLVisualizer> visualizer;
extern bool iterationFlag_visualizer;

void makeBall(PointCloudT::Ptr cloud, double x_p, double y_p, double z_p, int r_color, int g_color, int b_color, double radius, double gap = GAP_NORMAL);

void makeWall(PointCloudT::Ptr cloud, double min_x, double max_x, double min_y, double max_y, double min_z, double max_z, int r_color, int g_color, int b_color, double gap = GAP_TRANSPARENT);

void getTriangles(const PointCloudT::Ptr cloud, PolygonMesh &triangles);

void getExCloud(const PointCloudT::Ptr cloud, PointCloudT::Ptr exCloud);

void filterCloud(PointCloudX::Ptr cloud, double size = 0.05);

void filterCloud(PointCloudT::Ptr cloud, double size = 0.05);

void showPolygonMesh(PolygonMesh polygonMesh);

void showPointCloudX(PointCloudX::Ptr cloud0);

void showPointCloudT(PointCloudT::Ptr cloud0, PointCloudT::Ptr cloud1 = NULL);

void showTransform(const PointCloudWithNormals::Ptr targetCloud, const PointCloudWithNormals::Ptr sourceCloud);

void keyBoardEventOccurred(const pcl::visualization::KeyboardEvent& event, void *nothing);

void initVisualizer();

void cloudMerge(const PointCloudT::Ptr cloudSrc, const PointCloudT::Ptr cloudTgt, PointCloudT::Ptr cloudRet, Eigen::Matrix4f &transformingMatrix, bool flag_slow, bool filterFlag = true);

class PointRepresentationT :public PointRepresentation<PointNormal>
{
    using PointRepresentation<PointNormal>::nr_dimensions_;

public:
    PointRepresentationT();

    virtual void copyToFloatArray(const PointNormal &p, float *out) const;

};

#endif
PCLFxxL.h
#include <time.h>
#include <stdlib.h>
#include <map>
#include <time.h>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <thread>
#include <mutex>
#include <queue>
#include <boost/make_shared.hpp>                //boost指针相关头文件
#include <pcl/visualization/cloud_viewer.h>  
#include <pcl/point_types.h>                    //点类型定义头文件
#include <pcl/point_cloud.h>                    //点云类定义头文件
#include <pcl/point_representation.h>            //点表示相关的头文件
#include <pcl/io/io.h>  
#include <pcl/io/pcd_io.h>                        //PCD文件打开存储类头文件
#include <pcl/filters/voxel_grid.h>                //用于体素网格化的滤波类头文件 
#include <pcl/filters/filter.h>                    //滤波相关头文件
#include <pcl/features/normal_3d.h>                //法线特征头文件
#include <pcl/registration/icp.h>                //ICP类相关头文件
#include <pcl/registration/icp_nl.h>            //非线性ICP 相关头文件
#include <pcl/registration/transforms.h>        //变换矩阵类头文件
#include <pcl/visualization/pcl_visualizer.h>    //可视化类头文件
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/surface/gp3.h>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/opencv.hpp>
#include <cv.h>

#include "OpenCVFxxL.h"
#include "PCLFxxL.h"

boost::shared_ptr<pcl::visualization::PCLVisualizer> visualizer(new pcl::visualization::PCLVisualizer("fxxl"));
bool iterationFlag_visualizer;

void makeBall(PointCloudT::Ptr cloud, double x_p, double y_p, double z_p, int r_color, int g_color, int b_color, double radius, double gap)
{
    for (double x = x_p - radius; x <= x_p + radius; x += gap)
    {
        double tmp0 = sqrt(radius*radius - (x - x_p)*(x - x_p));
        for (double y = y_p - tmp0; y <= y_p + tmp0; y += gap)
        {
            double z = z_p + sqrt(radius*radius - (x - x_p)*(x - x_p) - (y - y_p)*(y - y_p));
            PointT tmpPoint;
            tmpPoint.x = x, tmpPoint.y = y, tmpPoint.z = z, tmpPoint.r = r_color, tmpPoint.g = g_color, tmpPoint.b = b_color;
            cloud->points.push_back(tmpPoint);
        }
    }
    cout << cloud->points.size() << endl;
}


void makeWall(PointCloudT::Ptr cloud, double min_x, double max_x, double min_y, double max_y, double min_z, double max_z, int r_color, int g_color, int b_color, double gap)
{
    for (double x = min_x; x <= max_x; x += gap)
        for (double y = min_y; y <= max_y; y += gap)
            for (double z = min_z; z <= max_z; z += gap)
            {
                PointT tmpPoint;
                tmpPoint.x = x, tmpPoint.y = y, tmpPoint.z = z, tmpPoint.r = r_color, tmpPoint.g = g_color, tmpPoint.b = b_color;
                cloud->points.push_back(tmpPoint);
            }
}

void getTriangles(const PointCloudT::Ptr cloud, PolygonMesh &triangles)
{
    PointCloudX::Ptr tmpCloud(new PointCloudX);
    tmpCloud->clear();
    for (int i = 0; i < cloud->points.size(); i++)
    {
        PointX tmpPointX;
        tmpPointX.x = cloud->points[i].x, tmpPointX.y = cloud->points[i].y, tmpPointX.z = cloud->points[i].z;
        tmpCloud->points.push_back(tmpPointX);
    }
    shapeCloud(tmpCloud);
    filterCloud(tmpCloud, 0.04);
    NormalEstimation<PointX, Normal> normalEstimation;
    PointCloud<Normal>::Ptr normalCloud(new PointCloud<Normal>);
    search::KdTree<PointX>::Ptr kdTree(new search::KdTree<PointX>);
    kdTree->setInputCloud(tmpCloud);
    normalEstimation.setInputCloud(tmpCloud);
    normalEstimation.setSearchMethod(kdTree);
    normalEstimation.setKSearch(20);
    normalEstimation.compute(*normalCloud);

    PointCloud<PointNormal>::Ptr pointWithNormalCloud(new PointCloud<PointNormal>);
    pcl::concatenateFields(*tmpCloud, *normalCloud, *pointWithNormalCloud);
    search::KdTree<PointNormal>::Ptr kdTree2(new search::KdTree<PointNormal>);
    kdTree2->setInputCloud(pointWithNormalCloud);

    GreedyProjectionTriangulation<PointNormal> gp3;

    gp3.setSearchRadius(0.24);
    gp3.setMu(2.5);
    gp3.setMaximumNearestNeighbors(100);                        //邻近点阈值
    gp3.setMaximumSurfaceAngle(M_PI / 4);                        //45度;两点的法向量角度差大于此值,这两点将不会连接成三角形
    gp3.setMinimumAngle(M_PI / 18);                                //三角形的最小角度
    gp3.setMaximumAngle(2 * M_PI / 3);
    gp3.setNormalConsistency(false);
    gp3.setInputCloud(pointWithNormalCloud);
    gp3.setSearchMethod(kdTree2);
    gp3.reconstruct(triangles);

//    vector<int> partIDs = gp3.getPartIDs();
//    vector<int> states = gp3.getPointStates();
}

void getExCloud(const PointCloudT::Ptr cloud, PointCloudT::Ptr exCloud)
{
    string op;
    puts("\nOwO\ninput:\n    1.ex1: transform ex1;\n    2.ex2: transform ex2.\nOwO\n");
    cin >> op;
    if (op.compare("ex1") == 0)
    {
        exCloud->points.clear(), *exCloud += *cloud, shapeCloud(exCloud);
        double max_x, min_x, max_y, min_y, max_z, min_z, colorStep_y, tmpColorValue;
        max_x = max_y = max_z = -1e9 - 44, min_x = min_y = min_z = 1e9 + 44;
        for (int i = 0; i < exCloud->points.size(); i++)
            max_y = max(max_y, 1.0*exCloud->points[i].y), min_y = min(min_y, 1.0*exCloud->points[i].y);
        colorStep_y = 255.0 / (max_y - min_y);
        for (int i = 0; i < exCloud->points.size(); i++)
        {
            tmpColorValue = (exCloud->points[i].y - min_y)*colorStep_y;
            exCloud->points[i].r = tmpColorValue, exCloud->points[i].g = tmpColorValue*2.0 / 3, exCloud->points[i].b = 0;
        }
        shapeCloud(exCloud);
    }
    else if (op.compare("ex2") == 0)
    {
        exCloud->clear(), *exCloud += *cloud, shapeCloud(exCloud);
        const int r_color0 = 12, g_color0 = 74, b_color0 = 82;
        double max_x, min_x, max_y, min_y, max_z, min_z, colorStep_z, tmpColorValue, y_surface;
        max_x = max_y = max_z = -1e9 - 44, min_x = min_y = min_z = 1e9 + 44;
        for (int i = 0; i < exCloud->points.size(); i++)
        {
            max_x = max(max_x, 1.0*exCloud->points[i].x), min_x = min(min_x, 1.0*exCloud->points[i].x);
            max_y = max(max_y, 1.0*exCloud->points[i].y), min_y = min(min_y, 1.0*exCloud->points[i].y);
            max_z = max(max_z, 1.0*exCloud->points[i].z), min_z = min(min_z, 1.0*exCloud->points[i].z);
        }
        y_surface = min_y + (max_y - min_y) / 3.0 * 2;
        makeWall(exCloud, min_x, min_x, min_y, y_surface, min_z, max_z, r_color0, g_color0, b_color0);
        makeWall(exCloud, max_x, max_x, min_y, y_surface, min_z, max_z, r_color0, g_color0, b_color0);
        makeWall(exCloud, min_x, max_x, min_y, min_y, min_z, max_z, r_color0, g_color0, b_color0);
        makeWall(exCloud, min_x, max_x, min_y, y_surface, min_z, min_z, r_color0, g_color0, b_color0);
        makeWall(exCloud, min_x, max_x, min_y, y_surface, max_z, max_z, r_color0, g_color0, b_color0);
        Mat imageMat_water = imread("res\\water_surface.jpg");
//        showImage(imageMat_water);
        double x_image = imageMat_water.rows - 4, z_image = imageMat_water.cols - 4, x_cloud = max_x - min_x, z_cloud = max_z - min_z;
        if (z_image / x_image > z_cloud / x_cloud)
            z_image = x_image * (z_cloud / x_cloud);
        else x_image = z_image / (z_cloud / x_cloud);
        double step_x = x_image / x_cloud, step_z = z_image / z_cloud;
        for (double x = min_x; x <= max_x; x += GAP_NORMAL)
            for (double z = min_z; z <= max_z; z += GAP_NORMAL)
            {
                PointT tmpPoint;
                int x_tmp = (int)(step_x*(x - min_x)), z_tmp = (int)(step_z*(z - min_z));
                x_tmp = max(0, x_tmp), x_tmp = min(imageMat_water.rows - 1, x_tmp), z_tmp = max(0, z_tmp), z_tmp = min(imageMat_water.cols - 1, z_tmp);
                tmpPoint.x = x, tmpPoint.y = y_surface, tmpPoint.z = z;
                tmpPoint.r = imageMat_water.at<Vec3b>(x_tmp, z_tmp)[2];
                tmpPoint.g = imageMat_water.at<Vec3b>(x_tmp, z_tmp)[1];
                tmpPoint.b = imageMat_water.at<Vec3b>(x_tmp, z_tmp)[0];
                exCloud->points.push_back(tmpPoint);
            }
        shapeCloud(exCloud);
    }
    else if (op.compare("ex3") == 0)
    {
        puts("\nOAO\ninvalid input, retry please\nOAO\n");
        getExCloud(cloud, exCloud);
/*        
        srand((int)time(0));
        const int r_color0 = 204, g_color0 = 207, b_color0 = 190, r_color1 = 94, g_color1 = 87, b_color1 = 46, r_color2 = 22, g_color2 = 35, b_color2 = 44, r_colorBas = 255, g_colorBas = 223, b_colorBas = 178;
        const int rateBound_color0 = 14, rateBound_color1 = 70, rateBound_color2 = 100,rateBound_colorBas=200;
        double max_x, min_x, max_y, min_y, max_z, min_z, colorStep_z, tmpColorValue, z_surface;
        max_x = max_y = max_z = -1e9 - 44, min_x = min_y = min_z = 1e9 + 44;
        for (int i = 0; i < exCloud->points.size(); i++)
        {
            max_x = max(max_x, 1.0*exCloud->points[i].x), min_x = min(min_x, 1.0*exCloud->points[i].x);
            max_y = max(max_y, 1.0*exCloud->points[i].y), min_y = min(min_y, 1.0*exCloud->points[i].y);
            max_z = max(max_z, 1.0*exCloud->points[i].z), min_z = min(min_z, 1.0*exCloud->points[i].z);
        }
        for (int i = 0; i < exCloud->points.size(); i++)
            exCloud->points[i].r = r_colorBas, exCloud->points[i].g = g_colorBas, exCloud->points[i].b = b_colorBas;
        int tmpSize_exCloud = exCloud->points.size();
        for (int i = 0; i < tmpSize_exCloud; i++)
            makeBall(exCloud, exCloud->points[i].x, exCloud->points[i].y, exCloud->points[i].z, r_colorBas, g_colorBas, b_colorBas, random(100000) / 100000.0*0.02);
        map<double, bool> mp;    mp.clear();
        const double sed0 = 16123512.0, sed1 = 743243.0, sed2 = 6143134.0;
        const double x_sun=0, y_sun=max_y*1.74, z_sun=0;
        vector<double> energy;    energy.clear();
        double k0, k1, k2, ktmp, kdis;
        for (int i = 0; i < exCloud->points.size(); i++)
        {
            k0 = x_sun - exCloud->points[i].x, k1 = y_sun - exCloud->points[i].y, k2 = z_sun - exCloud->points[i].z;
            kdis = sqrt(k0*k0 + k1*k1 + k2*k2), k0 /= kdis, k1 /= kdis, k2 /= kdis;
            ktmp = sed0*(int)(k0 * 2000) + sed1*(int)(k1 * 2000) + sed2*(int)(k2 * 2000);
            if (mp[ktmp]) energy.push_back(0);
            else
            {
                exCloud->points[i].r = r_color0, exCloud->points[i].g = g_color0, exCloud->points[i].b = b_color0;
                energy.push_back(1 / (kdis*kdis*kdis));
            } 
            mp[ktmp] = 1;
        }
        shapeCloud(exCloud);
*/
    }
    else
    {
        puts("\nOAO\ninvalid input, retry please\nOAO\n");
        getExCloud(cloud, exCloud);
    }
}

void filterCloud(PointCloudX::Ptr cloud, double size)
{
    VoxelGrid<PointX> voxelGrid;
    voxelGrid.setLeafSize(size, size, size);
    voxelGrid.setInputCloud(cloud), voxelGrid.filter(*cloud);
    printf("cloud size now : %d\n", cloud->size());
}

void filterCloud(PointCloudT::Ptr cloud, double size)
{
    VoxelGrid<PointT> voxelGrid;
    voxelGrid.setLeafSize(size, size, size);
    voxelGrid.setInputCloud(cloud), voxelGrid.filter(*cloud);
    printf("cloud size now : %d\n", cloud->size());
}

void showPolygonMesh(PolygonMesh polygonMesh)
{
    visualizer->addPolygonMesh(polygonMesh, "PolygonMesh0");
//    visualizer->addCoordinateSystem(1.0);
//    visualizer->initCameraParameters();    
    iterationFlag_visualizer = false;
    while (!iterationFlag_visualizer) visualizer->spinOnce();
    visualizer->removePolygonMesh("PolygonMesh0");
}

void showPointCloudX(PointCloudX::Ptr cloud0)
{
    visualizer->addPointCloud(cloud0, "Cloud0");
    iterationFlag_visualizer = false;
    while (!iterationFlag_visualizer) visualizer->spinOnce();
    visualizer->removePointCloud("Cloud0");
}


void showPointCloudT(PointCloudT::Ptr cloud0, PointCloudT::Ptr cloud1)
{
    visualizer->addPointCloud(cloud0, "Cloud0");
    if (cloud1 != NULL) visualizer->addPointCloud(cloud1, "Cloud1");
    iterationFlag_visualizer = false;
    while (!iterationFlag_visualizer) visualizer->spinOnce();
    visualizer->removePointCloud("Cloud0");
    if (cloud1 != NULL) visualizer->removePointCloud("Cloud1");
}

void showTransform(const PointCloudWithNormals::Ptr targetCloud, const PointCloudWithNormals::Ptr sourceCloud)
{
    PointCloudColorHandlerGenericField<PointNormal> colorHandler_target(targetCloud, "curvature");
    if (!colorHandler_target.isCapable()) PCL_WARN("colorHandler_target error~");
    PointCloudColorHandlerGenericField<PointNormal> colorHandler_source(sourceCloud, "curvature");
    if (!colorHandler_source.isCapable()) PCL_WARN("colorHandler_source error~");
    visualizer->addPointCloud(targetCloud, colorHandler_target, "targetCloud");
    visualizer->addPointCloud(sourceCloud, colorHandler_source, "sourceCloud");
    iterationFlag_visualizer = false;
    while (!iterationFlag_visualizer) visualizer->spinOnce();
    visualizer->removePointCloud("targetCloud");
    visualizer->removePointCloud("sourceCloud");
}

void keyBoardEventOccurred(const pcl::visualization::KeyboardEvent& event, void *nothing)
{
    if (event.getKeySym() == "space" && event.keyDown())
        iterationFlag_visualizer = true;
}

void initVisualizer()
{
    visualizer->registerKeyboardCallback(&keyBoardEventOccurred, (void*)NULL);
    visualizer->setBackgroundColor(246.0 / 255, 175.0 / 255, 245.0 / 255);
//    visualizer->setBackgroundColor(255.0 / 255, 255.0 / 255, 255.0 / 255);
}

// cloudRet 为 cloudTgt 反向转到与 cloudSrc 匹配后得到的点云
// transformingMatrix 为 cloudTgt 反向转到与 cloudSrc 匹配的时的矩阵 
void cloudMerge(const PointCloudT::Ptr cloudSrc, const PointCloudT::Ptr cloudTgt, PointCloudT::Ptr cloudRet, Eigen::Matrix4f &transformingMatrix, bool flag_slow, bool filterFlag)
{
    PointCloudT::Ptr src(new PointCloudT);
    PointCloudT::Ptr tgt(new PointCloudT);
    src->clear(), tgt->clear();
    *src += *cloudSrc, *tgt += *cloudTgt;
    if (filterFlag)
        filterCloud(src), filterCloud(tgt);
    printf("final size: %d %d \n", src->size(), tgt->size());
    PointCloudWithNormals::Ptr src_pointsWithNormals(new PointCloudWithNormals);
    PointCloudWithNormals::Ptr tgt_pointsWithNormals(new PointCloudWithNormals);
    NormalEstimation<PointT, PointNormal> normalEstimation;
    search::KdTree<PointT>::Ptr kdtree(new search::KdTree<PointT>());
    normalEstimation.setSearchMethod(kdtree);
    normalEstimation.setKSearch(30);
    normalEstimation.setInputCloud(src), normalEstimation.compute(*src_pointsWithNormals), copyPointCloud(*src, *src_pointsWithNormals);
    normalEstimation.setInputCloud(tgt), normalEstimation.compute(*tgt_pointsWithNormals), copyPointCloud(*tgt, *tgt_pointsWithNormals);

    //配准
    IterativeClosestPointNonLinear<PointNormal, PointNormal> reg;
    reg.setTransformationEpsilon(1e-6);
    reg.setMaxCorrespondenceDistance(0.1);                            //对应点最大距离0.1m
    float tmpFloatValueArray[4] = { 1.0, 1.0, 1.0, 1.0 };
    PointRepresentationT pointRepresentationT;
    pointRepresentationT.setRescaleValues(tmpFloatValueArray);
    reg.setPointRepresentation(boost::make_shared<const PointRepresentationT>(pointRepresentationT));
    reg.setInputCloud(src_pointsWithNormals);
    reg.setInputTarget(tgt_pointsWithNormals);

    if (flag_slow)
    {
        string op;
        reg.setMaximumIterations(2);

        Eigen::Matrix4f fin, prev, inv;
        fin = Eigen::Matrix4f::Identity();                                //单位矩阵
        PointCloudWithNormals::Ptr tmpCloud = src_pointsWithNormals;
        for (int i = 0;; i++)
        {
            PCL_INFO("No. %d\n", i);
            src_pointsWithNormals = tmpCloud, reg.setInputCloud(src_pointsWithNormals);
            reg.align(*tmpCloud);
            fin = reg.getFinalTransformation()*fin;
            if (i>0 && fabs((reg.getLastIncrementalTransformation() - prev).sum()) < reg.getTransformationEpsilon())
                reg.setMaxCorrespondenceDistance(reg.getMaxCorrespondenceDistance() - 0.001);
            prev = reg.getLastIncrementalTransformation();
            showTransform(tgt_pointsWithNormals, src_pointsWithNormals);
            puts("\nOwO\ninput:\n    1.continue: continue to the next transformation;\n    2.break: stop transformation;\nOwO\n");
            cin >> op;
            if (op.compare("continue") == 0) continue;
            else if (op.compare("break") == 0) break;
            else puts("\nOAO\ninvalid input, retry please\nOAO\n");
        }

        inv = fin.inverse();                                            //从目标点云到源点云的变换
        transformPointCloud(*cloudTgt, *cloudRet, inv);
        showPointCloudT(cloudSrc, cloudRet);
        transformingMatrix = inv;
    }
    else
    {
        int maximumIterations_input = 30;
        puts("\nOwO\ninput the maximum iterations (1 ~ 200), please\nOwO\n");
        scanf("%d", &maximumIterations_input);
        maximumIterations_input = max(maximumIterations_input, 1), maximumIterations_input = min(maximumIterations_input, 30);
        reg.setMaximumIterations(maximumIterations_input);

        PointCloudWithNormals::Ptr tmpCloud = src_pointsWithNormals;
        Eigen::Matrix4f fin, inv;
        reg.align(*tmpCloud);
        fin = reg.getFinalTransformation();
        inv = fin.inverse();                                            //从目标点云到源点云的变换
        transformPointCloud(*cloudTgt, *cloudRet, inv);
        showPointCloudT(cloudSrc, cloudRet);
        transformingMatrix = inv;
    }
}

PointRepresentationT::PointRepresentationT()
{
    nr_dimensions_ = 4;
}

void PointRepresentationT::copyToFloatArray(const PointNormal &p, float *out) const
{
    out[0] = p.x, out[1] = p.y, out[2] = p.z, out[3] = p.curvature;
}
PCLFxxL.cpp
#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS 

#include <time.h>
#include <stdlib.h>
#include "kinect.h"
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/opencv.hpp>
#include <cv.h>
#include <GLFW\glfw3.h>
#include <gl/glut.h>
#include <thread>
#include <mutex>
#include <queue>
#include <boost/make_shared.hpp>                //boost指针相关头文件
#include <pcl/io/io.h>  
#include <pcl/visualization/cloud_viewer.h>  
#include <pcl/point_types.h>                    //点类型定义头文件
#include <pcl/point_cloud.h>                    //点云类定义头文件
#include <pcl/point_representation.h>            //点表示相关的头文件
#include <pcl/io/pcd_io.h>                        //PCD文件打开存储类头文件
#include <pcl/filters/voxel_grid.h>                //用于体素网格化的滤波类头文件 
#include <pcl/filters/filter.h>                    //滤波相关头文件
#include <pcl/features/normal_3d.h>                //法线特征头文件
#include <pcl/registration/icp.h>                //ICP类相关头文件
#include <pcl/registration/icp_nl.h>            //非线性ICP 相关头文件
#include <pcl/registration/transforms.h>        //变换矩阵类头文件
#include <pcl/visualization/pcl_visualizer.h>    //可视化类头文件

#include "OpenCVFxxL.h"
#include "KinectFxxL.h"
#include "PCLFxxL.h"

#define check_hr(x) if(hr<0) return false
#define pause system("pause")

using namespace cv;
using namespace std;
using namespace pcl;
using pcl::visualization::PointCloudColorHandlerGenericField;
using pcl::visualization::PointCloudColorHandlerCustom;

typedef PointXYZRGBA PointT;
typedef PointCloud<PointT> PointCloudT;
typedef PointXYZ PointX;
typedef PointCloud<PointX> PointCloudX;
typedef PointCloud<PointNormal> PointCloudWithNormals;

const int n_depth = 424;
const int m_depth = 512;
const int n_color = 1080;
const int m_color = 1920;

HRESULT hr;
IKinectSensor *pKinectSensor;
ICoordinateMapper *pCoordinateMapper;
IDepthFrameReader *pDepthFrameReader;
IColorFrameReader *pColorFrameReader;
IDepthFrame *pDepthFrame = NULL;
IColorFrame *pColorFrame = NULL;
IFrameDescription *pFrameDescription = NULL;
IDepthFrameSource *pDepthFrameSource = NULL;
IColorFrameSource *pColorFrameSource = NULL;
USHORT depthMinReliableDistance, depthMaxReliableDistance;
UINT bufferSize_depth, bufferSize_color;
UINT16 *pBuffer_depth = NULL;
uchar *pBuffer_color = NULL;
ColorImageFormat imageFormat_color;
int width_depth, height_depth, width_color, height_color;
DepthSpacePoint *pDepthSpace = NULL;
ColorSpacePoint *pColorSpace = NULL;
CameraSpacePoint *pCameraSpace = NULL;

UINT16 *image_depth;
BYTE *image_color;
Mat imageMat_depth, imageMat_color;

PointCloudT::Ptr cloud(new PointCloudT), prevCloud(new PointCloudT), finCloud(new PointCloudT), tmpCloud(new PointCloudT), lastFinCloud(new PointCloudT), lastPrevCloud(new PointCloudT);

int cnt_image;

bool getDepthImage()
{
    pDepthFrame = NULL;
    while (hr < 0 || pDepthFrame == NULL)
        hr = pDepthFrameReader->AcquireLatestFrame(&pDepthFrame);
    hr = pDepthFrame->get_FrameDescription(&pFrameDescription);                    check_hr(hr);
    pFrameDescription->get_Width(&width_depth);    pFrameDescription->get_Height(&height_depth);
    hr = pDepthFrame->get_DepthMinReliableDistance(&depthMinReliableDistance);    check_hr(hr);
    hr = pDepthFrame->get_DepthMaxReliableDistance(&depthMaxReliableDistance);    check_hr(hr);
    pDepthFrame->AccessUnderlyingBuffer(&bufferSize_depth, &pBuffer_depth);
    imageMat_depth = convertDepthToMat(pBuffer_depth, width_depth, height_depth);
    hr = pDepthFrame->CopyFrameDataToArray(bufferSize_depth, image_depth);
    pDepthFrame->Release();
//    equalizeHist(imageMat_depth, imageMat_depth);
    return true;
}

bool getColorImage()
{
    pColorFrame = NULL;
    while (hr < 0 || pColorFrame == NULL)
        hr = pColorFrameReader->AcquireLatestFrame(&pColorFrame);
    hr = pColorFrame->get_FrameDescription(&pFrameDescription);                    check_hr(hr);
    pFrameDescription->get_Width(&width_color); pFrameDescription->get_Height(&height_color);
    imageMat_color = Mat(height_color, width_color, CV_8UC4);
    pBuffer_color = imageMat_color.data; bufferSize_color = width_color * height_color * 4;
    hr = pColorFrame->CopyConvertedFrameDataToArray(bufferSize_color, reinterpret_cast<BYTE*>(pBuffer_color), ColorImageFormat::ColorImageFormat_Bgra);
    hr = pColorFrame->CopyConvertedFrameDataToArray(bufferSize_color, image_color, ColorImageFormat::ColorImageFormat_Bgra);
    pColorFrame->Release();
    return true;
}

bool getPoints(bool flag_slow)
{
    hr = pCoordinateMapper->MapDepthFrameToColorSpace(n_depth*m_depth, image_depth, n_depth*m_depth, pColorSpace);        check_hr(hr);
    hr = pCoordinateMapper->MapDepthFrameToCameraSpace(n_depth*m_depth, image_depth, n_depth*m_depth, pCameraSpace);    check_hr(hr);

    CameraSpacePoint p_camera;
    ColorSpacePoint p_color;
    PointT p;
    int cnt = 0, px_color, py_color;
    for (int i = 0; i < n_depth*m_depth; i++)
    {
        p_camera = pCameraSpace[i];
        p_color = pColorSpace[i];

        px_color = (int)(p_color.X + 0.5), py_color = (int)(p_color.Y + 0.5);
        if (px_color >= 0 && px_color < m_color && py_color >= 0 && py_color < n_color)
        {
            cnt++;
            p.b = image_color[(py_color*m_color + px_color) * 4], p.g = image_color[(py_color*m_color + px_color) * 4 + 1], p.r = image_color[(py_color*m_color + px_color) * 4 + 2];
            p.x = p_camera.X, p.y = p_camera.Y, p.z = p_camera.Z;
            cloud->points.push_back(p);
        }
    }
    printf("number of points: %d\n", cnt);
    shapeCloud(cloud);
    showPointCloudT(cloud);
    if (cnt_image)
    {
        Eigen::Matrix4f transformingMatrix;
        cloudMerge(prevCloud, cloud, tmpCloud, transformingMatrix, flag_slow);
        cloud->clear(), *cloud += *tmpCloud, shapeCloud(cloud);
    }

    lastPrevCloud->points.clear(), *lastPrevCloud += *prevCloud, shapeCloud(lastPrevCloud);
    lastFinCloud->points.clear(), *lastFinCloud += *finCloud, shapeCloud(lastFinCloud);

    prevCloud->points.clear(), *prevCloud += *cloud, shapeCloud(prevCloud);
    *finCloud += *cloud, shapeCloud(finCloud);
    filterCloud(finCloud, 0.002), shapeCloud(finCloud);
    cloud->points.clear();
    return true;
}

void init()
{
    cnt_image = 0;
    finCloud->clear();

    initVisualizer();

    pColorSpace = new ColorSpacePoint[n_depth*m_depth];
    pCameraSpace = new CameraSpacePoint[n_depth*m_depth];
    image_color = new BYTE[n_color*m_color * 4];
    image_depth = new UINT16[n_depth*m_depth];
}

bool start()
{
    String op;
    
    hr = GetDefaultKinectSensor(&pKinectSensor);                                check_hr(hr);
    hr = pKinectSensor->Open();                                                    check_hr(hr);
    hr = pKinectSensor->get_CoordinateMapper(&pCoordinateMapper);                check_hr(hr);

    hr = pKinectSensor->get_DepthFrameSource(&pDepthFrameSource);                check_hr(hr);
    hr = pDepthFrameSource->OpenReader(&pDepthFrameReader);                        check_hr(hr);

    hr = pKinectSensor->get_ColorFrameSource(&pColorFrameSource);                check_hr(hr);
    hr = pColorFrameSource->OpenReader(&pColorFrameReader);                        check_hr(hr);

    while (1)
    {
        bool flag_slow;
        puts("\nOwO\ninput:\n    1.work_slow: get next cloud and show every step in transform;\n    2.work: get next cloud;\n    3.exit: exit this program;\n    4.show: show final cloud;\n    5.show_ex: show final cloud with some change;\n    6.show_triangles: show the triangles;\n    7.back: back to the cloud.\nOwO\n");
        cin >> op;
        if (op.compare("exit") == 0) return true;
        else if (op.compare("work") == 0 || op.compare("work_slow") == 0)
        {
            if (op.compare("work_slow") == 0) flag_slow = true;    else flag_slow = false;
            if (getDepthImage() == false) return false;
            if (getColorImage() == false) return false;
            imwrite("tmp\\" + convertIntToString(cnt_image) + "_image_depth.jpg", imageMat_depth);
//            showImage(imageMat_depth);
            imwrite("tmp\\" + convertIntToString(cnt_image) + "_image_color.jpg", imageMat_color);
//            showImage(imageMat_color);
            if (!getPoints(flag_slow)) return puts("\nOAO\nget points failed\nOAO\n"), false;
            cnt_image++;
        }
        else if (op.compare("show") == 0)
            showPointCloudT(finCloud);
        else if (op.compare("show_ex") == 0)
        {
            PointCloudT::Ptr exFinCloud(new PointCloudT);
            getExCloud(finCloud, exFinCloud);
            showPointCloudT(exFinCloud);
        }
        else if (op.compare("show_triangles") == 0)
        {
            PolygonMesh triangles;
            getTriangles(finCloud, triangles);
            showPolygonMesh(triangles);
        }
        else if (op.compare("back") == 0)
        {
            finCloud->clear(), *finCloud += *lastFinCloud, shapeCloud(finCloud);
            prevCloud->clear(), *prevCloud += *lastPrevCloud, shapeCloud(prevCloud);
            puts("OwO finished");
        }
        else puts("\nOAO\ninvalid input, retry please\nOAO\n");
    }

    return true;
}

int main()
{
    init();
    if (!start()) return puts("\nOAO\ninit failed\nOAO\n"), 0;
    puts("\nOwO\nprogram ends\nOwO\n");
    pause;
    return 0;
}
main.cpp

 

posted @ 2018-06-06 20:18  太阳星人FxxL  阅读(7724)  评论(4编辑  收藏  举报