通过调用pcl相关库及函数,将pcd、obj、las、ply格式3D文件统一转换成ply点云格式文件进行存储及显示,调用OpenGL相关函数进行三维显示及鼠标、键盘的简单操作。
1、transform.h(建立一个抽象类Modelloader,由三个子类分别继承,使其读取转换不同的3D文件)
#include <iostream>
#include <cstdlib>
#include<string>
#include <liblas/liblas.hpp>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/io/ply_io.h>
#include<pcl/PCLPointCloud2.h>
#include <pcl/io/obj_io.h>
using namespace pcl;
using namespace pcl::io;
using namespace std;
class ModelLoader {
public:
string filename;
string savefilename;
ModelLoader(string filename="", string savefilename="") {
this->filename = filename;
this->savefilename = savefilename;
}
virtual void TO_PLY(){}
~ModelLoader() {
this->filename = "";
}
};
class LasLoader:public ModelLoader {
public:
LasLoader(string filename="",string savefilename="") :ModelLoader(filename,savefilename) {}
void TO_PLY();
};
class PCDLoader :public ModelLoader {
public:
PCDLoader(string filename = "", string savefilename = "") :ModelLoader(filename, savefilename) {}
void TO_PLY();
};
class OBJLoader :public ModelLoader {
public:
OBJLoader(string filename = "", string savefilename = "") :ModelLoader(filename, savefilename) {}
void TO_PLY();
};
2、LAS_to_PLY.cpp
#include "transform.h"
void LasLoader::TO_PLY()
{
std::ifstream ifs;
ifs.open(this->filename, ios::in | ios::binary);
liblas::ReaderFactory f;
liblas::Reader reader = f.CreateWithStream(ifs);
unsigned long int nbPoints = reader.GetHeader().GetPointRecordsCount();
pcl::PointCloud<pcl::PointXYZRGB> cloud;
cloud.width = nbPoints;
cloud.height = 1;
cloud.is_dense = false;
cloud.points.resize(cloud.width * cloud.height);
int i = 0;
uint16_t r1, g1, b1;
int r2, g2, b2;
uint32_t rgb;
while (reader.ReadNextPoint())
{
cloud.points[i].x = (reader.GetPoint().GetX());
cloud.points[i].y = (reader.GetPoint().GetY());
cloud.points[i].z = (reader.GetPoint().GetZ());
r1 = (reader.GetPoint().GetColor().GetRed());
g1 = (reader.GetPoint().GetColor().GetGreen());
b1 = (reader.GetPoint().GetColor().GetBlue());
r2 = ceil(((float)r1 / 65536) * (float)256);
g2 = ceil(((float)g1 / 65536) * (float)256);
b2 = ceil(((float)b1 / 65536) * (float)256);
rgb = ((int)r2) << 16 | ((int)g2) << 8 | ((int)b2);
cloud.points[i].rgb = *reinterpret_cast<float*>(&rgb);
i++;
}
pcl::io::savePLYFileASCII(this->savefilename, cloud);
}
3、OBJ_to_PLY.cpp
#include "transform.h"
int OBJtoPLYconvertor(string& input_filename, string& output_filename)
{
pcl::PCLPointCloud2 cloud;
if (loadOBJFile(input_filename, cloud) < 0)
{
cout << "Error: cannot load the PCD file!!!" << endl;
return -1;
}
PLYWriter writer;
writer.writeASCII(output_filename, cloud, Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), 40, true);
return 0;
}
void OBJLoader::TO_PLY()
{
OBJtoPLYconvertor(this->filename, this->savefilename);
}
4、PCD_to_PLY.cpp
#include "transform.h"
int PCDtoPLYconvertor(string& input_filename, string& output_filename)
{
pcl::PCLPointCloud2 cloud;
if (loadPCDFile(input_filename, cloud) < 0)
{
cout << "Error: cannot load the PCD file!!!" << endl;
return -1;
}
PLYWriter writer;
writer.writeASCII(output_filename, cloud, Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), 20, true);
return 0;
}
void PCDLoader::TO_PLY()
{
PCDtoPLYconvertor(this->filename, this->savefilename);
}
5、PLYloader.h(将文件格式转换为ply后统一由一个plyloader类读取ps:提前声明了一些参数。)
#define PLYREADER_H_
#include <GL/glut.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <vector>
#include <Windows.h>
#include <cmath>
using namespace std;
static int mousetate = 0;//鼠标当前的状态
static int mousestate1 = 0;
static int mousestate2 = 0;
static GLfloat Oldx = 0.0; // 点击之前的位置
static GLfloat Oldy = 0.0;
static float xRotate = 0.0f;
static float yRotate = 0.0f;
static float scale = 1;
static float timesx = 0.0f;
static float timesy = 0.0f;
static float cx = 0.0f;
static float cy = 0.0f;
static float cz = 0.0f;
void OnMouse(int button, int state, int x, int y);
void onMouseMove(int x, int y);
void mySpecial(int key, int x, int y);
class CPLYLoader
{
public:
CPLYLoader();
int LoadModel(char* filename);
void Draw();
private:
GLfloat* mp_vertexXYZ;
int m_totalConnectedPoints;
};
6、PLYloader.cpp
#include "PLYLoader.h"
#include <iostream>
CPLYLoader::CPLYLoader()
{
this->m_totalConnectedPoints = 0;
}
int CPLYLoader::LoadModel(char* filename)
{
printf("Loading %s...\n", filename);
char* pch = strstr(filename, ".ply");
if (pch != NULL)
{
FILE* file = fopen(filename, "r");
if (!file)
{
printf("load PLY file %s failed\n", filename);
return false;
}
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
try
{
mp_vertexXYZ = (GLfloat*)malloc(ftell(file));
//mp_vertexNorm = (float*)malloc(ftell(file));
//mp_vertexRGB = (float*)malloc(ftell(file));
}
catch (char*)
{
return -1;
}
if (mp_vertexXYZ == NULL) return -1;
fseek(file, 0, SEEK_SET);
if (file)
{
int i = 0;
int temp = 0;
int quads_index = 0;
int triangle_index = 0;
int normal_index = 0;
int colorIndex = 0;
char buffer[1000];
fgets(buffer, 300, file);
while (strncmp("element vertex", buffer, strlen("element vertex")) != 0)
{
fgets(buffer, 300, file);
}
strcpy(buffer, buffer + strlen("element vertex"));
sscanf(buffer, "%i", &this->m_totalConnectedPoints);
cout << this->m_totalConnectedPoints << endl;
fseek(file, 0, SEEK_SET);
while (strncmp("end_header", buffer, strlen("end_header")) != 0)
{
fgets(buffer, 300, file);
}
i = 0;
for (int iterator = 0; iterator < this->m_totalConnectedPoints; iterator++)
{
char tmp[1];
fgets(buffer, 300, file);
sscanf(buffer, "%f %f %f ", &mp_vertexXYZ[i], &mp_vertexXYZ[i + 1], &mp_vertexXYZ[i + 2]);
i += 3;
}
i = 0;
fclose(file);
printf("%s Loaded!\n", filename);
}
else
{
printf("File can't be opened\n");
}
}
else
{
printf("File does not have a .PLY extension. ");
}
return 0;
}
void CPLYLoader::Draw()
{
glEnableClientState(GL_VERTEX_ARRAY);
glColor3f(0.0f, 0.0f, 0.0f);
glVertexPointer(3, GL_FLOAT, 0, mp_vertexXYZ);
glDrawArrays(GL_POINTS, 0, this->m_totalConnectedPoints);
glDisableClientState(GL_VERTEX_ARRAY);
}
7、main.cpp
#include "transform.h"
#include <stdio.h>
#include "PLYloader.h"
int width = 640;
int height = 480;
static bool sign = false;
static string p,t;
static char ptr[100];
void OnMouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
cout << "LEFT_DOWN" << endl;
mousetate = 1;
}
else
mousetate = 0;
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
mousestate1 = 1;
}
else
mousestate1 = 0;
if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
{
mousestate2 = 1;
}
else
mousestate2 = 0;
if (state == GLUT_UP && button == 3) {
cout << "WHEEL_UP" << endl;
scale += 0.02;
}
else if (state == GLUT_UP && button == 4)
{
cout << "WHEEL_DOWN" << endl;
scale -= 0.02;
}
glutPostRedisplay();
}
void onMouseMove(int x, int y) {
timesx = timesy = 0;
if (mousetate) {
yRotate += (x - Oldx) * 0.4f;
}
if (mousestate1){
xRotate += (y - Oldy) * 0.4f;
}
Oldx = x;
Oldy = y;
if (mousestate2)
{
timesx = x;
timesy = y;
}
glutPostRedisplay();
}
void mySpecial(int key, int x, int y) {
switch (key) {
//cx = cy = cz = 0;
case GLUT_KEY_F1://按F1主视图
xRotate = 0;
yRotate = 0;
timesx = timesy = 0;
break;
case GLUT_KEY_F2:
xRotate = 92.001;
yRotate = 0;
timesx = timesy = 0;
break;
case GLUT_KEY_F3:
xRotate = 0;
yRotate = 270.4;
timesx = timesy = 0;
break;
default:
break;
}
glutPostRedisplay();
}
CPLYLoader plyLoader;
void Initialize()
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glEnable(GL_DEPTH);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65, 1, 1, 50);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(12, 12, 20, 0, 0, 0, 0, 1, 0);
}
void Reshape(int w, int h)
{
width = w;
height = h;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (double)width / (double)height, 1.0, 1000.0);
}
void Display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//gluLookAt(0.0f, 0.0f, 0.0f, cx, cy, cz,0,0,0);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(yRotate, 0, 1,0 );
glRotatef(xRotate, 1, 0, 0);
glTranslatef(timesx*0.001f, -timesy*0.001f, 0.0f);
cout << "沿x轴旋转" << xRotate << "沿y轴旋转" << yRotate << endl;
glScalef(scale, scale, scale);
plyLoader.Draw();
glutSwapBuffers();
}
int main(int argc, char** argv)
{
ModelLoader* model;
cout << "输入要处理的文件路径!" << endl;
cin >> p;
char str[100];
p.copy(str, p.size(), 0);
char* q = str;
if (strstr(q, "las"))
{
cout << "输入要存储的文件路径" << endl;
cin >> t;
model = new LasLoader(p,t);
model->TO_PLY();
}
else if (strstr(q, "pcd"))
{
cout << "输入要存储的文件路径" << endl;
cin >> t;
model = new PCDLoader(p,t);
model->TO_PLY();
}
else if (strstr(q, "obj"))
{
cout << "输入要存储的文件路径" << endl;
cin >> t;
model = new OBJLoader(p,t);
model->TO_PLY();
}
else if (strstr(q, "ply"))
{
model = new ModelLoader();
model->savefilename = p;
}
else {
cout << "该文件类型暂不能处理!" << endl;
}
strcpy(ptr, model->savefilename.c_str());
plyLoader.LoadModel(ptr);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(600, 800);
glutInitWindowPosition(100, 100);
glutCreateWindow("F1、F2、F3分别进行模型三视图展示,鼠标左右键拖住旋转,鼠标滑轮放缩,鼠标中键拖住平移。");
Initialize();
glutMouseFunc(OnMouse);
glutMotionFunc(onMouseMove);
glutSpecialFunc(mySpecial);
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);
glutMainLoop();
return 0;
}
该代码为笔者c++实习时所写,逻辑格式问题较多,如有疑问请联系笔者,
该代码借鉴网络上部分代码,如有侵权,请联系删除。