我之前有一篇博客Convert PLY to VTK Using PCL 1.6.0 or PCL 1.8.0 使用PCL库将PLY格式转为VTK格式展示了如何将PLY格式文件转化为VTK格式的文件,在文章的最后提到了VTK文件保存纹理的两种方式,第一种是需要有texture的图片,然后每个点存储上该点在图片中的x,y坐标,一般会normalize到[0,1]之间。第二种方法是直接存每个点的rgb值,上面的方法用的是第二种,因为导入的PLY格式就直接存储的texture的rgb值,并没有额外提供texture图片。

对于一般的PLY或者PCD格式的点云,一般都是用第二种方式来保存纹理的,即直接存储rgb值,这样转换成的vtk文件自然也是第二种情况,而对于大多数的可视化软件,比如ParaView或者3D Slicer,貌似只支持第一种方式,即需要导入texture图片(如果大家知道直接显示rgb值的方法,请在下方留言告知博主)。这样就极大的不方便了,而且PCL库中的点云格式一般也是XYZRGBA,并没有带UV,纹理有专门的数据结构。我们的目标是生成带texture coordinates的VTK文件,那么可以通过修改pcl自带的saveVTKFile函数来实现目标。

这里我们把纹理坐标单独抽出来,用下面的数据结构来表示:

std::vector<Eigen::Vector2f> texcoord;

pcl自带的pcl::io::saveVTKFile函数所在的文件的地址是.../io/src/vtk_io.cpp。默认的是写入RGB的值,我们只需要注释掉写入RGB的部分,添加上写入纹理坐标的部分:

Using PCL 1.6.0

// PCL 1.6.0
int save_vtk_file(const std::string &file_name,
const sensor_msgs::PointCloud2 &cloud,
const std::vector<Eigen::Vector2f>& texcoord,
unsigned precision)
{
if (cloud.data.empty ())
{
PCL_ERROR ("[pcl::io::saveVTKFile] Input point cloud has no data!\n");
return (-);
} // Open file
std::ofstream fs;
fs.precision (precision);
fs.open (file_name.c_str ()); unsigned int nr_points = cloud.width * cloud.height;
unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points); // Write the header information
fs << "# vtk DataFile Version 3.0\nvtk output\nASCII\nDATASET POLYDATA\nPOINTS " << nr_points << " float" << std::endl; // Iterate through the points
for (unsigned int i = ; i < nr_points; ++i)
{
int xyz = ;
for (size_t d = ; d < cloud.fields.size (); ++d)
{
int count = cloud.fields[d].count;
if (count == )
count = ; // we simply cannot tolerate 0 counts (coming from older converter code)
int c = ;
if ((cloud.fields[d].datatype == sensor_msgs::PointField::FLOAT32) && (
cloud.fields[d].name == "x" ||
cloud.fields[d].name == "y" ||
cloud.fields[d].name == "z"))
{
float value;
memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
fs << value;
if (++xyz == )
break;
}
fs << " ";
}
if (xyz != )
{
PCL_ERROR ("[pcl::io::saveVTKFile] Input point cloud has no XYZ data!\n");
return (-);
}
fs << std::endl;
} // Write vertices
fs << "\nVERTICES " << nr_points << " " << *nr_points << std::endl;
for (unsigned int i = ; i < nr_points; ++i)
fs << "1 " << i << std::endl; // Write RGB values
// int field_index = pcl::getFieldIndex (cloud, "rgb");
// if (field_index != -1)
// {
// fs << "\nPOINT_DATA " << nr_points << "\nCOLOR_SCALARS scalars 3\n";
// for (unsigned int i = 0; i < nr_points; ++i)
// {
// int count = cloud.fields[field_index].count;
// if (count == 0)
// count = 1; // we simply cannot tolerate 0 counts (coming from older converter code)
// int c = 0;
// if (cloud.fields[field_index].datatype == sensor_msgs::PointField::FLOAT32)
// {
// pcl::RGB color;
// memcpy (&color, &cloud.data[i * point_size + cloud.fields[field_index].offset + c * sizeof (float)], sizeof (pcl::RGB));
// int r = color.r;
// int g = color.g;
// int b = color.b;
// fs << static_cast<float> (r) / 255.0f << " " << static_cast<float> (g) / 255.0f << " " << static_cast<float> (b) / 255.0f;
// }
// fs << std::endl;
// }
// } // Write texture coordinates
fs << "\nPOINT_DATA " << nr_points << "\nTEXTURE_COORDINATES tcoords 2 float\n";
for (unsigned int i = ; i < nr_points; ++i) { //fs << texcoord[i][0] << " " << texcoord[i][1] << "\n";
fs << texcoord[i][] << " " << texcoord[i][] << "\n";
}
fs << std::endl; // Close file
fs.close ();
return (); }

Using PCL 1.8.0

// PCL 1.8.0
int save_vtk_file (const std::string &file_name,
const pcl::PCLPointCloud2 &cloud,
const std::vector<Eigen::Vector2f>& texcoord,
unsigned precision)
{
if (cloud.data.empty ())
{
PCL_ERROR ("[pcl::io::saveVTKFile] Input point cloud has no data!\n");
return (-);
} // Open file
std::ofstream fs;
fs.precision (precision);
fs.open (file_name.c_str ()); unsigned int nr_points = cloud.width * cloud.height;
unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points); // Write the header information
fs << "# vtk DataFile Version 3.0\nvtk output\nASCII\nDATASET POLYDATA\nPOINTS " << nr_points << " float" << '\n'; // Iterate through the points
for (unsigned int i = ; i < nr_points; ++i)
{
int xyz = ;
for (size_t d = ; d < cloud.fields.size (); ++d)
{
int count = cloud.fields[d].count;
if (count == )
count = ; // we simply cannot tolerate 0 counts (coming from older converter code)
int c = ;
if ((cloud.fields[d].datatype == pcl::PCLPointField::FLOAT32) && (
cloud.fields[d].name == "x" ||
cloud.fields[d].name == "y" ||
cloud.fields[d].name == "z"))
{
float value;
memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
fs << value;
if (++xyz == )
break;
}
fs << " ";
}
if (xyz != )
{
PCL_ERROR ("[pcl::io::saveVTKFile] Input point cloud has no XYZ data!\n");
return (-);
}
fs << '\n';
} // Write vertices
fs << "\nVERTICES " << nr_points << " " << *nr_points << '\n';
for (unsigned int i = ; i < nr_points; ++i)
fs << "1 " << i << '\n'; // // Write RGB values
// int field_index = getFieldIndex (cloud, "rgb");
// if (field_index != -1)
// {
// fs << "\nPOINT_DATA " << nr_points << "\nCOLOR_SCALARS scalars 3\n";
// for (unsigned int i = 0; i < nr_points; ++i)
// {
// int count = cloud.fields[field_index].count;
// if (count == 0)
// count = 1; // we simply cannot tolerate 0 counts (coming from older converter code)
// int c = 0;
// if (cloud.fields[field_index].datatype == pcl::PCLPointField::FLOAT32)
// {
// pcl::RGB color;
// memcpy (&color, &cloud.data[i * point_size + cloud.fields[field_index].offset + c * sizeof (float)], sizeof (RGB));
// int r = color.r;
// int g = color.g;
// int b = color.b;
// fs << static_cast<float> (r) / 255.0f << " " << static_cast<float> (g) / 255.0f << " " << static_cast<float> (b) / 255.0f;
// }
// fs << '\n';
// }
// } // Write texture coordinates
fs << "\nPOINT_DATA " << nr_points << "\nTEXTURE_COORDINATES tcoords 2 float\n";
for (unsigned int i = ; i < nr_points; ++i) { //fs << texcoord[i][0] << " " << texcoord[i][1] << "\n";
fs << texcoord[i][] << " " << texcoord[i][] << "\n";
}
fs << '\n'; // Close file
fs.close ();
return ();
}

注意上面纹理的x和y的值,根据贴图的情况来看是否需要调换位置。

