OBJ格式转成PCD或者PLY格式(带纹理信息)

利用PCL库函数解析OBJ

利用pcl库函数解析obj的方法有bug,解析过来的时候纹理坐标确实,也就是缺少RGB信息。
这是PCL库的bug,见参考1 参考2
因此,只好自己读懂obj的格式后,自己写一下解析函数。

利用meshlab转化

转化后也缺失了RGB信息

自己解析OBJ

OBJ格式解析

obj文件如下:

mtllib Tile_+003_+002_+000.mtl
v -9.67653046e+001 -2.54838577e+002 2.69715271e+001
v -9.76558914e+001 -2.55053558e+002 2.70283375e+001
v -9.92712021e+001 -2.52890640e+002 2.68646297e+001
...
vt 0.11269743 0.9384023
vt 0.11295749 0.93755996
vt 0.11307663 0.93885833
vt 0.11191387 0.93955261
vt 0.11083307 0.93842274
vt 0.1146261 0.93710536
vt 0.11188133 0.93438381
vt 0.11429998 0.93874836
...
usemtl Tile_+003_+002_+000_0
f 4/59167 8/59168 3/59169
f 38/59173 32/59170 3/59169
f 106240/59180 64527/59188 2/59199
f 38/59173 35/59196 34/59198
f 3/59169 32/59170 4/59167
f 31/59192 10/59204 20/59217
f 21/151853 12/151854 49010/151855
f 13/151879 14/151881 64452/151880
f 18/151857 17/151862 15/151867
f 23/140584 22/140585 24/140586
f 113546/151859 25/151866 17/151862
f 25/151866 113546/151859 105583/151870
f 30275/59265 19/59229 105583/59286
f 30275/59265 28/59248 19/59229
...

v:vertices(顶点坐标)
vt:vertices texture(顶点纹理坐标,这里的坐标系与OPENCV的坐标系不一样,见下图,左边为这里的坐标系,右边为OpenCV的坐标系)
加粗样式在这里插入图片描述
f:face(面,一个面对应三个顶点)其格式如下(索引从1开始):

f 顶点索引/顶点纹理索引 顶点索引/顶点纹理索引 顶点索引/顶点纹理索引
f 1/1 2/2 3/3

转换代码

该代码并不通用,只试用于我的这种格式,其他的格式需要相应修改,仅供参考。

#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/obj_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/PolygonMesh.h>
#include <pcl/point_cloud.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <string>
#include <cstring>
#include <fstream>
#include <sstream>
#include <map>
#include <algorithm>
#include <bits/stdc++.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgcodecs.hpp>
using namespace cv;
using namespace std;
struct _xyz{
public:
    float x;
    float y;
    float z;
    unsigned char r;
    unsigned char g;
    unsigned char b;
public:
    _xyz():x(0.0),y(0.0),z(0.0),r(255),g(255),b(255)
    {
    }
};

struct _xy{
    float x;
    float y;
};

int WIDTH,HEIGHT;
Mat img;
vector<int> split(string s,string delim)
{
    vector<int> a;
    int index = 0;
    for(unsigned int i = 0;i < s.size();i++)
    {
        if(delim[0] == s[i] || i == s.size() - 1)
        {
            istringstream ss;

            if(i == s.size() - 1)
                ss.str(s.substr(index,i + 1 - index));
            else
                ss.str(s.substr(index,i - index));
            int tmp;
            ss >> tmp;
            a.push_back(tmp);
            index = i + 1;
        }
    }
    return a;
}

