PCL点云显示带颜色变换窗体工具实例源码

PCL点云显示带颜色变换窗体工具实例源码

如需安装运行环境或远程调试,可加QQ905733049由专业技术人员远程协助!

运行结果如下:

代码如下:

#include "PoPoints.h"

PoPoints::PoPoints(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);


	/***** Slots connection of dataTree(QTreeWidget) widget *****/
// Item in dataTree is left-clicked (connect)
	QObject::connect(ui.dataTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(itemSelected(QTreeWidgetItem*, int)));
	// Item in dataTree is right-clicked
	QObject::connect(ui.dataTree, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(itemPopmenu(const QPoint&)));

	// About (connect)
	QObject::connect(ui.aboutAction, &QAction::triggered, this, &PoPoints::about);
	QObject::connect(ui.helpAction, &QAction::triggered, this, &PoPoints::help);

	//initialization

	QString qss = dark_qss;
	qApp->setStyleSheet(qss);

	// point cloud initialization
	cloud_now.reset(new PointCloudT);

	// visualization
	viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
	ui.qvtkWidget->SetRenderWindow(viewer->getRenderWindow());
	viewer->setupInteractor(ui.qvtkWidget->GetInteractor(), ui.qvtkWidget->GetRenderWindow());
	ui.qvtkWidget->update();

}

