您的位置:首页 > 其它

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

2017-07-11 15:36 495 查看
我之前有一篇博客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 (-1);
}

// 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 = 0; i < nr_points; ++i)
{
int xyz = 0;
for (size_t d = 0; d < cloud.fields.size (); ++d)
{
int count = cloud.fields[d].count;
if (count == 0)
count = 1;          // we simply cannot tolerate 0 counts (coming from older converter code)
int c = 0;
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 == 3)
break;
}
fs << " ";
}
if (xyz != 3)
{
PCL_ERROR ("[pcl::io::saveVTKFile] Input point cloud has no XYZ data!\n");
return (-2);
}
fs << std::endl;
}

// Write vertices
fs << "\nVERTICES " << nr_points << " " << 2*nr_points << std::endl;
for (unsigned int i = 0; 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 = 0; i < nr_points; ++i) {

//fs << texcoord[i][0] << " " << texcoord[i][1] << "\n";
fs << texcoord[i][1] << " " << texcoord[i][0] << "\n";
}
fs << std::endl;

// Close file
fs.close ();
return (0);

}


 

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 (-1);
}

// 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 = 0; i < nr_points; ++i)
{
int xyz = 0;
for (size_t d = 0; d < cloud.fields.size (); ++d)
{
int count = cloud.fields[d].count;
if (count == 0)
count = 1;          // we simply cannot tolerate 0 counts (coming from older converter code)
int c = 0;
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 == 3)
break;
}
fs << " ";
}
if (xyz != 3)
{
PCL_ERROR ("[pcl::io::saveVTKFile] Input point cloud has no XYZ data!\n");
return (-2);
}
fs << '\n';
}

// Write vertices
fs << "\nVERTICES " << nr_points << " " << 2*nr_points << '\n';
for (unsigned int i = 0; 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 = 0; i < nr_points; ++i) {

//fs << texcoord[i][0] << " " << texcoord[i][1] << "\n";
fs << texcoord[i][1] << " " << texcoord[i][0] << "\n";
}
fs << '\n';

// Close file
fs.close ();
return (0);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: