使用 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 点云数据基本上是一堆来自现实世界的样本点。您在此类数据中没有表面信息。您所做的是使用平面拟合(二维回归)估计像素周围的表面。然后,您获得表面法线。您无法比较这两种方法。他们本质上给出了不同的目的。
对于问题二:是的。参考.
我正在尝试生成给定网格、相机姿势和相机内在函数的法线贴图。
我的计划是计算云中每个点的顶点法线,然后将它们投影到具有相应相机姿势和内在函数的图像平面上。更具体地说,我将首先计算顶点法线,然后将点坐标从世界坐标转换为具有相机姿势的相机坐标。最后,使用相机内在函数,可以将点云投影到图像上,其中每个像素代表相应 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 点云数据基本上是一堆来自现实世界的样本点。您在此类数据中没有表面信息。您所做的是使用平面拟合(二维回归)估计像素周围的表面。然后,您获得表面法线。您无法比较这两种方法。他们本质上给出了不同的目的。
对于问题二:是的。参考