int main(int argc,char** argv)
{
    ifstream file(argv[1],ios::in);
    if(!file.is_open())
    {
        cout << "open file error!" << endl;
        return -1;
    }
    string line;
    getline(file,line);
    vector<_xyz> xyz;
    vector<_xy> rgb_index;
    map<int,int> Imap;
    while(getline(file,line) && line.size() >0)
    {
        istringstream ss(line);
        string type;
        ss >> type;
        if(type == "v")
        {
            _xyz item;
            ss >> item.x >> item.y >> item.z;
            xyz.push_back(item);
        }
        else if(type == "vt")
        {
            _xy item;
            ss >> item.x >> item.y;
            rgb_index.push_back(item);
        }
        else if(type == "mtllib")
        {
            continue;
        }
        else if(type == "usemtl")
        {
            string img_path;
            ss >> img_path;
            if(img_path.find("untextured") != string::npos)
                continue;
            img_path+=".jpg";
            string img_path1(argv[1]);
            size_t pos = img_path1.rfind("/");
            img_path1.replace(pos+1,img_path1.size() - pos-1,img_path);

            img = imread(img_path1,1);
            if(img.data == NULL)
            {
                cout << "can not find the texture file!" << endl;
                return -1;
            }
            WIDTH = img.cols;
            HEIGHT = img.rows;
        }
        else if(type == "f")
        {
            string s1,s2,s3;
            ss >> s1 >> s2 >> s3;
            auto s1_v = split(s1,"/");
            auto s2_v = split(s2,"/");
            auto s3_v = split(s3,"/");
            Imap[s1_v[0]] = s1_v[1];
            Imap[s2_v[0]] = s2_v[1];
            Imap[s3_v[0]] = s3_v[1];
        }
    }
    for(int i = 0;i < xyz.size();++i)
    {
        int index = Imap[i+1];
        _xy tmp = rgb_index[index-1];
        int x = tmp.x * WIDTH;
        int y = tmp.y * HEIGHT;
        y = HEIGHT - y;
        int b = img.at<Vec3b>(y, x)[0];
        int g = img.at<Vec3b>(y, x)[1];
        int r = img.at<Vec3b>(y, x)[2];
        xyz[i].r = r;
        xyz[i].g = g;
        xyz[i].b = b;
    }
    // get label
//    pcl::PointCloud<pcl::PointXYZL>::Ptr cloud_xyzl (new pcl::PointCloud<pcl::PointXYZL>());
    pcl::PLYReader reader;
//    string label_file(argv[1]);
//    label_file.replace(label_file.find("good"),4,"good/data");
//    label_file.replace(label_file.rfind(".obj"),4,".ply");
    reader.read<pcl::PointXYZL>(label_file,*cloud_xyzl);
//    if (pcl::io::loadPLYFile<pcl::PointXYZL>(label_file, *cloud_xyzl) == -1) {
//          PCL_ERROR("Couldnot read file.\n");
//          return -1;
//    }
//    assert(cloud_xyzl->width * cloud_xyzl->height == xyz.size());

    pcl::PointCloud<pcl::PointXYZRGBL>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBL>());
    cloud->resize(xyz.size());
    for(int i = 0;i < xyz.size();++i)
    {
        cloud->points[i].x = xyz[i].x;
        cloud->points[i].y = xyz[i].y;
        cloud->points[i].z = xyz[i].z;
        cloud->points[i].r = xyz[i].r;
        cloud->points[i].g = xyz[i].g;
        cloud->points[i].b = xyz[i].b;
//        cloud->points[i].label = cloud_xyzl->points[i].label;
    }
    pcl::PLYWriter writer;
    string save_name(argv[1]);
    save_name.replace(save_name.rfind(".obj"),4,".ply");
    writer.write<pcl::PointXYZRGBL>(save_name,*cloud,false,false);
    cout << "convert finished" << endl;
    return 0;
}

编译环境

OpenCV3.4.0 + PCL1.9
CMakeLists.txt 如下:

cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
project(ObjToPly)
find_package(PCL 1.7 REQUIRED)
find_package(OpenCV REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
include_directories(/usr/include)

link_directories(${PCL_LIBRARY_DIRS})
link_directories(${OpenCV_LIBRARY_DIRS})

add_definitions(${PCL_DEFINITIONS})
add_definitions(-std=c++11)
add_executable(2_objTopcd 2_objTopcd.cpp)
target_link_libraries(2_objTopcd 
${PCL_LIBRARIES}
${OpenCV_LIBRARIES}
)

可视化效果

左边图为利用meshlab打开的obj格式图,右图为利用meshlab打开的ply图。
在这里插入图片描述 在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值