void PoPoints::open()
{
	QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Open point cloud file"), QString::fromLocal8Bit(model_dirname.c_str()), tr("Point cloud data(*.pcd *.ply *.obj);;All file(*.*)"));
	//Return if filenames is empty
	if (filenames.isEmpty())
		return;

	// Clear cache

	viewer->removeAllPointClouds();

	PointCloudT::Ptr  cloud_temp;
	// Open point cloud one by one
	for (int i = 0; i != filenames.size(); i++) {
		// time start

		cloud_temp.reset(new PointCloudT); // Reset cloud
		QString filename = filenames[i];
		std::string file_name = filename.toStdString();
		std::string subname = getFileName(file_name);  //提取全路径中的文件名(带后缀)

		//更新状态栏
		ui.statusBar->showMessage(QString::fromLocal8Bit(subname.c_str()) + ": " + QString::number(i) + "/" + QString::number(filenames.size()) + " point cloud loading...");

		int status = -1;
		if (filename.endsWith(".pcd", Qt::CaseInsensitive))
		{
			status = pcl::io::loadPCDFile(file_name, *cloud_temp);
		}
		else if (filename.endsWith(".ply", Qt::CaseInsensitive))
		{
			status = pcl::io::loadPLYFile(file_name, *cloud_temp);
		}
		else if (filename.endsWith(".obj", Qt::CaseInsensitive))
		{
			status = pcl::io::loadOBJFile(file_name, *cloud_temp);
		}

	{
		if (!(point_i % 10)) continue;
		cloud_temp->points[point_i].x = cloud_now->points[point_i].x + static_cast<float> (var_nor());
		cloud_temp->points[point_i].y = cloud_now->points[point_i].y + static_cast<float> (var_nor());
		cloud_temp->points[point_i].z = cloud_now->points[point_i].z + static_cast<float> (var_nor());
	}
	cloud_show.push_back(cloud_temp);
	updatePointcloud();
	ui.qvtkWidget->update();


}

void PoPoints::addOutlier()
{
	//添加高斯噪声
	int size = cloud_now->size();
	if (size == 0) return;
	std::cout << "Select : " << size << "point(s)" << std::endl;
	PointCloudT::Ptr cloud_temp(new PointCloudT);
	*cloud_temp = *cloud_now;

	//添加噪声
	size_t i = 0;
	for (; i < size; ++i)
	{
		

	}
	cloud_show.push_back(cloud_temp);
	updatePointcloud();
	ui.qvtkWidget->update();
}

void PoPoints::generateSphereShell()
{
	// populate our PointCloud with points
	PointCloudT::Ptr cloud_temp(new PointCloudT);
	cloud_temp->width = 6000;        
	cloud_temp->height = 1;           
	cloud_temp->is_dense = false;
	cloud_temp->resize(cloud_temp->width * cloud_temp->height); 
	float radius = 512;
	for (size_t i = 0; i < cloud_temp->points.size(); ++i)
	{
		
		cloud_temp->points[i].x = radius * 2 * rand() / (RAND_MAX + 1.0f)- radius;
		cloud_temp->points[i].y = radius * 2 * rand() / (RAND_MAX + 1.0f)- radius;
		//cloud_temp->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
		if (i % 2 == 0)
			cloud_temp->points[i].z = sqrt(radius *radius - (cloud_temp->points[i].x * cloud_temp->points[i].x) - (cloud_temp->points[i].y * cloud_temp->points[i].y));
		else
			cloud_temp->points[i].z = -sqrt(radius* radius - (cloud_temp->points[i].x * cloud_temp->points[i].x) - (cloud_temp->points[i].y * cloud_temp->points[i].y));
		
		cloud_temp->points[i].r = 255;
		cloud_temp->points[i].g = 255;
		cloud_temp->points[i].b = 255;
	}
	cloud_show.push_back(cloud_temp);
	updatePointcloud();
	ui.qvtkWidget->update();

}

void PoPoints::pointcolorChanged()
{
	QColor color = QColorDialog::getColor(Qt::white, this, "Select color for point cloud");

	if (color.isValid()) //判断所选的颜色是否有效
	{
		
		QList<QTreeWidgetItem*> itemList = ui.dataTree->selectedItems();
		int selected_item_count = ui.dataTree->selectedItems().size();
		if (selected_item_count == 0) {
			for (int i = 0; i != cloud_show.size(); i++) {
				for (int j = 0; j != cloud_show[i]->points.size(); j++) {
					cloud_show[i]->points[j].r = color.red();
					cloud_show[i]->points[j].g = color.green();
					cloud_show[i]->points[j].b = color.blue();
				}
			}

		}
		else {
			for (int i = 0; i != selected_item_count; i++) {
				int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
				for (int j = 0; j != cloud_show[cloud_id]->size(); j++) {
					cloud_show[cloud_id]->points[j].r = color.red();
					cloud_show[cloud_id]->points[j].g = color.green();
					cloud_show[cloud_id]->points[j].b = color.blue();
				}
			}
			// 输出窗口
			setConsole("Change cloud color", "to " + QString::number(color.red()) + " " + QString::number(color.green()) + " " + QString::number(color.blue()));
		}
	}
	updatePointcloud();
}

void PoPoints::pointcolorRamdom()
{
	unsigned int r = 255 * (rand() / (RAND_MAX + 1.0f));
	unsigned int g = 255 * (rand() / (RAND_MAX + 1.0f));
	unsigned int b = 255 * (rand() / (RAND_MAX + 1.0f));
	QList<QTreeWidgetItem*> itemList = ui.dataTree->selectedItems();
	int selected_item_count = ui.dataTree->selectedItems().size();
	if (selected_item_count == 0) {
		for (int i = 0; i != cloud_show.size(); i++) {
			for (int j = 0; j != cloud_show[i]->points.size(); j++) {
				cloud_show[i]->points[j].r = r;
				cloud_show[i]->points[j].g = g;
				cloud_show[i]->points[j].b = b;
			}
		}

	}
	else {
		for (int i = 0; i != selected_item_count; i++) {
			int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
			for (int j = 0; j != cloud_show[cloud_id]->size(); j++) {
				cloud_show[cloud_id]->points[j].r = r;
				cloud_show[cloud_id]->points[j].g = g;
				cloud_show[cloud_id]->points[j].b = b;
			}
		}
		// 输出窗口
		setConsole("Change cloud color", "to random color." );
	}
	updatePointcloud();
	ui.qvtkWidget->update();
}

void PoPoints::pointHide()
{
	QList<QTreeWidgetItem*> itemList = ui.dataTree->selectedItems();
	int selected_item_count = ui.dataTree->selectedItems().size();
	if (selected_item_count == 0) {
		for (int i = 0; i != cloud_show.size(); i++) {
			setCloudAlpha(cloud_show[i], 0);
		}

	}
	else {
		for (int i = 0; i != selected_item_count; i++) {
			int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
				setCloudAlpha(cloud_show[cloud_id], 0);
		}
		// 输出窗口
		setConsole("Hide", "");
	}
	updatePointcloud();
	ui.qvtkWidget->update();

}

void PoPoints::pointShow()
{
	QList<QTreeWidgetItem*> itemList = ui.dataTree->selectedItems();
	int selected_item_count = ui.dataTree->selectedItems().size();
	if (selected_item_count == 0) {
		for (int i = 0; i != cloud_show.size(); i++) {
			setCloudAlpha(cloud_show[i], 255);
		}

	}
	else {
		for (int i = 0; i != selected_item_count; i++) {
			int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
			setCloudAlpha(cloud_show[cloud_id], 255);
		}
		// 输出窗口
		setConsole("Hide", "");
	}
	updatePointcloud();
	ui.qvtkWidget->update();
}

void PoPoints::icp()
{
	int size = cloud_show.size();
	if ( size < 2) {
	// to do dlg
		setConsole("icp", " insufficient point cloud.");
		return;
	}
	PointCloudT::Ptr cloud_in(cloud_show[size-2]);  // Original point cloud
	PointCloudT::Ptr cloud_out(cloud_show[size - 1]);  // Transformed point cloud
	PointCloudT::Ptr cloud_icp(new PointCloudT);  // ICP output point cloud

	

  // The Iterative Closest Point algorithm
	pcl::console::TicToc time;
	int iterations = 10;  // Default number of ICP iterations
	time.tic();
	pcl::IterativeClosestPoint<PointT, PointT> icp;
	/*

	// Set the input source and target
	//icp.setInputCloud(cloud_source);
	//icp.setInputTarget(cloud_target);

	// Set the max correspondence distance to 5cm (e.g., correspondences with higher distances will be ignored)
	//icp.setMaxCorrespondenceDistance(0.05);
	// Set the maximum number of iterations (criterion 1)
	//icp.setMaximumIterations(50);
	// Set the transformation epsilon (criterion 2)
	//icp.setTransformationEpsilon(1e-8);
	// Set the euclidean distance difference epsilon (criterion 3)
	//icp.setEuclideanFitnessEpsilon(1);

	// Perform the alignment
	//icp.align(cloud_source_registered);
	// Obtain the transformation that aligned cloud_source to cloud_source_registered
	//Eigen::Matrix4f transformation = icp.getFinalTransformation();
	*/
	
	icp.setMaximumIterations(iterations);
	icp.setInputSource(cloud_in);
	icp.setInputTarget(cloud_out);
	icp.align(*cloud_icp);// Call the registration algorithm which estimates the transformation and returns the transformed source (input) as output.
	icp.setMaximumIterations(1);  // We set this variable to 1 for the next time we will call .align () function
	std::cout << "Applied " << iterations << " ICP iteration(s) in " << time.toc() << " ms" << std::endl;

	if (icp.hasConverged())
	{
		std::cout << "\nICP has converged, score is " << icp.getFitnessScore() << std::endl;
		std::cout << "\nICP transformation " << iterations << " : cloud_icp -> cloud_in" << std::endl;
		Eigen::Matrix4d transformation_matrix = icp.getFinalTransformation().cast<double>();
		print4x4MatrixT(transformation_matrix);
	}
	else
	{
		PCL_ERROR("\nICP has not converged.\n");
		return ;
	}
	cloud_show.push_back(cloud_icp);
	updatePointcloud();
	ui.qvtkWidget->update();
}


void PoPoints::naive_sfm()
{

	QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Open point cloud file"), QString::fromLocal8Bit(model_dirname.c_str()), tr("All file(*.*)"));
	//Return if filenames is empty
	if (filenames.size()<2)
		return;

	// Clear cache

	viewer->removeAllPointClouds();

	PointCloudT::Ptr  cloud_temp;
	// Open picture cloud one by one
	for (int i = 0; i != filenames.size(); i++) {
		// time start

		cloud_temp.reset(new PointCloudT); // Reset cloud
		QString filename = filenames[i];
		std::string file_name = filename.toStdString();
		std::string subname = getFileName(file_name);  //提取全路径中的文件名(带后缀)

		//更新状态栏
		ui.statusBar->showMessage(QString::fromLocal8Bit(subname.c_str()) + ": " + QString::number(i) + "/" + QString::number(filenames.size()) + " point cloud loading...");

		int status = 0;


		// 读取源图像并转化为灰度图像
		cv::Mat srcImage = cv::imread(file_name);
		// 判断文件是否读入正确
		if (!srcImage.data)
			status = 1;
		else {
			// 图像显示
			//cv::imshow("srcImage", srcImage);
			// 等待键盘键入
			//cv::waitKey(0);
		}
		//提示:后缀没问题,但文件内容无法读取
		if (status != 0)
		{
			QMessageBox::critical(this, tr("Reading file error"), tr("We can not open the file"));
			return;
		}
		//
	}
		cv::Mat img_1 = cv::imread(filenames[0].toStdString());
		cv::Mat img_2 = cv::imread(filenames[1].toStdString());
		if (!img_1.data || !img_2.data)
		{
			cout << "error reading images " << endl;
			return;

}


void PoPoints::about()
{
	AboutWin *aboutwin = new AboutWin(this);
	aboutwin->setModal(true);
	aboutwin->show();

	// 输出窗口
	setConsole("About", "All copyright given up.");

}

void PoPoints::help()
{
	HelpWin *helptwin = new HelpWin(this);
	helptwin->setModal(true);
	helptwin->show();

	// 输出窗口
	setConsole("Help", "Check the blog, will you?");
}

std::string PoPoints::getFileName(std::string file_name)
{

	std::string subname;
	for (auto i = file_name.end() - 1; *i != '/'; i--)
	{
		subname.insert(subname.begin(), *i);
	}
	return subname;
	
}

void PoPoints::print4x4MatrixT(const Eigen::Matrix4d & matrix)
{
	printf("Rotation matrix :\n");
	printf("    | %6.3f %6.3f %6.3f | \n", matrix(0, 0), matrix(0, 1), matrix(0, 2));
	printf("R = | %6.3f %6.3f %6.3f | \n", matrix(1, 0), matrix(1, 1), matrix(1, 2));
	printf("    | %6.3f %6.3f %6.3f | \n", matrix(2, 0), matrix(2, 1), matrix(2, 2));
	printf("Translation vector :\n");
	printf("t = < %6.3f, %6.3f, %6.3f >\n\n", matrix(0, 3), matrix(1, 3), matrix(2, 3));
}

void PoPoints::keyboardEventOccurred(const pcl::visualization::KeyboardEvent & event, void * nothing)
{
	if (event.getKeySym() == "space" && event.keyDown())
		next_iteration = true;
}


void PoPoints::setCloudRGB(PointCloudT::Ptr &cloud,unsigned int r, unsigned int g, unsigned int b)
{
	for (size_t i = 0; i < cloud->size(); i++)
	{
		cloud->points[i].r = r;
		cloud->points[i].g = g;
		cloud->points[i].b = b;
		cloud->points[i].a = 255;
	}
}

void PoPoints::setCloudAlpha(PointCloudT::Ptr & cloud, unsigned int a)
{
	for (size_t i = 0; i < cloud->size(); i++)
	{
		cloud->points[i].a = a;
	}
}

void PoPoints::setConsole(QString operation, QString detail)
{

	int rows = ui.consoleTable->rowCount();
	ui.consoleTable->setRowCount(++rows);
	QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间
	QString time_str = time.toString("MM-dd hh:mm:ss"); //设置显示格式
	ui.consoleTable->setItem(rows - 1, 0, new QTableWidgetItem(time_str));
	ui.consoleTable->setItem(rows - 1, 1, new QTableWidgetItem(operation));
	ui.consoleTable->setItem(rows - 1, 2, new QTableWidgetItem(detail));

	ui.consoleTable->scrollToBottom(); // 滑动自动滚到最底部
}

void PoPoints::itemSelected(QTreeWidgetItem * item, int count)
{
	count = ui.dataTree->indexOfTopLevelItem(item);  //获取item的行号

	for (int i = 0; i != cloud_show.size(); i++)
	{
		viewer->updatePointCloud(cloud_show[i], "cloud" + QString::number(i).toStdString());
		viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud" + QString::number(i).toStdString());
	}

	*cloud_now = *cloud_show[count];


	//选中item所对应的点云尺寸变大
	QList<QTreeWidgetItem*> itemList = ui.dataTree->selectedItems();
	int selected_item_count = ui.dataTree->selectedItems().size();
	for (int i = 0; i != selected_item_count; i++) {
		int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
		viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,
			2, "cloud" + QString::number(cloud_id).toStdString());
	}

	ui.qvtkWidget->update();

	setConsole("itemSelected", QString::number(selected_item_count)+ " item(s) selected.");

}

void PoPoints::itemPopmenu(const QPoint &)
{
	QTreeWidgetItem* curItem = ui.dataTree->currentItem(); //获取当前被点击的节点
	if (curItem == NULL)return;           //这种情况是右键的位置不在treeItem的范围内,即在空白位置右击
	QString name = curItem->text(0);
	int id = ui.dataTree->indexOfTopLevelItem(curItem);
	std::string cloud_id = "cloud" + QString::number(id).toStdString();


	//QAction deleteItemAction("Delete", this);
	QAction hideItemAction("Hide", this);
	QAction showItemAction("Show", this);
	QAction changeColorAction("Change color", this);
	QAction randomColorAction("Random color", this);


	//connect(&deleteItemAction, &QAction::triggered, this, &PoPoints::deleteItem);
	connect(&hideItemAction, &QAction::triggered, this, &PoPoints::pointHide);
	connect(&showItemAction, &QAction::triggered, this, &PoPoints::pointShow);
	connect(&changeColorAction, &QAction::triggered, this, &PoPoints::pointcolorChanged);
	connect(&randomColorAction, &QAction::triggered, this, &PoPoints::pointcolorRamdom);

	//QPoint pos;
	QMenu menu(ui.dataTree);
	menu.addAction(&hideItemAction);
	menu.addAction(&showItemAction);
	//menu.addAction(&deleteItemAction);
	menu.addAction(&changeColorAction);
	menu.addAction(&randomColorAction);

	//if (mycloud_vec[id].visible == true) {
	//	menu.actions()[1]->setVisible(false);
	//	menu.actions()[0]->setVisible(true);
	//}
	//else {
	//	menu.actions()[1]->setVisible(true);
	//	menu.actions()[0]->setVisible(false);
	//}


	menu.exec(QCursor::pos()); //在当前鼠标位置显示

	setConsole("popMenu", "popMenu");
}

void PoPoints::updatePointcloud()
{
	viewer->removeAllPointClouds();
	for (int i = 0; i != cloud_show.size(); i++)
	{
		viewer->addPointCloud(cloud_show[i], "cloud" + QString::number(i).toStdString());
		viewer->updatePointCloud(cloud_show[i], "cloud" + QString::number(i).toStdString());
	}
	//viewer->resetCamera();
	//ui.screen->update();
	updateDataTree();
	

}

void PoPoints::updateConsoleTable()
{
}

void PoPoints::updateDataTree()
{
	ui.dataTree->clear();
	//更新资源管理树
	for (int i = 0; i != cloud_show.size(); i++)
	{
		QTreeWidgetItem *cloudName = new QTreeWidgetItem(QStringList() << QString::fromLocal8Bit(std::to_string(i).c_str()));
		cloudName->setIcon(0, QIcon(":/Resources/images/icon.png"));
		ui.dataTree->addTopLevelItem(cloudName);
	}


}

void PoPoints::updatetPropertyTable()
{
}

运行结果如下:

C++学习参考实例

C++实现图形界面五子棋游戏源码:

https://blog.csdn.net/alicema1111/article/details/90035420

C++实现图形界面五子棋游戏源码2:

https://blog.csdn.net/alicema1111/article/details/106479579

C++ OpenCV相片视频人脸识别统计人数:

https://blog.csdn.net/alicema1111/article/details/105833928

VS2017+PCL开发环境配置:

https://blog.csdn.net/alicema1111/article/details/106877145

VS2017+Qt+PCL点云开发环境配置:

https://blog.csdn.net/alicema1111/article/details/105433636

C++ OpenCV汽车检测障碍物与测距:

https://blog.csdn.net/alicema1111/article/details/105833449

Windows VS2017安装配置PCL点云库:

https://blog.csdn.net/alicema1111/article/details/105111110

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荷塘月色2

您的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值