使用OpenGL读取off文件建立深度学习数据集

需要预装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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值