使用 PCL 将网格法线渲染为法线贴图

Rendering mesh normals as normal maps with PCL

我正在尝试生成给定网格、相机姿势和相机内在函数的法线贴图。

我的计划是计算云中每个点的顶点法线,然后将它们投影到具有相应相机姿势和内在函数的图像平面上。更具体地说,我将首先计算顶点法线,然后将点坐标从世界坐标转换为具有相机姿势的相机坐标。最后,使用相机内在函数,可以将点云投影到图像上,其中每个像素代表相应 3D 顶点的表面法线。

下面是我的代码:

#include <iostream>
#include <thread>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
#include <pcl/features/from_meshes.h>
#include <pcl/visualization/pcl_visualizer.h>

using namespace std;
using namespace pcl;

void readPLY(PolygonMesh::Ptr mesh, string fname, bool printResult=false)
{
    PLYReader reader;
    int success = reader.read(fname, *mesh); // load the file
    if (success == -1) {
        cout << "Couldn't read file " << fname << endl;
        exit(-1);
    }

    if(printResult){
        cout << "Loaded "
        << mesh->cloud.width * mesh->cloud.height
        << " data points from "
        << fname
        << " with the following fields: "
        << endl;

        // convert from pcl/PCLPointCloud2 to pcl::PointCloud<T>
        PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ>);
        fromPCLPointCloud2(mesh->cloud, *cloud);

        // print the first 10 vertices
        cout << "Vertices:" << endl;
        for (size_t i=0; i<10; ++i)
            cout << "    " << cloud->points[i].x
            << " "    << cloud->points[i].y
            << " "    << cloud->points[i].z << endl;

        // print the first 10 polygons
        cout << "Polygons:" << endl;
        for (size_t i=0; i<10; ++i){
            cout << mesh->polygons[i] << endl;
        }
    }
}

void computeNormal(PolygonMesh::Ptr mesh,
                   PointCloud<Normal>::Ptr normal,
                   bool printResult=false)
{
    // convert from pcl/PCLPointCloud2 to pcl::PointCloud<T>
    PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ>);
    fromPCLPointCloud2(mesh->cloud, *cloud);

    // compute surface normal
    pcl::features::computeApproximateNormals(*cloud, mesh->polygons, *normal);

    // print results
    if (printResult){
        cout << "Normal cloud contains "
             << normal->width * normal->height
             << " points" << endl;

         // print the first 10 vertices
         cout << "Vertex normals:" << endl;
         for (size_t i=0; i<10; ++i)
             cout << "    " << normal->points[i] << endl;
    }
}


int main (int argc, char** argv)
{
    // ./main [path/to/ply] (--debug)
    string fname = argv[1];

    // check if debug flag is set
    bool debug = false;
    for(int i=0;i<argc;++i){
        string arg = argv[i];
        if(arg == "--debug")
            debug = true;
    }

    // read file
    PolygonMesh::Ptr mesh (new PolygonMesh);
    readPLY(mesh, fname, debug);

    // calculate normals
    PointCloud<Normal>::Ptr normal (new PointCloud<Normal>);
    computeNormal(mesh, normal, debug);
}

目前,我已经用pcl::features::computeApproximateNormals获得了每个顶点的表面法线。有没有办法使用 PCL 将法线投影到图像平面上,并将法线的 xyz 元素映射到 RGB 通道并将图像保存到文件中?

欢迎来到 Stack Overflow。文档说的是:

Given a geometric surface, it’s usually trivial to infer the direction of the normal at a certain point on the surface as the vector perpendicular to the surface in that point.

根据我从你所说的收集到的信息,你已经有了可以轻松计算表面法线的表面。使用法线估计是因为 3D 点云数据基本上是一堆来自现实世界的样本点。您在此类数据中没有表面信息。您所做的是使用平面拟合(二维回归)估计像素周围的表面。然后,您获得表面法线。您无法比较这两种方法。他们本质上给出了不同的目的。

对于问题二:是的。参考.