296 lines
9.6 KiB
C++
296 lines
9.6 KiB
C++
|
/**
|
|||
|
* @file DialogPCLStatisticalRemoveFilter.cpp
|
|||
|
* @brief None
|
|||
|
* @author 陈增辉 (3045316072@qq.com)
|
|||
|
* @version 2.5.0
|
|||
|
* @date 2024/4/5
|
|||
|
* @copyright Copyright (c) Since 2024 中科卫星应用研究院 All rights reserved.
|
|||
|
*/
|
|||
|
|
|||
|
// You may need to build the project (run Qt uic code generator) to get
|
|||
|
// "ui_DialogPCLStatisticalRemoveFilter.h" resolved
|
|||
|
|
|||
|
#include "DialogPCLRadiusOutlierRemoval.h"
|
|||
|
#include "ui_DialogPCLRadiusOutlierRemoval.h"
|
|||
|
|
|||
|
#include "PythonModule/PyAgent.h"
|
|||
|
#include "MeshData/meshSingleton.h"
|
|||
|
#include "MeshData/meshSet.h"
|
|||
|
#include <QMenu>
|
|||
|
#include <QDebug>
|
|||
|
#include <pcl/filters/convolution_3d.h>
|
|||
|
#include <QFileDialog>
|
|||
|
#include <QFileInfo>
|
|||
|
#include <pcl/filters/statistical_outlier_removal.h>
|
|||
|
#include <pcl/filters/radius_outlier_removal.h>
|
|||
|
#include "MeshData/meshKernal.h"
|
|||
|
#include "PointCloudOperator/PointCloudCommon.h"
|
|||
|
#include "Settings/BusAPI.h"
|
|||
|
#include "BaseTool.h"
|
|||
|
#include "IO/IOConfig.h"
|
|||
|
#include "ModuleBase/ThreadControl.h"
|
|||
|
#include "ConfigOptions/ConfigOptions.h"
|
|||
|
#include "ConfigOptions/MeshConfig.h"
|
|||
|
#include "Common/DebugLogger.h"
|
|||
|
|
|||
|
namespace MainWidget {
|
|||
|
DialogPCLRadiusOutlierRemoval::DialogPCLRadiusOutlierRemoval(GUI::MainWindow *parent)
|
|||
|
: QFDialog(parent),
|
|||
|
_ui(new Ui::DialogPCLRadiusOutlierRemoval),
|
|||
|
_mw(parent),
|
|||
|
_selectdlg(new DialogSelectComponents(parent))
|
|||
|
{
|
|||
|
_ui->setupUi(this);
|
|||
|
_ui->geoSelectPoint->setToolTip(tr("Clicked Button Selected Components"));
|
|||
|
setWindowTitle(tr("Radius Outlier Removal"));
|
|||
|
_ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
|||
|
|
|||
|
|
|||
|
connect(_ui->geoSelectPoint, &QPushButton::clicked, [=]()
|
|||
|
{ _selectdlg->clearSelectItems(); _selectdlg->exec(); });
|
|||
|
connect(_selectdlg, SIGNAL(selectedComponentsSig(QList<MeshData::MeshSet *>)), this, SLOT(selectedComponentsSlot(QList<MeshData::MeshSet *>)));
|
|||
|
connect(_ui->listWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(customContextMenuRequestedSlot(const QPoint &)));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DialogPCLRadiusOutlierRemoval::~DialogPCLRadiusOutlierRemoval()
|
|||
|
{
|
|||
|
delete _ui;
|
|||
|
_ui = NULL;
|
|||
|
delete _selectdlg;
|
|||
|
_selectdlg = NULL;
|
|||
|
}
|
|||
|
|
|||
|
void DialogPCLRadiusOutlierRemoval::accept()
|
|||
|
{
|
|||
|
if (_components.size() == 0)
|
|||
|
return;
|
|||
|
|
|||
|
QString componentIds, rotate, moveLocation, scale;
|
|||
|
for (auto component : _components)
|
|||
|
componentIds.append(QString(",%1").arg(component->getID()));
|
|||
|
componentIds.remove(0, 1);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
double RadiusSearch=_ui->RadiusSearch->value();
|
|||
|
double MinNeighborsInRadius=_ui->MinNeighborsInRadius->value();
|
|||
|
|
|||
|
|
|||
|
QString outfilename="filter";
|
|||
|
for (auto component : _components)
|
|||
|
outfilename.append(QString("_%1").arg(component->getName()));
|
|||
|
|
|||
|
// 确定是否保存结果文件
|
|||
|
QMessageBox::StandardButton result=QMessageBox::critical(this, "info","save as result ?");
|
|||
|
QString filepath= JoinPath(Setting::BusAPI::instance()->getWorkingDir() ,outfilename+"_tmep.pcd");
|
|||
|
QString AbFileName;
|
|||
|
if(result==QMessageBox::StandardButton::Ok||result==QMessageBox::StandardButton::Yes){
|
|||
|
QStringList suffixlist = IO::IOConfigure::getPclExporters();
|
|||
|
if(suffixlist.isEmpty()) {
|
|||
|
QMessageBox::warning(this, tr("Warning"), tr("The MeshPlugin is not installed !"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if(MeshData::MeshData::getInstance()->getKernalCount() == 0) {
|
|||
|
QMessageBox::warning(this, tr("Warning"), tr("No one has any grid!"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
QStringList meshsuffix = ConfigOption::ConfigOption::getInstance()
|
|||
|
->getMeshConfig()
|
|||
|
->getExportSuffix(ConfigOption::MeshDataType::PointCloud)
|
|||
|
.split(";");
|
|||
|
QStringList list;
|
|||
|
|
|||
|
for(QString s : meshsuffix) {
|
|||
|
for(int i = 0; i < suffixlist.size(); i++) {
|
|||
|
QString suffix = suffixlist.at(i);
|
|||
|
if(suffix.contains(s))
|
|||
|
list.append(suffix);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
std::sort(list.begin(), list.end());
|
|||
|
QString suffixes = list.join(";;");
|
|||
|
QString workDir = Setting::BusAPI::instance()->getWorkingDir();
|
|||
|
QFileDialog dlg(this, tr("Export Pcl"), workDir, suffixes);
|
|||
|
dlg.setAcceptMode(QFileDialog::AcceptSave);
|
|||
|
if(dlg.exec() != QFileDialog::FileName)
|
|||
|
return;
|
|||
|
|
|||
|
QString aSuffix = dlg.selectedNameFilter();
|
|||
|
QString aFileName = dlg.selectedFiles().join(",");
|
|||
|
if(!(aFileName.isEmpty())){
|
|||
|
filepath=aFileName;
|
|||
|
|
|||
|
}else{}
|
|||
|
|
|||
|
AbFileName=filepath;
|
|||
|
QTextCodec *codec = QTextCodec::codecForName("GB18030");
|
|||
|
QByteArray ba = codec->fromUnicode(filepath);
|
|||
|
|
|||
|
std::string outFileName=ba.data();
|
|||
|
|
|||
|
}else{ // 不保存成点云数据
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// 启动线程
|
|||
|
auto pclfilter = new WBFZ::PCLRadiusOutlierRemoval(
|
|||
|
AbFileName,WBFZ::PointCloudOperation::POINTCLOUD_FILTER,_mainWindow,componentIds, RadiusSearch,MinNeighborsInRadius);
|
|||
|
ModuleBase::ThreadControl* tc = new ModuleBase::ThreadControl(pclfilter);
|
|||
|
emit tc->threadStart(); // emit MSHwriter->start();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
QFDialog::accept();
|
|||
|
}
|
|||
|
|
|||
|
void DialogPCLRadiusOutlierRemoval::selectedComponentsSlot(QList<MeshData::MeshSet *> components)
|
|||
|
{
|
|||
|
for (MeshData::MeshSet *set : components)
|
|||
|
{
|
|||
|
if (_components.contains(set))
|
|||
|
continue;
|
|||
|
_components.append(set);
|
|||
|
_ui->listWidget->addItem(set->getName());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void DialogPCLRadiusOutlierRemoval::customContextMenuRequestedSlot(const QPoint &point)
|
|||
|
{
|
|||
|
QListWidgetItem *curItem = _ui->listWidget->itemAt(point);
|
|||
|
if (!curItem)
|
|||
|
return;
|
|||
|
|
|||
|
QMenu *menu = new QMenu(this);
|
|||
|
QAction *deleteItem = new QAction(tr("delete this item"));
|
|||
|
menu->addAction(deleteItem);
|
|||
|
connect(menu, &QMenu::triggered, [=]()
|
|||
|
{ removeCurrentItem(curItem); });
|
|||
|
menu->exec(QCursor::pos());
|
|||
|
}
|
|||
|
|
|||
|
void DialogPCLRadiusOutlierRemoval::removeCurrentItem(QListWidgetItem *curItem)
|
|||
|
{
|
|||
|
auto meshData = MeshData::MeshData::getInstance();
|
|||
|
auto meshSet = meshData->getMeshSetByName(curItem->text());
|
|||
|
if (!meshSet)
|
|||
|
return;
|
|||
|
_components.removeOne(meshSet);
|
|||
|
_ui->listWidget->removeItemWidget(curItem);
|
|||
|
delete curItem;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
} // namespace MainWidget
|
|||
|
|
|||
|
|
|||
|
|
|||
|
namespace WBFZ{
|
|||
|
WBFZ::PCLRadiusOutlierRemoval::PCLRadiusOutlierRemoval(const QString &fileName, WBFZ::PointCloudOperation operation,
|
|||
|
GUI::MainWindow* mw, QString componentIds,
|
|||
|
double RadiusSearch,double MinNeighborsInRadius)
|
|||
|
: PointCloudThreadBase(fileName, operation, mw)
|
|||
|
, _fileName(fileName)
|
|||
|
, _operation(operation)
|
|||
|
, _componentIds(componentIds)
|
|||
|
, _RadiusSearch(RadiusSearch)
|
|||
|
, _MinNeighborsInRadius(MinNeighborsInRadius)
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
vtkDataSet* WBFZ::PCLRadiusOutlierRemoval::PCLRadiusOutlierRemovalAlg(QString componentIds, double RadiusSearch,
|
|||
|
double MinNeighborsInRadius)
|
|||
|
{
|
|||
|
emit _mainwindow->printMessage(Common::Message::Normal,"PCLRadiusOutlierRemovalAlg");
|
|||
|
// 获取vtdataset
|
|||
|
QStringList qCompontIds = QString(componentIds).split(',');
|
|||
|
|
|||
|
MeshData::MeshSet* meshSet = NULL;
|
|||
|
MeshData::MeshKernal* meshKernal = NULL;
|
|||
|
MeshData::MeshData* meshData = MeshData::MeshData::getInstance();
|
|||
|
QString kernalName, transformedName, setType, ids;
|
|||
|
|
|||
|
// 筛选其中的点云数据
|
|||
|
// 创建 vtkCellDataToPointData 过滤器
|
|||
|
vtkSmartPointer<vtkGeometryFilter> cellToPointFilter = vtkSmartPointer<vtkGeometryFilter>::New();
|
|||
|
|
|||
|
QString outfilename;
|
|||
|
for(QString compontId : qCompontIds) {
|
|||
|
meshSet = meshData->getMeshSetByID(compontId.toInt());
|
|||
|
DebugInfo("point count %d : %d ",compontId.toInt(),meshSet==nullptr);
|
|||
|
if(!meshSet)
|
|||
|
continue;
|
|||
|
outfilename=meshSet->getName();
|
|||
|
vtkPolyData* temppolyData=PointCloudOperator::PointCloudCommon::meshSetToVtkDataset(meshSet);
|
|||
|
cellToPointFilter->SetInputData(temppolyData);
|
|||
|
DebugInfo("point count %d : %d ",compontId.toInt(),temppolyData==nullptr);
|
|||
|
}
|
|||
|
|
|||
|
// 执行过滤操作
|
|||
|
cellToPointFilter->Update();
|
|||
|
DebugInfo("cellToPointFilter ");
|
|||
|
// 获取过滤后的 vtkPolyData
|
|||
|
vtkPolyData* outpolyData = cellToPointFilter->GetOutput();
|
|||
|
DebugInfo("outpolyData ");
|
|||
|
|
|||
|
|
|||
|
|
|||
|
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud_with_rgba(new pcl::PointCloud<pcl::PointXYZRGBA>);
|
|||
|
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGBA>);
|
|||
|
pcl::io::vtkPolyDataToPointCloud(outpolyData,*cloud_with_rgba);
|
|||
|
|
|||
|
|
|||
|
// 创建滤波器对象
|
|||
|
pcl::RadiusOutlierRemoval<pcl::PointXYZRGBA> sor;
|
|||
|
sor.setInputCloud(cloud_with_rgba); //设置待滤波的点云
|
|||
|
sor.setRadiusSearch(RadiusSearch); //设置在进行统计时考虑查询点邻居点数,K个最近邻点
|
|||
|
sor.setMinNeighborsInRadius(MinNeighborsInRadius); //设置判断是否为离群点的阈值
|
|||
|
sor.filter(*cloud_filtered); //将滤波结果保存在cloud_filtered中
|
|||
|
|
|||
|
// 转换处理结果
|
|||
|
vtkPolyData* polydata=nullptr;
|
|||
|
polydata=vtkPolyData::New(); // 创建新的指针,智能指针会释放
|
|||
|
pcl::io::pointCloudTovtkPolyData(*cloud_filtered,polydata);
|
|||
|
vtkDataSet* dataset= vtkDataSet::SafeDownCast(polydata); // 默认完成 vtkpolydata --> vtkdataset
|
|||
|
size_t pointCount = dataset->GetNumberOfPoints();
|
|||
|
if(pointCount==0){
|
|||
|
return nullptr;
|
|||
|
}
|
|||
|
|
|||
|
emit _mainwindow->printMessage(Common::Message::Normal,"PCLRadiusOutlierRemovalAlg successfully!! Point Count : "+QString::number(pointCount));
|
|||
|
outpolyData->Delete(); // 释放指针
|
|||
|
|
|||
|
QString filepath=_fileName;
|
|||
|
|
|||
|
// 加载文件
|
|||
|
QFileInfo info(filepath);
|
|||
|
QString name = info.fileName();
|
|||
|
QString path = info.filePath();
|
|||
|
QString suffix = info.suffix().toLower();
|
|||
|
QTextCodec *codec = QTextCodec::codecForName("GB18030");
|
|||
|
QByteArray ba = codec->fromUnicode(filepath);
|
|||
|
|
|||
|
std::string outFileName=ba.data();
|
|||
|
if (suffix == "pcd")
|
|||
|
{
|
|||
|
pcl::io::savePCDFileBinary(outFileName,*cloud_filtered);
|
|||
|
}
|
|||
|
else if (suffix == "ply")
|
|||
|
{
|
|||
|
pcl::io::savePLYFileBinary(outFileName,*cloud_filtered);
|
|||
|
}
|
|||
|
else{}
|
|||
|
return dataset;
|
|||
|
}
|
|||
|
vtkDataSet* PCLRadiusOutlierRemoval::filter()
|
|||
|
{
|
|||
|
return PCLRadiusOutlierRemovalAlg( _componentIds, _RadiusSearch,_MinNeighborsInRadius);
|
|||
|
}
|
|||
|
PCLRadiusOutlierRemoval::~PCLRadiusOutlierRemoval() {}
|
|||
|
|
|||
|
}
|