PCL Save VTK File With Texture Coordinates 使用PCL库来保存带纹理坐标的VTK文件的更多相关文章

  1. How to save/read file on different platforms

    You can use standard c functions, such as fopen, fwrite, to save and read file on different platform ...

  2. Render Texture coordinates

    https://docs.unity3d.com/550/Documentation/Manual/SL-PlatformDifferences.html Render Texture coordin ...

  3. Mac修改文件权限:You don’t have permission to save the file

    1.从互联网上或者其他途径拿过来的工程代码,往往会报下面的提示: (1)打开文件的时候出现窗口提示You don’t have permission to save the file “project ...

  4. error: exportArchive: You don’t have permission to save the file “HelloWorld.ipa” in the folder “HelloWorld”.

    成功clean环境和生成archive文件之后,最后一步导出ipa包,遇到了权限问题: you don’t have permission to save the file “HelloWorld.i ...

  5. [转]在eclipse打开的android虚拟手机,打开File Explorer,下面是空的没有data、mnt、system三个文件

    在eclipse打开的android虚拟手机,打开File Explorer,下面是空的没有data.mnt.system三个文件 这是因为模拟器没有选择打开的缘故,必须首先打开一个模拟器(AVD), ...

  6. PCL基础3.2-如何编写新的PCL类

    1.文件名为mainBilateralFilter.cpp的文件内容如下 #include <pcl/point_types.h> #include <pcl/io/pcd_io.h ...

  7. Matlab绘图基础——用print函数保存图片(Print figure or save to file)

    print(figure_handle,'formats','-rnumber','filename')  %将图形保存为png格式,分辨率为number的(默认为72),最好指定的分辨率大一点,否则 ...

  8. 关于在使用sparksql写程序是报错以及解决方案:org.apache.spark.sql.AnalysisException: Duplicate column(s): "name" found, cannot save to file.

    说明: spark --version : 2.2.0 我有两个json文件,分别是emp和dept: emp内容如下: {"name": "zhangsan" ...

  9. Matlab绘图基础——用print函数批量保存图片到文件(Print figure or save to file)

    一.用法解析 1.1. 分辨率-rnumber 1.2.  输出图片的“格式”formats 二.用法示例 2.1. 设置输出图片的“图像纵横比” 2.2. Batch Processing(图片保存 ...

随机推荐

  1. 使用Python登录Github网站

    在下面的代码中, 展示了使用Python脚本登录Github的方法. 如果需要登录别的网站,那么请使用Chrome的Inspect的功能寻找到目标的object,对代码进行替换. 代码先登录了gith ...

  2. phpBB3.2开发环境配置

    从Github导出项目 如果只是查看代码, 可以直接clone官方的git https://github.com/phpbb/phpbb.git . 如果需要开发, 就fork一下再从自己的Git里c ...

  3. 【Babble】批量学习与增量学习、稳定性与可塑性矛盾的乱想

    一.开场白 做机器学习的对这几个词应该比较熟悉了. 最好是拿到全部数据,那就模型慢慢选,参数慢慢调,一轮一轮迭代,总能取得不错效果. 但是面对新来数据,怎么能利用已经训练好的模型,把新的信息加进去? ...

  4. HDU 4666 Hyperspace (最远曼哈顿距离)

    Hyperspace Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Tota ...

  5. OpenCV 学习笔记 05 人脸检测和识别 AttributeError: module 'cv2' has no attribute 'face'

    1 环境设置: win10 python 3.6.8 opencv 4.0.1 2 尝试的方法 在学习人脸识别中,遇到了没有 cv2 中没有 face 属性.在网上找了几个方法,均没有成功解决掉该问题 ...

  6. [Aaronyang紫色博客] 写给自己的WPF4.5-Blend5公开课系列 1

     我的文章一定要做到对读者负责,否则就是失败的文章  ---------   www.ayjs.net    aaronyang技术分享 欢迎大家支持我的力作<[Aaronyang] 写给自己的 ...

  7. mysqlcheck与myisamchk的区别

    mysqlcheck和myisamchk都可以用来检测和修复表.(主要是MyISAM表)但是也有以下不同点:1.都可以检查.分析和修复myisam表.但是mysqlcheck也可以检查.分析innod ...

  8. C#-MVC开发微信应用(2)--微信消息的处理和应答

    微信应用使用场景和商机很多,所以这也是一个技术的方向,因此,有空研究下.学习下微信的相关开发,也就成为SNF完善的必要条件了.本系列文章希望从一个循序渐进的角度上,全面介绍微信的相关开发过程和相关经验 ...

  9. 一道简单的python面试题-购物车

    要求实现:1.程序开始运行时要求手动填入工资金额2.然后展示一份带有价格的商品列表3.选择某个商品,足够金额购买就添加到购物车,否则提示无法购买4.退出后列出购物车清单 #!/usr/bin/pyth ...

  10. 译:1. RabbitMQ Java Client 之 "Hello World"

    这些教程介绍了使用RabbitMQ创建消息传递应用程序的基础知识.您需要安装RabbitMQ服务器才能完成教程 1. 打造第一个Hello World 程序 RabbitMQ是一个消息代理:它接受和转 ...