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


    我之前有一篇博客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! "); 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 vtk output ASCII DATASET POLYDATA POINTS " << 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! "); return (-2); } fs << std::endl; } // Write vertices fs << " VERTICES " << 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 << " POINT_DATA " << nr_points << " COLOR_SCALARS scalars 3 "; // 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 << " POINT_DATA " << nr_points << " TEXTURE_COORDINATES tcoords 2 float "; for (unsigned int i = 0; i < nr_points; ++i) { //fs << texcoord[i][0] << " " << texcoord[i][1] << " "; fs << texcoord[i][1] << " " << texcoord[i][0] << " "; } 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!
    ");
            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
    vtk output
    ASCII
    DATASET POLYDATA
    POINTS " << nr_points << " float" << '
    ';
    
        // 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!
    ");
                return (-2);
            }
            fs << '
    ';
        }
    
        // Write vertices
        fs << "
    VERTICES " << nr_points << " " << 2*nr_points << '
    ';
        for (unsigned int i = 0; i < nr_points; ++i)
            fs << "1 " << i << '
    ';
    
    //     // Write RGB values
    //     int field_index = getFieldIndex (cloud, "rgb");
    //     if (field_index != -1)
    //     {
    //         fs << "
    POINT_DATA " << nr_points << "
    COLOR_SCALARS scalars 3
    ";
    //         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 << '
    ';
    //         }
    //     }
    
        // Write texture coordinates
        fs << "
    POINT_DATA " << nr_points << "
    TEXTURE_COORDINATES tcoords 2 float
    ";
        for (unsigned int i = 0; i < nr_points; ++i) {
    
            //fs << texcoord[i][0] << " " << texcoord[i][1] << "
    ";
            fs << texcoord[i][1] << " " << texcoord[i][0] << "
    ";
        }
        fs << '
    ';
    
        // Close file
        fs.close ();
        return (0);
    }

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

  • 相关阅读:
    一些内容
    ios开发 xcode6以上安装Alcatraz管理插件
    java锁的深度化-重入锁,读写锁,乐观锁,悲观锁
    并发队列
    并发工具类
    并发编程
    HashMap底层源码剖析
    双列集合map面试题
    单列集合List
    类加载
  • 原文地址:https://www.cnblogs.com/grandyang/p/6546701.html
Copyright © 2020-2023  润新知