需要预装opengl环境和pcl环境
整体思路是 opengl读取off转为obj文件,然后vtk读取obj文件下采样为点云,运用pcl生成深度图并保存,代码调用需要自行设置读取路径
如需转载请声明
#include <pcl/range_image/range_image.h>
//#include <pcl/visualization/range_image_visualizer.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/common/transforms.h>
#include <vtkVersion.h>
#include <vtkPLYReader.h>
#include <vtkOBJReader.h>
#include <vtkTriangle.h>
#include <vtkTriangleFilter.h>
#include <vtkPolyDataMapper.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <fstream>
#include <pcl/visualization/common/float_image_utils.h>//保存深度图像
#include <pcl/io/png_io.h>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <math.h>
#include <string>
#include <omp.h>
using namespace std;
using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;
float vertex[100000][3]; //读取的off最多10万点、面,无需要可以更改
int surface[100000][3];
void read_off_file(string input)//定义了OBJ,需与后面读入的文件名保持一致
{
//函数说明:读取off文件 需要同时存在off和obj文件 最终写入obj
char k;
int vertex_num;
int surface_num;
int other_num;
int i, j;
int s;
ifstream fin;
ofstream fout;
fin.open(input);
while (fin.fail())
{
cout << "Fail to open the off file!" << endl;
exit(1);
}
fout.open("test.obj");//建立一个中转文件
while (fout.fail())
{
cout << "Fail to open the obj file!" << endl;
exit(1);
}
do
{
//cout << fin.get();
} while (fin.get() != '\n');
fin >> vertex_num >> surface_num >> other_num;
//cout << vertex_num;
for (i = 0; i < vertex_num; i++)
{
for (j = 0; j < 3; j++)
{
fin >> vertex[i][j];
}
}
for (i = 0; i < surface_num; i++)
{
fin >> s;
// cout << s << endl;
for (j = 0; j < 3; j++)
{
fin >> surface[i][j];
}
}
for (i = 0; i < vertex_num; i++)
{
fout.put('v');
fout.put(' ');
for (j = 0; j < 3; j++)
{
fout << vertex[i][j];
fout.put(' ');
}
fout.put('\n');
}
fout.put('\n'); //注意控制换行
for (i = 0; i < surface_num; i++)
{
fout.put('f');
fout.put(' ');
for (j = 0; j < 3; j++)
{
fout << (surface[i][j] + 1);
fout.put(' ');
}
fout.put('\n');
}
fin.close();
fout.close();
//cout << "already covert to obj !" << endl;
}
inline double
uniform_deviate(int seed)
{
double ran = seed * (1.0 / (RAND_MAX + 1.0));
return ran;
}
inline void
randomPointTriangle(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3,
Eigen::Vector4f& p)
{
float r1 = static_cast<float> (uniform_deviate(rand()));
float r2 = static_cast<float> (uniform_deviate(rand()));
float r1sqr = std::sqrt(r1);
float OneMinR1Sqr = (1 - r1sqr);
float OneMinR2 = (1 - r2);
a1 *= OneMinR1Sqr;
a2 *= OneMinR1Sqr;
a3 *= OneMinR1Sqr;
b1 *= OneMinR2;
b2 *= OneMinR2;
b3 *= OneMinR2;
c1 = r1sqr * (r2 * c1 + b1) + a1;
c2 = r1sqr * (r2 * c2 + b2) + a2;
c3 = r1sqr * (r2 * c3 + b3) + a3;
p[0] = c1;
p[1] = c2;
p[2] = c3;
p[3] = 0;
}
inline void
randPSurface(vtkPolyData * polydata, std::vector<double> * cumulativeAreas, double totalArea, Eigen::Vector4f& p, bool calcNormal, Eigen::Vector3f& n)
{
float r = static_cast<float> (uniform_deviate(rand()) * totalArea);
std::vector<double>::iterator low = std::lower_bound(cumulativeAreas->begin(), cumulativeAreas->end(), r);
vtkIdType el = vtkIdType(low - cumulativeAreas->begin());
double A[3], B[3], C[3];
vtkIdType npts = 0;
vtkIdType *ptIds = NULL;
polydata->GetCellPoints(el, npts, ptIds);
polydata->GetPoint(ptIds[0], A);
polydata->GetPoint(ptIds[1], B);
polydata->GetPoint(ptIds[2], C);
if (calcNormal)
{
// OBJ: Vertices are stored in a counter-clockwise order by default
Eigen::Vector3f v1 = Eigen::Vector3f(A[0], A[1], A[2]) - Eigen::Vector3f(C[0], C[1], C[2]);
Eigen::Vector3f v2 = Eigen::Vector3f(B[0], B[1], B[2]) - Eigen::Vector3f(C[0], C[1], C[2]);
n = v1.cross(v2);
n.normalize();
}
randomPointTriangle(float(A[0]), float(A[1]), float(A[2]),
float(B[0]), float(B[1]), float(B[2]),
float(C[0]), float(C[1]), float(C[2]), p);
}
void
uniform_sampling(vtkSmartPointer<vtkPolyData> polydata, size_t n_samples, bool calc_normal, pcl::PointCloud<pcl::PointNormal> & cloud_out)
{
polydata->BuildCells();
vtkSmartPointer<vtkCellArray> cells = polydata->GetPolys();
double p1[3], p2[3], p3[3], totalArea = 0;
std::vector<double> cumulativeAreas(cells->GetNumberOfCells(), 0);
size_t i = 0;
vtkIdType npts = 0, *ptIds = NULL;
for (cells->InitTraversal(); cells->GetNextCell(npts, ptIds); i++)
{
polydata->GetPoint(ptIds[0], p1);
polydata->GetPoint(ptIds[1], p2);
polydata->GetPoint(ptIds[2], p3);
totalArea += vtkTriangle::TriangleArea(p1, p2, p3);
cumulativeAreas[i] = totalArea;
}
cloud_out.points.resize(n_samples);
cloud_out.width = static_cast<pcl::uint32_t> (n_samples);
cloud_out.height = 1;
for (i = 0; i < n_samples; i++)
{
Eigen::Vector4f p;
Eigen::Vector3f n;
randPSurface(polydata, &cumulativeAreas, totalArea, p, calc_normal, n);
cloud_out.points[i].x = p[0];
cloud_out.points[i].y = p[1];
cloud_out.points[i].z = p[2];
if (calc_normal)
{
cloud_out.points[i].normal_x = n[0];
cloud_out.points[i].normal_y = n[1];
cloud_out.points[i].normal_z = n[2];
}
}
}
const int default_number_samples = 100000; //定义转换参数
const float default_leaf_size = 0.002f;
//只需设置读取off的路径,后面会自动append
//需要设置输出位置,默认在D:\Git\regCNN\dataDepth
//不需要预先在目录下创建text.obj
//出现访问冲突,多半数组溢出
int main(int argc, char **argv)
{
//变量声明
int SAMPLE_POINTS_ = default_number_samples;
float leaf_size = default_leaf_size;
const bool write_normals = false;
//指针等声明
vtkSmartPointer<vtkPolyData> polydata1 = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkOBJReader> readerQuery = vtkSmartPointer<vtkOBJReader>::New();
vtkSmartPointer<vtkTriangleFilter> triangleFilter = vtkSmartPointer<vtkTriangleFilter>::New();
vtkSmartPointer<vtkPolyDataMapper> triangleMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_1(new pcl::PointCloud<pcl::PointNormal>);//点云指针
VoxelGrid<PointNormal> grid_; //voxel grid
pcl::PointCloud<pcl::PointNormal>::Ptr voxel_cloud(new pcl::PointCloud<pcl::PointNormal>);//voxel后点云指针
visualization::PCLVisualizer vis3("VOXELIZED SAMPLES CLOUD"); //声明可视化
pcl::PointCloud<pcl::PointXYZ>::Ptr voxelXYZCloud(new pcl::PointCloud<pcl::PointXYZ>);//注意从pointnormal转为pointxyz
pcl::PointCloud<pcl::PointXYZ> pointCloud; //声明保存voxel后点云
float random_x_angle;//6参数 xyz角度值(360)和xyz偏移
float random_y_angle;
float random_z_angle;
float random_x_dist;
float random_y_dist;
float random_z_dist;
Eigen::Matrix4f random_trans_matrix = Eigen::Matrix4f::Identity();
srand(time(NULL));
//以1度为角分辨率,从上面创建的点云创建深度图像。
float angularResolution = (float)(1.0f * (M_PI / 180.0f));
// 1度转弧度
float maxAngleWidth = (float)(360.0f * (M_PI / 180.0f));
// 360.0度转弧度
float maxAngleHeight = (float)(180.0f * (M_PI / 180.0f));
// 180.0度转弧度
Eigen::Affine3f sensorPose = (Eigen::Affine3f)Eigen::Translation3f(0.0f, 0.0f, 0.0f);
pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME;
float noiseLevel = 0.00;
float minRange = 0.0f;
int borderSize = 1;
pcl::RangeImage rangeImage;
float *ranges;
unsigned char* rgb_image;
string data_path_root = "D:/Git/regCNN/dataRaw/benchmark/db/"; //设置数据库目录
string off_path;//off目录
string path_ram;//存储路径缓存
int off_num = 0,data_num=0;
ofstream fout1("D:/Git/regCNN/dataDepth/label.txt");
string data_out_root = "D:/Git/regCNN/dataDepth/";//设置输出文件根目录
string path_out_ram0, path_out_ram1;
string path_out;//最终写入路径
string OBJfilename = "test.obj";//obj文件名 与函数read off中一致
for (int j = 0; j < 4; j++)//做0-3文件夹
{
#pragma omp parallel for //使用多线程for(也就提升一倍左右吧
for (int i = 0; i < 100; i++) //m0文件夹下做100次,下同
{
path_ram = "/m" + to_string(off_num) + "/m" + to_string(off_num) + ".off";
off_path = data_path_root;
off_path.append(to_string(data_num));
off_path.append(path_ram);
cout << "times " << off_num << endl;
//cout << "off_path " << off_path << endl;
read_off_file(off_path); //读取off并转为obj
//cout << "off read ok " << endl;
//读取obj
vtkSmartPointer<vtkOBJReader> readerQuery = vtkSmartPointer<vtkOBJReader>::New();
readerQuery->SetFileName(OBJfilename.c_str());
readerQuery->Update();
polydata1 = readerQuery->GetOutput();
//make sure that the polygons are triangles!
#if VTK_MAJOR_VERSION < 6
triangleFilter->SetInput(polydata1);
#else
triangleFilter->SetInputData(polydata1);
#endif
triangleFilter->Update();
triangleMapper->SetInputConnection(triangleFilter->GetOutputPort());
triangleMapper->Update();
polydata1 = triangleMapper->GetInput();
uniform_sampling(polydata1, SAMPLE_POINTS_, write_normals, *cloud_1);
// Voxelgrid
savePCDFileASCII("output1.pcd", *cloud_1);
grid_.setInputCloud(cloud_1);
grid_.setLeafSize(leaf_size, leaf_size, leaf_size);
grid_.filter(*voxel_cloud);
cout << "already covert to voxel point cloud !" << endl;
//显示转换后点云
//vis3.addPointCloud<pcl::PointNormal>(voxel_cloud);
//vis3.spin();
//保存PCD
savePCDFileASCII("output.pcd", *voxel_cloud);
copyPointCloud(*voxel_cloud, *voxelXYZCloud);
pointCloud = *voxelXYZCloud;
rangeImage.createFromPointCloud(pointCloud, angularResolution, maxAngleWidth, maxAngleHeight, sensorPose, coordinate_frame, noiseLevel, minRange, borderSize);
//std::cout << rangeImage << "\n";
ranges = rangeImage.getRangesArray();
rgb_image = pcl::visualization::FloatImageUtils::getVisualImage(ranges, rangeImage.width, rangeImage.height);
path_out_ram0 = "m" + to_string(off_num) + ".png";//设置深度图保存文件名
path_out_ram1 = "m" + to_string(off_num) + "-1.png";
path_out = data_out_root;
path_out.append(path_out_ram0);
pcl::io::saveRgbPNGFile(path_out, rgb_image, rangeImage.width, rangeImage.height);
std::cerr << "Picture Saved ! " << rangeImage.width << " x " << rangeImage.height << std::endl;
random_x_angle = (float)((rand() % 359 + 0.0) * (M_PI / 180.0f));//随机生成转角数据(rad
random_y_angle = (float)((rand() % 359 + 0.0) * (M_PI / 180.0f));
random_z_angle = (float)((rand() % 359 + 0.0) * (M_PI / 180.0f));
fout1 << random_x_angle << "," << random_y_angle << "," << random_z_angle << "\n";//写入label(rad
//赋值旋转矩阵
random_trans_matrix(0, 0) = cos(random_z_angle)*cos(random_y_angle);
random_trans_matrix(0, 1) = cos(random_z_angle)*sin(random_x_angle)*sin(random_y_angle) - cos(random_x_angle)*sin(random_z_angle);
random_trans_matrix(0, 2) = sin(random_z_angle)*sin(random_x_angle) + cos(random_z_angle)*cos(random_x_angle)*sin(random_y_angle);
random_trans_matrix(1, 0) = cos(random_y_angle)*sin(random_z_angle);
random_trans_matrix(1, 1) = cos(random_z_angle)*cos(random_x_angle) + sin(random_z_angle)*sin(random_x_angle)*sin(random_y_angle);
random_trans_matrix(1, 2) = cos(random_x_angle)*sin(random_z_angle)*sin(random_y_angle) - cos(random_z_angle)*sin(random_x_angle);
random_trans_matrix(2, 0) = -sin(random_y_angle);
random_trans_matrix(2, 1) = cos(random_y_angle)*sin(random_x_angle);
random_trans_matrix(2, 2) = cos(random_x_angle)*cos(random_y_angle);
pcl::transformPointCloud(pointCloud, pointCloud, random_trans_matrix);
//std::cerr << "random " << random_x_angle<<" "<< random_y_angle<<" "<< random_z_angle << std::endl;
//生成第二张深度图
rangeImage.createFromPointCloud(pointCloud, angularResolution, maxAngleWidth, maxAngleHeight, sensorPose, coordinate_frame, noiseLevel, minRange, borderSize);
//float *ranges;
ranges = rangeImage.getRangesArray();
//unsigned char* rgb_image;
rgb_image = pcl::visualization::FloatImageUtils::getVisualImage(ranges, rangeImage.width, rangeImage.height);
path_out = data_out_root;
path_out.append(path_out_ram1);
pcl::io::saveRgbPNGFile(path_out, rgb_image, rangeImage.width, rangeImage.height);
std::cerr << "Picture after Saved ! " << rangeImage.width << " x " << rangeImage.height << std::endl;
off_num = off_num + 1;//下一次读m1,类推
}
data_num++;//到1文件夹
}
fout1.close();
}