2014-07-29 00:52:35 +00:00
/*
2016-07-17 21:57:10 -04:00
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
2014-08-11 17:00:55 +00:00
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
2014-07-29 00:52:35 +00:00
#include "ExportCloudsDialog.h"
#include "ui_exportCloudsDialog.h"
2016-02-15 19:35:24 -05:00
#include "rtabmap/gui/CloudViewer.h"
2017-02-26 18:17:00 -05:00
#include "TexturingState.h"
2016-02-15 19:35:24 -05:00
#include "rtabmap/utilite/ULogger.h"
#include "rtabmap/utilite/UConversion.h"
#include "rtabmap/utilite/UThread.h"
#include "rtabmap/utilite/UStl.h"
2017-04-09 19:16:50 -04:00
#include "rtabmap/utilite/UMath.h"
2016-02-15 19:35:24 -05:00
#include "rtabmap/core/util3d_filtering.h"
#include "rtabmap/core/util3d_surface.h"
#include "rtabmap/core/util3d_transforms.h"
#include "rtabmap/core/util3d.h"
2016-11-03 17:04:31 -04:00
#include "rtabmap/core/util2d.h"
2016-02-15 19:35:24 -05:00
#include "rtabmap/core/Graph.h"
2016-09-07 12:15:44 -04:00
#include "rtabmap/core/GainCompensator.h"
2016-09-19 14:01:06 -04:00
#include "rtabmap/core/clams/discrete_depth_distortion_model.h"
2017-03-21 21:51:39 -04:00
#include "rtabmap/core/DBDriver.h"
2016-02-15 19:35:24 -05:00
#include <pcl/conversions.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/vtk_io.h>
#include <pcl/io/obj_io.h>
2016-10-24 16:31:57 -04:00
#include <pcl/pcl_config.h>
2017-01-15 19:09:37 -05:00
#include <pcl/surface/poisson.h>
2016-02-15 19:35:24 -05:00
2015-03-16 19:51:22 +00:00
#include <QPushButton>
2016-02-15 19:35:24 -05:00
#include <QDir>
2016-02-17 16:01:14 -05:00
#include <QFileInfo>
2016-02-15 19:35:24 -05:00
#include <QMessageBox>
#include <QFileDialog>
#include <QInputDialog>
2016-11-21 12:02:29 -05:00
#include <QDesktopWidget>
2014-07-29 00:52:35 +00:00
namespace rtabmap {
2014-10-01 17:52:27 +00:00
ExportCloudsDialog :: ExportCloudsDialog ( QWidget * parent ) :
2016-09-19 14:01:06 -04:00
QDialog ( parent ),
2017-01-16 18:29:14 -05:00
_canceled ( false ),
2017-03-21 21:51:39 -04:00
_compensator ( 0 ),
_dbDriver ( 0 )
2014-07-29 00:52:35 +00:00
{
_ui = new Ui_ExportCloudsDialog ();
_ui -> setupUi ( this );
2015-01-14 15:09:16 -05:00
connect ( _ui -> buttonBox -> button ( QDialogButtonBox :: RestoreDefaults ), SIGNAL ( clicked ()), this , SLOT ( restoreDefaults ()));
2015-01-23 11:17:42 -05:00
2015-08-24 11:59:26 -04:00
restoreDefaults ();
_ui -> comboBox_upsamplingMethod -> setItemData ( 1 , 0 , Qt :: UserRole - 1 ); // disable DISTINCT_CLOUD
connect ( _ui -> checkBox_binary , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_normalKSearch , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
2016-02-15 19:35:24 -05:00
connect ( _ui -> comboBox_pipeline , SIGNAL ( currentIndexChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> comboBox_pipeline , SIGNAL ( currentIndexChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2017-01-15 19:09:37 -05:00
connect ( _ui -> comboBox_meshingApproach , SIGNAL ( currentIndexChanged ( int )), this , SIGNAL ( configChanged ()));
2017-01-19 11:20:48 -05:00
connect ( _ui -> comboBox_meshingApproach , SIGNAL ( currentIndexChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_regenerate , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_regenerate , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2015-01-23 11:17:42 -05:00
connect ( _ui -> spinBox_decimation , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_maxDepth , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2016-04-12 15:14:04 -04:00
connect ( _ui -> doubleSpinBox_minDepth , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-01-16 01:32:53 -05:00
connect ( _ui -> spinBox_fillDepthHoles , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_fillDepthHolesError , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> lineEdit_roiRatios , SIGNAL ( textChanged ( const QString & )), this , SIGNAL ( configChanged ()));
2016-09-19 14:01:06 -04:00
connect ( _ui -> lineEdit_distortionModel , SIGNAL ( textChanged ( const QString & )), this , SIGNAL ( configChanged ()));
connect ( _ui -> toolButton_distortionModel , SIGNAL ( clicked ()), this , SLOT ( selectDistortionModel ()));
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_bilateral , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_bilateral , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2016-11-03 17:04:31 -04:00
connect ( _ui -> doubleSpinBox_bilateral_sigmaS , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_bilateral_sigmaR , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_filtering , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_filtering , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2015-08-24 17:12:39 -04:00
connect ( _ui -> doubleSpinBox_filteringRadius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_filteringMinNeighbors , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
2016-02-15 19:35:24 -05:00
connect ( _ui -> checkBox_assemble , SIGNAL ( clicked ( bool )), this , SIGNAL ( configChanged ()));
2017-01-19 11:20:48 -05:00
connect ( _ui -> checkBox_assemble , SIGNAL ( clicked ( bool )), this , SLOT ( updateReconstructionFlavor ()));
2015-08-24 11:59:26 -04:00
connect ( _ui -> doubleSpinBox_voxelSize_assembled , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_subtraction , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_subtraction , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2016-02-15 19:35:24 -05:00
connect ( _ui -> doubleSpinBox_subtractPointFilteringRadius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_subtractPointFilteringAngle , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_subtractFilteringMinPts , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_smoothing , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_smoothing , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2015-01-23 11:17:42 -05:00
connect ( _ui -> doubleSpinBox_mlsRadius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2015-08-24 11:59:26 -04:00
connect ( _ui -> spinBox_polygonialOrder , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> comboBox_upsamplingMethod , SIGNAL ( currentIndexChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_sampleStep , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_randomPoints , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_dilationVoxelSize , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_dilationSteps , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
_ui -> stackedWidget_upsampling -> setCurrentIndex ( _ui -> comboBox_upsamplingMethod -> currentIndex ());
connect ( _ui -> comboBox_upsamplingMethod , SIGNAL ( currentIndexChanged ( int )), _ui -> stackedWidget_upsampling , SLOT ( setCurrentIndex ( int )));
connect ( _ui -> comboBox_upsamplingMethod , SIGNAL ( currentIndexChanged ( int )), this , SLOT ( updateMLSGrpVisibility ()));
2016-09-07 12:15:44 -04:00
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_gainCompensation , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_gainCompensation , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2016-09-07 12:15:44 -04:00
connect ( _ui -> doubleSpinBox_gainRadius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_gainOverlap , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_gainBeta , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-03-30 15:33:48 -04:00
connect ( _ui -> checkBox_gainFull , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_textureBrightnessContrastRatioLow , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_textureBrightnessContrastRatioHigh , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
2017-03-30 21:33:15 -04:00
connect ( _ui -> checkBox_exposureFusion , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
2017-04-09 19:16:50 -04:00
connect ( _ui -> checkBox_blending , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> comboBox_blendingDecimation , SIGNAL ( currentIndexChanged ( int )), this , SIGNAL ( configChanged ()));
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_meshing , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_meshing , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
connect ( _ui -> checkBox_meshing , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2015-01-23 11:17:42 -05:00
connect ( _ui -> doubleSpinBox_gp3Radius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2015-08-11 17:19:12 -04:00
connect ( _ui -> doubleSpinBox_gp3Mu , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2015-08-24 12:49:45 -04:00
connect ( _ui -> doubleSpinBox_meshDecimationFactor , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-01-19 11:20:48 -05:00
connect ( _ui -> doubleSpinBox_meshDecimationFactor , SIGNAL ( valueChanged ( double )), this , SLOT ( updateReconstructionFlavor ()));
2017-03-30 15:33:48 -04:00
connect ( _ui -> spinBox_meshMaxPolygons , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_meshMaxPolygons , SIGNAL ( valueChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2017-01-15 19:09:37 -05:00
connect ( _ui -> doubleSpinBox_transferColorRadius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-01-16 01:32:53 -05:00
connect ( _ui -> checkBox_cleanMesh , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
2017-02-06 21:07:27 -05:00
connect ( _ui -> spinBox_mesh_minClusterSize , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
2015-08-24 11:59:26 -04:00
connect ( _ui -> checkBox_textureMapping , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
2017-01-19 11:20:48 -05:00
connect ( _ui -> checkBox_textureMapping , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2017-01-17 14:57:50 -05:00
connect ( _ui -> comboBox_meshingTextureFormat , SIGNAL ( currentIndexChanged ( int )), this , SIGNAL ( configChanged ()));
2017-01-19 11:20:48 -05:00
connect ( _ui -> comboBox_meshingTextureSize , SIGNAL ( currentIndexChanged ( int )), this , SIGNAL ( configChanged ()));
2017-01-31 23:26:35 -05:00
connect ( _ui -> doubleSpinBox_meshingTextureMaxDistance , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-03-04 18:20:26 -05:00
connect ( _ui -> spinBox_mesh_minTextureClusterSize , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
2017-04-20 11:51:23 -04:00
connect ( _ui -> lineEdit_meshingTextureRoiRatios , SIGNAL ( textChanged ( const QString & )), this , SIGNAL ( configChanged ()));
2017-02-26 18:17:00 -05:00
connect ( _ui -> checkBox_cameraFilter , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_cameraFilter , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
connect ( _ui -> doubleSpinBox_cameraFilterRadius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_cameraFilterAngle , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2016-02-15 19:35:24 -05:00
2017-01-15 19:09:37 -05:00
connect ( _ui -> checkBox_poisson_outputPolygons , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_poisson_manifold , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_poisson_depth , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_poisson_iso , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_poisson_solver , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_poisson_minDepth , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_poisson_samples , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_poisson_pointWeight , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_poisson_scale , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2016-02-15 19:35:24 -05:00
_progressDialog = new ProgressDialog ( this );
_progressDialog -> setVisible ( false );
_progressDialog -> setAutoClose ( true , 2 );
_progressDialog -> setMinimumWidth ( 600 );
2016-09-19 14:01:06 -04:00
_progressDialog -> setCancelButtonVisible ( true );
connect ( _progressDialog , SIGNAL ( canceled ()), this , SLOT ( cancel ()));
2016-02-15 19:35:24 -05:00
#ifdef DISABLE_VTK
_ui -> doubleSpinBox_meshDecimationFactor -> setEnabled ( false );
2017-03-30 15:33:48 -04:00
_ui -> spinBox_meshMaxPolygons -> setEnabled ( false );
_ui -> label_meshDecimation -> setEnabled ( false );
_ui -> label_meshMaxPolygons -> setEnabled ( false );
2016-02-15 19:35:24 -05:00
#endif
2017-03-31 18:53:46 -04:00
#if CV_MAJOR_VERSION < 3
_ui -> checkBox_exposureFusion -> setEnabled ( false );
_ui -> checkBox_exposureFusion -> setChecked ( false );
_ui -> label_exposureFusion -> setEnabled ( false );
#endif
2014-07-29 00:52:35 +00:00
}
ExportCloudsDialog ::~ ExportCloudsDialog ()
{
delete _ui ;
2017-01-16 18:29:14 -05:00
if ( _compensator )
{
delete _compensator ;
}
2014-07-29 00:52:35 +00:00
}
2015-08-24 11:59:26 -04:00
void ExportCloudsDialog :: updateMLSGrpVisibility ()
{
_ui -> groupBox -> setVisible ( _ui -> comboBox_upsamplingMethod -> currentIndex () == 0 );
_ui -> groupBox_2 -> setVisible ( _ui -> comboBox_upsamplingMethod -> currentIndex () == 1 );
_ui -> groupBox_3 -> setVisible ( _ui -> comboBox_upsamplingMethod -> currentIndex () == 2 );
_ui -> groupBox_4 -> setVisible ( _ui -> comboBox_upsamplingMethod -> currentIndex () == 3 );
_ui -> groupBox_5 -> setVisible ( _ui -> comboBox_upsamplingMethod -> currentIndex () == 4 );
}
2016-09-07 12:15:44 -04:00
2016-09-19 14:01:06 -04:00
void ExportCloudsDialog :: cancel ()
{
_canceled = true ;
_progressDialog -> appendText ( tr ( "Canceled!" ));
}
2015-03-04 17:27:44 -05:00
void ExportCloudsDialog :: saveSettings ( QSettings & settings , const QString & group ) const
{
if ( ! group . isEmpty ())
{
settings . beginGroup ( group );
}
2016-06-12 17:53:35 -04:00
settings . setValue ( "pipeline" , _ui -> comboBox_pipeline -> currentIndex ());
2016-02-15 19:35:24 -05:00
settings . setValue ( "binary" , _ui -> checkBox_binary -> isChecked ());
settings . setValue ( "normals_k" , _ui -> spinBox_normalKSearch -> value ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
settings . setValue ( "regenerate" , _ui -> checkBox_regenerate -> isChecked ());
2016-02-15 19:35:24 -05:00
settings . setValue ( "regenerate_decimation" , _ui -> spinBox_decimation -> value ());
settings . setValue ( "regenerate_max_depth" , _ui -> doubleSpinBox_maxDepth -> value ());
2016-04-12 15:14:04 -04:00
settings . setValue ( "regenerate_min_depth" , _ui -> doubleSpinBox_minDepth -> value ());
2017-01-16 01:32:53 -05:00
settings . setValue ( "regenerate_fill_size" , _ui -> spinBox_fillDepthHoles -> value ());
settings . setValue ( "regenerate_fill_error" , _ui -> spinBox_fillDepthHolesError -> value ());
settings . setValue ( "regenerate_roi" , _ui -> lineEdit_roiRatios -> text ());
2016-09-19 14:01:06 -04:00
settings . setValue ( "regenerate_distortion_model" , _ui -> lineEdit_distortionModel -> text ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
settings . setValue ( "bilateral" , _ui -> checkBox_bilateral -> isChecked ());
2016-11-03 17:04:31 -04:00
settings . setValue ( "bilateral_sigma_s" , _ui -> doubleSpinBox_bilateral_sigmaS -> value ());
settings . setValue ( "bilateral_sigma_r" , _ui -> doubleSpinBox_bilateral_sigmaR -> value ());
2015-08-24 17:12:39 -04:00
2017-02-26 18:17:00 -05:00
settings . setValue ( "filtering" , _ui -> checkBox_filtering -> isChecked ());
2016-02-15 19:35:24 -05:00
settings . setValue ( "filtering_radius" , _ui -> doubleSpinBox_filteringRadius -> value ());
settings . setValue ( "filtering_min_neighbors" , _ui -> spinBox_filteringMinNeighbors -> value ());
2015-08-24 11:59:26 -04:00
2016-02-15 19:35:24 -05:00
settings . setValue ( "assemble" , _ui -> checkBox_assemble -> isChecked ());
settings . setValue ( "assemble_voxel" , _ui -> doubleSpinBox_voxelSize_assembled -> value ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
settings . setValue ( "subtract" , _ui -> checkBox_subtraction -> isChecked ());
2016-02-15 19:35:24 -05:00
settings . setValue ( "subtract_point_radius" , _ui -> doubleSpinBox_subtractPointFilteringRadius -> value ());
settings . setValue ( "subtract_point_angle" , _ui -> doubleSpinBox_subtractPointFilteringAngle -> value ());
settings . setValue ( "subtract_min_neighbors" , _ui -> spinBox_subtractFilteringMinPts -> value ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
settings . setValue ( "mls" , _ui -> checkBox_smoothing -> isChecked ());
2016-02-15 19:35:24 -05:00
settings . setValue ( "mls_radius" , _ui -> doubleSpinBox_mlsRadius -> value ());
settings . setValue ( "mls_polygonial_order" , _ui -> spinBox_polygonialOrder -> value ());
settings . setValue ( "mls_upsampling_method" , _ui -> comboBox_upsamplingMethod -> currentIndex ());
settings . setValue ( "mls_upsampling_radius" , _ui -> doubleSpinBox_sampleRadius -> value ());
settings . setValue ( "mls_upsampling_step" , _ui -> doubleSpinBox_sampleStep -> value ());
settings . setValue ( "mls_point_density" , _ui -> spinBox_randomPoints -> value ());
settings . setValue ( "mls_dilation_voxel_size" , _ui -> doubleSpinBox_dilationVoxelSize -> value ());
settings . setValue ( "mls_dilation_iterations" , _ui -> spinBox_dilationSteps -> value ());
2017-02-26 18:17:00 -05:00
settings . setValue ( "gain" , _ui -> checkBox_gainCompensation -> isChecked ());
2016-09-07 12:15:44 -04:00
settings . setValue ( "gain_radius" , _ui -> doubleSpinBox_gainRadius -> value ());
settings . setValue ( "gain_overlap" , _ui -> doubleSpinBox_gainOverlap -> value ());
settings . setValue ( "gain_beta" , _ui -> doubleSpinBox_gainBeta -> value ());
2017-03-30 15:33:48 -04:00
settings . setValue ( "gain_full" , _ui -> checkBox_gainFull -> isChecked ());
2016-09-07 12:15:44 -04:00
2017-02-26 18:17:00 -05:00
settings . setValue ( "mesh" , _ui -> checkBox_meshing -> isChecked ());
2016-02-15 19:35:24 -05:00
settings . setValue ( "mesh_radius" , _ui -> doubleSpinBox_gp3Radius -> value ());
settings . setValue ( "mesh_mu" , _ui -> doubleSpinBox_gp3Mu -> value ());
settings . setValue ( "mesh_decimation_factor" , _ui -> doubleSpinBox_meshDecimationFactor -> value ());
2017-03-30 15:33:48 -04:00
settings . setValue ( "mesh_max_polygons" , _ui -> spinBox_meshMaxPolygons -> value ());
2017-01-15 19:09:37 -05:00
settings . setValue ( "mesh_color_radius" , _ui -> doubleSpinBox_transferColorRadius -> value ());
2017-01-16 01:32:53 -05:00
settings . setValue ( "mesh_clean" , _ui -> checkBox_cleanMesh -> isChecked ());
2016-09-03 18:59:43 -04:00
settings . setValue ( "mesh_min_cluster_size" , _ui -> spinBox_mesh_minClusterSize -> value ());
2016-02-15 19:35:24 -05:00
2017-01-15 19:09:37 -05:00
settings . setValue ( "mesh_dense_strategy" , _ui -> comboBox_meshingApproach -> currentIndex ());
2016-02-15 19:35:24 -05:00
settings . setValue ( "mesh_texture" , _ui -> checkBox_textureMapping -> isChecked ());
2017-01-17 14:57:50 -05:00
settings . setValue ( "mesh_textureFormat" , _ui -> comboBox_meshingTextureFormat -> currentIndex ());
2017-01-19 11:20:48 -05:00
settings . setValue ( "mesh_textureSize" , _ui -> comboBox_meshingTextureSize -> currentIndex ());
2017-01-31 23:26:35 -05:00
settings . setValue ( "mesh_textureMaxDistance" , _ui -> doubleSpinBox_meshingTextureMaxDistance -> value ());
2017-03-04 18:20:26 -05:00
settings . setValue ( "mesh_textureMinCluster" , _ui -> spinBox_mesh_minTextureClusterSize -> value ());
2017-04-20 11:51:23 -04:00
settings . setValue ( "mesh_textureRoiRatios" , _ui -> lineEdit_meshingTextureRoiRatios -> text ());
2017-02-26 18:17:00 -05:00
settings . setValue ( "mesh_textureCameraFiltering" , _ui -> checkBox_cameraFilter -> isChecked ());
settings . setValue ( "mesh_textureCameraFilteringRadius" , _ui -> doubleSpinBox_cameraFilterRadius -> value ());
settings . setValue ( "mesh_textureCameraFilteringAngle" , _ui -> doubleSpinBox_cameraFilterAngle -> value ());
2017-03-30 15:33:48 -04:00
settings . setValue ( "mesh_textureBrightnessConstrastRatioLow" , _ui -> spinBox_textureBrightnessContrastRatioLow -> value ());
settings . setValue ( "mesh_textureBrightnessConstrastRatioHigh" , _ui -> spinBox_textureBrightnessContrastRatioHigh -> value ());
2017-03-30 21:33:15 -04:00
settings . setValue ( "mesh_textureExposureFusion" , _ui -> checkBox_exposureFusion -> isChecked ());
2017-04-09 19:16:50 -04:00
settings . setValue ( "mesh_textureBlending" , _ui -> checkBox_blending -> isChecked ());
settings . setValue ( "mesh_textureBlendingDecimation" , _ui -> comboBox_blendingDecimation -> currentIndex ());
2017-01-31 23:26:35 -05:00
2016-02-15 19:35:24 -05:00
settings . setValue ( "mesh_angle_tolerance" , _ui -> doubleSpinBox_mesh_angleTolerance -> value ());
settings . setValue ( "mesh_quad" , _ui -> checkBox_mesh_quad -> isChecked ());
settings . setValue ( "mesh_triangle_size" , _ui -> spinBox_mesh_triangleSize -> value ());
2015-08-24 11:59:26 -04:00
2017-01-15 19:09:37 -05:00
settings . setValue ( "poisson_outputPolygons" , _ui -> checkBox_poisson_outputPolygons -> isChecked ());
settings . setValue ( "poisson_manifold" , _ui -> checkBox_poisson_manifold -> isChecked ());
settings . setValue ( "poisson_depth" , _ui -> spinBox_poisson_depth -> value ());
settings . setValue ( "poisson_iso" , _ui -> spinBox_poisson_iso -> value ());
settings . setValue ( "poisson_solver" , _ui -> spinBox_poisson_solver -> value ());
settings . setValue ( "poisson_minDepth" , _ui -> spinBox_poisson_minDepth -> value ());
settings . setValue ( "poisson_samples" , _ui -> doubleSpinBox_poisson_samples -> value ());
settings . setValue ( "poisson_pointWeight" , _ui -> doubleSpinBox_poisson_pointWeight -> value ());
settings . setValue ( "poisson_scale" , _ui -> doubleSpinBox_poisson_scale -> value ());
2015-03-04 17:27:44 -05:00
if ( ! group . isEmpty ())
{
settings . endGroup ();
}
}
void ExportCloudsDialog :: loadSettings ( QSettings & settings , const QString & group )
{
if ( ! group . isEmpty ())
{
settings . beginGroup ( group );
}
2015-08-24 11:59:26 -04:00
2016-06-12 17:53:35 -04:00
_ui -> comboBox_pipeline -> setCurrentIndex ( settings . value ( "pipeline" , _ui -> comboBox_pipeline -> currentIndex ()). toInt ());
2016-02-15 19:35:24 -05:00
_ui -> checkBox_binary -> setChecked ( settings . value ( "binary" , _ui -> checkBox_binary -> isChecked ()). toBool ());
_ui -> spinBox_normalKSearch -> setValue ( settings . value ( "normals_k" , _ui -> spinBox_normalKSearch -> value ()). toInt ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_regenerate -> setChecked ( settings . value ( "regenerate" , _ui -> checkBox_regenerate -> isChecked ()). toBool ());
2016-02-15 19:35:24 -05:00
_ui -> spinBox_decimation -> setValue ( settings . value ( "regenerate_decimation" , _ui -> spinBox_decimation -> value ()). toInt ());
_ui -> doubleSpinBox_maxDepth -> setValue ( settings . value ( "regenerate_max_depth" , _ui -> doubleSpinBox_maxDepth -> value ()). toDouble ());
2016-04-12 15:14:04 -04:00
_ui -> doubleSpinBox_minDepth -> setValue ( settings . value ( "regenerate_min_depth" , _ui -> doubleSpinBox_minDepth -> value ()). toDouble ());
2017-01-16 01:32:53 -05:00
_ui -> spinBox_fillDepthHoles -> setValue ( settings . value ( "regenerate_fill_size" , _ui -> spinBox_fillDepthHoles -> value ()). toInt ());
_ui -> spinBox_fillDepthHolesError -> setValue ( settings . value ( "regenerate_fill_error" , _ui -> spinBox_fillDepthHolesError -> value ()). toInt ());
_ui -> lineEdit_roiRatios -> setText ( settings . value ( "regenerate_roi" , _ui -> lineEdit_roiRatios -> text ()). toString ());
2016-09-19 14:01:06 -04:00
_ui -> lineEdit_distortionModel -> setText ( settings . value ( "regenerate_distortion_model" , _ui -> lineEdit_distortionModel -> text ()). toString ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_bilateral -> setChecked ( settings . value ( "bilateral" , _ui -> checkBox_bilateral -> isChecked ()). toBool ());
2016-11-03 17:04:31 -04:00
_ui -> doubleSpinBox_bilateral_sigmaS -> setValue ( settings . value ( "bilateral_sigma_s" , _ui -> doubleSpinBox_bilateral_sigmaS -> value ()). toDouble ());
_ui -> doubleSpinBox_bilateral_sigmaR -> setValue ( settings . value ( "bilateral_sigma_r" , _ui -> doubleSpinBox_bilateral_sigmaR -> value ()). toDouble ());
2017-02-26 18:17:00 -05:00
_ui -> checkBox_filtering -> setChecked ( settings . value ( "filtering" , _ui -> checkBox_filtering -> isChecked ()). toBool ());
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_filteringRadius -> setValue ( settings . value ( "filtering_radius" , _ui -> doubleSpinBox_filteringRadius -> value ()). toDouble ());
_ui -> spinBox_filteringMinNeighbors -> setValue ( settings . value ( "filtering_min_neighbors" , _ui -> spinBox_filteringMinNeighbors -> value ()). toInt ());
2015-08-24 17:12:39 -04:00
2016-02-15 19:35:24 -05:00
_ui -> checkBox_assemble -> setChecked ( settings . value ( "assemble" , _ui -> checkBox_assemble -> isChecked ()). toBool ());
_ui -> doubleSpinBox_voxelSize_assembled -> setValue ( settings . value ( "assemble_voxel" , _ui -> doubleSpinBox_voxelSize_assembled -> value ()). toDouble ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_subtraction -> setChecked ( settings . value ( "subtract" , _ui -> checkBox_subtraction -> isChecked ()). toBool ());
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_subtractPointFilteringRadius -> setValue ( settings . value ( "subtract_point_radius" , _ui -> doubleSpinBox_subtractPointFilteringRadius -> value ()). toDouble ());
_ui -> doubleSpinBox_subtractPointFilteringAngle -> setValue ( settings . value ( "subtract_point_angle" , _ui -> doubleSpinBox_subtractPointFilteringAngle -> value ()). toDouble ());
_ui -> spinBox_subtractFilteringMinPts -> setValue ( settings . value ( "subtract_min_neighbors" , _ui -> spinBox_subtractFilteringMinPts -> value ()). toInt ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_smoothing -> setChecked ( settings . value ( "mls" , _ui -> checkBox_smoothing -> isChecked ()). toBool ());
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_mlsRadius -> setValue ( settings . value ( "mls_radius" , _ui -> doubleSpinBox_mlsRadius -> value ()). toDouble ());
_ui -> spinBox_polygonialOrder -> setValue ( settings . value ( "mls_polygonial_order" , _ui -> spinBox_polygonialOrder -> value ()). toInt ());
_ui -> comboBox_upsamplingMethod -> setCurrentIndex ( settings . value ( "mls_upsampling_method" , _ui -> comboBox_upsamplingMethod -> currentIndex ()). toInt ());
_ui -> doubleSpinBox_sampleRadius -> setValue ( settings . value ( "mls_upsampling_radius" , _ui -> doubleSpinBox_sampleRadius -> value ()). toDouble ());
_ui -> doubleSpinBox_sampleStep -> setValue ( settings . value ( "mls_upsampling_step" , _ui -> doubleSpinBox_sampleStep -> value ()). toDouble ());
_ui -> spinBox_randomPoints -> setValue ( settings . value ( "mls_point_density" , _ui -> spinBox_randomPoints -> value ()). toInt ());
_ui -> doubleSpinBox_dilationVoxelSize -> setValue ( settings . value ( "mls_dilation_voxel_size" , _ui -> doubleSpinBox_dilationVoxelSize -> value ()). toDouble ());
_ui -> spinBox_dilationSteps -> setValue ( settings . value ( "mls_dilation_iterations" , _ui -> spinBox_dilationSteps -> value ()). toInt ());
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_gainCompensation -> setChecked ( settings . value ( "gain" , _ui -> checkBox_gainCompensation -> isChecked ()). toBool ());
2016-09-07 12:15:44 -04:00
_ui -> doubleSpinBox_gainRadius -> setValue ( settings . value ( "gain_radius" , _ui -> doubleSpinBox_gainRadius -> value ()). toDouble ());
_ui -> doubleSpinBox_gainOverlap -> setValue ( settings . value ( "gain_overlap" , _ui -> doubleSpinBox_gainOverlap -> value ()). toDouble ());
_ui -> doubleSpinBox_gainBeta -> setValue ( settings . value ( "gain_beta" , _ui -> doubleSpinBox_gainBeta -> value ()). toDouble ());
2017-03-30 15:33:48 -04:00
_ui -> checkBox_gainFull -> setChecked ( settings . value ( "gain_full" , _ui -> checkBox_gainFull -> isChecked ()). toBool ());
2016-09-07 12:15:44 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_meshing -> setChecked ( settings . value ( "mesh" , _ui -> checkBox_meshing -> isChecked ()). toBool ());
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_gp3Radius -> setValue ( settings . value ( "mesh_radius" , _ui -> doubleSpinBox_gp3Radius -> value ()). toDouble ());
_ui -> doubleSpinBox_gp3Mu -> setValue ( settings . value ( "mesh_mu" , _ui -> doubleSpinBox_gp3Mu -> value ()). toDouble ());
_ui -> doubleSpinBox_meshDecimationFactor -> setValue ( settings . value ( "mesh_decimation_factor" , _ui -> doubleSpinBox_meshDecimationFactor -> value ()). toDouble ());
2017-03-30 15:33:48 -04:00
_ui -> spinBox_meshMaxPolygons -> setValue ( settings . value ( "mesh_max_polygons" , _ui -> spinBox_meshMaxPolygons -> value ()). toDouble ());
2017-01-15 19:09:37 -05:00
_ui -> doubleSpinBox_transferColorRadius -> setValue ( settings . value ( "mesh_color_radius" , _ui -> doubleSpinBox_transferColorRadius -> value ()). toDouble ());
2017-01-16 01:32:53 -05:00
_ui -> checkBox_cleanMesh -> setChecked ( settings . value ( "mesh_clean" , _ui -> checkBox_cleanMesh -> isChecked ()). toBool ());
2016-09-03 18:59:43 -04:00
_ui -> spinBox_mesh_minClusterSize -> setValue ( settings . value ( "mesh_min_cluster_size" , _ui -> spinBox_mesh_minClusterSize -> value ()). toInt ());
2016-02-15 19:35:24 -05:00
2017-01-15 19:09:37 -05:00
_ui -> comboBox_meshingApproach -> setCurrentIndex ( settings . value ( "mesh_dense_strategy" , _ui -> comboBox_meshingApproach -> currentIndex ()). toInt ());
2016-02-15 19:35:24 -05:00
_ui -> checkBox_textureMapping -> setChecked ( settings . value ( "mesh_texture" , _ui -> checkBox_textureMapping -> isChecked ()). toBool ());
2017-01-17 14:57:50 -05:00
_ui -> comboBox_meshingTextureFormat -> setCurrentIndex ( settings . value ( "mesh_textureFormat" , _ui -> comboBox_meshingTextureFormat -> currentIndex ()). toInt ());
2017-01-19 11:20:48 -05:00
_ui -> comboBox_meshingTextureSize -> setCurrentIndex ( settings . value ( "mesh_textureSize" , _ui -> comboBox_meshingTextureSize -> currentIndex ()). toInt ());
2017-01-31 23:26:35 -05:00
_ui -> doubleSpinBox_meshingTextureMaxDistance -> setValue ( settings . value ( "mesh_textureMaxDistance" , _ui -> doubleSpinBox_meshingTextureMaxDistance -> value ()). toDouble ());
2017-03-04 18:20:26 -05:00
_ui -> spinBox_mesh_minTextureClusterSize -> setValue ( settings . value ( "mesh_textureMinCluster" , _ui -> spinBox_mesh_minTextureClusterSize -> value ()). toDouble ());
2017-04-20 11:51:23 -04:00
_ui -> lineEdit_meshingTextureRoiRatios -> setText ( settings . value ( "mesh_textureRoiRatios" , _ui -> lineEdit_meshingTextureRoiRatios -> text ()). toString ());
2017-02-26 18:17:00 -05:00
_ui -> checkBox_cameraFilter -> setChecked ( settings . value ( "mesh_textureCameraFiltering" , _ui -> checkBox_cameraFilter -> isChecked ()). toBool ());
_ui -> doubleSpinBox_cameraFilterRadius -> setValue ( settings . value ( "mesh_textureCameraFilteringRadius" , _ui -> doubleSpinBox_cameraFilterRadius -> value ()). toDouble ());
_ui -> doubleSpinBox_cameraFilterAngle -> setValue ( settings . value ( "mesh_textureCameraFilteringAngle" , _ui -> doubleSpinBox_cameraFilterAngle -> value ()). toDouble ());
2017-03-30 15:33:48 -04:00
_ui -> spinBox_textureBrightnessContrastRatioLow -> setValue ( settings . value ( "mesh_textureBrightnessConstrastRatioLow" , _ui -> spinBox_textureBrightnessContrastRatioLow -> value ()). toDouble ());
_ui -> spinBox_textureBrightnessContrastRatioHigh -> setValue ( settings . value ( "mesh_textureBrightnessConstrastRatioHigh" , _ui -> spinBox_textureBrightnessContrastRatioHigh -> value ()). toDouble ());
2017-03-31 18:53:46 -04:00
if ( _ui -> checkBox_exposureFusion -> isEnabled ())
{
_ui -> checkBox_exposureFusion -> setChecked ( settings . value ( "mesh_textureExposureFusion" , _ui -> checkBox_exposureFusion -> isChecked ()). toBool ());
}
2017-04-09 19:16:50 -04:00
_ui -> checkBox_blending -> setChecked ( settings . value ( "mesh_textureBlending" , _ui -> checkBox_blending -> isChecked ()). toBool ());
_ui -> comboBox_blendingDecimation -> setCurrentIndex ( settings . value ( "mesh_textureBlendingDecimation" , _ui -> comboBox_blendingDecimation -> currentIndex ()). toInt ());
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_mesh_angleTolerance -> setValue ( settings . value ( "mesh_angle_tolerance" , _ui -> doubleSpinBox_mesh_angleTolerance -> value ()). toDouble ());
_ui -> checkBox_mesh_quad -> setChecked ( settings . value ( "mesh_quad" , _ui -> checkBox_mesh_quad -> isChecked ()). toBool ());
_ui -> spinBox_mesh_triangleSize -> setValue ( settings . value ( "mesh_triangle_size" , _ui -> spinBox_mesh_triangleSize -> value ()). toInt ());
2015-08-24 11:59:26 -04:00
2017-01-15 19:09:37 -05:00
_ui -> checkBox_poisson_outputPolygons -> setChecked ( settings . value ( "poisson_outputPolygons" , _ui -> checkBox_poisson_outputPolygons -> isChecked ()). toBool ());
_ui -> checkBox_poisson_manifold -> setChecked ( settings . value ( "poisson_manifold" , _ui -> checkBox_poisson_manifold -> isChecked ()). toBool ());
_ui -> spinBox_poisson_depth -> setValue ( settings . value ( "poisson_depth" , _ui -> spinBox_poisson_depth -> value ()). toInt ());
_ui -> spinBox_poisson_iso -> setValue ( settings . value ( "poisson_iso" , _ui -> spinBox_poisson_iso -> value ()). toInt ());
_ui -> spinBox_poisson_solver -> setValue ( settings . value ( "poisson_solver" , _ui -> spinBox_poisson_solver -> value ()). toInt ());
_ui -> spinBox_poisson_minDepth -> setValue ( settings . value ( "poisson_minDepth" , _ui -> spinBox_poisson_minDepth -> value ()). toInt ());
_ui -> doubleSpinBox_poisson_samples -> setValue ( settings . value ( "poisson_samples" , _ui -> doubleSpinBox_poisson_samples -> value ()). toDouble ());
_ui -> doubleSpinBox_poisson_pointWeight -> setValue ( settings . value ( "poisson_pointWeight" , _ui -> doubleSpinBox_poisson_pointWeight -> value ()). toDouble ());
_ui -> doubleSpinBox_poisson_scale -> setValue ( settings . value ( "poisson_scale" , _ui -> doubleSpinBox_poisson_scale -> value ()). toDouble ());
2016-09-07 12:15:44 -04:00
updateReconstructionFlavor ();
updateMLSGrpVisibility ();
2015-03-04 17:27:44 -05:00
if ( ! group . isEmpty ())
{
settings . endGroup ();
}
}
2015-01-14 15:09:16 -05:00
void ExportCloudsDialog :: restoreDefaults ()
{
2017-02-04 18:28:43 -05:00
_ui -> comboBox_pipeline -> setCurrentIndex ( 1 );
2015-08-24 11:59:26 -04:00
_ui -> checkBox_binary -> setChecked ( true );
2017-03-21 21:51:39 -04:00
_ui -> spinBox_normalKSearch -> setValue ( 20 );
2015-08-24 11:59:26 -04:00
2017-03-21 21:51:39 -04:00
_ui -> checkBox_regenerate -> setChecked ( _dbDriver != 0 ? true : false );
2015-08-24 11:59:26 -04:00
_ui -> spinBox_decimation -> setValue ( 1 );
_ui -> doubleSpinBox_maxDepth -> setValue ( 4 );
2016-04-12 15:14:04 -04:00
_ui -> doubleSpinBox_minDepth -> setValue ( 0 );
2017-01-16 01:32:53 -05:00
_ui -> spinBox_fillDepthHoles -> setValue ( 0 );
_ui -> spinBox_fillDepthHolesError -> setValue ( 2 );
_ui -> lineEdit_roiRatios -> setText ( "0.0 0.0 0.0 0.0" );
2016-09-19 14:01:06 -04:00
_ui -> lineEdit_distortionModel -> setText ( "" );
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_bilateral -> setChecked ( false );
2016-11-03 17:04:31 -04:00
_ui -> doubleSpinBox_bilateral_sigmaS -> setValue ( 10.0 );
_ui -> doubleSpinBox_bilateral_sigmaR -> setValue ( 0.1 );
2017-02-26 18:17:00 -05:00
_ui -> checkBox_filtering -> setChecked ( false );
2015-08-24 17:12:39 -04:00
_ui -> doubleSpinBox_filteringRadius -> setValue ( 0.02 );
_ui -> spinBox_filteringMinNeighbors -> setValue ( 2 );
2016-02-15 19:35:24 -05:00
_ui -> checkBox_assemble -> setChecked ( true );
2016-06-08 11:53:25 -04:00
_ui -> doubleSpinBox_voxelSize_assembled -> setValue ( 0.0 );
2015-08-24 11:59:26 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_subtraction -> setChecked ( false );
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_subtractPointFilteringRadius -> setValue ( 0.02 );
2016-06-12 13:51:49 -04:00
_ui -> doubleSpinBox_subtractPointFilteringAngle -> setValue ( 0 );
2016-02-15 19:35:24 -05:00
_ui -> spinBox_subtractFilteringMinPts -> setValue ( 5 );
2017-02-26 18:17:00 -05:00
_ui -> checkBox_smoothing -> setChecked ( false );
2015-08-24 11:59:26 -04:00
_ui -> doubleSpinBox_mlsRadius -> setValue ( 0.04 );
_ui -> spinBox_polygonialOrder -> setValue ( 2 );
_ui -> comboBox_upsamplingMethod -> setCurrentIndex ( 0 );
_ui -> doubleSpinBox_sampleRadius -> setValue ( 0.01 );
_ui -> doubleSpinBox_sampleStep -> setValue ( 0.0 );
_ui -> spinBox_randomPoints -> setValue ( 0 );
_ui -> doubleSpinBox_dilationVoxelSize -> setValue ( 0.01 );
_ui -> spinBox_dilationSteps -> setValue ( 0 );
2017-02-26 18:17:00 -05:00
_ui -> checkBox_gainCompensation -> setChecked ( false );
2016-09-07 12:15:44 -04:00
_ui -> doubleSpinBox_gainRadius -> setValue ( 0.02 );
2017-03-30 15:33:48 -04:00
_ui -> doubleSpinBox_gainOverlap -> setValue ( 0.0 );
2016-09-07 12:15:44 -04:00
_ui -> doubleSpinBox_gainBeta -> setValue ( 10 );
2017-03-30 15:33:48 -04:00
_ui -> checkBox_gainFull -> setChecked ( false );
2016-09-07 12:15:44 -04:00
2017-02-26 18:17:00 -05:00
_ui -> checkBox_meshing -> setChecked ( false );
2017-01-19 11:20:48 -05:00
_ui -> doubleSpinBox_gp3Radius -> setValue ( 0.2 );
2015-08-24 11:59:26 -04:00
_ui -> doubleSpinBox_gp3Mu -> setValue ( 2.5 );
2015-08-24 18:35:24 -04:00
_ui -> doubleSpinBox_meshDecimationFactor -> setValue ( 0.0 );
2017-03-30 15:33:48 -04:00
_ui -> spinBox_meshMaxPolygons -> setValue ( 0 );
2017-02-28 21:50:50 -05:00
_ui -> doubleSpinBox_transferColorRadius -> setValue ( 0.025 );
2017-01-16 01:32:53 -05:00
_ui -> checkBox_cleanMesh -> setChecked ( true );
2017-02-04 18:28:43 -05:00
_ui -> spinBox_mesh_minClusterSize -> setValue ( 0 );
2017-01-15 19:09:37 -05:00
_ui -> comboBox_meshingApproach -> setCurrentIndex ( 1 );
2016-02-15 19:35:24 -05:00
2015-08-24 11:59:26 -04:00
_ui -> checkBox_textureMapping -> setChecked ( false );
2017-01-17 14:57:50 -05:00
_ui -> comboBox_meshingTextureFormat -> setCurrentIndex ( 0 );
2017-02-04 18:28:43 -05:00
_ui -> comboBox_meshingTextureSize -> setCurrentIndex ( 5 ); // 4096
2017-01-31 23:26:35 -05:00
_ui -> doubleSpinBox_meshingTextureMaxDistance -> setValue ( 3.0 );
2017-03-04 18:20:26 -05:00
_ui -> spinBox_mesh_minTextureClusterSize -> setValue ( 50 );
2017-04-20 11:51:23 -04:00
_ui -> lineEdit_meshingTextureRoiRatios -> setText ( "" );
2017-02-26 18:17:00 -05:00
_ui -> checkBox_cameraFilter -> setChecked ( false );
_ui -> doubleSpinBox_cameraFilterRadius -> setValue ( 0.1 );
_ui -> doubleSpinBox_cameraFilterAngle -> setValue ( 30 );
2017-03-30 15:33:48 -04:00
_ui -> spinBox_textureBrightnessContrastRatioLow -> setValue ( 0 );
_ui -> spinBox_textureBrightnessContrastRatioHigh -> setValue ( 0 );
2017-03-30 21:33:15 -04:00
_ui -> checkBox_exposureFusion -> setChecked ( false );
2017-04-09 19:16:50 -04:00
_ui -> checkBox_blending -> setChecked ( true );
_ui -> comboBox_blendingDecimation -> setCurrentIndex ( 0 );
2015-08-24 12:49:45 -04:00
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_mesh_angleTolerance -> setValue ( 15.0 );
_ui -> checkBox_mesh_quad -> setChecked ( false );
2016-11-10 09:48:51 -05:00
_ui -> spinBox_mesh_triangleSize -> setValue ( 1 );
2016-02-15 19:35:24 -05:00
2017-01-15 19:09:37 -05:00
_ui -> checkBox_poisson_outputPolygons -> setChecked ( false );
_ui -> checkBox_poisson_manifold -> setChecked ( true );
_ui -> spinBox_poisson_depth -> setValue ( 9 );
_ui -> spinBox_poisson_iso -> setValue ( 8 );
_ui -> spinBox_poisson_solver -> setValue ( 8 );
_ui -> spinBox_poisson_minDepth -> setValue ( 5 );
_ui -> doubleSpinBox_poisson_samples -> setValue ( 1.0 );
_ui -> doubleSpinBox_poisson_pointWeight -> setValue ( 4.0 );
_ui -> doubleSpinBox_poisson_scale -> setValue ( 1.1 );
2016-02-15 19:35:24 -05:00
updateReconstructionFlavor ();
2016-09-07 12:15:44 -04:00
updateMLSGrpVisibility ();
2016-02-15 19:35:24 -05:00
2015-08-24 12:49:45 -04:00
this -> update ();
2015-01-14 15:09:16 -05:00
}
2016-02-15 19:35:24 -05:00
void ExportCloudsDialog :: updateReconstructionFlavor ()
{
2017-02-26 18:17:00 -05:00
_ui -> checkBox_smoothing -> setVisible ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
_ui -> checkBox_smoothing -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
2017-01-15 19:09:37 -05:00
_ui -> label_denseReconstruction -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
2017-03-30 15:33:48 -04:00
#ifndef DISABLE_VTK
2017-01-16 01:32:53 -05:00
_ui -> doubleSpinBox_meshDecimationFactor -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
_ui -> label_meshDecimation -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
2017-03-30 15:33:48 -04:00
_ui -> spinBox_meshMaxPolygons -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
_ui -> label_meshMaxPolygons -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
#endif
2016-02-15 19:35:24 -05:00
_ui -> groupBox_organized -> setVisible ( _ui -> comboBox_pipeline -> currentIndex () == 0 );
2017-01-15 19:09:37 -05:00
2017-02-26 18:17:00 -05:00
_ui -> groupBox_regenerate -> setVisible ( _ui -> checkBox_regenerate -> isChecked ());
_ui -> groupBox_bilateral -> setVisible ( _ui -> checkBox_bilateral -> isChecked ());
_ui -> groupBox_filtering -> setVisible ( _ui -> checkBox_filtering -> isChecked ());
_ui -> groupBox_gain -> setVisible ( _ui -> checkBox_gainCompensation -> isChecked ());
_ui -> groupBox_mls -> setVisible ( _ui -> checkBox_smoothing -> isEnabled () && _ui -> checkBox_smoothing -> isChecked ());
_ui -> groupBox_meshing -> setVisible ( _ui -> checkBox_meshing -> isChecked ());
_ui -> groupBox_subtraction -> setVisible ( _ui -> checkBox_subtraction -> isChecked ());
_ui -> groupBox_textureMapping -> setVisible ( _ui -> checkBox_textureMapping -> isChecked ());
_ui -> groupBox_cameraFilter -> setVisible ( _ui -> checkBox_cameraFilter -> isChecked ());
2017-01-19 11:20:48 -05:00
// dense texturing options
2017-01-15 19:09:37 -05:00
_ui -> groupBox_gp3 -> setVisible ( _ui -> comboBox_pipeline -> currentIndex () == 1 && _ui -> comboBox_meshingApproach -> currentIndex () == 0 );
_ui -> groupBox_poisson -> setVisible ( _ui -> comboBox_pipeline -> currentIndex () == 1 && _ui -> comboBox_meshingApproach -> currentIndex () == 1 );
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_meshing -> isChecked ())
2017-01-19 11:20:48 -05:00
{
_ui -> comboBox_meshingApproach -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
_ui -> comboBox_meshingApproach -> setItemData ( 1 , _ui -> checkBox_assemble -> isChecked () ? 1 | 32 : 0 , Qt :: UserRole - 1 );
2017-02-26 18:17:00 -05:00
if ( ! _ui -> checkBox_assemble -> isChecked ())
{
_ui -> comboBox_meshingApproach -> setCurrentIndex ( 0 );
}
2017-01-19 11:20:48 -05:00
_ui -> checkBox_poisson_outputPolygons -> setDisabled (
_ui -> checkBox_binary -> isEnabled () ||
_ui -> doubleSpinBox_meshDecimationFactor -> value () != 0.0 ||
2017-03-30 15:33:48 -04:00
_ui -> spinBox_meshMaxPolygons -> value () != 0 ||
2017-01-19 11:20:48 -05:00
_ui -> checkBox_textureMapping -> isChecked ());
2017-02-04 18:28:43 -05:00
_ui -> checkBox_cleanMesh -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
2017-01-19 11:20:48 -05:00
_ui -> label_meshClean -> setEnabled ( _ui -> comboBox_pipeline -> currentIndex () == 1 );
}
2016-02-15 19:35:24 -05:00
}
2016-09-19 14:01:06 -04:00
void ExportCloudsDialog :: selectDistortionModel ()
{
QString dir = _ui -> lineEdit_distortionModel -> text ();
if ( dir . isEmpty ())
{
dir = _workingDirectory ;
}
2016-10-14 15:24:24 -04:00
QString path = QFileDialog :: getOpenFileName ( this , tr ( "Select file" ), dir , tr ( "Distortion model (*.bin *.txt)" ));
2016-09-19 14:01:06 -04:00
if ( path . size ())
{
_ui -> lineEdit_distortionModel -> setText ( path );
}
}
2014-10-01 17:52:27 +00:00
void ExportCloudsDialog :: setSaveButton ()
{
2015-01-14 15:09:16 -05:00
_ui -> buttonBox -> button ( QDialogButtonBox :: Ok ) -> setVisible ( false );
_ui -> buttonBox -> button ( QDialogButtonBox :: Save ) -> setVisible ( true );
2014-11-14 22:07:03 +00:00
_ui -> checkBox_binary -> setVisible ( true );
2016-11-01 12:04:10 -04:00
_ui -> checkBox_binary -> setEnabled ( true );
2015-08-24 11:59:26 -04:00
_ui -> label_binaryFile -> setVisible ( true );
2016-02-15 19:35:24 -05:00
_ui -> checkBox_mesh_quad -> setVisible ( false );
_ui -> checkBox_mesh_quad -> setEnabled ( false );
_ui -> label_quad -> setVisible ( false );
2017-01-19 11:20:48 -05:00
updateReconstructionFlavor ();
2014-10-01 17:52:27 +00:00
}
void ExportCloudsDialog :: setOkButton ()
{
2015-01-14 15:09:16 -05:00
_ui -> buttonBox -> button ( QDialogButtonBox :: Ok ) -> setVisible ( true );
_ui -> buttonBox -> button ( QDialogButtonBox :: Save ) -> setVisible ( false );
2014-11-14 22:07:03 +00:00
_ui -> checkBox_binary -> setVisible ( false );
2016-11-01 12:04:10 -04:00
_ui -> checkBox_binary -> setEnabled ( false );
2015-08-24 11:59:26 -04:00
_ui -> label_binaryFile -> setVisible ( false );
2016-02-15 19:35:24 -05:00
_ui -> checkBox_mesh_quad -> setVisible ( true );
_ui -> checkBox_mesh_quad -> setEnabled ( true );
_ui -> label_quad -> setVisible ( true );
2017-01-19 11:20:48 -05:00
updateReconstructionFlavor ();
2014-10-01 17:52:27 +00:00
}
2015-01-12 17:43:42 -05:00
void ExportCloudsDialog :: enableRegeneration ( bool enabled )
{
if ( ! enabled )
{
2017-02-26 18:17:00 -05:00
_ui -> checkBox_regenerate -> setChecked ( false );
2015-01-12 17:43:42 -05:00
}
2017-02-26 18:17:00 -05:00
_ui -> checkBox_regenerate -> setEnabled ( enabled );
2015-01-12 17:43:42 -05:00
}
2016-02-15 19:35:24 -05:00
void ExportCloudsDialog :: exportClouds (
const std :: map < int , Transform > & poses ,
2016-09-07 12:15:44 -04:00
const std :: multimap < int , Link > & links ,
2016-02-15 19:35:24 -05:00
const std :: map < int , int > & mapIds ,
const QMap < int , Signature > & cachedSignatures ,
2016-06-12 17:53:35 -04:00
const std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr , pcl :: IndicesPtr > > & cachedClouds ,
2016-05-31 19:09:49 -04:00
const QString & workingDirectory ,
const ParametersMap & parameters )
2014-07-29 00:52:35 +00:00
{
2016-02-15 19:35:24 -05:00
std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr > clouds ;
std :: map < int , pcl :: PolygonMesh :: Ptr > meshes ;
std :: map < int , pcl :: TextureMesh :: Ptr > textureMeshes ;
2017-04-09 19:16:50 -04:00
std :: vector < std :: map < int , pcl :: PointXY > > textureVertexToPixels ;
2016-02-15 19:35:24 -05:00
setSaveButton ();
if ( getExportedClouds (
poses ,
2016-09-07 12:15:44 -04:00
links ,
2016-02-15 19:35:24 -05:00
mapIds ,
cachedSignatures ,
2016-06-12 17:53:35 -04:00
cachedClouds ,
2016-02-15 19:35:24 -05:00
workingDirectory ,
2016-05-31 19:09:49 -04:00
parameters ,
2016-02-15 19:35:24 -05:00
clouds ,
meshes ,
2017-04-09 19:16:50 -04:00
textureMeshes ,
textureVertexToPixels ))
2016-02-15 19:35:24 -05:00
{
if ( textureMeshes . size ())
{
2017-04-09 19:16:50 -04:00
saveTextureMeshes ( workingDirectory , poses , textureMeshes , cachedSignatures , textureVertexToPixels );
2016-02-15 19:35:24 -05:00
}
else if ( meshes . size ())
{
bool exportMeshes = true ;
2016-10-21 16:56:29 -04:00
if ( _ui -> checkBox_textureMapping -> isEnabled () && _ui -> checkBox_textureMapping -> isChecked ())
2016-02-15 19:35:24 -05:00
{
QMessageBox :: StandardButton r = QMessageBox :: warning ( this , tr ( "Exporting Texture Mesh" ),
tr ( "No texture mesh could be created, do you want to continue with saving only the meshes (%1)?" ). arg ( meshes . size ()),
QMessageBox :: Yes | QMessageBox :: No , QMessageBox :: Yes );
exportMeshes = r == QMessageBox :: Yes ;
}
if ( exportMeshes )
{
saveMeshes ( workingDirectory , poses , meshes , _ui -> checkBox_binary -> isChecked ());
}
}
else
{
saveClouds ( workingDirectory , poses , clouds , _ui -> checkBox_binary -> isChecked ());
}
}
2016-09-19 14:01:06 -04:00
else if ( ! _canceled )
2016-09-07 12:15:44 -04:00
{
_progressDialog -> setAutoClose ( false );
}
_progressDialog -> setValue ( _progressDialog -> maximumSteps ());
2014-07-29 00:52:35 +00:00
}
2016-02-15 19:35:24 -05:00
void ExportCloudsDialog :: viewClouds (
const std :: map < int , Transform > & poses ,
2016-09-07 12:15:44 -04:00
const std :: multimap < int , Link > & links ,
2016-02-15 19:35:24 -05:00
const std :: map < int , int > & mapIds ,
const QMap < int , Signature > & cachedSignatures ,
2016-06-12 17:53:35 -04:00
const std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr , pcl :: IndicesPtr > > & cachedClouds ,
2016-05-31 19:09:49 -04:00
const QString & workingDirectory ,
const ParametersMap & parameters )
2014-07-29 00:52:35 +00:00
{
2016-02-15 19:35:24 -05:00
std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr > clouds ;
std :: map < int , pcl :: PolygonMesh :: Ptr > meshes ;
std :: map < int , pcl :: TextureMesh :: Ptr > textureMeshes ;
2017-04-09 19:16:50 -04:00
std :: vector < std :: map < int , pcl :: PointXY > > textureVertexToPixels ;
2016-02-15 19:35:24 -05:00
setOkButton ();
if ( getExportedClouds (
poses ,
2016-09-07 12:15:44 -04:00
links ,
2016-02-15 19:35:24 -05:00
mapIds ,
cachedSignatures ,
2016-06-12 17:53:35 -04:00
cachedClouds ,
2016-02-15 19:35:24 -05:00
workingDirectory ,
2016-05-31 19:09:49 -04:00
parameters ,
2016-02-15 19:35:24 -05:00
clouds ,
meshes ,
2017-04-09 19:16:50 -04:00
textureMeshes ,
textureVertexToPixels ))
2016-02-15 19:35:24 -05:00
{
QDialog * window = new QDialog ( this -> parentWidget () ? this -> parentWidget () : this , Qt :: Window );
window -> setAttribute ( Qt :: WA_DeleteOnClose , true );
if ( meshes . size ())
{
window -> setWindowTitle ( tr ( "Meshes (%1 nodes)" ). arg ( meshes . size ()));
}
else
{
window -> setWindowTitle ( tr ( "Clouds (%1 nodes)" ). arg ( clouds . size ()));
}
2016-11-21 12:02:29 -05:00
window -> setMinimumWidth ( 120 );
window -> setMinimumHeight ( 90 );
window -> resize ( QDesktopWidget (). availableGeometry ( this ). size () * 0.7 );
2016-02-15 19:35:24 -05:00
CloudViewer * viewer = new CloudViewer ( window );
if ( _ui -> comboBox_pipeline -> currentIndex () == 0 )
{
viewer -> setBackfaceCulling ( true , false );
}
2017-01-15 19:09:37 -05:00
viewer -> setLighting ( true );
2017-01-27 16:55:01 -05:00
viewer -> setDefaultBackgroundColor ( QColor ( 40 , 40 , 40 , 255 ));
2016-02-15 19:35:24 -05:00
QVBoxLayout * layout = new QVBoxLayout ();
layout -> addWidget ( viewer );
2016-11-21 12:02:29 -05:00
layout -> setContentsMargins ( 0 , 0 , 0 , 0 );
2016-02-15 19:35:24 -05:00
window -> setLayout ( layout );
connect ( window , SIGNAL ( finished ( int )), viewer , SLOT ( clear ()));
window -> show ();
2017-01-19 11:20:48 -05:00
_progressDialog -> appendText ( tr ( "Opening visualizer..." ));
QApplication :: processEvents ();
2016-02-15 19:35:24 -05:00
uSleep ( 500 );
2017-01-19 11:20:48 -05:00
QApplication :: processEvents ();
2016-02-15 19:35:24 -05:00
2016-09-07 12:15:44 -04:00
if ( textureMeshes . size ())
{
2017-01-30 21:23:56 -05:00
for ( std :: map < int , pcl :: TextureMesh :: Ptr >:: iterator iter = textureMeshes . begin (); iter != textureMeshes . end (); ++ iter )
2016-09-07 12:15:44 -04:00
{
2017-01-19 11:20:48 -05:00
pcl :: TextureMesh :: Ptr mesh = iter -> second ;
// As CloudViewer is not supporting more than one texture per mesh, merge them all by default
cv :: Mat globalTexture ;
2017-01-30 21:23:56 -05:00
if ( mesh -> tex_materials . size () > 1 )
2017-01-16 18:29:14 -05:00
{
2017-04-09 19:16:50 -04:00
globalTexture = mergeTextures ( * mesh , cachedSignatures , textureVertexToPixels );
2017-01-19 11:20:48 -05:00
}
2017-03-04 02:53:11 -05:00
_progressDialog -> appendText ( tr ( "Viewing the mesh %1 (%2 polygons)..." ). arg ( iter -> first ). arg ( mesh -> tex_polygons . size () ? mesh -> tex_polygons [ 0 ]. size () : 0 ));
_progressDialog -> incrementStep ();
2017-01-19 11:20:48 -05:00
// VTK issue:
// tex_coordinates should be linked to points, not
// polygon vertices. Points linked to multiple different TCoords (different textures) should
// be duplicated.
2017-01-30 21:23:56 -05:00
for ( unsigned int t = 0 ; t < mesh -> tex_coordinates . size (); ++ t )
2017-01-19 11:20:48 -05:00
{
2017-02-01 00:29:13 -05:00
if ( mesh -> tex_polygons [ t ]. size ())
2017-01-19 11:20:48 -05:00
{
2017-01-30 21:23:56 -05:00
2017-02-01 00:29:13 -05:00
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr originalCloud ( new pcl :: PointCloud < pcl :: PointXYZ > );
pcl :: fromPCLPointCloud2 ( mesh -> cloud , * originalCloud );
// make a cloud with as many points than polygon vertices
unsigned int nPoints = mesh -> tex_coordinates [ t ]. size ();
UASSERT ( nPoints == mesh -> tex_polygons [ t ]. size () * mesh -> tex_polygons [ t ][ 0 ]. vertices . size ()); // assuming polygon size is constant!
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr cloud ( new pcl :: PointCloud < pcl :: PointXYZ > );
cloud -> resize ( nPoints );
unsigned int oi = 0 ;
for ( unsigned int i = 0 ; i < mesh -> tex_polygons [ t ]. size (); ++ i )
2017-01-19 11:20:48 -05:00
{
2017-02-01 00:29:13 -05:00
pcl :: Vertices & vertices = mesh -> tex_polygons [ t ][ i ];
for ( unsigned int j = 0 ; j < vertices . vertices . size (); ++ j )
{
UASSERT ( oi < cloud -> size ());
UASSERT ( vertices . vertices [ j ] < originalCloud -> size ());
cloud -> at ( oi ) = originalCloud -> at ( vertices . vertices [ j ]);
vertices . vertices [ j ] = oi ; // new vertice index
++ oi ;
}
2017-01-19 11:20:48 -05:00
}
2017-02-01 00:29:13 -05:00
pcl :: toPCLPointCloud2 ( * cloud , mesh -> cloud );
}
else
{
UWARN ( "No polygons for texture %d of mesh %d?!" , t , iter -> first );
2017-01-19 11:20:48 -05:00
}
}
2017-01-30 21:23:56 -05:00
if ( globalTexture . empty ())
2017-01-19 11:20:48 -05:00
{
2017-03-03 00:19:46 -05:00
if ( mesh -> tex_materials . size () == 1 &&
2017-01-30 21:23:56 -05:00
! mesh -> tex_materials [ 0 ]. tex_file . empty () &&
2017-03-03 00:19:46 -05:00
uIsInteger ( mesh -> tex_materials [ 0 ]. tex_file , false ))
2017-01-30 21:23:56 -05:00
{
2017-03-03 00:19:46 -05:00
int textureId = uStr2Int ( mesh -> tex_materials [ 0 ]. tex_file );
2017-03-21 21:51:39 -04:00
SensorData data ;
if ( cachedSignatures . contains ( textureId ) && ! cachedSignatures . value ( textureId ). sensorData (). imageCompressed (). empty ())
{
data = cachedSignatures . value ( textureId ). sensorData ();
}
else if ( _dbDriver )
{
_dbDriver -> getNodeData ( textureId , data , true , false , false , false );
}
UASSERT ( ! data . imageCompressed (). empty ());
data . uncompressDataConst ( & globalTexture , 0 );
2017-03-03 00:19:46 -05:00
UASSERT ( ! globalTexture . empty ());
if ( _ui -> checkBox_gainCompensation -> isChecked () && _compensator && _compensator -> getIndex ( textureId ) >= 0 )
{
_compensator -> apply ( textureId , globalTexture );
}
}
else
{
_progressDialog -> appendText ( tr ( "No textures added to mesh %1!?" ). arg ( iter -> first ), Qt :: darkRed );
_progressDialog -> setAutoClose ( false );
2017-01-16 18:29:14 -05:00
}
}
2017-01-30 21:23:56 -05:00
viewer -> addCloudTextureMesh ( uFormat ( "mesh%d" , iter -> first ), mesh , globalTexture , iter -> first > 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
2017-01-19 11:20:48 -05:00
_progressDialog -> appendText ( tr ( "Viewing the mesh %1 (%2 polygons)... done." ). arg ( iter -> first ). arg ( mesh -> tex_polygons . size () ? mesh -> tex_polygons [ 0 ]. size () : 0 ));
2016-09-07 12:15:44 -04:00
QApplication :: processEvents ();
}
}
else if ( meshes . size ())
2016-02-15 19:35:24 -05:00
{
for ( std :: map < int , pcl :: PolygonMesh :: Ptr >:: iterator iter = meshes . begin (); iter != meshes . end (); ++ iter )
{
_progressDialog -> appendText ( tr ( "Viewing the mesh %1 (%2 polygons)..." ). arg ( iter -> first ). arg ( iter -> second -> polygons . size ()));
_progressDialog -> incrementStep ();
bool isRGB = false ;
for ( unsigned int i = 0 ; i < iter -> second -> cloud . fields . size (); ++ i )
{
if ( iter -> second -> cloud . fields [ i ]. name . compare ( "rgb" ) == 0 )
{
isRGB = true ;
break ;
}
}
if ( isRGB )
{
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr cloud ( new pcl :: PointCloud < pcl :: PointXYZRGB > );
pcl :: fromPCLPointCloud2 ( iter -> second -> cloud , * cloud );
viewer -> addCloudMesh ( uFormat ( "mesh%d" , iter -> first ), cloud , iter -> second -> polygons , iter -> first > 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
}
else
{
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr cloud ( new pcl :: PointCloud < pcl :: PointXYZ > );
pcl :: fromPCLPointCloud2 ( iter -> second -> cloud , * cloud );
viewer -> addCloudMesh ( uFormat ( "mesh%d" , iter -> first ), cloud , iter -> second -> polygons , iter -> first > 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
}
_progressDialog -> appendText ( tr ( "Viewing the mesh %1 (%2 polygons)... done." ). arg ( iter -> first ). arg ( iter -> second -> polygons . size ()));
QApplication :: processEvents ();
}
}
else if ( clouds . size ())
{
for ( std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr >:: iterator iter = clouds . begin (); iter != clouds . end (); ++ iter )
{
_progressDialog -> appendText ( tr ( "Viewing the cloud %1 (%2 points)..." ). arg ( iter -> first ). arg ( iter -> second -> size ()));
_progressDialog -> incrementStep ();
QColor color = Qt :: gray ;
int mapId = uValue ( mapIds , iter -> first , - 1 );
if ( mapId >= 0 )
{
color = ( Qt :: GlobalColor )( mapId % 12 + 7 );
}
viewer -> addCloud ( uFormat ( "cloud%d" , iter -> first ), iter -> second , iter -> first > 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
2017-01-15 19:09:37 -05:00
viewer -> setCloudPointSize ( uFormat ( "cloud%d" , iter -> first ), 2 );
2016-02-15 19:35:24 -05:00
_progressDialog -> appendText ( tr ( "Viewing the cloud %1 (%2 points)... done." ). arg ( iter -> first ). arg ( iter -> second -> size ()));
}
}
viewer -> update ();
}
2016-09-07 12:15:44 -04:00
else
{
_progressDialog -> setAutoClose ( false );
}
_progressDialog -> setValue ( _progressDialog -> maximumSteps ());
2014-07-29 00:52:35 +00:00
}
2016-09-07 12:15:44 -04:00
bool ExportCloudsDialog :: removeDirRecursively ( const QString & dirName )
2014-07-29 00:52:35 +00:00
{
2016-02-15 19:35:24 -05:00
bool result = true ;
QDir dir ( dirName );
if ( dir . exists ( dirName )) {
Q_FOREACH ( QFileInfo info , dir . entryInfoList ( QDir :: NoDotAndDotDot | QDir :: System | QDir :: Hidden | QDir :: AllDirs | QDir :: Files , QDir :: DirsFirst )) {
if ( info . isDir ()) {
2016-03-14 17:27:53 -04:00
result = removeDirRecursively ( info . absoluteFilePath ());
2016-02-15 19:35:24 -05:00
}
else {
result = QFile :: remove ( info . absoluteFilePath ());
}
if ( ! result ) {
return result ;
}
}
result = dir . rmdir ( dirName );
}
return result ;
2014-07-29 00:52:35 +00:00
}
2016-02-15 19:35:24 -05:00
bool ExportCloudsDialog :: getExportedClouds (
const std :: map < int , Transform > & poses ,
2016-09-07 12:15:44 -04:00
const std :: multimap < int , Link > & links ,
2016-02-15 19:35:24 -05:00
const std :: map < int , int > & mapIds ,
const QMap < int , Signature > & cachedSignatures ,
2016-06-12 17:53:35 -04:00
const std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr , pcl :: IndicesPtr > > & cachedClouds ,
2016-02-15 19:35:24 -05:00
const QString & workingDirectory ,
2016-05-31 19:09:49 -04:00
const ParametersMap & parameters ,
2016-02-15 19:35:24 -05:00
std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr > & cloudsWithNormals ,
std :: map < int , pcl :: PolygonMesh :: Ptr > & meshes ,
2017-04-09 19:16:50 -04:00
std :: map < int , pcl :: TextureMesh :: Ptr > & textureMeshes ,
std :: vector < std :: map < int , pcl :: PointXY > > & textureVertexToPixels )
2014-07-29 00:52:35 +00:00
{
2016-09-19 14:01:06 -04:00
_canceled = false ;
_workingDirectory = workingDirectory ;
2017-03-21 21:51:39 -04:00
enableRegeneration ( _dbDriver || cachedSignatures . size ());
if ( cachedSignatures . empty () && _dbDriver )
{
_ui -> checkBox_regenerate -> setChecked ( true );
}
2017-01-16 18:29:14 -05:00
if ( _compensator )
{
delete _compensator ;
_compensator = 0 ;
}
2016-02-15 19:35:24 -05:00
if ( this -> exec () == QDialog :: Accepted )
{
2016-09-07 12:15:44 -04:00
if ( poses . empty ())
{
QMessageBox :: critical ( this , tr ( "Creating clouds..." ), tr ( "Poses are null! Cannot export/view clouds." ));
return false ;
}
2016-02-15 19:35:24 -05:00
_progressDialog -> resetProgress ();
_progressDialog -> show ();
int mul = 1 ;
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_meshing -> isChecked ())
2016-02-15 19:35:24 -05:00
{
mul += 1 ;
}
if ( _ui -> checkBox_assemble -> isChecked ())
{
mul += 1 ;
}
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_subtraction -> isChecked ())
2016-02-15 19:35:24 -05:00
{
mul += 1 ;
}
if ( _ui -> checkBox_textureMapping -> isChecked ())
{
mul += 1 ;
}
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_gainCompensation -> isChecked ())
2016-09-07 12:15:44 -04:00
{
mul += 1 ;
}
if ( _ui -> checkBox_mesh_quad -> isEnabled ()) // when enabled we are viewing the clouds
{
mul += 1 ;
}
2016-02-15 19:35:24 -05:00
_progressDialog -> setMaximumSteps ( int ( poses . size ()) * mul + 1 );
std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > > clouds = this -> getClouds (
poses ,
cachedSignatures ,
2016-06-12 17:53:35 -04:00
cachedClouds ,
2016-05-31 19:09:49 -04:00
parameters );
2016-02-15 19:35:24 -05:00
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-09-07 12:15:44 -04:00
if ( clouds . empty ())
{
_progressDialog -> setAutoClose ( false );
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_regenerate -> isEnabled () && ! _ui -> checkBox_regenerate -> isChecked ())
2016-09-07 12:15:44 -04:00
{
QMessageBox :: warning ( this , tr ( "Creating clouds..." ), tr ( "Could create clouds for %1 node(s). You "
"may want to activate clouds regeneration option." ). arg ( poses . size ()));
}
else
{
QMessageBox :: warning ( this , tr ( "Creating clouds..." ), tr ( "Could not create clouds for %1 "
"node(s). The cache may not contain point cloud data. Try re-downloading the map." ). arg ( poses . size ()));
}
return false ;
}
2017-04-09 19:16:50 -04:00
if ( _ui -> checkBox_gainCompensation -> isChecked () && clouds . size () > 1 &&
// Do compensation later if we are merging textures on a dense assembled cloud
! ( _ui -> checkBox_meshing -> isChecked () &&
_ui -> checkBox_textureMapping -> isEnabled () &&
_ui -> checkBox_textureMapping -> isChecked () &&
_ui -> comboBox_pipeline -> currentIndex () == 1 &&
_ui -> checkBox_assemble -> isChecked () &&
_ui -> comboBox_meshingTextureSize -> isEnabled () &&
_ui -> comboBox_meshingTextureSize -> currentIndex () > 0 ))
2016-09-07 12:15:44 -04:00
{
2017-01-16 18:29:14 -05:00
UASSERT ( _compensator == 0 );
2017-03-30 15:33:48 -04:00
_compensator = new GainCompensator ( _ui -> doubleSpinBox_gainRadius -> value (), _ui -> doubleSpinBox_gainOverlap -> value (), 0.01 , _ui -> doubleSpinBox_gainBeta -> value ());
2017-01-16 18:29:14 -05:00
2017-03-30 15:33:48 -04:00
if ( _ui -> checkBox_gainFull -> isChecked ())
2016-11-09 16:44:08 -05:00
{
_progressDialog -> appendText ( tr ( "Full gain compensation of %1 clouds..." ). arg ( clouds . size ()));
}
else
{
_progressDialog -> appendText ( tr ( "Gain compensation of %1 clouds..." ). arg ( clouds . size ()));
}
2016-09-07 12:15:44 -04:00
QApplication :: processEvents ();
2017-02-01 00:29:13 -05:00
uSleep ( 100 );
2016-09-07 12:15:44 -04:00
QApplication :: processEvents ();
2017-03-30 15:33:48 -04:00
if ( _ui -> checkBox_gainFull -> isChecked ())
2016-10-26 19:03:44 -04:00
{
std :: multimap < int , Link > allLinks ;
for ( std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > >:: const_iterator iter = clouds . begin (); iter != clouds . end (); ++ iter )
{
int from = iter -> first ;
std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > >:: const_iterator jter = iter ;
++ jter ;
for (; jter != clouds . end (); ++ jter )
{
int to = jter -> first ;
allLinks . insert ( std :: make_pair ( from , Link ( from , to , Link :: kUserClosure , poses . at ( from ). inverse () * poses . at ( to ))));
}
}
2017-01-16 18:29:14 -05:00
_compensator -> feed ( clouds , allLinks );
2016-10-26 19:03:44 -04:00
}
else
{
2017-01-16 18:29:14 -05:00
_compensator -> feed ( clouds , links );
2016-10-26 19:03:44 -04:00
}
2016-09-07 12:15:44 -04:00
2017-02-26 18:17:00 -05:00
if ( ! ( _ui -> checkBox_meshing -> isChecked () &&
2017-02-03 16:12:58 -05:00
_ui -> checkBox_textureMapping -> isEnabled () &&
_ui -> checkBox_textureMapping -> isChecked ()))
2016-09-07 12:15:44 -04:00
{
2017-02-03 16:12:58 -05:00
_progressDialog -> appendText ( tr ( "Applying gain compensation..." ));
for ( std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > >:: iterator jter = clouds . begin (); jter != clouds . end (); ++ jter )
2016-09-07 12:15:44 -04:00
{
2017-02-03 16:12:58 -05:00
if ( jter != clouds . end ())
2016-09-19 14:01:06 -04:00
{
2017-02-03 16:12:58 -05:00
double gain = _compensator -> getGain ( jter -> first );;
_compensator -> apply ( jter -> first , jter -> second . first , jter -> second . second );
_progressDialog -> appendText ( tr ( "Cloud %1 has gain %2" ). arg ( jter -> first ). arg ( gain ));
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
if ( _canceled )
{
return false ;
}
2016-09-19 14:01:06 -04:00
}
2016-09-07 12:15:44 -04:00
}
}
}
2016-02-15 19:35:24 -05:00
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr rawAssembledCloud ( new pcl :: PointCloud < pcl :: PointXYZ > );
std :: vector < int > rawCameraIndices ;
if ( _ui -> checkBox_assemble -> isChecked () &&
2017-02-26 18:17:00 -05:00
! ( _ui -> comboBox_pipeline -> currentIndex () == 0 && _ui -> checkBox_meshing -> isChecked ()))
2016-02-15 19:35:24 -05:00
{
_progressDialog -> appendText ( tr ( "Assembling %1 clouds..." ). arg ( clouds . size ()));
QApplication :: processEvents ();
int i = 0 ;
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr assembledCloud ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
for ( std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > >:: iterator iter = clouds . begin ();
iter != clouds . end ();
++ iter )
{
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr transformed ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
if ( iter -> second . first -> isOrganized ())
{
pcl :: copyPointCloud ( * iter -> second . first , * iter -> second . second , * transformed );
transformed = util3d :: transformPointCloud ( transformed , poses . at ( iter -> first ));
}
else
{
transformed = util3d :: transformPointCloud ( iter -> second . first , poses . at ( iter -> first ));
}
* assembledCloud += * transformed ;
rawCameraIndices . resize ( assembledCloud -> size (), iter -> first );
_progressDialog -> appendText ( tr ( "Assembled cloud %1, total=%2 (%3/%4)." ). arg ( iter -> first ). arg ( assembledCloud -> size ()). arg ( ++ i ). arg ( clouds . size ()));
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-02-15 19:35:24 -05:00
}
pcl :: copyPointCloud ( * assembledCloud , * rawAssembledCloud );
if ( _ui -> doubleSpinBox_voxelSize_assembled -> value ())
{
_progressDialog -> appendText ( tr ( "Voxelize cloud (%1 points, voxel size = %2 m)..." )
. arg ( assembledCloud -> size ())
. arg ( _ui -> doubleSpinBox_voxelSize_assembled -> value ()));
QApplication :: processEvents ();
2017-01-30 21:23:56 -05:00
unsigned int before = assembledCloud -> size ();
2016-02-15 19:35:24 -05:00
assembledCloud = util3d :: voxelize (
assembledCloud ,
_ui -> doubleSpinBox_voxelSize_assembled -> value ());
2017-01-19 11:20:48 -05:00
_progressDialog -> appendText ( tr ( "Voxelize cloud (%1 points, voxel size = %2 m)...done! (%3 points)" )
. arg ( before )
. arg ( _ui -> doubleSpinBox_voxelSize_assembled -> value ())
. arg ( assembledCloud -> size ()));
2016-02-15 19:35:24 -05:00
}
clouds . clear ();
clouds . insert ( std :: make_pair ( 0 , std :: make_pair ( assembledCloud , pcl :: IndicesPtr ( new std :: vector < int > ))));
}
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-06-12 17:53:35 -04:00
std :: map < int , Transform > viewPoints = poses ;
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_smoothing -> isEnabled () && _ui -> checkBox_smoothing -> isChecked ())
2016-02-15 19:35:24 -05:00
{
_progressDialog -> appendText ( tr ( "Smoothing the surface using Moving Least Squares (MLS) algorithm... "
"[search radius=%1m voxel=%2m]" ). arg ( _ui -> doubleSpinBox_mlsRadius -> value ()). arg ( _ui -> doubleSpinBox_voxelSize_assembled -> value ()));
2016-06-12 17:53:35 -04:00
QApplication :: processEvents ();
2017-02-01 00:29:13 -05:00
uSleep ( 100 );
2016-06-12 17:53:35 -04:00
QApplication :: processEvents ();
// Adjust view points with local transforms
for ( std :: map < int , Transform >:: iterator iter = viewPoints . begin (); iter != viewPoints . end (); ++ iter )
{
2017-03-21 21:51:39 -04:00
std :: vector < CameraModel > models ;
StereoCameraModel stereoModel ;
2016-06-12 17:53:35 -04:00
if ( cachedSignatures . contains ( iter -> first ))
{
const SensorData & data = cachedSignatures . find ( iter -> first ) -> sensorData ();
2017-03-21 21:51:39 -04:00
models = data . cameraModels ();
stereoModel = data . stereoCameraModel ();
}
else if ( _dbDriver )
{
_dbDriver -> getCalibration ( iter -> first , models , stereoModel );
}
if ( models . size () && ! models [ 0 ]. localTransform (). isNull ())
{
iter -> second *= models [ 0 ]. localTransform ();
}
else if ( ! stereoModel . localTransform (). isNull ())
{
iter -> second *= stereoModel . localTransform ();
2016-06-12 17:53:35 -04:00
}
}
2016-02-15 19:35:24 -05:00
}
//fill cloudWithNormals
for ( std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > >:: iterator iter = clouds . begin ();
iter != clouds . end ();
++ iter )
{
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr cloudWithNormals = iter -> second . first ;
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_smoothing -> isEnabled () && _ui -> checkBox_smoothing -> isChecked ())
2016-02-15 19:35:24 -05:00
{
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr cloudWithoutNormals ( new pcl :: PointCloud < pcl :: PointXYZRGB > );
2016-10-30 16:03:23 -04:00
if ( iter -> second . second -> size ())
2016-02-15 19:35:24 -05:00
{
pcl :: copyPointCloud ( * cloudWithNormals , * iter -> second . second , * cloudWithoutNormals );
}
else
{
pcl :: copyPointCloud ( * cloudWithNormals , * cloudWithoutNormals );
}
_progressDialog -> appendText ( tr ( "Smoothing (MLS) the cloud (%1 points)..." ). arg ( cloudWithNormals -> size ()));
QApplication :: processEvents ();
2017-01-19 11:20:48 -05:00
uSleep ( 100 );
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-02-15 19:35:24 -05:00
cloudWithNormals = util3d :: mls (
cloudWithoutNormals ,
( float ) _ui -> doubleSpinBox_mlsRadius -> value (),
_ui -> spinBox_polygonialOrder -> value (),
_ui -> comboBox_upsamplingMethod -> currentIndex (),
( float ) _ui -> doubleSpinBox_sampleRadius -> value (),
( float ) _ui -> doubleSpinBox_sampleStep -> value (),
_ui -> spinBox_randomPoints -> value (),
( float ) _ui -> doubleSpinBox_dilationVoxelSize -> value (),
_ui -> spinBox_dilationSteps -> value ());
if ( _ui -> checkBox_assemble -> isChecked ())
{
// Re-voxelize to make sure to have uniform density
if ( _ui -> doubleSpinBox_voxelSize_assembled -> value ())
{
_progressDialog -> appendText ( tr ( "Voxelize cloud (%1 points, voxel size = %2 m)..." )
. arg ( cloudWithNormals -> size ())
. arg ( _ui -> doubleSpinBox_voxelSize_assembled -> value ()));
QApplication :: processEvents ();
cloudWithNormals = util3d :: voxelize (
cloudWithNormals ,
_ui -> doubleSpinBox_voxelSize_assembled -> value ());
}
2016-06-12 17:53:35 -04:00
2016-02-15 19:35:24 -05:00
_progressDialog -> appendText ( tr ( "Update %1 normals with %2 camera views..." ). arg ( cloudWithNormals -> size ()). arg ( poses . size ()));
2016-06-12 17:53:35 -04:00
2016-02-15 19:35:24 -05:00
util3d :: adjustNormalsToViewPoints (
2016-06-12 17:53:35 -04:00
viewPoints ,
2016-02-15 19:35:24 -05:00
rawAssembledCloud ,
rawCameraIndices ,
cloudWithNormals );
}
}
2017-02-26 18:17:00 -05:00
else if ( iter -> second . first -> isOrganized () && _ui -> checkBox_filtering -> isChecked ())
2016-02-15 19:35:24 -05:00
{
cloudWithNormals = util3d :: extractIndices ( iter -> second . first , iter -> second . second , false , true );
}
cloudsWithNormals . insert ( std :: make_pair ( iter -> first , cloudWithNormals ));
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-02-15 19:35:24 -05:00
}
2016-03-22 20:44:18 -04:00
//used for organized texturing below
2016-09-07 19:59:25 -04:00
std :: map < int , std :: vector < int > > organizedIndices ;
2016-09-07 12:15:44 -04:00
std :: map < int , cv :: Size > organizedCloudSizes ;
2016-03-22 20:44:18 -04:00
2016-02-15 19:35:24 -05:00
//mesh
2017-02-26 18:17:00 -05:00
UDEBUG ( "Meshing=%d" , _ui -> checkBox_meshing -> isChecked () ? 1 : 0 );
if ( _ui -> checkBox_meshing -> isChecked ())
2016-02-15 19:35:24 -05:00
{
if ( _ui -> comboBox_pipeline -> currentIndex () == 0 )
{
_progressDialog -> appendText ( tr ( "Organized fast mesh... " ));
QApplication :: processEvents ();
2017-01-19 11:20:48 -05:00
uSleep ( 100 );
2016-06-12 17:53:35 -04:00
QApplication :: processEvents ();
2016-02-15 19:35:24 -05:00
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr mergedClouds ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
std :: vector < pcl :: Vertices > mergedPolygons ;
int i = 0 ;
for ( std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr >:: iterator iter = cloudsWithNormals . begin ();
iter != cloudsWithNormals . end ();
++ iter )
{
2016-06-12 13:51:49 -04:00
if ( iter -> second -> isOrganized ())
2016-02-15 19:35:24 -05:00
{
2016-06-12 13:51:49 -04:00
if ( iter -> second -> size ())
2016-04-12 16:47:55 -04:00
{
2016-06-12 13:51:49 -04:00
Eigen :: Vector3f viewpoint ( 0.0f , 0.0f , 0.0f );
2017-03-21 21:51:39 -04:00
std :: vector < CameraModel > models ;
StereoCameraModel stereoModel ;
2016-06-12 13:51:49 -04:00
if ( cachedSignatures . contains ( iter -> first ))
2016-04-12 16:47:55 -04:00
{
2016-06-12 13:51:49 -04:00
const SensorData & data = cachedSignatures . find ( iter -> first ) -> sensorData ();
2017-03-21 21:51:39 -04:00
models = data . cameraModels ();
stereoModel = data . stereoCameraModel ();
2016-04-12 16:47:55 -04:00
}
2017-03-21 21:51:39 -04:00
else if ( _dbDriver )
{
_dbDriver -> getCalibration ( iter -> first , models , stereoModel );
}
if ( models . size () && ! models [ 0 ]. localTransform (). isNull ())
{
viewpoint [ 0 ] = models [ 0 ]. localTransform (). x ();
viewpoint [ 1 ] = models [ 0 ]. localTransform (). y ();
viewpoint [ 2 ] = models [ 0 ]. localTransform (). z ();
}
else if ( ! stereoModel . localTransform (). isNull ())
{
viewpoint [ 0 ] = stereoModel . localTransform (). x ();
viewpoint [ 1 ] = stereoModel . localTransform (). y ();
viewpoint [ 2 ] = stereoModel . localTransform (). z ();
}
2016-06-12 13:51:49 -04:00
std :: vector < pcl :: Vertices > polygons = util3d :: organizedFastMesh (
iter -> second ,
_ui -> doubleSpinBox_mesh_angleTolerance -> value () * M_PI / 180.0 ,
_ui -> checkBox_mesh_quad -> isEnabled () && _ui -> checkBox_mesh_quad -> isChecked (),
_ui -> spinBox_mesh_triangleSize -> value (),
viewpoint );
2016-09-03 18:59:43 -04:00
2017-02-04 18:28:43 -05:00
if ( _ui -> spinBox_mesh_minClusterSize -> value () != 0 )
2016-09-03 18:59:43 -04:00
{
2017-01-16 01:32:53 -05:00
_progressDialog -> appendText ( tr ( "Filter small polygon clusters..." ));
QApplication :: processEvents ();
2016-09-03 18:59:43 -04:00
// filter polygons
std :: vector < std :: set < int > > neighbors ;
std :: vector < std :: set < int > > vertexToPolygons ;
util3d :: createPolygonIndexes ( polygons ,
2017-01-30 21:23:56 -05:00
( int ) iter -> second -> size (),
2016-09-03 18:59:43 -04:00
neighbors ,
vertexToPolygons );
std :: list < std :: list < int > > clusters = util3d :: clusterPolygons (
neighbors ,
2017-02-04 18:28:43 -05:00
_ui -> spinBox_mesh_minClusterSize -> value () < 0 ? 0 : _ui -> spinBox_mesh_minClusterSize -> value ());
2016-09-03 18:59:43 -04:00
std :: vector < pcl :: Vertices > filteredPolygons ( polygons . size ());
2017-02-04 18:28:43 -05:00
if ( _ui -> spinBox_mesh_minClusterSize -> value () < 0 )
2016-09-03 18:59:43 -04:00
{
2017-02-04 18:28:43 -05:00
// only keep the biggest cluster
std :: list < std :: list < int > >:: iterator biggestClusterIndex = clusters . end ();
unsigned int biggestClusterSize = 0 ;
for ( std :: list < std :: list < int > >:: iterator iter = clusters . begin (); iter != clusters . end (); ++ iter )
2016-09-03 18:59:43 -04:00
{
2017-02-04 18:28:43 -05:00
if ( iter -> size () > biggestClusterSize )
{
biggestClusterIndex = iter ;
biggestClusterSize = iter -> size ();
}
}
if ( biggestClusterIndex != clusters . end ())
{
int oi = 0 ;
for ( std :: list < int >:: iterator jter = biggestClusterIndex -> begin (); jter != biggestClusterIndex -> end (); ++ jter )
{
filteredPolygons [ oi ++ ] = polygons . at ( * jter );
}
filteredPolygons . resize ( oi );
2016-09-03 18:59:43 -04:00
}
}
2017-02-04 18:28:43 -05:00
else
{
int oi = 0 ;
for ( std :: list < std :: list < int > >:: iterator iter = clusters . begin (); iter != clusters . end (); ++ iter )
{
for ( std :: list < int >:: iterator jter = iter -> begin (); jter != iter -> end (); ++ jter )
{
filteredPolygons [ oi ++ ] = polygons . at ( * jter );
}
}
filteredPolygons . resize ( oi );
}
2017-01-30 21:23:56 -05:00
int before = ( int ) polygons . size ();
2016-09-03 18:59:43 -04:00
polygons = filteredPolygons ;
2017-01-16 01:32:53 -05:00
2017-02-04 18:28:43 -05:00
if ( polygons . size () == 0 )
2017-01-19 11:20:48 -05:00
{
std :: string msg = uFormat ( "All %d polygons filtered after polygon cluster filtering. Cluster minimum size is %d." , before , _ui -> spinBox_mesh_minClusterSize -> value ());
_progressDialog -> appendText ( msg . c_str ());
UWARN ( msg . c_str ());
}
2017-02-04 18:28:43 -05:00
_progressDialog -> appendText ( tr ( "Filtered %1 polygons." ). arg ( before - ( int ) polygons . size ()));
2017-01-16 01:32:53 -05:00
QApplication :: processEvents ();
2016-09-03 18:59:43 -04:00
}
2016-06-12 13:51:49 -04:00
_progressDialog -> appendText ( tr ( "Mesh %1 created with %2 polygons (%3/%4)." ). arg ( iter -> first ). arg ( polygons . size ()). arg ( ++ i ). arg ( clouds . size ()));
2016-02-15 19:35:24 -05:00
2016-06-12 13:51:49 -04:00
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr denseCloud ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
std :: vector < pcl :: Vertices > densePolygons ;
2016-09-07 19:59:25 -04:00
std :: vector < int > denseToOrganizedIndices = util3d :: filterNotUsedVerticesFromMesh ( * iter -> second , polygons , * denseCloud , densePolygons );
2016-02-15 19:35:24 -05:00
2016-06-12 13:51:49 -04:00
if ( ! _ui -> checkBox_assemble -> isChecked () ||
( _ui -> checkBox_textureMapping -> isEnabled () &&
_ui -> checkBox_textureMapping -> isChecked () &&
_ui -> doubleSpinBox_voxelSize_assembled -> value () == 0.0 )) // don't assemble now if we are texturing
2016-03-22 20:44:18 -04:00
{
2016-06-12 13:51:49 -04:00
if ( _ui -> checkBox_assemble -> isChecked ())
{
denseCloud = util3d :: transformPointCloud ( denseCloud , poses . at ( iter -> first ));
}
2016-03-22 20:44:18 -04:00
2016-06-12 13:51:49 -04:00
pcl :: PolygonMesh :: Ptr mesh ( new pcl :: PolygonMesh );
pcl :: toPCLPointCloud2 ( * denseCloud , mesh -> cloud );
mesh -> polygons = densePolygons ;
2017-01-15 19:09:37 -05:00
2017-01-16 01:32:53 -05:00
organizedIndices . insert ( std :: make_pair ( iter -> first , denseToOrganizedIndices ));
organizedCloudSizes . insert ( std :: make_pair ( iter -> first , cv :: Size ( iter -> second -> width , iter -> second -> height )));
2017-01-15 19:09:37 -05:00
2016-06-12 13:51:49 -04:00
meshes . insert ( std :: make_pair ( iter -> first , mesh ));
2016-03-22 20:44:18 -04:00
}
else
{
2016-06-12 13:51:49 -04:00
denseCloud = util3d :: transformPointCloud ( denseCloud , poses . at ( iter -> first ));
if ( mergedClouds -> size () == 0 )
{
* mergedClouds = * denseCloud ;
mergedPolygons = densePolygons ;
}
else
{
util3d :: appendMesh ( * mergedClouds , mergedPolygons , * denseCloud , densePolygons );
}
2016-03-22 20:44:18 -04:00
}
}
else
2016-02-15 19:35:24 -05:00
{
2016-06-12 13:51:49 -04:00
_progressDialog -> appendText ( tr ( "Mesh %1 not created (no valid points) (%2/%3)." ). arg ( iter -> first ). arg ( ++ i ). arg ( clouds . size ()));
2016-02-15 19:35:24 -05:00
}
}
else
{
2016-06-12 13:51:49 -04:00
_progressDialog -> appendText ( tr ( "Mesh %1 not created (cloud is not organized). You may want to check cloud regeneration option (%2/%3)." ). arg ( iter -> first ). arg ( ++ i ). arg ( clouds . size ()));
2016-02-15 19:35:24 -05:00
}
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-02-15 19:35:24 -05:00
}
if ( _ui -> checkBox_assemble -> isChecked () && mergedClouds -> size ())
{
if ( _ui -> doubleSpinBox_voxelSize_assembled -> value ())
{
2016-03-22 20:44:18 -04:00
_progressDialog -> appendText ( tr ( "Filtering assembled mesh for close vertices (points=%1, polygons=%2)..." ). arg ( mergedClouds -> size ()). arg ( mergedPolygons . size ()));
2016-02-15 19:35:24 -05:00
QApplication :: processEvents ();
mergedPolygons = util3d :: filterCloseVerticesFromMesh (
mergedClouds ,
mergedPolygons ,
_ui -> doubleSpinBox_voxelSize_assembled -> value (),
M_PI / 4 ,
true );
// filter invalid polygons
unsigned int count = mergedPolygons . size ();
mergedPolygons = util3d :: filterInvalidPolygons ( mergedPolygons );
_progressDialog -> appendText ( tr ( "Filtered %1 invalid polygons." ). arg ( count - mergedPolygons . size ()));
QApplication :: processEvents ();
// filter not used vertices
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr filteredCloud ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
std :: vector < pcl :: Vertices > filteredPolygons ;
util3d :: filterNotUsedVerticesFromMesh ( * mergedClouds , mergedPolygons , * filteredCloud , filteredPolygons );
mergedClouds = filteredCloud ;
mergedPolygons = filteredPolygons ;
}
pcl :: PolygonMesh :: Ptr mesh ( new pcl :: PolygonMesh );
pcl :: toPCLPointCloud2 ( * mergedClouds , mesh -> cloud );
mesh -> polygons = mergedPolygons ;
meshes . insert ( std :: make_pair ( 0 , mesh ));
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
}
}
2017-03-30 15:33:48 -04:00
else // dense pipeline
2016-02-15 19:35:24 -05:00
{
2017-01-15 19:09:37 -05:00
if ( _ui -> comboBox_meshingApproach -> currentIndex () == 0 )
{
_progressDialog -> appendText ( tr ( "Greedy projection triangulation... [radius=%1m]" ). arg ( _ui -> doubleSpinBox_gp3Radius -> value ()));
}
else
{
_progressDialog -> appendText ( tr ( "Poisson surface reconstruction..." ));
}
2016-02-15 19:35:24 -05:00
QApplication :: processEvents ();
2017-01-19 11:20:48 -05:00
uSleep ( 100 );
2016-06-12 17:53:35 -04:00
QApplication :: processEvents ();
2016-02-15 19:35:24 -05:00
int i = 0 ;
for ( std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr >:: iterator iter = cloudsWithNormals . begin ();
iter != cloudsWithNormals . end ();
++ iter )
{
2017-01-15 19:09:37 -05:00
bool lostColors = false ;
pcl :: PolygonMesh :: Ptr mesh ( new pcl :: PolygonMesh );
if ( _ui -> comboBox_meshingApproach -> currentIndex () == 0 )
{
mesh = util3d :: createMesh (
iter -> second ,
_ui -> doubleSpinBox_gp3Radius -> value (),
_ui -> doubleSpinBox_gp3Mu -> value ());
}
else
{
pcl :: Poisson < pcl :: PointXYZRGBNormal > poisson ;
2017-01-17 14:57:50 -05:00
poisson . setOutputPolygons ( _ui -> checkBox_poisson_outputPolygons -> isEnabled () ? _ui -> checkBox_poisson_outputPolygons -> isChecked () : false );
2017-01-15 19:09:37 -05:00
poisson . setManifold ( _ui -> checkBox_poisson_manifold -> isChecked ());
poisson . setSamplesPerNode ( _ui -> doubleSpinBox_poisson_samples -> value ());
poisson . setDepth ( _ui -> spinBox_poisson_depth -> value ());
poisson . setIsoDivide ( _ui -> spinBox_poisson_iso -> value ());
poisson . setSolverDivide ( _ui -> spinBox_poisson_solver -> value ());
poisson . setMinDepth ( _ui -> spinBox_poisson_minDepth -> value ());
poisson . setPointWeight ( _ui -> doubleSpinBox_poisson_pointWeight -> value ());
poisson . setScale ( _ui -> doubleSpinBox_poisson_scale -> value ());
poisson . setInputCloud ( iter -> second );
poisson . reconstruct ( * mesh );
lostColors = true ;
}
2016-09-03 18:59:43 -04:00
2016-02-15 19:35:24 -05:00
_progressDialog -> appendText ( tr ( "Mesh %1 created with %2 polygons (%3/%4)." ). arg ( iter -> first ). arg ( mesh -> polygons . size ()). arg ( ++ i ). arg ( clouds . size ()));
QApplication :: processEvents ();
2017-03-30 15:33:48 -04:00
if ( mesh -> polygons . size () > 0 )
2016-02-15 19:35:24 -05:00
{
2017-03-30 15:33:48 -04:00
double meshDecimationFactor = 0.0 ;
if ( _ui -> doubleSpinBox_meshDecimationFactor -> isEnabled () &&
_ui -> doubleSpinBox_meshDecimationFactor -> value () > 0.0 )
2017-01-15 19:09:37 -05:00
{
2017-03-30 15:33:48 -04:00
meshDecimationFactor = _ui -> doubleSpinBox_meshDecimationFactor -> value ();
2017-01-15 19:09:37 -05:00
}
2017-03-30 15:33:48 -04:00
if ( _ui -> spinBox_meshMaxPolygons -> isEnabled () &&
_ui -> spinBox_meshMaxPolygons -> value () > 0 )
2017-01-15 19:09:37 -05:00
{
2017-03-30 15:33:48 -04:00
double factor = 1.0 - double ( _ui -> spinBox_meshMaxPolygons -> value ()) / double ( mesh -> polygons . size ());
if ( factor > meshDecimationFactor )
2017-01-26 09:42:52 -05:00
{
2017-03-30 15:33:48 -04:00
meshDecimationFactor = factor ;
2017-01-26 09:42:52 -05:00
}
2017-03-30 15:33:48 -04:00
}
if ( meshDecimationFactor > 0.0 )
{
unsigned int count = mesh -> polygons . size ();
_progressDialog -> appendText ( tr ( "Mesh decimation (factor=%1) from %2 polygons..." ). arg ( meshDecimationFactor ). arg ( count ));
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
mesh = util3d :: meshDecimation ( mesh , ( float ) meshDecimationFactor );
_progressDialog -> appendText ( tr ( "Mesh decimated (factor=%1) from %2 to %3 polygons" ). arg ( meshDecimationFactor ). arg ( count ). arg ( mesh -> polygons . size ()));
if ( count < mesh -> polygons . size ())
2017-01-26 09:42:52 -05:00
{
2017-03-30 15:33:48 -04:00
_progressDialog -> appendText ( tr ( "Decimated mesh %1 has more polygons than before!" ). arg ( iter -> first ), Qt :: darkYellow );
_progressDialog -> setAutoClose ( false );
2017-01-26 09:42:52 -05:00
}
2017-03-30 15:33:48 -04:00
QApplication :: processEvents ();
lostColors = true ;
}
if ( lostColors &&
_ui -> doubleSpinBox_transferColorRadius -> value () >= 0.0 &&
( ! _ui -> checkBox_textureMapping -> isEnabled () || ! _ui -> checkBox_textureMapping -> isChecked ()))
{
_progressDialog -> appendText ( tr ( "Transferring color from point cloud to mesh..." ));
QApplication :: processEvents ();
// transfer color from point cloud to mesh
pcl :: search :: KdTree < pcl :: PointXYZRGBNormal >:: Ptr tree ( new pcl :: search :: KdTree < pcl :: PointXYZRGBNormal > ( true ));
tree -> setInputCloud ( iter -> second );
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr coloredCloud ( new pcl :: PointCloud < pcl :: PointXYZRGB > );
pcl :: fromPCLPointCloud2 ( mesh -> cloud , * coloredCloud );
std :: vector < bool > coloredPts ( coloredCloud -> size ());
for ( unsigned int i = 0 ; i < coloredCloud -> size (); ++ i )
2017-01-15 19:09:37 -05:00
{
2017-03-30 15:33:48 -04:00
std :: vector < int > kIndices ;
std :: vector < float > kDistances ;
pcl :: PointXYZRGBNormal pt ;
pt . x = coloredCloud -> at ( i ). x ;
pt . y = coloredCloud -> at ( i ). y ;
pt . z = coloredCloud -> at ( i ). z ;
if ( _ui -> doubleSpinBox_transferColorRadius -> value () > 0.0 )
2017-02-28 21:50:50 -05:00
{
2017-03-30 15:33:48 -04:00
tree -> radiusSearch ( pt , _ui -> doubleSpinBox_transferColorRadius -> value (), kIndices , kDistances );
}
else
{
tree -> nearestKSearch ( pt , 1 , kIndices , kDistances );
}
if ( kIndices . size ())
{
//compute average color
int r = 0 ;
int g = 0 ;
int b = 0 ;
int a = 0 ;
for ( unsigned int j = 0 ; j < kIndices . size (); ++ j )
{
r += ( int ) iter -> second -> at ( kIndices [ j ]). r ;
g += ( int ) iter -> second -> at ( kIndices [ j ]). g ;
b += ( int ) iter -> second -> at ( kIndices [ j ]). b ;
a += ( int ) iter -> second -> at ( kIndices [ j ]). a ;
}
coloredCloud -> at ( i ). r = r / kIndices . size ();
coloredCloud -> at ( i ). g = g / kIndices . size ();
coloredCloud -> at ( i ). b = b / kIndices . size ();
coloredCloud -> at ( i ). a = a / kIndices . size ();
coloredPts . at ( i ) = true ;
}
else
{
//white
coloredCloud -> at ( i ). r = coloredCloud -> at ( i ). g = coloredCloud -> at ( i ). b = 255 ;
coloredPts . at ( i ) = false ;
2017-02-28 21:50:50 -05:00
}
2017-01-15 19:09:37 -05:00
}
2017-03-30 15:33:48 -04:00
pcl :: toPCLPointCloud2 ( * coloredCloud , mesh -> cloud );
// remove polygons with no color
if ( _ui -> checkBox_cleanMesh -> isChecked ())
2017-01-15 19:09:37 -05:00
{
2017-03-30 15:33:48 -04:00
std :: vector < pcl :: Vertices > filteredPolygons ( mesh -> polygons . size ());
int oi = 0 ;
for ( unsigned int i = 0 ; i < mesh -> polygons . size (); ++ i )
{
bool coloredPolygon = true ;
for ( unsigned int j = 0 ; j < mesh -> polygons [ i ]. vertices . size (); ++ j )
{
if ( ! coloredPts . at ( mesh -> polygons [ i ]. vertices [ j ]))
{
coloredPolygon = false ;
break ;
}
}
if ( coloredPolygon )
{
filteredPolygons [ oi ++ ] = mesh -> polygons [ i ];
}
}
filteredPolygons . resize ( oi );
mesh -> polygons = filteredPolygons ;
2017-01-15 19:09:37 -05:00
}
}
2017-03-30 15:33:48 -04:00
else if ( lostColors &&
_ui -> doubleSpinBox_transferColorRadius -> value () > 0.0 &&
_ui -> checkBox_cleanMesh -> isChecked () &&
( _ui -> checkBox_textureMapping -> isEnabled () && _ui -> checkBox_textureMapping -> isChecked ()))
2017-01-16 01:32:53 -05:00
{
2017-03-30 15:33:48 -04:00
_progressDialog -> appendText ( tr ( "Removing polygons too far from the cloud..." ));
QApplication :: processEvents ();
// transfer color from point cloud to mesh
pcl :: search :: KdTree < pcl :: PointXYZRGBNormal >:: Ptr tree ( new pcl :: search :: KdTree < pcl :: PointXYZRGBNormal > ( true ));
tree -> setInputCloud ( iter -> second );
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr optimizedCloud ( new pcl :: PointCloud < pcl :: PointXYZ > );
pcl :: fromPCLPointCloud2 ( mesh -> cloud , * optimizedCloud );
std :: vector < bool > closePts ( optimizedCloud -> size ());
for ( unsigned int i = 0 ; i < optimizedCloud -> size (); ++ i )
{
std :: vector < int > kIndices ;
std :: vector < float > kDistances ;
pcl :: PointXYZRGBNormal pt ;
pt . x = optimizedCloud -> at ( i ). x ;
pt . y = optimizedCloud -> at ( i ). y ;
pt . z = optimizedCloud -> at ( i ). z ;
tree -> radiusSearch ( pt , _ui -> doubleSpinBox_transferColorRadius -> value (), kIndices , kDistances );
if ( kIndices . size ())
{
closePts . at ( i ) = true ;
}
else
{
closePts . at ( i ) = false ;
}
}
// remove far polygons
2017-01-16 01:32:53 -05:00
std :: vector < pcl :: Vertices > filteredPolygons ( mesh -> polygons . size ());
int oi = 0 ;
for ( unsigned int i = 0 ; i < mesh -> polygons . size (); ++ i )
{
2017-03-30 15:33:48 -04:00
bool keepPolygon = true ;
2017-01-16 01:32:53 -05:00
for ( unsigned int j = 0 ; j < mesh -> polygons [ i ]. vertices . size (); ++ j )
{
2017-03-30 15:33:48 -04:00
if ( ! closePts . at ( mesh -> polygons [ i ]. vertices [ j ]))
2017-01-16 01:32:53 -05:00
{
2017-03-30 15:33:48 -04:00
keepPolygon = false ;
2017-01-16 01:32:53 -05:00
break ;
}
}
2017-03-30 15:33:48 -04:00
if ( keepPolygon )
2017-01-16 01:32:53 -05:00
{
filteredPolygons [ oi ++ ] = mesh -> polygons [ i ];
}
}
filteredPolygons . resize ( oi );
mesh -> polygons = filteredPolygons ;
}
2017-02-27 17:31:02 -05:00
2017-03-30 15:33:48 -04:00
if ( _ui -> spinBox_mesh_minClusterSize -> value () &&
! ( _ui -> checkBox_textureMapping -> isEnabled () &&
_ui -> checkBox_textureMapping -> isChecked () &&
_ui -> checkBox_cleanMesh -> isChecked ()))
2017-02-27 17:31:02 -05:00
{
2017-03-30 15:33:48 -04:00
_progressDialog -> appendText ( tr ( "Filter small polygon clusters..." ));
QApplication :: processEvents ();
// filter polygons
std :: vector < std :: set < int > > neighbors ;
std :: vector < std :: set < int > > vertexToPolygons ;
util3d :: createPolygonIndexes ( mesh -> polygons ,
mesh -> cloud . height * mesh -> cloud . width ,
neighbors ,
vertexToPolygons );
std :: list < std :: list < int > > clusters = util3d :: clusterPolygons (
neighbors ,
_ui -> spinBox_mesh_minClusterSize -> value () < 0 ? 0 : _ui -> spinBox_mesh_minClusterSize -> value ());
std :: vector < pcl :: Vertices > filteredPolygons ( mesh -> polygons . size ());
if ( _ui -> spinBox_mesh_minClusterSize -> value () < 0 )
2017-02-27 17:31:02 -05:00
{
2017-03-30 15:33:48 -04:00
// only keep the biggest cluster
std :: list < std :: list < int > >:: iterator biggestClusterIndex = clusters . end ();
unsigned int biggestClusterSize = 0 ;
for ( std :: list < std :: list < int > >:: iterator iter = clusters . begin (); iter != clusters . end (); ++ iter )
{
if ( iter -> size () > biggestClusterSize )
{
biggestClusterIndex = iter ;
biggestClusterSize = iter -> size ();
}
}
if ( biggestClusterIndex != clusters . end ())
{
int oi = 0 ;
for ( std :: list < int >:: iterator jter = biggestClusterIndex -> begin (); jter != biggestClusterIndex -> end (); ++ jter )
{
filteredPolygons [ oi ++ ] = mesh -> polygons . at ( * jter );
}
filteredPolygons . resize ( oi );
}
2017-02-27 17:31:02 -05:00
}
else
2017-02-04 18:28:43 -05:00
{
int oi = 0 ;
2017-03-30 15:33:48 -04:00
for ( std :: list < std :: list < int > >:: iterator iter = clusters . begin (); iter != clusters . end (); ++ iter )
2017-02-04 18:28:43 -05:00
{
2017-03-30 15:33:48 -04:00
for ( std :: list < int >:: iterator jter = iter -> begin (); jter != iter -> end (); ++ jter )
{
filteredPolygons [ oi ++ ] = mesh -> polygons . at ( * jter );
}
2017-02-04 18:28:43 -05:00
}
filteredPolygons . resize ( oi );
2017-01-16 01:32:53 -05:00
}
2017-03-30 15:33:48 -04:00
int before = ( int ) mesh -> polygons . size ();
mesh -> polygons = filteredPolygons ;
_progressDialog -> appendText ( tr ( "Filtered %1 polygons." ). arg ( before - ( int ) mesh -> polygons . size ()));
2017-02-04 18:28:43 -05:00
}
2017-03-30 15:33:48 -04:00
meshes . insert ( std :: make_pair ( iter -> first , mesh ));
}
else
{
_progressDialog -> appendText ( tr ( "No polygons created for cloud %d!" ). arg ( iter -> first ), Qt :: darkYellow );
_progressDialog -> setAutoClose ( false );
2016-02-15 19:35:24 -05:00
}
2017-03-03 15:22:20 -05:00
_progressDialog -> incrementStep ( _ui -> checkBox_assemble -> isChecked () ? poses . size () : 1 );
2016-02-15 19:35:24 -05:00
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-02-15 19:35:24 -05:00
}
}
}
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-02-15 19:35:24 -05:00
// texture mesh
2016-10-21 16:56:29 -04:00
UDEBUG ( "texture mapping=%d" , _ui -> checkBox_textureMapping -> isEnabled () && _ui -> checkBox_textureMapping -> isChecked () ? 1 : 0 );
2016-02-15 19:35:24 -05:00
if ( _ui -> checkBox_textureMapping -> isEnabled () && _ui -> checkBox_textureMapping -> isChecked ())
{
2017-01-19 11:20:48 -05:00
_progressDialog -> appendText ( tr ( "Texturing..." ));
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
2016-02-15 19:35:24 -05:00
int i = 0 ;
for ( std :: map < int , pcl :: PolygonMesh :: Ptr >:: iterator iter = meshes . begin ();
iter != meshes . end ();
++ iter )
{
std :: map < int , Transform > cameras ;
if ( iter -> first == 0 )
{
cameras = poses ;
}
else
{
UASSERT ( uContains ( poses , iter -> first ));
2016-03-22 20:44:18 -04:00
cameras . insert ( std :: make_pair ( iter -> first , _ui -> checkBox_assemble -> isChecked () ? poses . at ( iter -> first ) : Transform :: getIdentity ()));
2016-02-15 19:35:24 -05:00
}
std :: map < int , Transform > cameraPoses ;
std :: map < int , CameraModel > cameraModels ;
for ( std :: map < int , Transform >:: iterator jter = cameras . begin (); jter != cameras . end (); ++ jter )
{
2017-03-21 21:51:39 -04:00
std :: vector < CameraModel > models ;
StereoCameraModel stereoModel ;
bool cacheHasCompressedImage = false ;
2016-02-15 19:35:24 -05:00
if ( cachedSignatures . contains ( jter -> first ))
{
2017-03-21 21:51:39 -04:00
const SensorData & data = cachedSignatures . find ( jter -> first ) -> sensorData ();
models = data . cameraModels ();
stereoModel = data . stereoCameraModel ();
cacheHasCompressedImage = ! data . imageCompressed (). empty ();
}
else if ( _dbDriver )
{
_dbDriver -> getCalibration ( jter -> first , models , stereoModel );
}
2017-03-03 00:19:46 -05:00
2017-03-21 21:51:39 -04:00
CameraModel model ;
if ( stereoModel . isValidForProjection ())
{
model = stereoModel . left ();
}
else if ( models . size () == 1 && models [ 0 ]. isValidForProjection ())
{
model = models [ 0 ];
}
if ( ! jter -> second . isNull () && model . isValidForProjection ())
{
if ( model . imageWidth () == 0 || model . imageHeight () == 0 )
{
// we are using an old database format (image size not saved in calibrations), we should
// uncompress images to get their size
cv :: Mat img ;
if ( cacheHasCompressedImage )
{
cachedSignatures . find ( jter -> first ) -> sensorData (). uncompressDataConst ( & img , 0 );
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( jter -> first , data , true , false , false , false );
data . uncompressDataConst ( & img , 0 );
}
model . setImageSize ( img . size ());
}
if ( model . imageWidth () != 0 && model . imageHeight () != 0 )
{
2016-02-15 19:35:24 -05:00
cameraPoses . insert ( std :: make_pair ( jter -> first , jter -> second ));
cameraModels . insert ( std :: make_pair ( jter -> first , model ));
}
}
}
2017-01-26 16:46:24 -05:00
if ( cameraPoses . size () && iter -> second -> polygons . size ())
2016-02-15 19:35:24 -05:00
{
2016-03-22 20:44:18 -04:00
pcl :: TextureMesh :: Ptr textureMesh ( new pcl :: TextureMesh );
2016-09-07 19:59:25 -04:00
std :: map < int , std :: vector < int > >:: iterator oter = organizedIndices . find ( iter -> first );
2016-09-07 12:15:44 -04:00
std :: map < int , cv :: Size >:: iterator ster = organizedCloudSizes . find ( iter -> first );
2016-03-22 20:44:18 -04:00
if ( iter -> first != 0 && oter != organizedIndices . end ())
{
2016-09-07 12:15:44 -04:00
UASSERT ( ster != organizedCloudSizes . end () && ster -> first == oter -> first );
2016-03-22 20:44:18 -04:00
UDEBUG ( "Texture by pixels" );
textureMesh -> cloud = iter -> second -> cloud ;
textureMesh -> tex_polygons . push_back ( iter -> second -> polygons );
2016-09-07 12:15:44 -04:00
int w = ster -> second . width ;
int h = ster -> second . height ;
2016-03-22 20:44:18 -04:00
UASSERT ( w > 1 && h > 1 );
2016-10-30 16:03:23 -04:00
if ( textureMesh -> tex_polygons . size () && textureMesh -> tex_polygons [ 0 ]. size ())
2016-03-22 20:44:18 -04:00
{
2016-10-30 16:03:23 -04:00
textureMesh -> tex_coordinates . resize ( 1 );
2017-01-19 11:20:48 -05:00
//tex_coordinates should be linked to polygon vertices
2017-01-30 21:23:56 -05:00
int polygonSize = ( int ) textureMesh -> tex_polygons [ 0 ][ 0 ]. vertices . size ();
2017-01-19 11:20:48 -05:00
textureMesh -> tex_coordinates [ 0 ]. resize ( polygonSize * textureMesh -> tex_polygons [ 0 ]. size ());
for ( unsigned int i = 0 ; i < textureMesh -> tex_polygons [ 0 ]. size (); ++ i )
2016-09-07 12:15:44 -04:00
{
2017-01-19 11:20:48 -05:00
const pcl :: Vertices & vertices = textureMesh -> tex_polygons [ 0 ][ i ];
UASSERT ( polygonSize == ( int ) vertices . vertices . size ());
for ( int k = 0 ; k < polygonSize ; ++ k )
2016-09-07 12:15:44 -04:00
{
//uv
2017-01-19 11:20:48 -05:00
UASSERT ( vertices . vertices [ k ] < oter -> second . size ());
int originalVertex = oter -> second [ vertices . vertices [ k ]];
textureMesh -> tex_coordinates [ 0 ][ i * polygonSize + k ] = Eigen :: Vector2f (
2016-09-07 12:15:44 -04:00
float ( originalVertex % w ) / float ( w ), // u
float ( h - originalVertex / w ) / float ( h )); // v
}
}
2016-10-30 16:03:23 -04:00
pcl :: TexMaterial mesh_material ;
mesh_material . tex_d = 1.0f ;
mesh_material . tex_Ns = 75.0f ;
mesh_material . tex_illum = 1 ;
std :: stringstream tex_name ;
tex_name << "material_" << iter -> first ;
tex_name >> mesh_material . tex_name ;
2017-01-17 14:57:50 -05:00
mesh_material . tex_file = uFormat ( "%d" , iter -> first );
2016-10-30 16:03:23 -04:00
textureMesh -> tex_materials . push_back ( mesh_material );
2016-03-22 20:44:18 -04:00
}
else
{
2016-10-30 16:03:23 -04:00
UWARN ( "No polygons for mesh %d!?" , iter -> first );
2016-03-22 20:44:18 -04:00
}
}
else
{
UDEBUG ( "Texture by projection" );
2017-02-26 18:17:00 -05:00
if ( cameraPoses . size () && _ui -> checkBox_cameraFilter -> isChecked ())
{
int before = ( int ) cameraPoses . size ();
cameraPoses = graph :: radiusPosesFiltering ( cameraPoses ,
_ui -> doubleSpinBox_cameraFilterRadius -> value (),
_ui -> doubleSpinBox_cameraFilterAngle -> value ());
for ( std :: map < int , CameraModel >:: iterator modelIter = cameraModels . begin (); modelIter != cameraModels . end ();)
{
if ( cameraPoses . find ( modelIter -> first ) == cameraPoses . end ())
{
cameraModels . erase ( modelIter ++ );
}
else
{
++ modelIter ;
}
}
_progressDialog -> appendText ( tr ( "Camera filtering: keeping %1/%2 cameras for texturing." ). arg ( cameraPoses . size ()). arg ( before ));
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
}
if ( _canceled )
{
return false ;
}
TexturingState texturingState ( _progressDialog );
2017-03-03 15:22:20 -05:00
_progressDialog -> setMaximumSteps ( _progressDialog -> maximumSteps () + iter -> second -> polygons . size () / 10000 + 1 );
2017-04-20 11:51:23 -04:00
std :: vector < float > roiRatios ;
QStringList strings = _ui -> lineEdit_meshingTextureRoiRatios -> text (). split ( ' ' );
if ( ! _ui -> lineEdit_meshingTextureRoiRatios -> text (). isEmpty ())
{
if ( strings . size () == 4 )
{
roiRatios . resize ( 4 );
roiRatios [ 0 ] = strings [ 0 ]. toDouble ();
roiRatios [ 1 ] = strings [ 1 ]. toDouble ();
roiRatios [ 2 ] = strings [ 2 ]. toDouble ();
roiRatios [ 3 ] = strings [ 3 ]. toDouble ();
if ( ! ( roiRatios [ 0 ] >= 0.0f && roiRatios [ 0 ] <= 1.0f &&
roiRatios [ 1 ] >= 0.0f && roiRatios [ 1 ] <= 1.0f &&
roiRatios [ 2 ] >= 0.0f && roiRatios [ 2 ] <= 1.0f &&
roiRatios [ 3 ] >= 0.0f && roiRatios [ 3 ] <= 1.0f ))
{
roiRatios . clear ();
}
}
if ( roiRatios . empty ())
{
QString msg = tr ( "Wrong ROI format. Region of Interest (ROI) must have 4 values [left right top bottom] between 0 and 1 separated by space (%1), ignoring it for texturing..." ). arg ( _ui -> lineEdit_meshingTextureRoiRatios -> text ());
UWARN ( msg . toStdString (). c_str ());
_progressDialog -> appendText ( msg , Qt :: darkYellow );
_progressDialog -> setAutoClose ( false );
}
}
2016-03-22 20:44:18 -04:00
textureMesh = util3d :: createTextureMesh (
iter -> second ,
cameraPoses ,
cameraModels ,
2017-02-26 18:17:00 -05:00
_ui -> doubleSpinBox_meshingTextureMaxDistance -> value (),
2017-03-04 18:20:26 -05:00
_ui -> spinBox_mesh_minTextureClusterSize -> value (),
2017-04-20 11:51:23 -04:00
roiRatios ,
2017-04-09 19:16:50 -04:00
& texturingState ,
cameraPoses . size () > 1 ?& textureVertexToPixels : 0 ); // only get vertexToPixels if merged clouds with multi textures
2017-02-26 18:17:00 -05:00
if ( _canceled )
{
return false ;
}
2016-10-21 19:34:29 -04:00
2017-01-16 01:32:53 -05:00
// Remove occluded polygons (polygons with no texture)
if ( _ui -> checkBox_cleanMesh -> isChecked () &&
textureMesh -> tex_coordinates . size ())
{
// assume last texture is the occluded texture
textureMesh -> tex_coordinates . pop_back ();
textureMesh -> tex_polygons . pop_back ();
textureMesh -> tex_materials . pop_back ();
if ( _ui -> spinBox_mesh_minClusterSize -> value ())
{
_progressDialog -> appendText ( tr ( "Filter small polygon clusters..." ));
QApplication :: processEvents ();
// concatenate all polygons
2017-01-30 21:23:56 -05:00
unsigned int totalSize = 0 ;
2017-01-16 01:32:53 -05:00
for ( unsigned int t = 0 ; t < textureMesh -> tex_polygons . size (); ++ t )
{
totalSize += textureMesh -> tex_polygons [ t ]. size ();
}
std :: vector < pcl :: Vertices > allPolygons ( totalSize );
int oi = 0 ;
for ( unsigned int t = 0 ; t < textureMesh -> tex_polygons . size (); ++ t )
{
for ( unsigned int i = 0 ; i < textureMesh -> tex_polygons [ t ]. size (); ++ i )
{
allPolygons [ oi ++ ] = textureMesh -> tex_polygons [ t ][ i ];
}
}
// filter polygons
std :: vector < std :: set < int > > neighbors ;
std :: vector < std :: set < int > > vertexToPolygons ;
util3d :: createPolygonIndexes ( allPolygons ,
2017-01-30 21:23:56 -05:00
( int ) textureMesh -> cloud . data . size () / textureMesh -> cloud . point_step ,
2017-01-16 01:32:53 -05:00
neighbors ,
vertexToPolygons );
2017-02-04 18:28:43 -05:00
2017-01-16 01:32:53 -05:00
std :: list < std :: list < int > > clusters = util3d :: clusterPolygons (
neighbors ,
2017-02-04 18:28:43 -05:00
_ui -> spinBox_mesh_minClusterSize -> value () < 0 ? 0 : _ui -> spinBox_mesh_minClusterSize -> value ());
2017-01-16 01:32:53 -05:00
std :: set < int > validPolygons ;
2017-02-04 18:28:43 -05:00
if ( _ui -> spinBox_mesh_minClusterSize -> value () < 0 )
2017-01-16 01:32:53 -05:00
{
2017-02-04 18:28:43 -05:00
// only keep the biggest cluster
std :: list < std :: list < int > >:: iterator biggestClusterIndex = clusters . end ();
unsigned int biggestClusterSize = 0 ;
for ( std :: list < std :: list < int > >:: iterator iter = clusters . begin (); iter != clusters . end (); ++ iter )
2017-01-16 01:32:53 -05:00
{
2017-02-04 18:28:43 -05:00
if ( iter -> size () > biggestClusterSize )
{
biggestClusterIndex = iter ;
biggestClusterSize = iter -> size ();
}
}
if ( biggestClusterIndex != clusters . end ())
{
for ( std :: list < int >:: iterator jter = biggestClusterIndex -> begin (); jter != biggestClusterIndex -> end (); ++ jter )
{
validPolygons . insert ( * jter );
}
2017-01-16 01:32:53 -05:00
}
}
2017-02-04 18:28:43 -05:00
else
{
for ( std :: list < std :: list < int > >:: iterator iter = clusters . begin (); iter != clusters . end (); ++ iter )
{
for ( std :: list < int >:: iterator jter = iter -> begin (); jter != iter -> end (); ++ jter )
{
validPolygons . insert ( * jter );
}
}
}
2017-01-19 11:20:48 -05:00
if ( validPolygons . size () == 0 )
{
std :: string msg = uFormat ( "All %d polygons filtered after polygon cluster filtering. Cluster minimum size is %d." , totalSize , _ui -> spinBox_mesh_minClusterSize -> value ());
_progressDialog -> appendText ( msg . c_str ());
UWARN ( msg . c_str ());
}
2017-01-16 01:32:53 -05:00
// for each texture
2017-01-16 11:21:40 -05:00
unsigned int allPolygonsIndex = 0 ;
2017-01-16 01:32:53 -05:00
for ( unsigned int t = 0 ; t < textureMesh -> tex_polygons . size (); ++ t )
{
std :: vector < pcl :: Vertices > filteredPolygons ( textureMesh -> tex_polygons [ t ]. size ());
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std :: vector < Eigen :: Vector2f , Eigen :: aligned_allocator < Eigen :: Vector2f > > filteredCoordinates ( textureMesh -> tex_coordinates [ t ]. size ());
#else
std :: vector < Eigen :: Vector2f > filteredCoordinates ( textureMesh -> tex_coordinates [ t ]. size ());
#endif
2017-01-19 11:20:48 -05:00
2017-01-16 01:32:53 -05:00
if ( textureMesh -> tex_polygons [ t ]. size ())
{
2017-01-26 09:42:52 -05:00
UASSERT_MSG ( allPolygonsIndex < allPolygons . size (), uFormat ( "%d vs %d" , ( int ) allPolygonsIndex , ( int ) allPolygons . size ()). c_str ());
2017-01-19 11:20:48 -05:00
// make index polygon to coordinate
std :: vector < unsigned int > polygonToCoord ( textureMesh -> tex_polygons [ t ]. size ());
unsigned int totalCoord = 0 ;
for ( unsigned int i = 0 ; i < textureMesh -> tex_polygons [ t ]. size (); ++ i )
{
polygonToCoord [ i ] = totalCoord ;
totalCoord += textureMesh -> tex_polygons [ t ][ i ]. vertices . size ();
}
UASSERT_MSG ( totalCoord == textureMesh -> tex_coordinates [ t ]. size (), uFormat ( "%d vs %d" , totalCoord , ( int ) textureMesh -> tex_coordinates [ t ]. size ()). c_str ());
2017-01-16 01:32:53 -05:00
2017-01-19 11:20:48 -05:00
int oi = 0 ;
int ci = 0 ;
2017-01-16 01:32:53 -05:00
for ( unsigned int i = 0 ; i < textureMesh -> tex_polygons [ t ]. size (); ++ i )
{
if ( validPolygons . find ( allPolygonsIndex ) != validPolygons . end ())
{
filteredPolygons [ oi ] = textureMesh -> tex_polygons [ t ]. at ( i );
2017-01-19 11:20:48 -05:00
for ( unsigned int j = 0 ; j < filteredPolygons [ oi ]. vertices . size (); ++ j )
2017-01-16 01:32:53 -05:00
{
2017-01-19 11:20:48 -05:00
UASSERT ( polygonToCoord [ i ] < textureMesh -> tex_coordinates [ t ]. size ());
filteredCoordinates [ ci ] = textureMesh -> tex_coordinates [ t ][ polygonToCoord [ i ] + j ];
++ ci ;
2017-01-16 01:32:53 -05:00
}
++ oi ;
}
++ allPolygonsIndex ;
}
filteredPolygons . resize ( oi );
2017-01-19 11:20:48 -05:00
filteredCoordinates . resize ( ci );
2017-01-16 01:32:53 -05:00
textureMesh -> tex_polygons [ t ] = filteredPolygons ;
textureMesh -> tex_coordinates [ t ] = filteredCoordinates ;
}
}
_progressDialog -> appendText ( tr ( "Filtered %1 polygons." ). arg ( allPolygons . size () - validPolygons . size ()));
QApplication :: processEvents ();
}
}
2016-03-22 20:44:18 -04:00
}
2016-02-15 19:35:24 -05:00
textureMeshes . insert ( std :: make_pair ( iter -> first , textureMesh ));
}
2017-01-26 16:46:24 -05:00
else if ( cameraPoses . size () == 0 )
2016-02-15 19:35:24 -05:00
{
2017-03-03 00:19:46 -05:00
_progressDialog -> appendText ( tr ( "No cameras from %1 poses with valid calibration found!" ). arg ( poses . size ()), Qt :: darkYellow );
_progressDialog -> setAutoClose ( false );
2016-02-15 19:35:24 -05:00
UWARN ( "No camera poses!?" );
}
2017-01-26 16:46:24 -05:00
else
{
2017-03-03 00:19:46 -05:00
_progressDialog -> appendText ( tr ( "No polygons!?" ), Qt :: darkYellow );
_progressDialog -> setAutoClose ( false );
2017-01-26 16:46:24 -05:00
UWARN ( "No polygons!" );
}
2016-02-15 19:35:24 -05:00
_progressDialog -> appendText ( tr ( "TextureMesh %1 created [cameras=%2] (%3/%4)." ). arg ( iter -> first ). arg ( cameraPoses . size ()). arg ( ++ i ). arg ( meshes . size ()));
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2016-02-15 19:35:24 -05:00
}
2016-03-22 20:44:18 -04:00
if ( textureMeshes . size () > 1 && _ui -> checkBox_assemble -> isChecked ())
{
2016-11-01 12:04:10 -04:00
UDEBUG ( "Concatenate texture meshes" );
2016-03-22 20:44:18 -04:00
_progressDialog -> appendText ( tr ( "Assembling %1 meshes..." ). arg ( textureMeshes . size ()));
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
pcl :: TextureMesh :: Ptr assembledMesh = util3d :: concatenateTextureMeshes ( uValuesList ( textureMeshes ));
textureMeshes . clear ();
textureMeshes . insert ( std :: make_pair ( 0 , assembledMesh ));
}
2016-02-15 19:35:24 -05:00
}
2016-11-01 12:04:10 -04:00
UDEBUG ( "" );
2016-02-15 19:35:24 -05:00
return true ;
}
return false ;
2014-07-29 00:52:35 +00:00
}
2016-02-15 19:35:24 -05:00
std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > > ExportCloudsDialog :: getClouds (
const std :: map < int , Transform > & poses ,
const QMap < int , Signature > & cachedSignatures ,
2016-06-12 17:53:35 -04:00
const std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr , pcl :: IndicesPtr > > & cachedClouds ,
2016-05-31 19:09:49 -04:00
const ParametersMap & parameters ) const
2014-07-29 00:52:35 +00:00
{
2016-02-15 19:35:24 -05:00
std :: map < int , std :: pair < pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr , pcl :: IndicesPtr > > clouds ;
2016-09-07 12:15:44 -04:00
int index = 1 ;
2016-02-15 19:35:24 -05:00
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr previousCloud ;
pcl :: IndicesPtr previousIndices ;
Transform previousPose ;
2016-09-19 14:01:06 -04:00
for ( std :: map < int , Transform >:: const_iterator iter = poses . begin (); iter != poses . end () && ! _canceled ; ++ iter , ++ index )
2016-02-15 19:35:24 -05:00
{
int points = 0 ;
int totalIndices = 0 ;
if ( ! iter -> second . isNull ())
{
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr cloud ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
pcl :: IndicesPtr indices ( new std :: vector < int > );
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_regenerate -> isChecked ())
2016-02-15 19:35:24 -05:00
{
2017-03-21 21:51:39 -04:00
SensorData data ;
cv :: Mat image , depth ;
2016-02-15 19:35:24 -05:00
if ( cachedSignatures . contains ( iter -> first ))
{
const Signature & s = cachedSignatures . find ( iter -> first ). value ();
2017-03-21 21:51:39 -04:00
data = s . sensorData ();
data . uncompressData ( & image , & depth , 0 );
}
else if ( _dbDriver )
{
_dbDriver -> getNodeData ( iter -> first , data , true , false , false , false );
data . uncompressData ( & image , & depth , 0 );
}
if ( ! image . empty () && ! depth . empty ())
{
if ( _ui -> spinBox_fillDepthHoles -> value () > 0 )
2016-02-15 19:35:24 -05:00
{
2017-03-21 21:51:39 -04:00
depth = util2d :: fillDepthHoles ( depth , _ui -> spinBox_fillDepthHoles -> value (), float ( _ui -> spinBox_fillDepthHolesError -> value ()) / 100.f );
}
2017-01-16 01:32:53 -05:00
2017-03-21 21:51:39 -04:00
if ( ! _ui -> lineEdit_distortionModel -> text (). isEmpty () &&
QFileInfo ( _ui -> lineEdit_distortionModel -> text ()). exists ())
{
clams :: DiscreteDepthDistortionModel model ;
model . load ( _ui -> lineEdit_distortionModel -> text (). toStdString ());
depth = depth . clone (); // make sure we are not modifying data in cached signatures.
model . undistort ( depth );
data . setDepthOrRightRaw ( depth );
}
2016-09-19 14:01:06 -04:00
2017-03-21 21:51:39 -04:00
// bilateral filtering
if ( _ui -> checkBox_bilateral -> isChecked ())
{
depth = util2d :: fastBilateralFiltering ( depth ,
_ui -> doubleSpinBox_bilateral_sigmaS -> value (),
_ui -> doubleSpinBox_bilateral_sigmaR -> value ());
data . setDepthOrRightRaw ( depth );
}
2016-11-03 17:04:31 -04:00
2017-03-21 21:51:39 -04:00
UASSERT ( iter -> first == data . id ());
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr cloudWithoutNormals ;
std :: vector < float > roiRatios ;
if ( ! _ui -> lineEdit_roiRatios -> text (). isEmpty ())
{
QStringList values = _ui -> lineEdit_roiRatios -> text (). split ( ' ' );
if ( values . size () == 4 )
2017-01-16 01:32:53 -05:00
{
2017-03-21 21:51:39 -04:00
roiRatios . resize ( 4 );
for ( int i = 0 ; i < values . size (); ++ i )
2017-01-16 01:32:53 -05:00
{
2017-03-21 21:51:39 -04:00
roiRatios [ i ] = uStr2Float ( values [ i ]. toStdString (). c_str ());
2017-01-16 01:32:53 -05:00
}
}
2017-03-21 21:51:39 -04:00
}
cloudWithoutNormals = util3d :: cloudRGBFromSensorData (
data ,
_ui -> spinBox_decimation -> value () == 0 ? 1 : _ui -> spinBox_decimation -> value (),
_ui -> doubleSpinBox_maxDepth -> value (),
_ui -> doubleSpinBox_minDepth -> value (),
indices . get (),
parameters ,
roiRatios );
2016-02-15 19:35:24 -05:00
2017-03-21 21:51:39 -04:00
if ( cloudWithoutNormals -> size ())
{
// Don't voxelize if we create organized mesh
if ( ! ( _ui -> comboBox_pipeline -> currentIndex () == 0 && _ui -> checkBox_meshing -> isChecked ()) && _ui -> doubleSpinBox_voxelSize_assembled -> value () > 0.0 )
2016-04-12 15:14:04 -04:00
{
2017-03-21 21:51:39 -04:00
cloudWithoutNormals = util3d :: voxelize ( cloudWithoutNormals , indices , _ui -> doubleSpinBox_voxelSize_assembled -> value ());
indices -> resize ( cloudWithoutNormals -> size ());
for ( unsigned int i = 0 ; i < indices -> size (); ++ i )
2016-04-12 15:14:04 -04:00
{
2017-03-21 21:51:39 -04:00
indices -> at ( i ) = i ;
2016-04-12 15:14:04 -04:00
}
2017-03-21 21:51:39 -04:00
}
2016-02-15 19:35:24 -05:00
2017-03-21 21:51:39 -04:00
// view point
Eigen :: Vector3f viewPoint ( 0.0f , 0.0f , 0.0f );
if ( data . cameraModels (). size () && ! data . cameraModels ()[ 0 ]. localTransform (). isNull ())
{
viewPoint [ 0 ] = data . cameraModels ()[ 0 ]. localTransform (). x ();
viewPoint [ 1 ] = data . cameraModels ()[ 0 ]. localTransform (). y ();
viewPoint [ 2 ] = data . cameraModels ()[ 0 ]. localTransform (). z ();
}
else if ( ! data . stereoCameraModel (). localTransform (). isNull ())
{
viewPoint [ 0 ] = data . stereoCameraModel (). localTransform (). x ();
viewPoint [ 1 ] = data . stereoCameraModel (). localTransform (). y ();
viewPoint [ 2 ] = data . stereoCameraModel (). localTransform (). z ();
}
2016-10-31 11:29:07 -04:00
2017-03-21 21:51:39 -04:00
pcl :: PointCloud < pcl :: Normal >:: Ptr normals = util3d :: computeNormals ( cloudWithoutNormals , indices , _ui -> spinBox_normalKSearch -> value (), viewPoint );
pcl :: concatenateFields ( * cloudWithoutNormals , * normals , * cloud );
2016-10-31 11:29:07 -04:00
2017-03-21 21:51:39 -04:00
if ( _ui -> checkBox_subtraction -> isChecked () &&
_ui -> doubleSpinBox_subtractPointFilteringRadius -> value () > 0.0 )
{
pcl :: IndicesPtr beforeSubtractionIndices = indices ;
if ( cloud -> size () &&
previousCloud . get () != 0 &&
previousIndices . get () != 0 &&
previousIndices -> size () &&
! previousPose . isNull ())
2016-10-31 11:29:07 -04:00
{
2017-03-21 21:51:39 -04:00
rtabmap :: Transform t = iter -> second . inverse () * previousPose ;
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr transformedCloud = rtabmap :: util3d :: transformPointCloud ( previousCloud , t );
indices = rtabmap :: util3d :: subtractFiltering (
cloud ,
indices ,
transformedCloud ,
previousIndices ,
_ui -> doubleSpinBox_subtractPointFilteringRadius -> value (),
_ui -> doubleSpinBox_subtractPointFilteringAngle -> value (),
_ui -> spinBox_subtractFilteringMinPts -> value ());
2016-02-15 19:35:24 -05:00
}
2017-03-21 21:51:39 -04:00
previousCloud = cloud ;
previousIndices = beforeSubtractionIndices ;
previousPose = iter -> second ;
2016-02-15 19:35:24 -05:00
}
}
}
else
{
UERROR ( "Cloud %d not found in cache!" , iter -> first );
}
}
2016-06-12 17:53:35 -04:00
else if ( uContains ( cachedClouds , iter -> first ))
2016-02-15 19:35:24 -05:00
{
2016-06-12 13:51:49 -04:00
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr cloudWithoutNormals ;
2017-02-26 18:17:00 -05:00
if ( ! _ui -> checkBox_meshing -> isChecked () &&
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_voxelSize_assembled -> value () > 0.0 )
{
2016-06-12 13:51:49 -04:00
cloudWithoutNormals = util3d :: voxelize (
2016-06-12 17:53:35 -04:00
cachedClouds . at ( iter -> first ). first ,
cachedClouds . at ( iter -> first ). second ,
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_voxelSize_assembled -> value ());
2016-06-12 13:51:49 -04:00
2016-02-15 19:35:24 -05:00
//generate indices for all points (they are all valid)
2016-06-12 13:51:49 -04:00
indices -> resize ( cloudWithoutNormals -> size ());
for ( unsigned int i = 0 ; i < cloudWithoutNormals -> size (); ++ i )
2016-02-15 19:35:24 -05:00
{
indices -> at ( i ) = i ;
}
}
else
{
2016-06-12 17:53:35 -04:00
cloudWithoutNormals = cachedClouds . at ( iter -> first ). first ;
indices = cachedClouds . at ( iter -> first ). second ;
2016-02-15 19:35:24 -05:00
}
2016-06-12 17:53:35 -04:00
// view point
Eigen :: Vector3f viewPoint ( 0.0f , 0.0f , 0.0f );
2017-03-21 21:51:39 -04:00
std :: vector < CameraModel > models ;
StereoCameraModel stereoModel ;
2016-06-12 17:53:35 -04:00
if ( cachedSignatures . contains ( iter -> first ))
{
const Signature & s = cachedSignatures . find ( iter -> first ). value ();
2017-03-21 21:51:39 -04:00
models = s . sensorData (). cameraModels ();
stereoModel = s . sensorData (). stereoCameraModel ();
}
else if ( _dbDriver )
{
_dbDriver -> getCalibration ( iter -> first , models , stereoModel );
}
if ( models . size () && ! models [ 0 ]. localTransform (). isNull ())
{
viewPoint [ 0 ] = models [ 0 ]. localTransform (). x ();
viewPoint [ 1 ] = models [ 0 ]. localTransform (). y ();
viewPoint [ 2 ] = models [ 0 ]. localTransform (). z ();
}
else if ( ! stereoModel . localTransform (). isNull ())
{
viewPoint [ 0 ] = stereoModel . localTransform (). x ();
viewPoint [ 1 ] = stereoModel . localTransform (). y ();
viewPoint [ 2 ] = stereoModel . localTransform (). z ();
2016-06-12 17:53:35 -04:00
}
else
{
2016-09-07 12:15:44 -04:00
_progressDialog -> appendText ( tr ( "Cached cloud %1 is not found in cached data, the view point for normal computation will not be set (%2/%3)." ). arg ( iter -> first ). arg ( index ). arg ( poses . size ()), Qt :: darkYellow );
2016-06-12 17:53:35 -04:00
}
pcl :: PointCloud < pcl :: Normal >:: Ptr normals = util3d :: computeNormals ( cloudWithoutNormals , indices , _ui -> spinBox_normalKSearch -> value (), viewPoint );
2016-06-12 13:51:49 -04:00
pcl :: concatenateFields ( * cloudWithoutNormals , * normals , * cloud );
2016-02-15 19:35:24 -05:00
}
2016-06-12 17:53:35 -04:00
else
{
2016-09-07 12:15:44 -04:00
_progressDialog -> appendText ( tr ( "Cached cloud %1 not found. You may want to regenerate the clouds (%2/%3)." ). arg ( iter -> first ). arg ( index ). arg ( poses . size ()), Qt :: darkYellow );
2016-06-12 17:53:35 -04:00
}
2016-02-15 19:35:24 -05:00
if ( indices -> size ())
{
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_filtering -> isChecked () &&
2016-02-15 19:35:24 -05:00
_ui -> doubleSpinBox_filteringRadius -> value () > 0.0f &&
_ui -> spinBox_filteringMinNeighbors -> value () > 0 )
{
indices = util3d :: radiusFiltering ( cloud , indices , _ui -> doubleSpinBox_filteringRadius -> value (), _ui -> spinBox_filteringMinNeighbors -> value ());
}
clouds . insert ( std :: make_pair ( iter -> first , std :: make_pair ( cloud , indices )));
2017-01-30 21:23:56 -05:00
points = ( int ) cloud -> size ();
totalIndices = ( int ) indices -> size ();
2016-02-15 19:35:24 -05:00
}
}
else
{
UERROR ( "transform is null!?" );
}
if ( points > 0 )
{
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_regenerate -> isChecked ())
2016-06-12 17:53:35 -04:00
{
_progressDialog -> appendText ( tr ( "Generated cloud %1 with %2 points and %3 indices (%4/%5)." )
2016-09-07 12:15:44 -04:00
. arg ( iter -> first ). arg ( points ). arg ( totalIndices ). arg ( index ). arg ( poses . size ()));
2016-06-12 17:53:35 -04:00
}
else
{
_progressDialog -> appendText ( tr ( "Copied cloud %1 from cache with %2 points and %3 indices (%4/%5)." )
2016-09-07 12:15:44 -04:00
. arg ( iter -> first ). arg ( points ). arg ( totalIndices ). arg ( index ). arg ( poses . size ()));
2016-06-12 17:53:35 -04:00
}
2016-02-15 19:35:24 -05:00
}
else
{
2016-09-07 12:15:44 -04:00
_progressDialog -> appendText ( tr ( "Ignored cloud %1 (%2/%3)." ). arg ( iter -> first ). arg ( index ). arg ( poses . size ()));
2016-02-15 19:35:24 -05:00
}
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
}
return clouds ;
2014-07-29 00:52:35 +00:00
}
2016-02-15 19:35:24 -05:00
void ExportCloudsDialog :: saveClouds (
const QString & workingDirectory ,
const std :: map < int , Transform > & poses ,
const std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr > & clouds ,
bool binaryMode )
2015-08-24 17:12:39 -04:00
{
2016-02-15 19:35:24 -05:00
if ( clouds . size () == 1 )
{
QString path = QFileDialog :: getSaveFileName ( this , tr ( "Save cloud to ..." ), workingDirectory + QDir :: separator () + "cloud.ply" , tr ( "Point cloud data (*.ply *.pcd)" ));
if ( ! path . isEmpty ())
{
if ( clouds . begin () -> second -> size ())
{
_progressDialog -> appendText ( tr ( "Saving the cloud (%1 points)..." ). arg ( clouds . begin () -> second -> size ()));
bool success = false ;
if ( QFileInfo ( path ). suffix () == "pcd" )
{
success = pcl :: io :: savePCDFile ( path . toStdString (), * clouds . begin () -> second , binaryMode ) == 0 ;
}
else if ( QFileInfo ( path ). suffix () == "ply" )
{
success = pcl :: io :: savePLYFile ( path . toStdString (), * clouds . begin () -> second , binaryMode ) == 0 ;
}
else if ( QFileInfo ( path ). suffix () == "" )
{
//use ply by default
path += ".ply" ;
success = pcl :: io :: savePLYFile ( path . toStdString (), * clouds . begin () -> second , binaryMode ) == 0 ;
}
else
{
UERROR ( "Extension not recognized! (%s) Should be one of (*.ply *.pcd)." , QFileInfo ( path ). suffix (). toStdString (). c_str ());
}
if ( success )
{
_progressDialog -> incrementStep ();
_progressDialog -> appendText ( tr ( "Saving the cloud (%1 points)... done." ). arg ( clouds . begin () -> second -> size ()));
QMessageBox :: information ( this , tr ( "Save successful!" ), tr ( "Cloud saved to \" %1 \" " ). arg ( path ));
}
else
{
QMessageBox :: warning ( this , tr ( "Save failed!" ), tr ( "Failed to save to \" %1 \" " ). arg ( path ));
}
}
else
{
QMessageBox :: warning ( this , tr ( "Save failed!" ), tr ( "Cloud is empty..." ));
}
}
}
else if ( clouds . size ())
{
QString path = QFileDialog :: getExistingDirectory ( this , tr ( "Save clouds to (*.ply *.pcd)..." ), workingDirectory , 0 );
if ( ! path . isEmpty ())
{
bool ok = false ;
QStringList items ;
items . push_back ( "ply" );
items . push_back ( "pcd" );
QString suffix = QInputDialog :: getItem ( this , tr ( "File format" ), tr ( "Which format?" ), items , 0 , false , & ok );
if ( ok )
{
QString prefix = QInputDialog :: getText ( this , tr ( "File prefix" ), tr ( "Prefix:" ), QLineEdit :: Normal , "cloud" , & ok );
if ( ok )
{
for ( std :: map < int , pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr >:: const_iterator iter = clouds . begin (); iter != clouds . end (); ++ iter )
{
if ( iter -> second -> size ())
{
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr transformedCloud ;
transformedCloud = util3d :: transformPointCloud ( iter -> second , poses . at ( iter -> first ));
QString pathFile = path + QDir :: separator () + QString ( "%1%2.%3" ). arg ( prefix ). arg ( iter -> first ). arg ( suffix );
bool success = false ;
if ( suffix == "pcd" )
{
success = pcl :: io :: savePCDFile ( pathFile . toStdString (), * transformedCloud , binaryMode ) == 0 ;
}
else if ( suffix == "ply" )
{
success = pcl :: io :: savePLYFile ( pathFile . toStdString (), * transformedCloud , binaryMode ) == 0 ;
}
else
{
UFATAL ( "Extension not recognized! (%s)" , suffix . toStdString (). c_str ());
}
if ( success )
{
_progressDialog -> appendText ( tr ( "Saved cloud %1 (%2 points) to %3." ). arg ( iter -> first ). arg ( iter -> second -> size ()). arg ( pathFile ));
}
else
{
2016-09-07 12:15:44 -04:00
_progressDialog -> appendText ( tr ( "Failed saving cloud %1 (%2 points) to %3." ). arg ( iter -> first ). arg ( iter -> second -> size ()). arg ( pathFile ), Qt :: darkRed );
_progressDialog -> setAutoClose ( false );
2016-02-15 19:35:24 -05:00
}
}
else
{
_progressDialog -> appendText ( tr ( "Cloud %1 is empty!" ). arg ( iter -> first ));
}
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return ;
}
2016-02-15 19:35:24 -05:00
}
}
}
}
}
2015-08-24 17:12:39 -04:00
}
2016-02-15 19:35:24 -05:00
void ExportCloudsDialog :: saveMeshes (
const QString & workingDirectory ,
const std :: map < int , Transform > & poses ,
const std :: map < int , pcl :: PolygonMesh :: Ptr > & meshes ,
bool binaryMode )
2014-11-14 22:07:03 +00:00
{
2016-02-15 19:35:24 -05:00
if ( meshes . size () == 1 )
{
QString path = QFileDialog :: getSaveFileName ( this , tr ( "Save mesh to ..." ), workingDirectory + QDir :: separator () + "mesh.ply" , tr ( "Mesh (*.ply)" ));
if ( ! path . isEmpty ())
{
if ( meshes . begin () -> second -> polygons . size ())
{
_progressDialog -> appendText ( tr ( "Saving the mesh (%1 polygons)..." ). arg ( meshes . begin () -> second -> polygons . size ()));
2016-03-22 20:44:18 -04:00
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
2016-02-15 19:35:24 -05:00
bool success = false ;
if ( QFileInfo ( path ). suffix () == "" )
{
path += ".ply" ;
}
2016-10-21 16:56:29 -04:00
if ( QFileInfo ( path ). suffix () == "ply" )
2016-02-15 19:35:24 -05:00
{
if ( binaryMode )
{
success = pcl :: io :: savePLYFileBinary ( path . toStdString (), * meshes . begin () -> second ) == 0 ;
}
else
{
success = pcl :: io :: savePLYFile ( path . toStdString (), * meshes . begin () -> second ) == 0 ;
}
}
else if ( QFileInfo ( path ). suffix () == "obj" )
{
success = pcl :: io :: saveOBJFile ( path . toStdString (), * meshes . begin () -> second ) == 0 ;
}
else
{
UERROR ( "Extension not recognized! (%s) Should be (*.ply)." , QFileInfo ( path ). suffix (). toStdString (). c_str ());
}
if ( success )
{
_progressDialog -> incrementStep ();
_progressDialog -> appendText ( tr ( "Saving the mesh (%1 polygons)... done." ). arg ( meshes . begin () -> second -> polygons . size ()));
QMessageBox :: information ( this , tr ( "Save successful!" ), tr ( "Mesh saved to \" %1 \" " ). arg ( path ));
}
else
{
QMessageBox :: warning ( this , tr ( "Save failed!" ), tr ( "Failed to save to \" %1 \" " ). arg ( path ));
}
}
else
{
QMessageBox :: warning ( this , tr ( "Save failed!" ), tr ( "Cloud is empty..." ));
}
}
}
else if ( meshes . size ())
{
QString path = QFileDialog :: getExistingDirectory ( this , tr ( "Save meshes to (*.ply *.obj)..." ), workingDirectory , 0 );
if ( ! path . isEmpty ())
{
bool ok = false ;
QStringList items ;
items . push_back ( "ply" );
items . push_back ( "obj" );
QString suffix = QInputDialog :: getItem ( this , tr ( "File format" ), tr ( "Which format?" ), items , 0 , false , & ok );
if ( ok )
{
QString prefix = QInputDialog :: getText ( this , tr ( "File prefix" ), tr ( "Prefix:" ), QLineEdit :: Normal , "mesh" , & ok );
if ( ok )
{
for ( std :: map < int , pcl :: PolygonMesh :: Ptr >:: const_iterator iter = meshes . begin (); iter != meshes . end (); ++ iter )
{
if ( iter -> second -> polygons . size ())
{
pcl :: PolygonMesh mesh ;
mesh . polygons = iter -> second -> polygons ;
bool isRGB = false ;
for ( unsigned int i = 0 ; i < iter -> second -> cloud . fields . size (); ++ i )
{
if ( iter -> second -> cloud . fields [ i ]. name . compare ( "rgb" ) == 0 )
{
isRGB = true ;
break ;
}
}
if ( isRGB )
{
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr tmp ( new pcl :: PointCloud < pcl :: PointXYZRGB > );
pcl :: fromPCLPointCloud2 ( iter -> second -> cloud , * tmp );
tmp = util3d :: transformPointCloud ( tmp , poses . at ( iter -> first ));
pcl :: toPCLPointCloud2 ( * tmp , mesh . cloud );
}
else
{
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr tmp ( new pcl :: PointCloud < pcl :: PointXYZ > );
pcl :: fromPCLPointCloud2 ( iter -> second -> cloud , * tmp );
tmp = util3d :: transformPointCloud ( tmp , poses . at ( iter -> first ));
pcl :: toPCLPointCloud2 ( * tmp , mesh . cloud );
}
QString pathFile = path + QDir :: separator () + QString ( "%1%2.%3" ). arg ( prefix ). arg ( iter -> first ). arg ( suffix );
bool success = false ;
if ( suffix == "ply" )
{
if ( binaryMode )
{
success = pcl :: io :: savePLYFileBinary ( pathFile . toStdString (), mesh ) == 0 ;
}
else
{
success = pcl :: io :: savePLYFile ( pathFile . toStdString (), mesh ) == 0 ;
}
}
else if ( suffix == "obj" )
{
success = pcl :: io :: saveOBJFile ( pathFile . toStdString (), mesh ) == 0 ;
}
else
{
UFATAL ( "Extension not recognized! (%s)" , suffix . toStdString (). c_str ());
}
if ( success )
{
_progressDialog -> appendText ( tr ( "Saved mesh %1 (%2 polygons) to %3." )
. arg ( iter -> first ). arg ( iter -> second -> polygons . size ()). arg ( pathFile ));
}
else
{
_progressDialog -> appendText ( tr ( "Failed saving mesh %1 (%2 polygons) to %3." )
2016-09-07 12:15:44 -04:00
. arg ( iter -> first ). arg ( iter -> second -> polygons . size ()). arg ( pathFile ), Qt :: darkRed );
_progressDialog -> setAutoClose ( false );
2016-02-15 19:35:24 -05:00
}
}
else
{
_progressDialog -> appendText ( tr ( "Mesh %1 is empty!" ). arg ( iter -> first ));
}
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return ;
}
2016-02-15 19:35:24 -05:00
}
}
}
}
}
2014-11-14 22:07:03 +00:00
}
2017-04-09 19:16:50 -04:00
double sqr ( uchar v )
{
return double ( v ) * double ( v );
}
cv :: Mat ExportCloudsDialog :: mergeTextures (
pcl :: TextureMesh & mesh ,
const QMap < int , Signature > & cachedSignatures ,
const std :: vector < std :: map < int , pcl :: PointXY > > & textureVertexToPixels ) const
2017-01-19 11:20:48 -05:00
{
//get texture size, if disabled use default 1024
int textureSize = 1024 ;
if ( _ui -> comboBox_meshingTextureSize -> currentIndex () > 0 )
{
textureSize = 128 << _ui -> comboBox_meshingTextureSize -> currentIndex (); // start at 256
}
UDEBUG ( "textureSize = %d" , textureSize );
cv :: Mat globalTexture ;
if ( mesh . tex_materials . size () > 1 )
{
std :: vector < int > textures ( mesh . tex_materials . size (), - 1 );
cv :: Size imageSize ;
2017-03-21 21:51:39 -04:00
const int imageType = CV_8UC3 ;
2017-01-19 11:20:48 -05:00
UDEBUG ( "" );
for ( unsigned int i = 0 ; i < mesh . tex_materials . size (); ++ i )
{
if ( ! mesh . tex_materials [ i ]. tex_file . empty () &&
mesh . tex_polygons [ i ]. size () &&
uIsInteger ( mesh . tex_materials [ i ]. tex_file , false ))
{
int textureId = uStr2Int ( mesh . tex_materials [ i ]. tex_file );
textures [ i ] = textureId ;
2017-03-21 21:51:39 -04:00
if ( imageSize . width == 0 || imageSize . height == 0 )
2017-01-19 11:20:48 -05:00
{
2017-03-21 21:51:39 -04:00
if ( cachedSignatures . find ( textureId ) != cachedSignatures . end () && ! cachedSignatures . find ( textureId ) -> sensorData (). imageCompressed (). empty ())
2017-01-19 11:20:48 -05:00
{
2017-03-21 21:51:39 -04:00
SensorData data = cachedSignatures . find ( textureId ). value (). sensorData ();
if ( data . cameraModels (). size () == 1 &&
data . cameraModels ()[ 0 ]. imageHeight () > 0 &&
data . cameraModels ()[ 0 ]. imageWidth () > 0 )
{
imageSize = data . cameraModels ()[ 0 ]. imageSize ();
}
else if ( data . stereoCameraModel (). left (). imageHeight () > 0 &&
data . stereoCameraModel (). left (). imageWidth () > 0 )
{
imageSize = data . stereoCameraModel (). left (). imageSize ();
}
else // backward compatibility for image size not set in CameraModel
{
cv :: Mat image ;
data . uncompressDataConst ( & image , 0 );
UASSERT ( ! image . empty ());
imageSize = image . size ();
}
}
else if ( _dbDriver )
{
std :: vector < CameraModel > models ;
StereoCameraModel stereoModel ;
_dbDriver -> getCalibration ( textureId , models , stereoModel );
if ( models . size () == 1 &&
models [ 0 ]. imageHeight () > 0 &&
models [ 0 ]. imageWidth () > 0 )
{
imageSize = models [ 0 ]. imageSize ();
}
else if ( stereoModel . left (). imageHeight () > 0 &&
stereoModel . left (). imageWidth () > 0 )
{
imageSize = stereoModel . left (). imageSize ();
}
else // backward compatibility for image size not set in CameraModel
{
SensorData data ;
_dbDriver -> getNodeData ( textureId , data , true , false , false , false );
cv :: Mat image ;
data . uncompressDataConst ( & image , 0 );
UASSERT ( ! image . empty ());
imageSize = image . size ();
}
2017-01-19 11:20:48 -05:00
}
}
}
}
2017-04-09 19:16:50 -04:00
if ( textures . size () && imageSize . height > 0 && imageSize . width > 0 )
2017-01-19 11:20:48 -05:00
{
float scale = 0.0f ;
UDEBUG ( "" );
2017-01-26 09:42:52 -05:00
std :: vector < bool > materialsKept ;
util3d :: concatenateTextureMaterials ( mesh , imageSize , textureSize , scale , & materialsKept );
2017-01-19 11:20:48 -05:00
if ( scale && mesh . tex_materials . size () == 1 )
{
int cols = float ( textureSize ) / ( scale * imageSize . width );
globalTexture = cv :: Mat ( textureSize , textureSize , imageType , cv :: Scalar :: all ( 255 ));
2017-03-30 15:33:48 -04:00
cv :: Mat globalTextureMask = cv :: Mat ( textureSize , textureSize , CV_8UC1 , cv :: Scalar :: all ( 0 ));
2017-01-19 11:20:48 -05:00
// make a blank texture
cv :: Mat emptyImage ( int ( imageSize . height * scale ), int ( imageSize . width * scale ), imageType , cv :: Scalar :: all ( 255 ));
2017-03-30 15:33:48 -04:00
cv :: Mat emptyImageMask ( int ( imageSize . height * scale ), int ( imageSize . width * scale ), CV_8UC1 , cv :: Scalar :: all ( 255 ));
2017-01-26 09:42:52 -05:00
int oi = 0 ;
2017-04-09 19:16:50 -04:00
std :: vector < cv :: Point2i > imageOrigin ( textures . size ());
std :: vector < int > newCamIndex ( textures . size (), - 1 );
2017-01-26 09:42:52 -05:00
for ( int t = 0 ; t < ( int ) textures . size (); ++ t )
2017-01-19 11:20:48 -05:00
{
2017-01-26 09:42:52 -05:00
if ( materialsKept . at ( t ))
2017-01-19 11:20:48 -05:00
{
2017-04-09 19:16:50 -04:00
newCamIndex [ t ] = oi ;
2017-01-26 09:42:52 -05:00
int u = oi % cols * emptyImage . cols ;
int v = oi / cols * emptyImage . rows ;
UASSERT ( u < textureSize - emptyImage . cols );
UASSERT ( v < textureSize - emptyImage . rows );
2017-04-09 19:16:50 -04:00
imageOrigin [ t ]. x = u ;
imageOrigin [ t ]. y = v ;
2017-01-26 09:42:52 -05:00
if ( textures [ t ] >= 0 )
2017-01-19 11:20:48 -05:00
{
2017-01-26 09:42:52 -05:00
cv :: Mat image ;
2017-03-21 21:51:39 -04:00
if ( cachedSignatures . find ( textures [ t ]) != cachedSignatures . end () &&
! cachedSignatures . find ( textures [ t ]) -> sensorData (). imageCompressed (). empty ())
{
cachedSignatures . find ( textures [ t ]) -> sensorData (). uncompressDataConst ( & image , 0 );
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( textures [ t ], data , true , false , false , false );
data . uncompressDataConst ( & image , 0 );
}
2017-01-26 09:42:52 -05:00
UASSERT ( ! image . empty ());
cv :: Mat resizedImage ;
cv :: resize ( image , resizedImage , emptyImage . size (), 0.0f , 0.0f , cv :: INTER_AREA );
2017-03-21 21:51:39 -04:00
UASSERT ( resizedImage . type () == CV_8UC1 || resizedImage . type () == CV_8UC3 );
if ( resizedImage . type () == CV_8UC1 )
{
cv :: Mat resizedImageColor ;
cv :: cvtColor ( resizedImage , resizedImageColor , CV_GRAY2BGR );
resizedImage = resizedImageColor ;
}
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_gainCompensation -> isChecked () && _compensator && _compensator -> getIndex ( textures [ t ]) >= 0 )
2017-01-26 09:42:52 -05:00
{
_compensator -> apply ( textures [ t ], resizedImage );
}
UASSERT ( resizedImage . type () == globalTexture . type ());
resizedImage . copyTo ( globalTexture ( cv :: Rect ( u , v , resizedImage . cols , resizedImage . rows )));
2017-03-30 15:33:48 -04:00
emptyImageMask . copyTo ( globalTextureMask ( cv :: Rect ( u , v , resizedImage . cols , resizedImage . rows )));
2017-01-19 11:20:48 -05:00
}
2017-01-26 09:42:52 -05:00
else
{
emptyImage . copyTo ( globalTexture ( cv :: Rect ( u , v , emptyImage . cols , emptyImage . rows )));
}
++ oi ;
2017-01-19 11:20:48 -05:00
}
}
2017-04-09 19:16:50 -04:00
if ( textureVertexToPixels . size ())
{
//UWARN("Saving original.png", globalTexture);
//cv::imwrite("original.png", globalTexture);
if ( _ui -> checkBox_gainCompensation -> isChecked ())
{
const int num_images = static_cast < int > ( oi );
cv :: Mat_ < int > N ( num_images , num_images ); N . setTo ( 0 );
cv :: Mat_ < double > I ( num_images , num_images ); I . setTo ( 0 );
cv :: Mat_ < double > IR ( num_images , num_images ); IR . setTo ( 0 );
cv :: Mat_ < double > IG ( num_images , num_images ); IG . setTo ( 0 );
cv :: Mat_ < double > IB ( num_images , num_images ); IB . setTo ( 0 );
// Adjust UV coordinates to globalTexture
for ( unsigned int p = 0 ; p < textureVertexToPixels . size (); ++ p )
{
for ( std :: map < int , pcl :: PointXY >:: const_iterator iter = textureVertexToPixels [ p ]. begin (); iter != textureVertexToPixels [ p ]. end (); ++ iter )
{
if ( materialsKept . at ( iter -> first ))
{
N ( newCamIndex [ iter -> first ], newCamIndex [ iter -> first ]) += 1 ;
std :: map < int , pcl :: PointXY >:: const_iterator jter = iter ;
++ jter ;
int k = 1 ;
for (; jter != textureVertexToPixels [ p ]. end (); ++ jter , ++ k )
{
if ( materialsKept . at ( jter -> first ))
{
int i = newCamIndex [ iter -> first ];
int j = newCamIndex [ jter -> first ];
N ( i , j ) += 1 ;
N ( j , i ) += 1 ;
// uv in globalTexture
int ui = iter -> second . x * emptyImage . cols + imageOrigin [ iter -> first ]. x ;
int vi = ( 1.0 - iter -> second . y ) * emptyImage . rows + imageOrigin [ iter -> first ]. y ;
int uj = jter -> second . x * emptyImage . cols + imageOrigin [ jter -> first ]. x ;
int vj = ( 1.0 - jter -> second . y ) * emptyImage . rows + imageOrigin [ jter -> first ]. y ;
cv :: Vec3b * pt1 = globalTexture . ptr < cv :: Vec3b > ( vi , ui );
cv :: Vec3b * pt2 = globalTexture . ptr < cv :: Vec3b > ( vj , uj );
I ( i , j ) += std :: sqrt ( static_cast < double > ( sqr ( pt1 -> val [ 0 ]) + sqr ( pt1 -> val [ 1 ]) + sqr ( pt1 -> val [ 2 ])));
I ( j , i ) += std :: sqrt ( static_cast < double > ( sqr ( pt2 -> val [ 0 ]) + sqr ( pt2 -> val [ 1 ]) + sqr ( pt2 -> val [ 2 ])));
IR ( i , j ) += static_cast < double > ( pt1 -> val [ 2 ]);
IR ( j , i ) += static_cast < double > ( pt2 -> val [ 2 ]);
IG ( i , j ) += static_cast < double > ( pt1 -> val [ 1 ]);
IG ( j , i ) += static_cast < double > ( pt2 -> val [ 1 ]);
IB ( i , j ) += static_cast < double > ( pt1 -> val [ 0 ]);
IB ( j , i ) += static_cast < double > ( pt2 -> val [ 0 ]);
}
}
}
}
}
for ( int i = 0 ; i < num_images ; ++ i )
{
for ( int j = i + 1 ; j < num_images ; ++ j )
{
if ( N ( i , j ))
{
I ( i , j ) /= N ( i , j );
I ( j , i ) /= N ( j , i );
IR ( i , j ) /= N ( i , j );
IR ( j , i ) /= N ( j , i );
IG ( i , j ) /= N ( i , j );
IG ( j , i ) /= N ( j , i );
IB ( i , j ) /= N ( i , j );
IB ( j , i ) /= N ( j , i );
}
}
}
cv :: Mat_ < double > A ( num_images , num_images ); A . setTo ( 0 );
cv :: Mat_ < double > b ( num_images , 1 ); b . setTo ( 0 );
cv :: Mat_ < double > AR ( num_images , num_images ); AR . setTo ( 0 );
cv :: Mat_ < double > AG ( num_images , num_images ); AG . setTo ( 0 );
cv :: Mat_ < double > AB ( num_images , num_images ); AB . setTo ( 0 );
double alpha = 0.01 ;
double beta = _ui -> doubleSpinBox_gainBeta -> value ();
for ( int i = 0 ; i < num_images ; ++ i )
{
for ( int j = 0 ; j < num_images ; ++ j )
{
b ( i , 0 ) += beta * N ( i , j );
A ( i , i ) += beta * N ( i , j );
AR ( i , i ) += beta * N ( i , j );
AG ( i , i ) += beta * N ( i , j );
AB ( i , i ) += beta * N ( i , j );
if ( j == i ) continue ;
A ( i , i ) += 2 * alpha * I ( i , j ) * I ( i , j ) * N ( i , j );
A ( i , j ) -= 2 * alpha * I ( i , j ) * I ( j , i ) * N ( i , j );
AR ( i , i ) += 2 * alpha * IR ( i , j ) * IR ( i , j ) * N ( i , j );
AR ( i , j ) -= 2 * alpha * IR ( i , j ) * IR ( j , i ) * N ( i , j );
AG ( i , i ) += 2 * alpha * IG ( i , j ) * IG ( i , j ) * N ( i , j );
AG ( i , j ) -= 2 * alpha * IG ( i , j ) * IG ( j , i ) * N ( i , j );
AB ( i , i ) += 2 * alpha * IB ( i , j ) * IB ( i , j ) * N ( i , j );
AB ( i , j ) -= 2 * alpha * IB ( i , j ) * IB ( j , i ) * N ( i , j );
}
}
cv :: Mat_ < double > gainsGray , gainsR , gainsG , gainsB ;
cv :: solve ( A , b , gainsGray );
cv :: solve ( AR , b , gainsR );
cv :: solve ( AG , b , gainsG );
cv :: solve ( AB , b , gainsB );
cv :: Mat_ < double > gains ( gainsGray . rows , 4 );
gainsGray . copyTo ( gains . col ( 0 ));
gainsR . copyTo ( gains . col ( 1 ));
gainsG . copyTo ( gains . col ( 2 ));
gainsB . copyTo ( gains . col ( 3 ));
for ( int t = 0 ; t < ( int ) textures . size (); ++ t )
{
//break;
if ( materialsKept . at ( t ))
{
int u = imageOrigin [ t ]. x ;
int v = imageOrigin [ t ]. y ;
UDEBUG ( "Gain cam%d = %f" , newCamIndex [ t ], gainsGray ( newCamIndex [ t ], 0 ));
cv :: Mat roi = globalTexture ( cv :: Rect ( u , v , emptyImage . cols , emptyImage . rows ));
std :: vector < cv :: Mat > channels ;
cv :: split ( roi , channels );
// assuming BGR
cv :: multiply ( channels [ 0 ], gains ( newCamIndex [ t ], 3 ), channels [ 0 ]);
cv :: multiply ( channels [ 1 ], gains ( newCamIndex [ t ], 2 ), channels [ 1 ]);
cv :: multiply ( channels [ 2 ], gains ( newCamIndex [ t ], 1 ), channels [ 2 ]);
cv :: merge ( channels , roi );
}
}
//UWARN("Saving gain.png", globalTexture);
//cv::imwrite("gain.png", globalTexture);
}
if ( _ui -> checkBox_blending -> isChecked ())
{
// blending BGR
int decimation = 1 ;
if ( _ui -> comboBox_blendingDecimation -> currentIndex () == 0 )
{
// determinate decimation to apply
std :: vector < float > edgeLengths ;
if ( mesh . tex_coordinates . size () && mesh . tex_coordinates [ 0 ]. size ())
{
UASSERT ( mesh . tex_polygons . size () && mesh . tex_polygons [ 0 ]. size () && mesh . tex_polygons [ 0 ][ 0 ]. vertices . size ());
int polygonSize = mesh . tex_polygons [ 0 ][ 0 ]. vertices . size ();
UDEBUG ( "polygon size=%d" , polygonSize );
for ( unsigned int i = 0 ; i < mesh . tex_coordinates [ 0 ]. size (); i += polygonSize )
{
for ( int j = 0 ; j < polygonSize ; ++ j )
{
const Eigen :: Vector2f & uc1 = mesh . tex_coordinates [ 0 ][ i + j ];
const Eigen :: Vector2f & uc2 = mesh . tex_coordinates [ 0 ][ i + ( j + 1 ) % polygonSize ];
Eigen :: Vector2f edge = ( uc1 - uc2 ) * textureSize ;
edgeLengths . push_back ( fabs ( edge [ 0 ]));
edgeLengths . push_back ( fabs ( edge [ 1 ]));
}
}
float edgeLength = 0.0f ;
if ( edgeLengths . size ())
{
std :: sort ( edgeLengths . begin (), edgeLengths . end ());
float m = uMean ( edgeLengths . data (), edgeLengths . size ());
float stddev = std :: sqrt ( uVariance ( edgeLengths . data (), edgeLengths . size (), m ));
edgeLength = m + stddev ;
decimation = 1 << 6 ;
for ( int i = 1 ; i <= 6 ; ++ i )
{
if ( float ( 1 << i ) >= edgeLength )
{
decimation = 1 << i ;
break ;
}
}
}
UDEBUG ( "edge length=%f decimation=%d" , edgeLength , decimation );
}
}
else
{
decimation = 1 << ( _ui -> comboBox_blendingDecimation -> currentIndex () - 1 );
UDEBUG ( "decimation=%d" , decimation );
}
cv :: Mat blendGains ( globalTexture . rows / decimation , globalTexture . cols / decimation , CV_32FC3 , cv :: Scalar :: all ( 1.0f ));
for ( unsigned int p = 0 ; p < textureVertexToPixels . size (); ++ p )
{
if ( textureVertexToPixels [ p ]. size () > 1 )
{
std :: vector < float > gainsB ( textureVertexToPixels [ p ]. size ());
std :: vector < float > gainsG ( textureVertexToPixels [ p ]. size ());
std :: vector < float > gainsR ( textureVertexToPixels [ p ]. size ());
float sumWeight = 0.0f ;
int k = 0 ;
for ( std :: map < int , pcl :: PointXY >:: const_iterator iter = textureVertexToPixels [ p ]. begin (); iter != textureVertexToPixels [ p ]. end (); ++ iter )
{
if ( materialsKept . at ( iter -> first ))
{
int u = iter -> second . x * emptyImage . cols + imageOrigin [ iter -> first ]. x ;
int v = ( 1.0 - iter -> second . y ) * emptyImage . rows + imageOrigin [ iter -> first ]. y ;
float x = iter -> second . x - 0.5f ;
float y = iter -> second . y - 0.5f ;
float weight = 0.7f - sqrt ( x * x + y * y );
if ( weight < 0.0f )
{
weight = 0.0f ;
}
cv :: Vec3b * pt = globalTexture . ptr < cv :: Vec3b > ( v , u );
gainsB [ k ] = static_cast < double > ( pt -> val [ 0 ]) * weight ;
gainsG [ k ] = static_cast < double > ( pt -> val [ 1 ]) * weight ;
gainsR [ k ] = static_cast < double > ( pt -> val [ 2 ]) * weight ;
sumWeight += weight ;
++ k ;
}
}
gainsB . resize ( k );
gainsG . resize ( k );
gainsR . resize ( k );
if ( sumWeight > 0 )
{
float targetColor [ 3 ];
targetColor [ 0 ] = uSum ( gainsB . data (), gainsB . size ()) / sumWeight ;
targetColor [ 1 ] = uSum ( gainsG . data (), gainsG . size ()) / sumWeight ;
targetColor [ 2 ] = uSum ( gainsR . data (), gainsR . size ()) / sumWeight ;
for ( std :: map < int , pcl :: PointXY >:: const_iterator iter = textureVertexToPixels [ p ]. begin (); iter != textureVertexToPixels [ p ]. end (); ++ iter )
{
if ( materialsKept . at ( iter -> first ))
{
int u = iter -> second . x * emptyImage . cols + imageOrigin [ iter -> first ]. x ;
int v = ( 1.0 - iter -> second . y ) * emptyImage . rows + imageOrigin [ iter -> first ]. y ;
cv :: Vec3b * pt = globalTexture . ptr < cv :: Vec3b > ( v , u );
float gB = targetColor [ 0 ] / ( pt -> val [ 0 ] == 0 ? 1.0f : pt -> val [ 0 ]);
float gG = targetColor [ 1 ] / ( pt -> val [ 1 ] == 0 ? 1.0f : pt -> val [ 1 ]);
float gR = targetColor [ 2 ] / ( pt -> val [ 2 ] == 0 ? 1.0f : pt -> val [ 2 ]);
cv :: Vec3f * ptr = blendGains . ptr < cv :: Vec3f > ( v / decimation , u / decimation );
ptr -> val [ 0 ] = ( gB > 1.3f ) ? 1.3f : ( gB < 0.7f ) ? 0.7f : gB ;
ptr -> val [ 1 ] = ( gG > 1.3f ) ? 1.3f : ( gG < 0.7f ) ? 0.7f : gG ;
ptr -> val [ 2 ] = ( gR > 1.3f ) ? 1.3f : ( gR < 0.7f ) ? 0.7f : gR ;
}
}
}
}
}
/*std::vector<cv::Mat> channels;
cv::split(blendGains, channels);
cv::Mat img;
channels[0].convertTo(img,CV_8U,128.0,0);
cv::imwrite("blendSmallB.png", img);
channels[1].convertTo(img,CV_8U,128.0,0);
cv::imwrite("blendSmallG.png", img);
channels[2].convertTo(img,CV_8U,128.0,0);
cv::imwrite("blendSmallR.png", img);*/
cv :: Mat dst ;
cv :: blur ( blendGains , dst , cv :: Size ( 3 , 3 ));
cv :: resize ( dst , blendGains , globalTexture . size (), 0 , 0 , cv :: INTER_LINEAR );
/*cv::split(blendGains, channels);
channels[0].convertTo(img,CV_8U,128.0,0);
cv::imwrite("blendFullB.png", img);
channels[1].convertTo(img,CV_8U,128.0,0);
cv::imwrite("blendFullG.png", img);
channels[2].convertTo(img,CV_8U,128.0,0);
cv::imwrite("blendFullR.png", img);*/
cv :: multiply ( globalTexture , blendGains , globalTexture , 1.0 , CV_8UC3 );
//UWARN("Saving blending.png", globalTexture);
//cv::imwrite("blending.png", globalTexture);
}
}
2017-03-30 15:33:48 -04:00
if ( _ui -> spinBox_textureBrightnessContrastRatioLow -> value () > 0 || _ui -> spinBox_textureBrightnessContrastRatioHigh -> value () > 0 )
{
2017-03-31 18:53:46 -04:00
if ( _ui -> checkBox_exposureFusion -> isEnabled () && _ui -> checkBox_exposureFusion -> isChecked ())
2017-03-30 21:33:15 -04:00
{
std :: vector < cv :: Mat > images ;
images . push_back ( globalTexture );
if ( _ui -> spinBox_textureBrightnessContrastRatioLow -> value () > 0 )
{
images . push_back ( util2d :: brightnessAndContrastAuto (
globalTexture ,
globalTextureMask ,
( float ) _ui -> spinBox_textureBrightnessContrastRatioLow -> value (),
0.0f ));
}
if ( _ui -> spinBox_textureBrightnessContrastRatioHigh -> value () > 0 )
{
images . push_back ( util2d :: brightnessAndContrastAuto (
globalTexture ,
globalTextureMask ,
0.0f ,
( float ) _ui -> spinBox_textureBrightnessContrastRatioHigh -> value ()));
}
globalTexture = util2d :: exposureFusion ( images );
}
else
{
globalTexture = util2d :: brightnessAndContrastAuto (
globalTexture ,
globalTextureMask ,
( float ) _ui -> spinBox_textureBrightnessContrastRatioLow -> value (),
( float ) _ui -> spinBox_textureBrightnessContrastRatioHigh -> value ());
}
2017-03-30 15:33:48 -04:00
}
2017-01-19 11:20:48 -05:00
}
}
}
return globalTexture ;
}
2016-02-15 19:35:24 -05:00
void ExportCloudsDialog :: saveTextureMeshes (
const QString & workingDirectory ,
const std :: map < int , Transform > & poses ,
2017-01-16 18:29:14 -05:00
std :: map < int , pcl :: TextureMesh :: Ptr > & meshes ,
2017-04-09 19:16:50 -04:00
const QMap < int , Signature > & cachedSignatures ,
const std :: vector < std :: map < int , pcl :: PointXY > > & textureVertexToPixels )
2014-07-29 00:52:35 +00:00
{
2016-02-15 19:35:24 -05:00
if ( meshes . size () == 1 )
{
QString path = QFileDialog :: getSaveFileName ( this , tr ( "Save texture mesh to ..." ), workingDirectory + QDir :: separator () + "mesh.obj" , tr ( "Mesh (*.obj)" ));
if ( ! path . isEmpty ())
{
if ( meshes . begin () -> second -> tex_materials . size ())
{
_progressDialog -> appendText ( tr ( "Saving the mesh (with %1 textures)..." ). arg ( meshes . begin () -> second -> tex_materials . size ()));
2016-03-22 20:44:18 -04:00
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
2014-07-29 00:52:35 +00:00
2016-02-15 19:35:24 -05:00
bool success = false ;
if ( QFileInfo ( path ). suffix () == "" )
{
path += ".obj" ;
}
2017-01-16 18:29:14 -05:00
pcl :: TextureMesh :: Ptr mesh = meshes . begin () -> second ;
2017-01-19 11:20:48 -05:00
cv :: Mat globalTexture ;
bool texturesMerged = _ui -> comboBox_meshingTextureSize -> isEnabled () && _ui -> comboBox_meshingTextureSize -> currentIndex () > 0 ;
if ( texturesMerged && mesh -> tex_materials . size () > 1 )
{
2017-04-09 19:16:50 -04:00
globalTexture = mergeTextures ( * mesh , cachedSignatures , textureVertexToPixels );
2017-01-19 11:20:48 -05:00
}
bool singleTexture = mesh -> tex_materials . size () == 1 ;
if ( ! singleTexture )
{
removeDirRecursively ( QFileInfo ( path ). absoluteDir (). absolutePath () + QDir :: separator () + QFileInfo ( path ). baseName ());
QDir ( QFileInfo ( path ). absoluteDir (). absolutePath ()). mkdir ( QFileInfo ( path ). baseName ());
}
2017-01-16 18:29:14 -05:00
cv :: Size imageSize ;
for ( unsigned int i = 0 ; i < mesh -> tex_materials . size (); ++ i )
2016-02-15 19:35:24 -05:00
{
2017-01-16 18:29:14 -05:00
if ( ! mesh -> tex_materials [ i ]. tex_file . empty ())
2016-02-15 19:35:24 -05:00
{
2017-01-16 18:29:14 -05:00
// absolute path
2017-01-19 11:20:48 -05:00
QString fullPath ;
if ( singleTexture )
{
2017-02-01 12:53:05 -05:00
fullPath = QFileInfo ( path ). absoluteDir (). absolutePath () + QDir :: separator () + QFileInfo ( path ). baseName () + _ui -> comboBox_meshingTextureFormat -> currentText ();
2017-01-19 11:20:48 -05:00
}
else
{
fullPath = QFileInfo ( path ). absoluteDir (). absolutePath () + QDir :: separator () + QFileInfo ( path ). baseName () + QDir :: separator () + QString ( mesh -> tex_materials [ i ]. tex_file . c_str ()) + _ui -> comboBox_meshingTextureFormat -> currentText ();
}
2017-01-31 23:26:35 -05:00
UDEBUG ( "Saving %s..." , fullPath . toStdString (). c_str ());
if ( singleTexture || ! QFileInfo ( fullPath ). exists ())
2017-01-16 18:29:14 -05:00
{
2017-01-17 14:57:50 -05:00
if ( uIsInteger ( mesh -> tex_materials [ i ]. tex_file , false ))
2017-01-16 18:29:14 -05:00
{
2017-01-17 14:57:50 -05:00
int textureId = uStr2Int ( mesh -> tex_materials [ i ]. tex_file );
2017-01-16 18:29:14 -05:00
cv :: Mat image ;
2017-03-21 21:51:39 -04:00
if ( cachedSignatures . contains ( textureId ) && ! cachedSignatures . value ( textureId ). sensorData (). imageCompressed (). empty ())
{
cachedSignatures . value ( textureId ). sensorData (). uncompressDataConst ( & image , 0 );
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( textureId , data , true , false , false , false );
data . uncompressDataConst ( & image , 0 );
}
2017-01-16 18:29:14 -05:00
UASSERT ( ! image . empty ());
imageSize = image . size ();
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_gainCompensation -> isChecked () && _compensator && _compensator -> getIndex ( textureId ) >= 0 )
2017-01-16 18:29:14 -05:00
{
_compensator -> apply ( textureId , image );
}
if ( ! cv :: imwrite ( fullPath . toStdString (), image ))
{
_progressDialog -> appendText ( tr ( "Failed saving texture \" %1 \" to \" %2 \" ." )
. arg ( mesh -> tex_materials [ i ]. tex_file . c_str ()). arg ( fullPath ), Qt :: darkRed );
_progressDialog -> setAutoClose ( false );
}
}
else if ( imageSize . height && imageSize . width )
{
// make a blank texture
cv :: Mat image = cv :: Mat :: ones ( imageSize , CV_8UC1 ) * 255 ;
cv :: imwrite ( fullPath . toStdString (), image );
}
2017-01-19 11:20:48 -05:00
else if ( ! globalTexture . empty ())
{
if ( ! cv :: imwrite ( fullPath . toStdString (), globalTexture ))
{
_progressDialog -> appendText ( tr ( "Failed saving texture \" %1 \" to \" %2 \" ." )
. arg ( mesh -> tex_materials [ i ]. tex_file . c_str ()). arg ( fullPath ), Qt :: darkRed );
_progressDialog -> setAutoClose ( false );
}
}
2017-01-16 18:29:14 -05:00
else
{
UWARN ( "Ignored texture %s (no image size set yet)" , mesh -> tex_materials [ i ]. tex_file . c_str ());
}
}
2017-01-31 23:26:35 -05:00
else
{
UWARN ( "File %s already exists!" , fullPath . toStdString (). c_str ());
}
2017-01-16 18:29:14 -05:00
// relative path
2017-01-19 11:20:48 -05:00
if ( singleTexture )
{
2017-02-01 12:53:05 -05:00
mesh -> tex_materials [ i ]. tex_file = QFileInfo ( path ). baseName (). toStdString () + _ui -> comboBox_meshingTextureFormat -> currentText (). toStdString ();
2017-01-19 11:20:48 -05:00
}
else
{
mesh -> tex_materials [ i ]. tex_file = ( QFileInfo ( path ). baseName () + QDir :: separator () + QString ( mesh -> tex_materials [ i ]. tex_file . c_str ()) + _ui -> comboBox_meshingTextureFormat -> currentText ()). toStdString ();
}
2016-02-15 19:35:24 -05:00
}
}
2017-01-16 18:29:14 -05:00
success = pcl :: io :: saveOBJFile ( path . toStdString (), * mesh ) == 0 ;
2016-02-15 19:35:24 -05:00
if ( success )
{
_progressDialog -> incrementStep ();
2017-01-16 18:29:14 -05:00
_progressDialog -> appendText ( tr ( "Saving the mesh (with %1 textures)... done." ). arg ( mesh -> tex_materials . size ()));
2016-02-15 19:35:24 -05:00
QMessageBox :: information ( this , tr ( "Save successful!" ), tr ( "Mesh saved to \" %1 \" " ). arg ( path ));
}
else
{
QMessageBox :: warning ( this , tr ( "Save failed!" ), tr ( "Failed to save to \" %1 \" " ). arg ( path ));
}
}
else
{
QMessageBox :: warning ( this , tr ( "Save failed!" ), tr ( "No textures..." ));
}
}
}
else if ( meshes . size ())
{
QString path = QFileDialog :: getExistingDirectory ( this , tr ( "Save texture meshes to (*.obj)..." ), workingDirectory , 0 );
if ( ! path . isEmpty ())
{
bool ok = false ;
QString prefix = QInputDialog :: getText ( this , tr ( "File prefix" ), tr ( "Prefix:" ), QLineEdit :: Normal , "mesh" , & ok );
QString suffix = "obj" ;
if ( ok )
{
2017-01-16 18:29:14 -05:00
for ( std :: map < int , pcl :: TextureMesh :: Ptr >:: iterator iter = meshes . begin (); iter != meshes . end (); ++ iter )
2016-02-15 19:35:24 -05:00
{
QString currentPrefix = prefix + QString :: number ( iter -> first );
if ( iter -> second -> tex_materials . size ())
{
2017-01-16 18:29:14 -05:00
pcl :: TextureMesh :: Ptr mesh = iter -> second ;
2017-01-19 11:20:48 -05:00
cv :: Mat globalTexture ;
bool texturesMerged = _ui -> comboBox_meshingTextureSize -> isEnabled () && _ui -> comboBox_meshingTextureSize -> currentIndex () > 0 ;
if ( texturesMerged && mesh -> tex_materials . size () > 1 )
{
2017-04-09 19:16:50 -04:00
globalTexture = mergeTextures ( * mesh , cachedSignatures , textureVertexToPixels );
2017-01-19 11:20:48 -05:00
}
bool singleTexture = mesh -> tex_materials . size () == 1 ;
if ( ! singleTexture )
{
removeDirRecursively ( path + QDir :: separator () + currentPrefix );
QDir ( path ). mkdir ( currentPrefix );
}
2017-01-16 18:29:14 -05:00
cv :: Size imageSize ;
for ( unsigned int i = 0 ; i < mesh -> tex_materials . size (); ++ i )
2016-02-15 19:35:24 -05:00
{
2017-01-16 18:29:14 -05:00
if ( ! mesh -> tex_materials [ i ]. tex_file . empty ())
2016-02-15 19:35:24 -05:00
{
2017-01-16 18:29:14 -05:00
// absolute path
2017-01-19 11:20:48 -05:00
QString fullPath ;
if ( singleTexture )
2017-01-16 18:29:14 -05:00
{
2017-01-19 11:20:48 -05:00
mesh -> tex_materials [ i ]. tex_file = uNumber2Str ( iter -> first );
fullPath = path + QDir :: separator () + prefix + QString ( mesh -> tex_materials [ i ]. tex_file . c_str ()) + _ui -> comboBox_meshingTextureFormat -> currentText ();
}
else
{
fullPath = path + QDir :: separator () + currentPrefix + QDir :: separator () + QString ( mesh -> tex_materials [ i ]. tex_file . c_str ()) + _ui -> comboBox_meshingTextureFormat -> currentText ();
}
if ( uIsInteger ( mesh -> tex_materials [ i ]. tex_file , false ))
{
int textureId = uStr2Int ( mesh -> tex_materials [ i ]. tex_file );
cv :: Mat image ;
2017-03-21 21:51:39 -04:00
if ( cachedSignatures . contains ( textureId ) && ! cachedSignatures . value ( textureId ). sensorData (). imageCompressed (). empty ())
{
cachedSignatures . value ( textureId ). sensorData (). uncompressDataConst ( & image , 0 );
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( textureId , data , true , false , false , false );
data . uncompressDataConst ( & image , 0 );
}
2017-01-19 11:20:48 -05:00
UASSERT ( ! image . empty ());
imageSize = image . size ();
2017-02-26 18:17:00 -05:00
if ( _ui -> checkBox_gainCompensation -> isChecked () && _compensator && _compensator -> getIndex ( textureId ) >= 0 )
2017-01-16 18:29:14 -05:00
{
2017-01-19 11:20:48 -05:00
_compensator -> apply ( textureId , image );
}
2017-01-16 18:29:14 -05:00
2017-01-19 11:20:48 -05:00
if ( ! cv :: imwrite ( fullPath . toStdString (), image ))
2017-01-16 18:29:14 -05:00
{
2017-01-19 11:20:48 -05:00
_progressDialog -> appendText ( tr ( "Failed saving texture \" %1 \" to \" %2 \" ." )
. arg ( mesh -> tex_materials [ i ]. tex_file . c_str ()). arg ( fullPath ), Qt :: darkRed );
_progressDialog -> setAutoClose ( false );
2017-01-16 18:29:14 -05:00
}
}
2017-01-19 11:20:48 -05:00
else if ( imageSize . height && imageSize . width )
{
// make a blank texture
cv :: Mat image = cv :: Mat :: ones ( imageSize , CV_8UC1 ) * 255 ;
cv :: imwrite ( fullPath . toStdString (), image );
}
else if ( ! globalTexture . empty ())
{
if ( ! cv :: imwrite ( fullPath . toStdString (), globalTexture ))
{
_progressDialog -> appendText ( tr ( "Failed saving texture \" %1 \" to \" %2 \" ." )
. arg ( mesh -> tex_materials [ i ]. tex_file . c_str ()). arg ( fullPath ), Qt :: darkRed );
_progressDialog -> setAutoClose ( false );
}
}
else
{
UWARN ( "Ignored texture %s (no image size set yet)" , mesh -> tex_materials [ i ]. tex_file . c_str ());
}
2017-01-16 18:29:14 -05:00
// relative path
2017-01-19 11:20:48 -05:00
if ( singleTexture )
{
mesh -> tex_materials [ i ]. tex_file = ( prefix + QString ( mesh -> tex_materials [ i ]. tex_file . c_str ()) + _ui -> comboBox_meshingTextureFormat -> currentText ()). toStdString ();
}
else
{
mesh -> tex_materials [ i ]. tex_file = ( currentPrefix + QDir :: separator () + QString ( mesh -> tex_materials [ i ]. tex_file . c_str ()) + _ui -> comboBox_meshingTextureFormat -> currentText ()). toStdString ();
}
2016-02-15 19:35:24 -05:00
}
}
pcl :: PointCloud < pcl :: PointNormal >:: Ptr tmp ( new pcl :: PointCloud < pcl :: PointNormal > );
2017-01-16 18:29:14 -05:00
pcl :: fromPCLPointCloud2 ( mesh -> cloud , * tmp );
2016-02-15 19:35:24 -05:00
tmp = util3d :: transformPointCloud ( tmp , poses . at ( iter -> first ));
2017-01-16 18:29:14 -05:00
pcl :: toPCLPointCloud2 ( * tmp , mesh -> cloud );
2016-02-15 19:35:24 -05:00
QString pathFile = path + QDir :: separator () + QString ( "%1.%3" ). arg ( currentPrefix ). arg ( suffix );
bool success = false ;
if ( suffix == "obj" )
{
2017-01-16 18:29:14 -05:00
success = pcl :: io :: saveOBJFile ( pathFile . toStdString (), * mesh ) == 0 ;
2016-02-15 19:35:24 -05:00
}
else
{
UFATAL ( "Extension not recognized! (%s)" , suffix . toStdString (). c_str ());
}
if ( success )
{
_progressDialog -> appendText ( tr ( "Saved mesh %1 (%2 textures) to %3." )
2017-01-16 18:29:14 -05:00
. arg ( iter -> first ). arg ( mesh -> tex_materials . size ()). arg ( pathFile ));
2016-02-15 19:35:24 -05:00
}
else
{
_progressDialog -> appendText ( tr ( "Failed saving mesh %1 (%2 textures) to %3." )
2017-01-16 18:29:14 -05:00
. arg ( iter -> first ). arg ( mesh -> tex_materials . size ()). arg ( pathFile ), Qt :: darkRed );
2016-09-07 12:15:44 -04:00
_progressDialog -> setAutoClose ( false );
2016-02-15 19:35:24 -05:00
}
}
else
{
_progressDialog -> appendText ( tr ( "Mesh %1 is empty!" ). arg ( iter -> first ));
}
_progressDialog -> incrementStep ();
QApplication :: processEvents ();
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return ;
}
2016-02-15 19:35:24 -05:00
}
}
}
}
2015-08-11 17:19:12 -04:00
}
2014-07-29 00:52:35 +00:00
}