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"
2017-05-05 21:44:06 -04:00
#include "rtabmap/core/Version.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
2017-05-05 21:44:06 -04:00
#ifdef RTABMAP_CPUTSDF
#include <cpu_tsdf/tsdf_volume_octree.h>
#include <cpu_tsdf/marching_cubes_tsdf_octree.h>
#endif
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
2017-05-11 13:20:51 -04:00
connect ( _ui -> checkBox_fromDepth , SIGNAL ( stateChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> checkBox_fromDepth , SIGNAL ( stateChanged ( int )), this , SLOT ( updateReconstructionFlavor ()));
2015-08-24 11:59:26 -04:00
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-05-10 15:53:02 -04:00
connect ( _ui -> comboBox_frame , SIGNAL ( currentIndexChanged ( int )), this , SIGNAL ( configChanged ()));
connect ( _ui -> comboBox_frame , 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_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-06-03 18:24:56 -04:00
connect ( _ui -> checkBox_gainRGB , SIGNAL ( stateChanged ( int )), 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-06-03 18:24:56 -04:00
connect ( _ui -> spinBox_mesh_maxTextures , SIGNAL ( valueChanged ( int )), this , SIGNAL ( configChanged ()));
2017-01-31 23:26:35 -05:00
connect ( _ui -> doubleSpinBox_meshingTextureMaxDistance , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
2017-06-06 11:42:42 -04:00
connect ( _ui -> doubleSpinBox_meshingTextureMaxDepthError , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_meshingTextureMaxAngle , 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 ()));
2017-05-05 21:44:06 -04:00
connect ( _ui -> doubleSpinBox_cputsdf_size , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_cputsdf_resolution , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_cputsdf_tuncPos , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_cputsdf_tuncNeg , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_cputsdf_minWeight , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> doubleSpinBox_cputsdf_flattenRadius , SIGNAL ( valueChanged ( double )), this , SIGNAL ( configChanged ()));
connect ( _ui -> spinBox_cputsdf_randomSplit , SIGNAL ( valueChanged ( int )), 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 ());
2017-05-11 13:20:51 -04:00
settings . setValue ( "from_depth" , _ui -> checkBox_fromDepth -> isChecked ());
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 ());
2017-05-10 15:53:02 -04:00
settings . setValue ( "frame" , _ui -> comboBox_frame -> currentIndex ());
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-06-03 18:24:56 -04:00
settings . setValue ( "gain_rgb" , _ui -> checkBox_gainRGB -> isChecked ());
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-06-03 18:24:56 -04:00
settings . setValue ( "mesh_textureMaxCount" , _ui -> spinBox_mesh_maxTextures -> value ());
2017-01-31 23:26:35 -05:00
settings . setValue ( "mesh_textureMaxDistance" , _ui -> doubleSpinBox_meshingTextureMaxDistance -> value ());
2017-06-06 11:42:42 -04:00
settings . setValue ( "mesh_textureMaxDepthError" , _ui -> doubleSpinBox_meshingTextureMaxDepthError -> value ());
settings . setValue ( "mesh_textureMaxAngle" , _ui -> doubleSpinBox_meshingTextureMaxAngle -> 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 ());
2017-05-05 21:44:06 -04:00
settings . setValue ( "cputsdf_size" , _ui -> doubleSpinBox_cputsdf_size -> value ());
settings . setValue ( "cputsdf_resolution" , _ui -> doubleSpinBox_cputsdf_resolution -> value ());
settings . setValue ( "cputsdf_truncPos" , _ui -> doubleSpinBox_cputsdf_tuncPos -> value ());
settings . setValue ( "cputsdf_truncNeg" , _ui -> doubleSpinBox_cputsdf_tuncNeg -> value ());
settings . setValue ( "cputsdf_minWeight" , _ui -> doubleSpinBox_cputsdf_minWeight -> value ());
settings . setValue ( "cputsdf_flattenRadius" , _ui -> doubleSpinBox_cputsdf_flattenRadius -> value ());
settings . setValue ( "cputsdf_randomSplit" , _ui -> spinBox_cputsdf_randomSplit -> 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 ());
2017-05-11 13:20:51 -04:00
_ui -> checkBox_fromDepth -> setChecked ( settings . value ( "from_depth" , _ui -> checkBox_fromDepth -> isChecked ()). toBool ());
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 ());
2017-05-10 15:53:02 -04:00
_ui -> comboBox_frame -> setCurrentIndex ( settings . value ( "frame" , _ui -> comboBox_frame -> currentIndex ()). toInt ());
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-06-03 18:24:56 -04:00
_ui -> checkBox_gainRGB -> setChecked ( settings . value ( "gain_rgb" , _ui -> checkBox_gainRGB -> isChecked ()). toBool ());
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-06-03 18:24:56 -04:00
_ui -> spinBox_mesh_maxTextures -> setValue ( settings . value ( "mesh_textureMaxCount" , _ui -> spinBox_mesh_maxTextures -> value ()). toInt ());
2017-01-31 23:26:35 -05:00
_ui -> doubleSpinBox_meshingTextureMaxDistance -> setValue ( settings . value ( "mesh_textureMaxDistance" , _ui -> doubleSpinBox_meshingTextureMaxDistance -> value ()). toDouble ());
2017-06-06 11:42:42 -04:00
_ui -> doubleSpinBox_meshingTextureMaxDepthError -> setValue ( settings . value ( "mesh_textureMaxDepthError" , _ui -> doubleSpinBox_meshingTextureMaxDepthError -> value ()). toDouble ());
_ui -> doubleSpinBox_meshingTextureMaxAngle -> setValue ( settings . value ( "mesh_textureMaxAngle" , _ui -> doubleSpinBox_meshingTextureMaxAngle -> 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 ());
2017-05-05 21:44:06 -04:00
_ui -> doubleSpinBox_cputsdf_size -> setValue ( settings . value ( "cputsdf_size" , _ui -> doubleSpinBox_cputsdf_size -> value ()). toDouble ());
_ui -> doubleSpinBox_cputsdf_resolution -> setValue ( settings . value ( "cputsdf_resolution" , _ui -> doubleSpinBox_cputsdf_resolution -> value ()). toDouble ());
_ui -> doubleSpinBox_cputsdf_tuncPos -> setValue ( settings . value ( "cputsdf_truncPos" , _ui -> doubleSpinBox_cputsdf_tuncPos -> value ()). toDouble ());
_ui -> doubleSpinBox_cputsdf_tuncNeg -> setValue ( settings . value ( "cputsdf_truncNeg" , _ui -> doubleSpinBox_cputsdf_tuncNeg -> value ()). toDouble ());
_ui -> doubleSpinBox_cputsdf_minWeight -> setValue ( settings . value ( "cputsdf_minWeight" , _ui -> doubleSpinBox_cputsdf_minWeight -> value ()). toDouble ());
_ui -> doubleSpinBox_cputsdf_flattenRadius -> setValue ( settings . value ( "cputsdf_flattenRadius" , _ui -> doubleSpinBox_cputsdf_flattenRadius -> value ()). toDouble ());
_ui -> spinBox_cputsdf_randomSplit -> setValue ( settings . value ( "cputsdf_randomSplit" , _ui -> spinBox_cputsdf_randomSplit -> value ()). toInt ());
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 );
2017-05-11 13:20:51 -04:00
_ui -> checkBox_fromDepth -> setChecked ( true );
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 );
2017-05-10 15:53:02 -04:00
_ui -> comboBox_frame -> setCurrentIndex ( 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-06-03 18:24:56 -04:00
_ui -> checkBox_gainRGB -> setChecked ( true );
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-06-03 18:24:56 -04:00
_ui -> spinBox_mesh_maxTextures -> setValue ( 1 );
2017-01-31 23:26:35 -05:00
_ui -> doubleSpinBox_meshingTextureMaxDistance -> setValue ( 3.0 );
2017-06-06 11:42:42 -04:00
_ui -> doubleSpinBox_meshingTextureMaxDepthError -> setValue ( 0.0 );
_ui -> doubleSpinBox_meshingTextureMaxAngle -> setValue ( 0.0 );
2017-03-04 18:20:26 -05:00
_ui -> spinBox_mesh_minTextureClusterSize -> setValue ( 50 );
2017-04-20 12:01:20 -04:00
_ui -> lineEdit_meshingTextureRoiRatios -> setText ( "0.0 0.0 0.0 0.0" );
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 );
2017-05-05 21:44:06 -04:00
_ui -> doubleSpinBox_cputsdf_size -> setValue ( 12.0 );
_ui -> doubleSpinBox_cputsdf_resolution -> setValue ( 0.01 );
_ui -> doubleSpinBox_cputsdf_tuncPos -> setValue ( 0.03 );
_ui -> doubleSpinBox_cputsdf_tuncNeg -> setValue ( 0.03 );
_ui -> doubleSpinBox_cputsdf_minWeight -> setValue ( 0 );
_ui -> doubleSpinBox_cputsdf_flattenRadius -> setValue ( 0.005 );
_ui -> spinBox_cputsdf_randomSplit -> setValue ( 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-05-11 13:20:51 -04:00
if ( ! _ui -> checkBox_fromDepth -> isChecked ())
{
_ui -> comboBox_pipeline -> setCurrentIndex ( 1 );
_ui -> comboBox_pipeline -> setEnabled ( false );
_ui -> comboBox_frame -> setItemData ( 2 , 0 , Qt :: UserRole - 1 );
_ui -> comboBox_frame -> setItemData ( 3 , 1 | 32 , Qt :: UserRole - 1 );
if ( _ui -> comboBox_frame -> currentIndex () == 2 )
{
_ui -> comboBox_frame -> setCurrentIndex ( 0 );
}
}
else
{
_ui -> comboBox_pipeline -> setEnabled ( true );
_ui -> comboBox_frame -> setItemData ( 2 , 1 | 32 , Qt :: UserRole - 1 );
_ui -> comboBox_frame -> setItemData ( 3 , 0 , Qt :: UserRole - 1 );
if ( _ui -> comboBox_frame -> currentIndex () == 3 )
{
_ui -> comboBox_frame -> setCurrentIndex ( 0 );
}
}
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
2017-05-10 15:53:02 -04:00
_ui -> comboBox_frame -> setEnabled ( ! _ui -> checkBox_assemble -> isChecked () && _ui -> checkBox_binary -> isEnabled ());
_ui -> comboBox_frame -> setVisible ( _ui -> comboBox_frame -> isEnabled ());
_ui -> label_frame -> setVisible ( _ui -> comboBox_frame -> isEnabled ());
_ui -> checkBox_gainCompensation -> setEnabled ( ! ( _ui -> comboBox_frame -> isEnabled () && _ui -> comboBox_frame -> currentIndex () == 2 ));
_ui -> checkBox_gainCompensation -> setVisible ( _ui -> checkBox_gainCompensation -> isEnabled ());
_ui -> label_gainCompensation -> setVisible ( _ui -> checkBox_gainCompensation -> isEnabled ());
2017-05-11 13:20:51 -04:00
_ui -> groupBox_regenerate -> setVisible ( _ui -> checkBox_regenerate -> isChecked () && _ui -> checkBox_fromDepth -> isChecked ());
_ui -> groupBox_regenerateScans -> setVisible ( _ui -> checkBox_regenerate -> isChecked () && ! _ui -> checkBox_fromDepth -> isChecked ());
2017-02-26 18:17:00 -05:00
_ui -> groupBox_bilateral -> setVisible ( _ui -> checkBox_bilateral -> isChecked ());
_ui -> groupBox_filtering -> setVisible ( _ui -> checkBox_filtering -> isChecked ());
2017-05-10 15:53:02 -04:00
_ui -> groupBox_gain -> setVisible ( _ui -> checkBox_gainCompensation -> isEnabled () && _ui -> checkBox_gainCompensation -> isChecked ());
2017-02-26 18:17:00 -05:00
_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-02-26 18:17:00 -05:00
if ( _ui -> checkBox_meshing -> isChecked ())
2017-01-19 11:20:48 -05:00
{
2017-05-05 21:44:06 -04:00
_ui -> comboBox_meshingApproach -> setItemData ( 0 , _ui -> comboBox_pipeline -> currentIndex () == 1 ? 1 | 32 : 0 , Qt :: UserRole - 1 );
_ui -> comboBox_meshingApproach -> setItemData ( 1 , _ui -> comboBox_pipeline -> currentIndex () == 1 && _ui -> checkBox_assemble -> isChecked () ? 1 | 32 : 0 , Qt :: UserRole - 1 );
#ifdef RTABMAP_CPUTSDF
_ui -> comboBox_meshingApproach -> setItemData ( 2 , _ui -> comboBox_pipeline -> currentIndex () == 0 && _ui -> checkBox_assemble -> isChecked () ? 1 | 32 : 0 , Qt :: UserRole - 1 );
#else
_ui -> comboBox_meshingApproach -> setItemData ( 2 , Qt :: UserRole - 1 );
#endif
_ui -> comboBox_meshingApproach -> setItemData ( 3 , _ui -> comboBox_pipeline -> currentIndex () == 0 ? 1 | 32 : 0 , Qt :: UserRole - 1 );
if ( _ui -> comboBox_pipeline -> currentIndex () == 0 && _ui -> comboBox_meshingApproach -> currentIndex () < 2 )
{
_ui -> comboBox_meshingApproach -> setCurrentIndex ( 3 );
}
if ( _ui -> comboBox_pipeline -> currentIndex () == 1 && _ui -> comboBox_meshingApproach -> currentIndex () > 1 )
{
_ui -> comboBox_meshingApproach -> setCurrentIndex ( 1 );
}
2017-02-26 18:17:00 -05:00
if ( ! _ui -> checkBox_assemble -> isChecked ())
{
2017-05-05 21:44:06 -04:00
_ui -> comboBox_meshingApproach -> setCurrentIndex ( _ui -> comboBox_pipeline -> currentIndex () == 1 ? 0 : 3 );
2017-02-26 18:17:00 -05:00
}
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 );
2017-05-05 21:44:06 -04: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 );
_ui -> groupBox_cputsdf -> setVisible ( _ui -> comboBox_pipeline -> currentIndex () == 0 && _ui -> comboBox_meshingApproach -> currentIndex () == 2 );
_ui -> groupBox_organized -> setVisible ( _ui -> comboBox_pipeline -> currentIndex () == 0 && _ui -> comboBox_meshingApproach -> currentIndex () == 3 );
#ifndef DISABLE_VTK
_ui -> doubleSpinBox_meshDecimationFactor -> setEnabled ( _ui -> comboBox_meshingApproach -> currentIndex () != 3 );
_ui -> label_meshDecimation -> setEnabled ( _ui -> comboBox_meshingApproach -> currentIndex () != 3 );
_ui -> spinBox_meshMaxPolygons -> setEnabled ( _ui -> comboBox_meshingApproach -> currentIndex () != 3 );
_ui -> label_meshMaxPolygons -> setEnabled ( _ui -> comboBox_meshingApproach -> currentIndex () != 3 );
#endif
2017-01-19 11:20:48 -05:00
}
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
}
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 ,
2017-05-11 13:20:51 -04:00
const std :: map < int , cv :: Mat > & cachedScans ,
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 ,
2017-05-11 13:20:51 -04:00
cachedScans ,
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 ,
2017-05-11 13:20:51 -04:00
const std :: map < int , cv :: Mat > & cachedScans ,
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 ,
2017-05-11 13:20:51 -04:00
cachedScans ,
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-06-13 19:20:09 -04:00
std :: map < int , cv :: Mat > images ;
std :: map < int , std :: vector < CameraModel > > calibrations ;
for ( QMap < int , Signature >:: const_iterator iter = cachedSignatures . constBegin (); iter != cachedSignatures . constEnd (); ++ iter )
{
std :: vector < CameraModel > models ;
if ( iter -> sensorData (). cameraModels (). size ())
{
models = iter -> sensorData (). cameraModels ();
}
else if ( iter -> sensorData (). stereoCameraModel (). isValidForProjection ())
{
models . push_back ( iter -> sensorData (). stereoCameraModel (). left ());
}
if ( ! models . empty ())
{
if ( ! iter -> sensorData (). imageRaw (). empty ())
{
calibrations . insert ( std :: make_pair ( iter . key (), models ));
images . insert ( std :: make_pair ( iter . key (), iter -> sensorData (). imageRaw ()));
}
else if ( ! iter -> sensorData (). imageCompressed (). empty ())
{
calibrations . insert ( std :: make_pair ( iter . key (), models ));
images . insert ( std :: make_pair ( iter . key (), iter -> sensorData (). imageCompressed ()));
}
}
}
int textureSize = 1024 ;
if ( _ui -> comboBox_meshingTextureSize -> currentIndex () > 0 )
{
textureSize = 128 << _ui -> comboBox_meshingTextureSize -> currentIndex (); // start at 256
}
int blendingDecimation = 0 ;
if ( _ui -> checkBox_blending -> isChecked ())
{
if ( _ui -> comboBox_blendingDecimation -> currentIndex () > 0 )
{
blendingDecimation = 1 << ( _ui -> comboBox_blendingDecimation -> currentIndex () - 1 );
}
}
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-06-20 17:57:32 -04:00
cv :: Mat globalTextures ;
2017-06-13 19:20:09 -04:00
globalTextures = util3d :: mergeTextures (
* mesh ,
images ,
calibrations ,
0 ,
_dbDriver ,
textureSize ,
1 ,
textureVertexToPixels ,
_ui -> checkBox_gainCompensation -> isChecked (),
_ui -> doubleSpinBox_gainBeta -> value (),
_ui -> checkBox_gainRGB -> isChecked (),
_ui -> checkBox_blending -> isChecked (),
blendingDecimation ,
_ui -> spinBox_textureBrightnessContrastRatioLow -> value (),
_ui -> spinBox_textureBrightnessContrastRatioHigh -> value (),
_ui -> checkBox_exposureFusion -> isEnabled () && _ui -> checkBox_exposureFusion -> isChecked ());
2017-06-20 17:57:32 -04:00
if ( globalTextures . rows == globalTextures . cols )
2017-06-03 18:24:56 -04:00
{
2017-06-20 17:57:32 -04:00
globalTexture = globalTextures ;
2017-06-03 18:24:56 -04:00
}
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 ());
2017-04-26 18:39:57 -04:00
UASSERT_MSG ( vertices . vertices [ j ] < originalCloud -> size (), uFormat ( "%d vs %d" , vertices . vertices [ j ], ( int ) originalCloud -> size ()). c_str ());
2017-02-01 00:29:13 -05:00
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 )
{
2017-06-03 18:24:56 -04:00
_compensator -> apply ( textureId , globalTexture , _ui -> checkBox_gainRGB -> isChecked ());
2017-03-03 00:19:46 -05:00
}
}
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 ,
2017-05-11 13:20:51 -04:00
const std :: map < int , cv :: Mat > & cachedScans ,
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-05-11 13:20:51 -04:00
_ui -> checkBox_regenerate -> setEnabled ( true );
2017-03-21 21:51:39 -04:00
if ( cachedSignatures . empty () && _dbDriver )
{
_ui -> checkBox_regenerate -> setChecked ( true );
2017-05-11 13:20:51 -04:00
_ui -> checkBox_regenerate -> setEnabled ( false );
2017-03-21 21:51:39 -04:00
}
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 );
2017-05-11 13:20:51 -04:00
bool has2dScans = false ;
2016-02-15 19:35:24 -05:00
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 ,
2017-05-11 13:20:51 -04:00
cachedScans ,
parameters ,
has2dScans );
2016-02-15 19:35:24 -05:00
2017-05-22 11:48:01 -04:00
std :: set < int > validCameras = uKeysSet ( clouds );
2017-05-11 13:20:51 -04:00
UDEBUG ( "" );
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-05-11 13:20:51 -04:00
UDEBUG ( "" );
if ( _ui -> checkBox_gainCompensation -> isChecked () && _ui -> checkBox_fromDepth -> isChecked () && clouds . size () > 1 &&
2017-04-09 19:16:50 -04:00
// 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 () &&
2017-05-10 15:53:02 -04:00
_ui -> comboBox_meshingTextureSize -> currentIndex () > 0 ) &&
// Don't do compensation if clouds are in camera frame
! ( _ui -> comboBox_frame -> isEnabled () && _ui -> comboBox_frame -> currentIndex () == 2 ))
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 );;
2017-06-03 18:24:56 -04:00
_compensator -> apply ( jter -> first , jter -> second . first , jter -> second . second , _ui -> checkBox_gainRGB -> isChecked ());
2017-02-03 16:12:58 -05:00
_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
}
}
}
2017-05-11 13:20:51 -04:00
UDEBUG ( "" );
std :: map < int , Transform > normalViewpoints = poses ;
if ( _ui -> checkBox_assemble -> isChecked ())
{
// Adjust view points with local transforms
for ( std :: map < int , Transform >:: iterator iter = normalViewpoints . begin (); iter != normalViewpoints . end (); ++ iter )
{
if ( _ui -> checkBox_fromDepth -> isChecked ())
{
std :: vector < CameraModel > models ;
StereoCameraModel stereoModel ;
if ( cachedSignatures . contains ( iter -> first ))
{
const SensorData & data = cachedSignatures . find ( iter -> first ) -> sensorData ();
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 ();
}
}
else
{
LaserScanInfo info ;
if ( cachedSignatures . contains ( iter -> first ))
{
const SensorData & data = cachedSignatures . find ( iter -> first ) -> sensorData ();
info = data . laserScanInfo ();
}
else if ( _dbDriver )
{
_dbDriver -> getLaserScanInfo ( iter -> first , info );
}
if ( ! info . localTransform (). isNull ())
{
iter -> second *= info . localTransform ();
}
}
}
}
UDEBUG ( "" );
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
{
2017-04-26 18:39:57 -04:00
// it looks like that using only transformPointCloud with indices
// flushes the colors, so we should extract points before... maybe a too old PCL version
pcl :: copyPointCloud ( * iter -> second . first , * iter -> second . second , * transformed );
transformed = rtabmap :: util3d :: transformPointCloud ( transformed , poses . at ( iter -> first ));
2016-02-15 19:35:24 -05:00
}
* 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 ();
2017-04-26 18:39:57 -04:00
pcl :: IndicesPtr indices ( new std :: vector < int > );
indices -> resize ( assembledCloud -> size ());
for ( unsigned int i = 0 ; i < indices -> size (); ++ i )
{
indices -> at ( i ) = i ;
}
2017-05-11 13:20:51 -04:00
if ( ! _ui -> checkBox_fromDepth -> isChecked () && ! has2dScans )
{
// recompute normals
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr cloudWithoutNormals ( new pcl :: PointCloud < pcl :: PointXYZ > );
pcl :: copyPointCloud ( * assembledCloud , * cloudWithoutNormals );
pcl :: PointCloud < pcl :: Normal >:: Ptr normals = util3d :: computeNormals ( cloudWithoutNormals , indices , _ui -> spinBox_normalKSearch -> value ());
UASSERT ( assembledCloud -> size () == normals -> size ());
for ( unsigned int i = 0 ; i < normals -> size (); ++ i )
{
assembledCloud -> points [ i ]. normal_x = normals -> points [ i ]. normal_x ;
assembledCloud -> points [ i ]. normal_y = normals -> points [ i ]. normal_y ;
assembledCloud -> points [ i ]. normal_z = normals -> points [ i ]. normal_z ;
}
// adjust with point of views
util3d :: adjustNormalsToViewPoints (
normalViewpoints ,
rawAssembledCloud ,
rawCameraIndices ,
assembledCloud );
}
2017-04-26 18:39:57 -04:00
clouds . insert ( std :: make_pair ( 0 , std :: make_pair ( assembledCloud , indices )));
2016-02-15 19:35:24 -05:00
}
2017-05-11 13:20:51 -04:00
UDEBUG ( "" );
2016-09-19 14:01:06 -04:00
if ( _canceled )
{
return false ;
}
2017-05-11 13:20:51 -04:00
if ( _ui -> checkBox_smoothing -> isEnabled () && _ui -> checkBox_smoothing -> isChecked () && ! has2dScans )
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 ();
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 ();
2017-05-11 13:20:51 -04:00
iter != clouds . end ();)
2016-02-15 19:35:24 -05:00
{
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr cloudWithNormals = iter -> second . first ;
2017-05-11 13:20:51 -04:00
if ( _ui -> checkBox_smoothing -> isEnabled () && _ui -> checkBox_smoothing -> isChecked () && ! has2dScans )
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 (
2017-05-11 13:20:51 -04:00
normalViewpoints ,
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 ));
2017-05-11 13:20:51 -04:00
// clear memory
clouds . erase ( iter ++ );
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
}
2017-05-11 13:20:51 -04:00
UDEBUG ( "" );
2017-05-05 21:44:06 -04:00
#ifdef RTABMAP_CPUTSDF
cpu_tsdf :: TSDFVolumeOctree :: Ptr tsdf ;
#endif
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 );
2017-05-11 13:20:51 -04:00
if ( _ui -> checkBox_meshing -> isChecked () && ! has2dScans )
2016-02-15 19:35:24 -05:00
{
if ( _ui -> comboBox_pipeline -> currentIndex () == 0 )
{
2017-05-05 21:44:06 -04:00
if ( _ui -> comboBox_meshingApproach -> currentIndex () == 2 )
{
_progressDialog -> appendText ( tr ( "Creating TSDF volume... " ));
}
else
{
_progressDialog -> appendText ( tr ( "Organized fast mesh... " ));
}
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
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 );
}
2017-05-05 21:44:06 -04:00
#ifdef RTABMAP_CPUTSDF
if ( _ui -> comboBox_meshingApproach -> currentIndex () == 2 && _ui -> checkBox_assemble -> isChecked ())
2017-03-21 21:51:39 -04:00
{
2017-05-05 21:44:06 -04:00
if ( tsdf . get () == 0 )
2016-09-03 18:59:43 -04:00
{
2017-05-05 21:44:06 -04:00
if ( models . size () == 1 && models [ 0 ]. isValidForProjection () && models [ 0 ]. imageHeight () > 0 && models [ 0 ]. imageWidth () > 0 )
2016-09-03 18:59:43 -04:00
{
2017-05-05 21:44:06 -04:00
float tsdf_size = _ui -> doubleSpinBox_cputsdf_size -> value ();
float cell_size = _ui -> doubleSpinBox_cputsdf_resolution -> value ();
int num_random_splits = _ui -> spinBox_cputsdf_randomSplit -> value ();
int tsdf_res ;
int desired_res = tsdf_size / cell_size ;
// Snap to nearest power of 2;
int n = 1 ;
while ( desired_res > n )
2017-02-04 18:28:43 -05:00
{
2017-05-05 21:44:06 -04:00
n *= 2 ;
}
tsdf_res = n ;
_progressDialog -> appendText ( tr ( "CPU-TSDF: Setting resolution: %1 with grid size %2" ). arg ( tsdf_res ). arg ( tsdf_size ));
tsdf . reset ( new cpu_tsdf :: TSDFVolumeOctree );
tsdf -> setGridSize ( tsdf_size , tsdf_size , tsdf_size );
tsdf -> setResolution ( tsdf_res , tsdf_res , tsdf_res );
float decimation = float ( models [ 0 ]. imageWidth ()) / float ( iter -> second -> width );
tsdf -> setImageSize ( models [ 0 ]. imageWidth () / decimation , models [ 0 ]. imageHeight () / decimation );
tsdf -> setCameraIntrinsics ( models [ 0 ]. fx () / decimation , models [ 0 ]. fy () / decimation , models [ 0 ]. cx () / decimation , models [ 0 ]. cy () / decimation );
tsdf -> setNumRandomSplts ( num_random_splits );
tsdf -> setSensorDistanceBounds ( 0 , 9999 );
tsdf -> setIntegrateColor ( true );
tsdf -> setDepthTruncationLimits ( _ui -> doubleSpinBox_cputsdf_tuncPos -> value (), _ui -> doubleSpinBox_cputsdf_tuncNeg -> value ());
tsdf -> reset ();
}
else
{
_progressDialog -> appendText ( tr ( "CPU-TSDF: Invalid camera model! Only single RGB-D camera supported." ), Qt :: darkYellow );
_progressDialog -> setAutoClose ( false );
break ;
}
}
if ( tsdf . get ())
{
if ( tsdf . get () && models . size () == 1 && ! models [ 0 ]. localTransform (). isNull ())
{
Eigen :: Affine3d pose_rel_to_first_frame = (( poses . begin () -> second . inverse () * poses . at ( iter -> first )) * models [ 0 ]. localTransform ()). toEigen3d ();
if ( ! tsdf -> integrateCloud ( * util3d :: transformPointCloud ( iter -> second , models [ 0 ]. localTransform (). inverse ()), pcl :: PointCloud < pcl :: Normal > (), pose_rel_to_first_frame ))
{
_progressDialog -> appendText ( tr ( "CPU-TSDF: Failed integrating cloud %1 to TSDF volume" ). arg ( iter -> first ));
}
else
{
_progressDialog -> appendText ( tr ( "CPU-TSDF: Integrated cloud %1 to TSDF volume" ). arg ( iter -> first ));
2017-02-04 18:28:43 -05:00
}
}
2017-05-05 21:44:06 -04:00
}
}
else
#endif
{
2017-05-10 15:53:02 -04:00
if (( _ui -> comboBox_frame -> isEnabled () && _ui -> comboBox_frame -> currentIndex () != 2 ) ||
! iter -> second -> isOrganized ())
2017-05-05 21:44:06 -04:00
{
2017-05-10 15:53:02 -04:00
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 ();
}
2017-05-05 21:44:06 -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 );
if ( _ui -> spinBox_mesh_minClusterSize -> value () != 0 )
{
_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 ( polygons ,
( int ) iter -> second -> size (),
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 ( polygons . size ());
if ( _ui -> spinBox_mesh_minClusterSize -> value () < 0 )
{
// 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 ++ ] = polygons . at ( * jter );
}
filteredPolygons . resize ( oi );
}
}
else
2017-02-04 18:28:43 -05:00
{
int oi = 0 ;
2017-05-05 21:44:06 -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-05-05 21:44:06 -04:00
for ( std :: list < int >:: iterator jter = iter -> begin (); jter != iter -> end (); ++ jter )
{
filteredPolygons [ oi ++ ] = polygons . at ( * jter );
}
2017-02-04 18:28:43 -05:00
}
filteredPolygons . resize ( oi );
2016-09-03 18:59:43 -04:00
}
2017-05-05 21:44:06 -04:00
int before = ( int ) polygons . size ();
polygons = filteredPolygons ;
if ( polygons . size () == 0 )
{
std :: string msg = uFormat ( "All %d polygons filtered after polygon cluster filtering. Cluster minimum size is %d." , before , _ui -> spinBox_mesh_minClusterSize -> value ());
2017-05-11 13:20:51 -04:00
_progressDialog -> appendText ( msg . c_str (), Qt :: darkYellow );
2017-05-05 21:44:06 -04:00
UWARN ( msg . c_str ());
}
_progressDialog -> appendText ( tr ( "Filtered %1 polygons." ). arg ( before - ( int ) polygons . size ()));
QApplication :: processEvents ();
}
2017-05-11 13:20:51 -04:00
_progressDialog -> appendText ( tr ( "Mesh %1 created with %2 polygons (%3/%4)." ). arg ( iter -> first ). arg ( polygons . size ()). arg ( ++ i ). arg ( cloudsWithNormals . size ()));
2017-05-05 21:44:06 -04:00
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr denseCloud ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
std :: vector < pcl :: Vertices > densePolygons ;
std :: vector < int > denseToOrganizedIndices = util3d :: filterNotUsedVerticesFromMesh ( * iter -> second , polygons , * denseCloud , densePolygons );
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
{
if ( _ui -> checkBox_assemble -> isChecked ())
{
denseCloud = util3d :: transformPointCloud ( denseCloud , poses . at ( iter -> first ));
}
pcl :: PolygonMesh :: Ptr mesh ( new pcl :: PolygonMesh );
pcl :: toPCLPointCloud2 ( * denseCloud , mesh -> cloud );
mesh -> polygons = densePolygons ;
organizedIndices . insert ( std :: make_pair ( iter -> first , denseToOrganizedIndices ));
organizedCloudSizes . insert ( std :: make_pair ( iter -> first , cv :: Size ( iter -> second -> width , iter -> second -> height )));
meshes . insert ( std :: make_pair ( iter -> first , mesh ));
2016-09-03 18:59:43 -04:00
}
2017-02-04 18:28:43 -05:00
else
2016-06-12 13:51:49 -04:00
{
denseCloud = util3d :: transformPointCloud ( denseCloud , poses . at ( iter -> first ));
2017-05-05 21:44:06 -04:00
if ( mergedClouds -> size () == 0 )
{
* mergedClouds = * denseCloud ;
mergedPolygons = densePolygons ;
}
else
{
util3d :: appendMesh ( * mergedClouds , mergedPolygons , * denseCloud , densePolygons );
}
2016-06-12 13:51:49 -04:00
}
2016-03-22 20:44:18 -04:00
}
}
else
2016-02-15 19:35:24 -05:00
{
2017-05-11 13:20:51 -04:00
_progressDialog -> appendText ( tr ( "Mesh %1 not created (no valid points) (%2/%3)." ). arg ( iter -> first ). arg ( ++ i ). arg ( cloudsWithNormals . size ()));
2016-02-15 19:35:24 -05:00
}
}
else
{
2017-05-11 13:20:51 -04:00
int weight = 0 ;
if ( cachedSignatures . contains ( iter -> first ))
{
const Signature & s = cachedSignatures . find ( iter -> first ). value ();
weight = s . getWeight ();
}
else if ( _dbDriver )
{
_dbDriver -> getWeight ( iter -> first , weight );
}
if ( weight >= 0 ) // don't show error for intermediate nodes
{
_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 ( cloudsWithNormals . 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
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 );
}
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-06-13 19:20:09 -04:00
TexturingState texturingState ( _progressDialog , false );
util3d :: denseMeshPostProcessing < pcl :: PointXYZRGBNormal > (
mesh ,
_ui -> doubleSpinBox_meshDecimationFactor -> isEnabled () ? ( float ) _ui -> doubleSpinBox_meshDecimationFactor -> value () : 0.0f ,
_ui -> spinBox_meshMaxPolygons -> isEnabled () ? _ui -> spinBox_meshMaxPolygons -> value () : 0 ,
iter -> second ,
( float ) _ui -> doubleSpinBox_transferColorRadius -> value (),
! ( _ui -> checkBox_textureMapping -> isEnabled () && _ui -> checkBox_textureMapping -> isChecked ()),
_ui -> checkBox_cleanMesh -> isChecked (),
_ui -> spinBox_mesh_minClusterSize -> value (),
& texturingState );
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
}
}
}
2017-05-11 13:20:51 -04:00
else if ( _ui -> checkBox_meshing -> isChecked ())
{
std :: string msg = uFormat ( "Some clouds are 2D laser scans. Meshing can be done only from RGB-D clouds or 3D laser scans." );
_progressDialog -> appendText ( msg . c_str (), Qt :: darkYellow );
UWARN ( msg . c_str ());
}
2016-02-15 19:35:24 -05:00
2017-05-11 13:20:51 -04:00
UDEBUG ( "" );
2017-05-05 21:44:06 -04:00
#ifdef RTABMAP_CPUTSDF
if ( tsdf . get ())
{
_progressDialog -> appendText ( tr ( "CPU-TSDF: Creating mesh from TSDF volume..." ));
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
cpu_tsdf :: MarchingCubesTSDFOctree mc ;
mc . setMinWeight ( _ui -> doubleSpinBox_cputsdf_minWeight -> value ());
mc . setInputTSDF ( tsdf );
mc . setColorByRGB ( true );
pcl :: PolygonMesh :: Ptr mesh ( new pcl :: PolygonMesh );
mc . reconstruct ( * mesh );
_progressDialog -> appendText ( tr ( "CPU-TSDF: Creating mesh from TSDF volume...done!" ));
meshes . clear ();
if ( mesh -> polygons . size () > 0 )
{
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr vertices ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
pcl :: fromPCLPointCloud2 ( mesh -> cloud , * vertices );
if ( _ui -> doubleSpinBox_cputsdf_flattenRadius -> value () > 0.0 )
{
_progressDialog -> appendText ( tr ( "CPU-TSDF: Flattening mesh (radius=%1)..." ). arg ( _ui -> doubleSpinBox_cputsdf_flattenRadius -> value ()));
QApplication :: processEvents ();
uSleep ( 100 );
QApplication :: processEvents ();
float min_dist = _ui -> doubleSpinBox_cputsdf_flattenRadius -> value ();
pcl :: search :: KdTree < pcl :: PointXYZRGBNormal > vert_tree ( true );
vert_tree . setInputCloud ( vertices );
// Find duplicates
std :: vector < int > vertex_remap ( vertices -> size (), - 1 );
int idx = 0 ;
std :: vector < int > neighbors ;
std :: vector < float > dists ;
pcl :: PointCloud < pcl :: PointXYZRGBNormal >:: Ptr vertices_new ( new pcl :: PointCloud < pcl :: PointXYZRGBNormal > );
vertices_new -> resize ( vertices -> size ());
for ( size_t i = 0 ; i < vertices -> size (); i ++ )
{
if ( vertex_remap [ i ] >= 0 )
continue ;
vertex_remap [ i ] = idx ;
vert_tree . radiusSearch ( i , min_dist , neighbors , dists );
for ( size_t j = 1 ; j < neighbors . size (); j ++ )
{
if ( dists [ j ] < min_dist )
vertex_remap [ neighbors [ j ]] = idx ;
}
vertices_new -> at ( idx ++ ) = vertices -> at ( i );
}
vertices_new -> resize ( idx );
std :: vector < size_t > faces_to_remove ;
size_t face_idx = 0 ;
for ( size_t i = 0 ; i < mesh -> polygons . size (); i ++ )
{
pcl :: Vertices & v = mesh -> polygons [ i ];
for ( size_t j = 0 ; j < v . vertices . size (); j ++ )
{
v . vertices [ j ] = vertex_remap [ v . vertices [ j ]];
}
if ( ! ( v . vertices [ 0 ] == v . vertices [ 1 ] || v . vertices [ 1 ] == v . vertices [ 2 ] || v . vertices [ 2 ] == v . vertices [ 0 ]))
{
mesh -> polygons [ face_idx ++ ] = mesh -> polygons [ i ];
}
}
mesh -> polygons . resize ( face_idx );
pcl :: toPCLPointCloud2 ( * vertices_new , mesh -> cloud );
vertices = vertices_new ;
}
pcl :: fromPCLPointCloud2 ( mesh -> cloud , * vertices );
2017-06-13 19:20:09 -04:00
TexturingState texturingState ( _progressDialog , false );
util3d :: denseMeshPostProcessing < pcl :: PointXYZRGBNormal > (
mesh ,
_ui -> doubleSpinBox_meshDecimationFactor -> isEnabled () ? ( float ) _ui -> doubleSpinBox_meshDecimationFactor -> value () : 0.0f ,
_ui -> spinBox_meshMaxPolygons -> isEnabled () ? _ui -> spinBox_meshMaxPolygons -> value () : 0 ,
vertices ,
( float ) _ui -> doubleSpinBox_transferColorRadius -> value (),
! ( _ui -> checkBox_textureMapping -> isEnabled () && _ui -> checkBox_textureMapping -> isChecked ()),
_ui -> checkBox_cleanMesh -> isChecked (),
_ui -> spinBox_mesh_minClusterSize -> value (),
& texturingState );
2017-05-05 21:44:06 -04:00
meshes . insert ( std :: make_pair ( 0 , mesh ));
}
else
{
_progressDialog -> appendText ( tr ( "No polygons created TSDF volume!" ), Qt :: darkYellow );
_progressDialog -> setAutoClose ( false );
}
}
#endif
2017-05-11 13:20:51 -04:00
UDEBUG ( "" );
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 );
2017-05-11 13:20:51 -04:00
if ( ! has2dScans && _ui -> checkBox_textureMapping -> isEnabled () && _ui -> checkBox_textureMapping -> isChecked ())
2016-02-15 19:35:24 -05:00
{
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 ;
2017-04-26 18:39:57 -04:00
std :: map < int , std :: vector < CameraModel > > cameraModels ;
2017-06-06 11:42:42 -04:00
std :: map < int , cv :: Mat > cameraDepths ;
2016-02-15 19:35:24 -05:00
for ( std :: map < int , Transform >:: iterator jter = cameras . begin (); jter != cameras . end (); ++ jter )
{
2017-05-22 11:48:01 -04:00
if ( validCameras . find ( jter -> first ) != validCameras . end ())
2016-02-15 19:35:24 -05:00
{
2017-05-22 11:48:01 -04:00
std :: vector < CameraModel > models ;
StereoCameraModel stereoModel ;
bool cacheHasCompressedImage = false ;
if ( cachedSignatures . contains ( jter -> first ))
2017-03-21 21:51:39 -04:00
{
2017-05-22 11:48:01 -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-21 21:51:39 -04:00
}
2017-06-06 11:42:42 -04:00
bool stereo = false ;
2017-05-22 11:48:01 -04:00
if ( stereoModel . isValidForProjection ())
2017-03-21 21:51:39 -04:00
{
2017-06-06 11:42:42 -04:00
stereo = true ;
2017-05-22 11:48:01 -04:00
models . clear ();
models . push_back ( stereoModel . left ());
}
else if ( models . size () == 0 || ! models [ 0 ]. isValidForProjection ())
{
models . clear ();
}
2017-06-06 11:42:42 -04:00
2017-05-22 11:48:01 -04:00
if ( ! jter -> second . isNull () && models . size ())
{
2017-06-06 11:42:42 -04:00
cv :: Mat depth ;
bool getDepth = ! stereo && _ui -> doubleSpinBox_meshingTextureMaxDepthError -> value () >= 0.0f ;
2017-05-22 11:48:01 -04:00
if ( models [ 0 ]. imageWidth () == 0 || models [ 0 ]. 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 )
{
2017-06-06 11:42:42 -04:00
cachedSignatures . find ( jter -> first ) -> sensorData (). uncompressDataConst ( & img , getDepth ?& depth : 0 );
2017-05-22 11:48:01 -04:00
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( jter -> first , data , true , false , false , false );
2017-06-06 11:42:42 -04:00
data . uncompressDataConst ( & img , getDepth ?& depth : 0 );
2017-05-22 11:48:01 -04:00
}
cv :: Size imageSize = img . size ();
imageSize . width /= models . size ();
for ( unsigned int i = 0 ; i < models . size (); ++ i )
{
models [ i ]. setImageSize ( imageSize );
}
2017-06-06 11:42:42 -04:00
}
else
{
// get just the depth
if ( cacheHasCompressedImage )
{
cachedSignatures . find ( jter -> first ) -> sensorData (). uncompressDataConst ( 0 , getDepth ?& depth : 0 );
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( jter -> first , data , true , false , false , false );
data . uncompressDataConst ( 0 , getDepth ?& depth : 0 );
}
2017-05-22 11:48:01 -04:00
}
if ( models [ 0 ]. imageWidth () != 0 && models [ 0 ]. imageHeight () != 0 )
{
cameraPoses . insert ( std :: make_pair ( jter -> first , jter -> second ));
cameraModels . insert ( std :: make_pair ( jter -> first , models ));
2017-06-06 11:42:42 -04:00
if ( ! depth . empty ())
{
cameraDepths . insert ( std :: make_pair ( jter -> first , depth ));
}
2017-05-22 11:48:01 -04:00
}
2016-02-15 19:35:24 -05:00
}
}
}
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 ());
2017-04-26 18:39:57 -04:00
for ( std :: map < int , std :: vector < CameraModel > >:: iterator modelIter = cameraModels . begin (); modelIter != cameraModels . end ();)
2017-02-26 18:17:00 -05:00
{
if ( cameraPoses . find ( modelIter -> first ) == cameraPoses . end ())
{
cameraModels . erase ( modelIter ++ );
2017-06-06 11:42:42 -04:00
cameraDepths . erase ( modelIter -> first );
2017-02-26 18:17:00 -05:00
}
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 ;
}
2017-06-13 19:20:09 -04:00
TexturingState texturingState ( _progressDialog , true );
2017-03-03 15:22:20 -05:00
_progressDialog -> setMaximumSteps ( _progressDialog -> maximumSteps () + iter -> second -> polygons . size () / 10000 + 1 );
2017-04-26 18:39:57 -04:00
if ( cameraModels . size () && cameraModels . begin () -> second . size () > 1 )
{
_progressDialog -> setMaximumSteps ( _progressDialog -> maximumSteps () + cameraModels . size () * ( cameraModels . begin () -> second . size () - 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-06-06 11:42:42 -04:00
cameraDepths ,
2017-02-26 18:17:00 -05:00
_ui -> doubleSpinBox_meshingTextureMaxDistance -> value (),
2017-06-06 11:42:42 -04:00
_ui -> doubleSpinBox_meshingTextureMaxDepthError -> value (),
_ui -> doubleSpinBox_meshingTextureMaxAngle -> value () * M_PI / 180.0 ,
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)
2017-06-15 14:10:08 -04:00
if ( _ui -> checkBox_cleanMesh -> isChecked ())
2017-01-16 01:32:53 -05:00
{
2017-06-15 14:10:08 -04:00
unsigned int totalSize = 0 ;
for ( unsigned int t = 0 ; t < textureMesh -> tex_polygons . size (); ++ t )
2017-01-16 01:32:53 -05:00
{
2017-06-15 14:10:08 -04:00
totalSize += textureMesh -> tex_polygons [ t ]. size ();
2017-01-16 01:32:53 -05:00
}
2017-06-15 14:10:08 -04:00
util3d :: cleanTextureMesh ( * textureMesh , _ui -> spinBox_mesh_minClusterSize -> value ());
unsigned int totalSizeAfter = 0 ;
for ( unsigned int t = 0 ; t < textureMesh -> tex_polygons . size (); ++ t )
{
totalSizeAfter += textureMesh -> tex_polygons [ t ]. size ();
}
_progressDialog -> appendText ( tr ( "Cleaned texture mesh: %1 -> %2 polygons" ). arg ( totalSize ). arg ( totalSizeAfter ));
2017-01-16 01:32:53 -05:00
}
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 ,
2017-05-11 13:20:51 -04:00
const std :: map < int , cv :: Mat > & cachedScans ,
const ParametersMap & parameters ,
bool & has2dScans ) const
2014-07-29 00:52:35 +00:00
{
2017-05-11 13:20:51 -04:00
has2dScans = false ;
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-05-10 15:53:02 -04:00
Transform localTransform = Transform :: getIdentity ();
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 ;
2017-05-11 13:20:51 -04:00
cv :: Mat image , depth , scan ;
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 ();
2017-05-11 13:20:51 -04:00
data . uncompressData (
_ui -> checkBox_fromDepth -> isChecked () ?& image : 0 ,
_ui -> checkBox_fromDepth -> isChecked () ?& depth : 0 ,
! _ui -> checkBox_fromDepth -> isChecked () ?& scan : 0 );
2017-03-21 21:51:39 -04:00
}
else if ( _dbDriver )
{
2017-05-11 13:20:51 -04:00
_dbDriver -> getNodeData ( iter -> first , data , _ui -> checkBox_fromDepth -> isChecked (), ! _ui -> checkBox_fromDepth -> isChecked (), false , false );
data . uncompressData (
_ui -> checkBox_fromDepth -> isChecked () ?& image : 0 ,
_ui -> checkBox_fromDepth -> isChecked () ?& depth : 0 ,
! _ui -> checkBox_fromDepth -> isChecked () ?& scan : 0 );
2017-03-21 21:51:39 -04:00
}
2017-05-11 13:20:51 -04:00
if ( _ui -> checkBox_fromDepth -> isChecked () && ! image . empty () && ! depth . empty ())
2017-03-21 21:51:39 -04:00
{
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 ())
{
2017-05-10 15:53:02 -04:00
localTransform = data . cameraModels ()[ 0 ]. localTransform ();
2017-03-21 21:51:39 -04:00
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 ())
{
2017-05-10 15:53:02 -04:00
localTransform = data . stereoCameraModel (). localTransform ();
2017-03-21 21:51:39 -04:00
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
}
}
}
2017-05-11 13:20:51 -04:00
else if ( ! _ui -> checkBox_fromDepth -> isChecked () && ! scan . empty ())
{
bool is2D = scan . channels () == 2 ;
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr cloudWithoutNormals ;
localTransform = Transform :: getIdentity ();
Eigen :: Vector3f viewPoint ( 0.0f , 0.0f , 0.0f );
2017-06-26 12:02:48 -04:00
if ( ! data . laserScanInfo (). localTransform (). isNull ())
2017-05-11 13:20:51 -04:00
{
localTransform = data . laserScanInfo (). localTransform ();
viewPoint [ 0 ] = localTransform . x ();
viewPoint [ 1 ] = localTransform . y ();
viewPoint [ 2 ] = localTransform . z ();
}
2017-06-26 12:02:48 -04:00
cloudWithoutNormals = util3d :: laserScanToPointCloudRGB ( scan , localTransform ); // put in base frame by default
2017-05-11 13:20:51 -04:00
if ( cloudWithoutNormals -> size ())
{
if ( _ui -> doubleSpinBox_voxelSize_assembled -> value () > 0.0 )
{
cloudWithoutNormals = util3d :: voxelize ( cloudWithoutNormals , _ui -> doubleSpinBox_voxelSize_assembled -> value ());
}
indices -> resize ( cloudWithoutNormals -> size ());
for ( unsigned int i = 0 ; i < indices -> size (); ++ i )
{
indices -> at ( i ) = i ;
}
pcl :: PointCloud < pcl :: Normal >:: Ptr normals ;
if ( is2D )
{
// set nan normals
normals . reset ( new pcl :: PointCloud < pcl :: Normal > );
normals -> resize ( cloudWithoutNormals -> size ());
for ( unsigned int i = 0 ; i < cloudWithoutNormals -> size (); ++ i )
{
normals -> points [ i ]. normal_x = std :: numeric_limits < float >:: quiet_NaN ();
normals -> points [ i ]. normal_y = std :: numeric_limits < float >:: quiet_NaN ();
normals -> points [ i ]. normal_z = std :: numeric_limits < float >:: quiet_NaN ();
}
has2dScans = true ;
}
else
{
normals = util3d :: computeNormals ( cloudWithoutNormals , indices , _ui -> spinBox_normalKSearch -> value (), viewPoint );
}
pcl :: concatenateFields ( * cloudWithoutNormals , * normals , * cloud );
}
}
2016-02-15 19:35:24 -05:00
else
{
2017-04-24 12:17:18 -04:00
int weight = 0 ;
2017-05-11 13:20:51 -04:00
if ( cachedSignatures . contains ( iter -> first ))
{
const Signature & s = cachedSignatures . find ( iter -> first ). value ();
weight = s . getWeight ();
}
else if ( _dbDriver )
2017-04-24 12:17:18 -04:00
{
_dbDriver -> getWeight ( iter -> first , weight );
}
if ( weight >= 0 ) // don't show error for intermediate nodes
{
UERROR ( "Cloud %d not found in cache!" , iter -> first );
}
2016-02-15 19:35:24 -05:00
}
}
2017-05-11 13:20:51 -04:00
else if ( _ui -> checkBox_fromDepth -> isChecked () && 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 ())
{
2017-05-10 15:53:02 -04:00
localTransform = models [ 0 ]. localTransform ();
2017-03-21 21:51:39 -04:00
viewPoint [ 0 ] = models [ 0 ]. localTransform (). x ();
viewPoint [ 1 ] = models [ 0 ]. localTransform (). y ();
viewPoint [ 2 ] = models [ 0 ]. localTransform (). z ();
}
else if ( ! stereoModel . localTransform (). isNull ())
{
2017-05-10 15:53:02 -04:00
localTransform = stereoModel . localTransform ();
2017-03-21 21:51:39 -04:00
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
}
2017-05-11 13:20:51 -04:00
else if ( ! _ui -> checkBox_fromDepth -> isChecked () && uContains ( cachedScans , iter -> first ))
{
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr cloudWithoutNormals ;
localTransform = Transform :: getIdentity ();
Eigen :: Vector3f viewPoint ( 0.0f , 0.0f , 0.0f );
LaserScanInfo info ;
if ( cachedSignatures . contains ( iter -> first ))
{
const Signature & s = cachedSignatures . find ( iter -> first ). value ();
info = s . sensorData (). laserScanInfo ();
}
else if ( _dbDriver )
{
_dbDriver -> getLaserScanInfo ( iter -> first , info );
}
if ( ! info . localTransform (). isNull ())
{
2017-06-26 12:02:48 -04:00
viewPoint [ 0 ] = localTransform . x ();
viewPoint [ 1 ] = localTransform . y ();
viewPoint [ 2 ] = localTransform . z ();
localTransform = info . localTransform (). inverse ();
2017-05-11 13:20:51 -04:00
}
bool is2D = cachedScans . at ( iter -> first ). channels () == 2 ;
2017-06-26 12:02:48 -04:00
cloudWithoutNormals = util3d :: laserScanToPointCloudRGB ( cachedScans . at ( iter -> first )); // already in base frame
2017-05-11 13:20:51 -04:00
if ( cloudWithoutNormals -> size ())
{
if ( _ui -> doubleSpinBox_voxelSize_assembled -> value () > 0.0 )
{
cloudWithoutNormals = util3d :: voxelize ( cloudWithoutNormals , _ui -> doubleSpinBox_voxelSize_assembled -> value ());
}
indices -> resize ( cloudWithoutNormals -> size ());
for ( unsigned int i = 0 ; i < indices -> size (); ++ i )
{
indices -> at ( i ) = i ;
}
pcl :: PointCloud < pcl :: Normal >:: Ptr normals ;
if ( is2D )
{
// set nan normals
normals . reset ( new pcl :: PointCloud < pcl :: Normal > );
normals -> resize ( cloudWithoutNormals -> size ());
for ( unsigned int i = 0 ; i < cloudWithoutNormals -> size (); ++ i )
{
normals -> points [ i ]. normal_x = std :: numeric_limits < float >:: quiet_NaN ();
normals -> points [ i ]. normal_y = std :: numeric_limits < float >:: quiet_NaN ();
normals -> points [ i ]. normal_z = std :: numeric_limits < float >:: quiet_NaN ();
}
has2dScans = true ;
}
else
{
normals = util3d :: computeNormals ( cloudWithoutNormals , indices , _ui -> spinBox_normalKSearch -> value (), viewPoint );
}
pcl :: concatenateFields ( * cloudWithoutNormals , * normals , * cloud );
}
}
2016-06-12 17:53:35 -04:00
else
{
2017-05-11 13:20:51 -04:00
int weight = 0 ;
if ( cachedSignatures . contains ( iter -> first ))
{
const Signature & s = cachedSignatures . find ( iter -> first ). value ();
weight = s . getWeight ();
}
else if ( _dbDriver )
{
_dbDriver -> getWeight ( iter -> first , weight );
}
if ( weight >= 0 ) // don't show error for intermediate nodes
{
_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 ());
}
2017-05-10 15:53:02 -04:00
if (( _ui -> comboBox_frame -> isEnabled () && _ui -> comboBox_frame -> currentIndex () == 2 ) && cloud -> isOrganized ())
{
cloud = util3d :: transformPointCloud ( cloud , localTransform . inverse ()); // put back in camera frame
}
2017-06-26 12:02:48 -04:00
else if ( _ui -> comboBox_frame -> isEnabled () && _ui -> comboBox_frame -> currentIndex () == 3 )
{
cloud = util3d :: transformPointCloud ( cloud , localTransform . inverse ()); // put back in scan frame
}
2017-05-10 15:53:02 -04:00
2016-02-15 19:35:24 -05:00
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 ;
2017-05-10 15:53:02 -04:00
transformedCloud = util3d :: transformPointCloud ( iter -> second , ! _ui -> comboBox_frame -> isEnabled () || _ui -> comboBox_frame -> currentIndex () == 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
2016-02-15 19:35:24 -05:00
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 );
2017-05-10 15:53:02 -04:00
tmp = util3d :: transformPointCloud ( tmp , ! _ui -> comboBox_frame -> isEnabled () || _ui -> comboBox_frame -> currentIndex () == 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
2016-02-15 19:35:24 -05:00
pcl :: toPCLPointCloud2 ( * tmp , mesh . cloud );
}
else
{
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr tmp ( new pcl :: PointCloud < pcl :: PointXYZ > );
pcl :: fromPCLPointCloud2 ( iter -> second -> cloud , * tmp );
2017-05-10 15:53:02 -04:00
tmp = util3d :: transformPointCloud ( tmp , ! _ui -> comboBox_frame -> isEnabled () || _ui -> comboBox_frame -> currentIndex () == 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
2016-02-15 19:35:24 -05:00
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
}
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
{
2017-06-13 19:20:09 -04:00
std :: map < int , cv :: Mat > images ;
std :: map < int , std :: vector < CameraModel > > calibrations ;
for ( QMap < int , Signature >:: const_iterator iter = cachedSignatures . constBegin (); iter != cachedSignatures . constEnd (); ++ iter )
{
std :: vector < CameraModel > models ;
if ( iter -> sensorData (). cameraModels (). size ())
{
models = iter -> sensorData (). cameraModels ();
}
else if ( iter -> sensorData (). stereoCameraModel (). isValidForProjection ())
{
models . push_back ( iter -> sensorData (). stereoCameraModel (). left ());
}
if ( ! models . empty ())
{
if ( ! iter -> sensorData (). imageRaw (). empty ())
{
calibrations . insert ( std :: make_pair ( iter . key (), models ));
images . insert ( std :: make_pair ( iter . key (), iter -> sensorData (). imageRaw ()));
}
else if ( ! iter -> sensorData (). imageCompressed (). empty ())
{
calibrations . insert ( std :: make_pair ( iter . key (), models ));
images . insert ( std :: make_pair ( iter . key (), iter -> sensorData (). imageCompressed ()));
}
}
}
int textureSize = 1024 ;
if ( _ui -> comboBox_meshingTextureSize -> currentIndex () > 0 )
{
textureSize = 128 << _ui -> comboBox_meshingTextureSize -> currentIndex (); // start at 256
}
int blendingDecimation = 0 ;
if ( _ui -> checkBox_blending -> isChecked ())
{
if ( _ui -> comboBox_blendingDecimation -> currentIndex () > 0 )
{
blendingDecimation = 1 << ( _ui -> comboBox_blendingDecimation -> currentIndex () - 1 );
}
}
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
2017-06-20 17:57:32 -04:00
cv :: Mat globalTextures ;
2017-01-19 11:20:48 -05:00
bool texturesMerged = _ui -> comboBox_meshingTextureSize -> isEnabled () && _ui -> comboBox_meshingTextureSize -> currentIndex () > 0 ;
if ( texturesMerged && mesh -> tex_materials . size () > 1 )
{
2017-06-13 19:20:09 -04:00
globalTextures = util3d :: mergeTextures (
* mesh ,
images ,
calibrations ,
0 ,
_dbDriver ,
textureSize ,
_ui -> spinBox_mesh_maxTextures -> value (),
textureVertexToPixels ,
_ui -> checkBox_gainCompensation -> isChecked (),
_ui -> doubleSpinBox_gainBeta -> value (),
_ui -> checkBox_gainRGB -> isChecked (),
_ui -> checkBox_blending -> isChecked (),
blendingDecimation ,
_ui -> spinBox_textureBrightnessContrastRatioLow -> value (),
_ui -> spinBox_textureBrightnessContrastRatioHigh -> value (),
_ui -> checkBox_exposureFusion -> isEnabled () && _ui -> checkBox_exposureFusion -> isChecked ());
2017-01-19 11:20:48 -05:00
}
2017-06-13 19:20:09 -04:00
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-04-26 18:39:57 -04:00
// used for multi camera texturing, to avoid reloading same texture for sub cameras
cv :: Mat previousImage ;
int previousTextureId = 0 ;
std :: vector < CameraModel > previousCameraModels ;
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-04-26 18:39:57 -04:00
std :: list < std :: string > texFileSplit = uSplit ( mesh -> tex_materials [ i ]. tex_file , '_' );
if ( texFileSplit . size () && uIsInteger ( texFileSplit . front (), false ))
2017-01-16 18:29:14 -05:00
{
2017-04-26 18:39:57 -04:00
int textureId = uStr2Int ( texFileSplit . front ());
int textureSubCamera = - 1 ;
if ( texFileSplit . size () == 2 &&
uIsInteger ( texFileSplit . back (), false ))
2017-03-21 21:51:39 -04:00
{
2017-04-26 18:39:57 -04:00
textureSubCamera = uStr2Int ( texFileSplit . back ());
2017-03-21 21:51:39 -04:00
}
2017-04-26 18:39:57 -04:00
cv :: Mat image ;
std :: vector < CameraModel > cameraModels ;
if ( textureId == previousTextureId )
2017-03-21 21:51:39 -04:00
{
2017-04-26 18:39:57 -04:00
image = previousImage ;
cameraModels = previousCameraModels ;
}
else
{
if ( cachedSignatures . contains ( textureId ) && ! cachedSignatures . value ( textureId ). sensorData (). imageCompressed (). empty ())
{
cachedSignatures . value ( textureId ). sensorData (). uncompressDataConst ( & image , 0 );
cameraModels = cachedSignatures . value ( textureId ). sensorData (). cameraModels ();
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( textureId , data , true , false , false , false );
data . uncompressDataConst ( & image , 0 );
StereoCameraModel stereoModel ;
_dbDriver -> getCalibration ( textureId , cameraModels , stereoModel );
}
previousImage = image ;
previousCameraModels = cameraModels ;
previousTextureId = textureId ;
2017-03-21 21:51:39 -04:00
}
2017-01-16 18:29:14 -05:00
UASSERT ( ! image . empty ());
imageSize = image . size ();
2017-04-26 18:39:57 -04:00
if ( textureSubCamera >= 0 )
{
UASSERT ( cameraModels . size ());
imageSize . width /= cameraModels . size ();
image = image . colRange ( imageSize . width * textureSubCamera , imageSize . width * ( textureSubCamera + 1 ));
}
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-06-03 18:24:56 -04:00
_compensator -> apply ( textureId , image , _ui -> checkBox_gainRGB -> isChecked ());
2017-01-16 18:29:14 -05:00
}
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-06-20 17:57:32 -04:00
else if ( ! globalTextures . empty ())
2017-01-19 11:20:48 -05:00
{
2017-06-20 17:57:32 -04:00
if ( ! cv :: imwrite ( fullPath . toStdString (), globalTextures ( cv :: Range :: all (), cv :: Range ( i * globalTextures . rows , ( i + 1 ) * globalTextures . rows ))))
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
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-06-20 17:57:32 -04:00
cv :: Mat globalTextures ;
2017-01-19 11:20:48 -05:00
bool texturesMerged = _ui -> comboBox_meshingTextureSize -> isEnabled () && _ui -> comboBox_meshingTextureSize -> currentIndex () > 0 ;
if ( texturesMerged && mesh -> tex_materials . size () > 1 )
{
2017-06-13 19:20:09 -04:00
globalTextures = util3d :: mergeTextures (
* mesh ,
images ,
calibrations ,
0 ,
_dbDriver ,
textureSize ,
_ui -> spinBox_mesh_maxTextures -> value (),
textureVertexToPixels ,
_ui -> checkBox_gainCompensation -> isChecked (),
_ui -> doubleSpinBox_gainBeta -> value (),
_ui -> checkBox_gainRGB -> isChecked (),
_ui -> checkBox_blending -> isChecked (),
blendingDecimation ,
_ui -> spinBox_textureBrightnessContrastRatioLow -> value (),
_ui -> spinBox_textureBrightnessContrastRatioHigh -> value (),
_ui -> checkBox_exposureFusion -> isEnabled () && _ui -> checkBox_exposureFusion -> isChecked ());
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-04-26 18:39:57 -04:00
// used for multi camera texturing, to avoid reloading same texture for sub cameras
cv :: Mat previousImage ;
int previousTextureId = 0 ;
std :: vector < CameraModel > previousCameraModels ;
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-04-26 18:39:57 -04:00
std :: list < std :: string > texFileSplit = uSplit ( mesh -> tex_materials [ i ]. tex_file , '_' );
int textureId = 0 ;
int textureSubCamera = - 1 ;
if ( texFileSplit . size () && uIsInteger ( texFileSplit . front (), false ))
{
textureId = uStr2Int ( texFileSplit . front ());
if ( texFileSplit . size () == 2 &&
uIsInteger ( texFileSplit . back (), false ))
{
textureSubCamera = uStr2Int ( texFileSplit . back ());
}
}
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 ();
}
2017-04-26 18:39:57 -04:00
if ( textureId > 0 )
2017-01-19 11:20:48 -05:00
{
cv :: Mat image ;
2017-04-26 18:39:57 -04:00
std :: vector < CameraModel > cameraModels ;
if ( textureId == previousTextureId )
2017-03-21 21:51:39 -04:00
{
2017-04-26 18:39:57 -04:00
image = previousImage ;
cameraModels = previousCameraModels ;
2017-03-21 21:51:39 -04:00
}
2017-04-26 18:39:57 -04:00
else
2017-03-21 21:51:39 -04:00
{
2017-04-26 18:39:57 -04:00
if ( cachedSignatures . contains ( textureId ) && ! cachedSignatures . value ( textureId ). sensorData (). imageCompressed (). empty ())
{
cachedSignatures . value ( textureId ). sensorData (). uncompressDataConst ( & image , 0 );
cameraModels = cachedSignatures . value ( textureId ). sensorData (). cameraModels ();
}
else if ( _dbDriver )
{
SensorData data ;
_dbDriver -> getNodeData ( textureId , data , true , false , false , false );
data . uncompressDataConst ( & image , 0 );
StereoCameraModel stereoModel ;
_dbDriver -> getCalibration ( textureId , cameraModels , stereoModel );
}
previousImage = image ;
previousCameraModels = cameraModels ;
previousTextureId = textureId ;
2017-03-21 21:51:39 -04:00
}
2017-06-16 16:59:55 -04:00
2017-03-21 21:51:39 -04:00
2017-01-19 11:20:48 -05:00
UASSERT ( ! image . empty ());
imageSize = image . size ();
2017-04-26 18:39:57 -04:00
if ( textureSubCamera >= 0 )
{
UASSERT ( cameraModels . size ());
imageSize . width /= cameraModels . size ();
image = image . colRange ( imageSize . width * textureSubCamera , imageSize . width * ( textureSubCamera + 1 ));
}
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-06-03 18:24:56 -04:00
_compensator -> apply ( textureId , image , _ui -> checkBox_gainRGB -> isChecked ());
2017-01-19 11:20:48 -05:00
}
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 );
}
2017-06-20 17:57:32 -04:00
else if ( ! globalTextures . empty ())
2017-01-19 11:20:48 -05:00
{
2017-06-20 17:57:32 -04:00
if ( ! cv :: imwrite ( fullPath . toStdString (), globalTextures ( cv :: Range :: all (), cv :: Range ( i * globalTextures . rows , ( i + 1 ) * globalTextures . rows ))))
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 );
}
}
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 );
2017-05-10 15:53:02 -04:00
tmp = util3d :: transformPointCloud ( tmp , ! _ui -> comboBox_frame -> isEnabled () || _ui -> comboBox_frame -> currentIndex () == 0 ? poses . at ( iter -> first ) : Transform :: getIdentity ());
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
}