mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 01:20:25 +08:00
DatabaseViewer: Added ExportCloudsDialog, added Occupancy Grid View
This commit is contained in:
@@ -456,8 +456,8 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr OctoMap::createCloud(
|
|||||||
(*cloud)[oi].g = g*255.0f;
|
(*cloud)[oi].g = g*255.0f;
|
||||||
(*cloud)[oi].b = b*255.0f;
|
(*cloud)[oi].b = b*255.0f;
|
||||||
}
|
}
|
||||||
(*cloud)[oi].x = pt.x();
|
(*cloud)[oi].x = pt.x()-octree_->getResolution()/2.0;
|
||||||
(*cloud)[oi].y = pt.y();
|
(*cloud)[oi].y = pt.y()-octree_->getResolution()/2.0;
|
||||||
(*cloud)[oi].z = pt.z();
|
(*cloud)[oi].z = pt.z();
|
||||||
if(obstacleIndices)
|
if(obstacleIndices)
|
||||||
{
|
{
|
||||||
@@ -469,8 +469,8 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr OctoMap::createCloud(
|
|||||||
{
|
{
|
||||||
octomap::point3d pt = octree_->keyToCoord(it.getKey());
|
octomap::point3d pt = octree_->keyToCoord(it.getKey());
|
||||||
(*cloud)[oi] = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
|
(*cloud)[oi] = pcl::PointXYZRGB(it->getColor().r, it->getColor().g, it->getColor().b);
|
||||||
(*cloud)[oi].x = pt.x();
|
(*cloud)[oi].x = pt.x()-octree_->getResolution()/2.0f;
|
||||||
(*cloud)[oi].y = pt.y();
|
(*cloud)[oi].y = pt.y()-octree_->getResolution()/2.0f;
|
||||||
(*cloud)[oi].z = pt.z();
|
(*cloud)[oi].z = pt.z();
|
||||||
if(emptyIndices)
|
if(emptyIndices)
|
||||||
{
|
{
|
||||||
@@ -501,23 +501,21 @@ cv::Mat OctoMap::createProjectionMap(float & xMin, float & yMin, float & gridCel
|
|||||||
pcl::PointCloud<pcl::PointXYZ>::Ptr ground(new pcl::PointCloud<pcl::PointXYZ>);
|
pcl::PointCloud<pcl::PointXYZ>::Ptr ground(new pcl::PointCloud<pcl::PointXYZ>);
|
||||||
pcl::PointCloud<pcl::PointXYZ>::Ptr obstacles(new pcl::PointCloud<pcl::PointXYZ>);
|
pcl::PointCloud<pcl::PointXYZ>::Ptr obstacles(new pcl::PointCloud<pcl::PointXYZ>);
|
||||||
|
|
||||||
ground->resize(occupiedCells_.size());
|
ground->resize(octree_->size());
|
||||||
obstacles->resize(occupiedCells_.size());
|
obstacles->resize(octree_->size());
|
||||||
int gi=0;
|
int gi=0;
|
||||||
int oi=0;
|
int oi=0;
|
||||||
for(std::map<octomap::ColorOcTreeNode*, OcTreeNodeInfo>::const_iterator iter = occupiedCells_.begin();
|
for (octomap::ColorOcTree::iterator it = octree_->begin(octree_->getTreeDepth()); it != octree_->end(); ++it)
|
||||||
iter!=occupiedCells_.end();
|
|
||||||
++iter)
|
|
||||||
{
|
{
|
||||||
if(iter->second.isObstacle_ && octree_->isNodeOccupied(iter->first))
|
if(octree_->isNodeOccupied(*it))
|
||||||
{
|
{
|
||||||
octomap::point3d pt = octree_->keyToCoord(iter->second.key_);
|
octomap::point3d pt = octree_->keyToCoord(it.getKey());
|
||||||
(*obstacles)[oi++] = pcl::PointXYZ(pt.x(), pt.y(), 0); // projected on ground
|
(*obstacles)[oi++] = pcl::PointXYZ(pt.x()-gridCellSize/2.0f, pt.y()-gridCellSize/2.0f, 0); // projected on ground
|
||||||
}
|
}
|
||||||
else if(!iter->second.isObstacle_)
|
else
|
||||||
{
|
{
|
||||||
octomap::point3d pt = octree_->keyToCoord(iter->second.key_);
|
octomap::point3d pt = octree_->keyToCoord(it.getKey());
|
||||||
(*ground)[gi++] = pcl::PointXYZ(pt.x(), pt.y(), 0); // projected on ground
|
(*ground)[gi++] = pcl::PointXYZ(pt.x()-gridCellSize/2.0f, pt.y()-gridCellSize/2.0f, 0); // projected on ground
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obstacles->resize(oi);
|
obstacles->resize(oi);
|
||||||
@@ -525,11 +523,11 @@ cv::Mat OctoMap::createProjectionMap(float & xMin, float & yMin, float & gridCel
|
|||||||
|
|
||||||
if(obstacles->size())
|
if(obstacles->size())
|
||||||
{
|
{
|
||||||
obstacles = util3d::voxelize(obstacles, gridCellSize);
|
obstacles = util3d::voxelize(obstacles, gridCellSize/2.0f);
|
||||||
}
|
}
|
||||||
if(ground->size())
|
if(ground->size())
|
||||||
{
|
{
|
||||||
ground = util3d::voxelize(ground, gridCellSize);
|
ground = util3d::voxelize(ground, gridCellSize/2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Mat obstaclesMat = cv::Mat(1, (int)obstacles->size(), CV_32FC2);
|
cv::Mat obstaclesMat = cv::Mat(1, (int)obstacles->size(), CV_32FC2);
|
||||||
|
|||||||
@@ -308,7 +308,9 @@ cv::Mat create2DMapFromOccupancyLocalMaps(
|
|||||||
//Get map size
|
//Get map size
|
||||||
float margin = cellSize*10.0f;
|
float margin = cellSize*10.0f;
|
||||||
xMin = minX-margin;
|
xMin = minX-margin;
|
||||||
|
xMin -= cellSize/2.0f;
|
||||||
yMin = minY-margin;
|
yMin = minY-margin;
|
||||||
|
yMin += cellSize/2.0f;
|
||||||
float xMax = maxX+margin;
|
float xMax = maxX+margin;
|
||||||
float yMax = maxY+margin;
|
float yMax = maxY+margin;
|
||||||
if(fabs((yMax - yMin) / cellSize) > 99999 ||
|
if(fabs((yMax - yMin) / cellSize) > 99999 ||
|
||||||
@@ -323,7 +325,7 @@ cv::Mat create2DMapFromOccupancyLocalMaps(
|
|||||||
UDEBUG("map min=(%f, %f) max=(%f,%f)", xMin, yMin, xMax, yMax);
|
UDEBUG("map min=(%f, %f) max=(%f,%f)", xMin, yMin, xMax, yMax);
|
||||||
|
|
||||||
|
|
||||||
map = cv::Mat::ones((yMax - yMin) / cellSize + 0.5f, (xMax - xMin) / cellSize + 0.5f, CV_8S)*-1;
|
map = cv::Mat::ones((yMax - yMin) / cellSize, (xMax - xMin) / cellSize, CV_8S)*-1;
|
||||||
for(std::list<std::pair<int, Transform> >::const_iterator kter = poses.begin(); kter!=poses.end(); ++kter)
|
for(std::list<std::pair<int, Transform> >::const_iterator kter = poses.begin(); kter!=poses.end(); ++kter)
|
||||||
{
|
{
|
||||||
std::map<int, cv::Mat >::iterator iter = emptyLocalMaps.find(kter->first);
|
std::map<int, cv::Mat >::iterator iter = emptyLocalMaps.find(kter->first);
|
||||||
@@ -333,7 +335,7 @@ cv::Mat create2DMapFromOccupancyLocalMaps(
|
|||||||
for(int i=0; i<iter->second.cols; ++i)
|
for(int i=0; i<iter->second.cols; ++i)
|
||||||
{
|
{
|
||||||
float * ptf = iter->second.ptr<float>(0, i);
|
float * ptf = iter->second.ptr<float>(0, i);
|
||||||
cv::Point2i pt((ptf[0]-xMin)/cellSize + 0.5f, (ptf[1]-yMin)/cellSize + 0.5f);
|
cv::Point2i pt((ptf[0]-xMin)/cellSize, (ptf[1]-yMin)/cellSize);
|
||||||
char & value = map.at<char>(pt.y, pt.x);
|
char & value = map.at<char>(pt.y, pt.x);
|
||||||
if(value != -2)
|
if(value != -2)
|
||||||
{
|
{
|
||||||
@@ -345,8 +347,8 @@ cv::Mat create2DMapFromOccupancyLocalMaps(
|
|||||||
if(footprintRadius >= cellSize*1.5f)
|
if(footprintRadius >= cellSize*1.5f)
|
||||||
{
|
{
|
||||||
// place free space under the footprint of the robot
|
// place free space under the footprint of the robot
|
||||||
cv::Point2i ptBegin((kter->second.x()-footprintRadius-xMin)/cellSize + 0.5f, (kter->second.y()-footprintRadius-yMin)/cellSize + 0.5f);
|
cv::Point2i ptBegin((kter->second.x()-footprintRadius-xMin)/cellSize, (kter->second.y()-footprintRadius-yMin)/cellSize);
|
||||||
cv::Point2i ptEnd((kter->second.x()+footprintRadius-xMin)/cellSize + 0.5f, (kter->second.y()+footprintRadius-yMin)/cellSize + 0.5f);
|
cv::Point2i ptEnd((kter->second.x()+footprintRadius-xMin)/cellSize, (kter->second.y()+footprintRadius-yMin)/cellSize);
|
||||||
if(ptBegin.x < 0)
|
if(ptBegin.x < 0)
|
||||||
ptBegin.x = 0;
|
ptBegin.x = 0;
|
||||||
if(ptEnd.x >= map.cols)
|
if(ptEnd.x >= map.cols)
|
||||||
@@ -370,7 +372,7 @@ cv::Mat create2DMapFromOccupancyLocalMaps(
|
|||||||
for(int i=0; i<jter->second.cols; ++i)
|
for(int i=0; i<jter->second.cols; ++i)
|
||||||
{
|
{
|
||||||
float * ptf = jter->second.ptr<float>(0, i);
|
float * ptf = jter->second.ptr<float>(0, i);
|
||||||
cv::Point2i pt((ptf[0]-xMin)/cellSize + 0.5f, (ptf[1]-yMin)/cellSize + 0.5f);
|
cv::Point2i pt((ptf[0]-xMin)/cellSize, (ptf[1]-yMin)/cellSize);
|
||||||
char & value = map.at<char>(pt.y, pt.x);
|
char & value = map.at<char>(pt.y, pt.x);
|
||||||
if(value != -2)
|
if(value != -2)
|
||||||
{
|
{
|
||||||
@@ -595,7 +597,7 @@ cv::Mat create2DMap(const std::map<int, Transform> & poses,
|
|||||||
|
|
||||||
UTimer timer;
|
UTimer timer;
|
||||||
|
|
||||||
map = cv::Mat::ones((yMax - yMin) / cellSize + 0.5f, (xMax - xMin) / cellSize + 0.5f, CV_8S)*-1;
|
map = cv::Mat::ones((yMax - yMin) / cellSize, (xMax - xMin) / cellSize, CV_8S)*-1;
|
||||||
int j=0;
|
int j=0;
|
||||||
for(std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >::iterator iter = localScans.begin(); iter!=localScans.end(); ++iter)
|
for(std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >::iterator iter = localScans.begin(); iter!=localScans.end(); ++iter)
|
||||||
{
|
{
|
||||||
@@ -606,7 +608,7 @@ cv::Mat create2DMap(const std::map<int, Transform> & poses,
|
|||||||
{
|
{
|
||||||
viewpoint = kter->second;
|
viewpoint = kter->second;
|
||||||
}
|
}
|
||||||
cv::Point2i start(((pose.x()+viewpoint.x)-xMin)/cellSize + 0.5f, ((pose.y()+viewpoint.y)-yMin)/cellSize + 0.5f);
|
cv::Point2i start(((pose.x()+viewpoint.x)-xMin)/cellSize, ((pose.y()+viewpoint.y)-yMin)/cellSize);
|
||||||
for(unsigned int i=0; i<iter->second->size(); ++i)
|
for(unsigned int i=0; i<iter->second->size(); ++i)
|
||||||
{
|
{
|
||||||
cv::Point2i end((iter->second->points[i].x-xMin)/cellSize, (iter->second->points[i].y-yMin)/cellSize);
|
cv::Point2i end((iter->second->points[i].x-xMin)/cellSize, (iter->second->points[i].y-yMin)/cellSize);
|
||||||
@@ -638,7 +640,7 @@ cv::Mat create2DMap(const std::map<int, Transform> & poses,
|
|||||||
{
|
{
|
||||||
viewpoint = kter->second;
|
viewpoint = kter->second;
|
||||||
}
|
}
|
||||||
cv::Point2i start(((pose.x()+viewpoint.x)-xMin)/cellSize + 0.5f, ((pose.y()+viewpoint.y)-yMin)/cellSize + 0.5f);
|
cv::Point2i start(((pose.x()+viewpoint.x)-xMin)/cellSize, ((pose.y()+viewpoint.y)-yMin)/cellSize);
|
||||||
|
|
||||||
//UWARN("maxLength = %f", maxLength);
|
//UWARN("maxLength = %f", maxLength);
|
||||||
//rotate counterclockwise from the first point until we pass the last point
|
//rotate counterclockwise from the first point until we pass the last point
|
||||||
@@ -680,7 +682,7 @@ cv::Mat create2DMap(const std::map<int, Transform> & poses,
|
|||||||
angle = angle<-1.0f?-1.0f:angle>1.0f?1.0f:angle;
|
angle = angle<-1.0f?-1.0f:angle>1.0f?1.0f:angle;
|
||||||
while(acos(angle) > M_PI_4 || endRotatedVector.cross(endLastVector).at<float>(2) > 0.0f)
|
while(acos(angle) > M_PI_4 || endRotatedVector.cross(endLastVector).at<float>(2) > 0.0f)
|
||||||
{
|
{
|
||||||
cv::Point2i end((endRotated.at<float>(0)-xMin)/cellSize + 0.5f, (endRotated.at<float>(1)-yMin)/cellSize + 0.5f);
|
cv::Point2i end((endRotated.at<float>(0)-xMin)/cellSize, (endRotated.at<float>(1)-yMin)/cellSize);
|
||||||
//end must be inside the grid
|
//end must be inside the grid
|
||||||
end.x = end.x < 0?0:end.x;
|
end.x = end.x < 0?0:end.x;
|
||||||
end.x = end.x >= map.cols?map.cols-1:end.x;
|
end.x = end.x >= map.cols?map.cols-1:end.x;
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ class DBDriver;
|
|||||||
class ImageView;
|
class ImageView;
|
||||||
class SensorData;
|
class SensorData;
|
||||||
class CloudViewer;
|
class CloudViewer;
|
||||||
|
class OctoMap;
|
||||||
|
class ExportCloudsDialog;
|
||||||
|
|
||||||
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
|
class RTABMAPGUI_EXP DatabaseViewer : public QMainWindow
|
||||||
{
|
{
|
||||||
@@ -102,6 +104,7 @@ private slots:
|
|||||||
void sliderLoopValueChanged(int);
|
void sliderLoopValueChanged(int);
|
||||||
void sliderIterationsValueChanged(int);
|
void sliderIterationsValueChanged(int);
|
||||||
void updateGrid();
|
void updateGrid();
|
||||||
|
void updateOctomapView();
|
||||||
void updateGraphView();
|
void updateGraphView();
|
||||||
void refineConstraint();
|
void refineConstraint();
|
||||||
void addConstraint();
|
void addConstraint();
|
||||||
@@ -159,6 +162,7 @@ private:
|
|||||||
CloudViewer * cloudViewerA_;
|
CloudViewer * cloudViewerA_;
|
||||||
CloudViewer * cloudViewerB_;
|
CloudViewer * cloudViewerB_;
|
||||||
CloudViewer * stereoViewer_;
|
CloudViewer * stereoViewer_;
|
||||||
|
CloudViewer * occupancyGridViewer_;
|
||||||
QList<int> ids_;
|
QList<int> ids_;
|
||||||
std::map<int, int> mapIds_;
|
std::map<int, int> mapIds_;
|
||||||
QMap<int, int> idToIndex_;
|
QMap<int, int> idToIndex_;
|
||||||
@@ -176,8 +180,11 @@ private:
|
|||||||
std::multimap<int, rtabmap::Link> linksAdded_;
|
std::multimap<int, rtabmap::Link> linksAdded_;
|
||||||
std::multimap<int, rtabmap::Link> linksRemoved_;
|
std::multimap<int, rtabmap::Link> linksRemoved_;
|
||||||
std::map<int, std::pair<cv::Mat, cv::Mat> > localMaps_; // <ground, obstacles>
|
std::map<int, std::pair<cv::Mat, cv::Mat> > localMaps_; // <ground, obstacles>
|
||||||
|
std::map<int, std::pair<float, cv::Point3f> > localMapsInfo_; // <cell size, viewpoint>
|
||||||
std::map<int, std::pair<cv::Mat, cv::Mat> > generatedLocalMaps_; // <ground, obstacles>
|
std::map<int, std::pair<cv::Mat, cv::Mat> > generatedLocalMaps_; // <ground, obstacles>
|
||||||
std::map<int, std::pair<float, cv::Point3f> > generatedLocalMapsInfo_; // <cell size, viewpoint>
|
std::map<int, std::pair<float, cv::Point3f> > generatedLocalMapsInfo_; // <cell size, viewpoint>
|
||||||
|
OctoMap * octomap_;
|
||||||
|
ExportCloudsDialog * exportDialog_;
|
||||||
|
|
||||||
bool savedMaximized_;
|
bool savedMaximized_;
|
||||||
bool firstCall_;
|
bool firstCall_;
|
||||||
|
|||||||
@@ -753,11 +753,15 @@ bool CloudViewer::addOctomap(const OctoMap * octomap, unsigned int treeDepth)
|
|||||||
|
|
||||||
pcl::IndicesPtr obstacles(new std::vector<int>);
|
pcl::IndicesPtr obstacles(new std::vector<int>);
|
||||||
|
|
||||||
if(treeDepth > octomap->octree()->getTreeDepth())
|
if(treeDepth == 0 || treeDepth > octomap->octree()->getTreeDepth())
|
||||||
{
|
{
|
||||||
UWARN("Tree depth requested (%d) is deeper than the "
|
if(treeDepth>0)
|
||||||
"actual maximum tree depth of %d. Using maximum depth.",
|
{
|
||||||
(int)treeDepth, (int)octomap->octree()->getTreeDepth());
|
UWARN("Tree depth requested (%d) is deeper than the "
|
||||||
|
"actual maximum tree depth of %d. Using maximum depth.",
|
||||||
|
(int)treeDepth, (int)octomap->octree()->getTreeDepth());
|
||||||
|
}
|
||||||
|
treeDepth = octomap->octree()->getTreeDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap->createCloud(treeDepth, obstacles.get());
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap->createCloud(treeDepth, obstacles.get());
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "rtabmap/core/Graph.h"
|
#include "rtabmap/core/Graph.h"
|
||||||
#include "rtabmap/core/GainCompensator.h"
|
#include "rtabmap/core/GainCompensator.h"
|
||||||
#include "rtabmap/core/clams/discrete_depth_distortion_model.h"
|
#include "rtabmap/core/clams/discrete_depth_distortion_model.h"
|
||||||
|
#include "rtabmap/core/DBDriver.h"
|
||||||
|
|
||||||
#include <pcl/conversions.h>
|
#include <pcl/conversions.h>
|
||||||
#include <pcl/io/pcd_io.h>
|
#include <pcl/io/pcd_io.h>
|
||||||
@@ -65,7 +66,8 @@ namespace rtabmap {
|
|||||||
ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
|
ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
_canceled(false),
|
_canceled(false),
|
||||||
_compensator(0)
|
_compensator(0),
|
||||||
|
_dbDriver(0)
|
||||||
{
|
{
|
||||||
_ui = new Ui_ExportCloudsDialog();
|
_ui = new Ui_ExportCloudsDialog();
|
||||||
_ui->setupUi(this);
|
_ui->setupUi(this);
|
||||||
@@ -392,9 +394,9 @@ void ExportCloudsDialog::restoreDefaults()
|
|||||||
{
|
{
|
||||||
_ui->comboBox_pipeline->setCurrentIndex(1);
|
_ui->comboBox_pipeline->setCurrentIndex(1);
|
||||||
_ui->checkBox_binary->setChecked(true);
|
_ui->checkBox_binary->setChecked(true);
|
||||||
_ui->spinBox_normalKSearch->setValue(10);
|
_ui->spinBox_normalKSearch->setValue(20);
|
||||||
|
|
||||||
_ui->checkBox_regenerate->setChecked(false);
|
_ui->checkBox_regenerate->setChecked(_dbDriver!=0?true:false);
|
||||||
_ui->spinBox_decimation->setValue(1);
|
_ui->spinBox_decimation->setValue(1);
|
||||||
_ui->doubleSpinBox_maxDepth->setValue(4);
|
_ui->doubleSpinBox_maxDepth->setValue(4);
|
||||||
_ui->doubleSpinBox_minDepth->setValue(0);
|
_ui->doubleSpinBox_minDepth->setValue(0);
|
||||||
@@ -749,8 +751,17 @@ void ExportCloudsDialog::viewClouds(
|
|||||||
uIsInteger(mesh->tex_materials[0].tex_file, false))
|
uIsInteger(mesh->tex_materials[0].tex_file, false))
|
||||||
{
|
{
|
||||||
int textureId = uStr2Int(mesh->tex_materials[0].tex_file);
|
int textureId = uStr2Int(mesh->tex_materials[0].tex_file);
|
||||||
UASSERT(cachedSignatures.contains(textureId) && !cachedSignatures.value(textureId).sensorData().imageCompressed().empty());
|
SensorData data;
|
||||||
cachedSignatures.value(textureId).sensorData().uncompressDataConst(&globalTexture, 0);
|
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);
|
||||||
UASSERT(!globalTexture.empty());
|
UASSERT(!globalTexture.empty());
|
||||||
if (_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textureId) >= 0)
|
if (_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textureId) >= 0)
|
||||||
{
|
{
|
||||||
@@ -864,7 +875,11 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
{
|
{
|
||||||
_canceled = false;
|
_canceled = false;
|
||||||
_workingDirectory = workingDirectory;
|
_workingDirectory = workingDirectory;
|
||||||
enableRegeneration(cachedSignatures.size());
|
enableRegeneration(_dbDriver || cachedSignatures.size());
|
||||||
|
if(cachedSignatures.empty() && _dbDriver)
|
||||||
|
{
|
||||||
|
_ui->checkBox_regenerate->setChecked(true);
|
||||||
|
}
|
||||||
if(_compensator)
|
if(_compensator)
|
||||||
{
|
{
|
||||||
delete _compensator;
|
delete _compensator;
|
||||||
@@ -1073,17 +1088,26 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
// Adjust view points with local transforms
|
// Adjust view points with local transforms
|
||||||
for(std::map<int, Transform>::iterator iter= viewPoints.begin(); iter!=viewPoints.end(); ++iter)
|
for(std::map<int, Transform>::iterator iter= viewPoints.begin(); iter!=viewPoints.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
std::vector<CameraModel> models;
|
||||||
|
StereoCameraModel stereoModel;
|
||||||
if(cachedSignatures.contains(iter->first))
|
if(cachedSignatures.contains(iter->first))
|
||||||
{
|
{
|
||||||
const SensorData & data = cachedSignatures.find(iter->first)->sensorData();
|
const SensorData & data = cachedSignatures.find(iter->first)->sensorData();
|
||||||
if(data.cameraModels().size() && !data.cameraModels()[0].localTransform().isNull())
|
models = data.cameraModels();
|
||||||
{
|
stereoModel = data.stereoCameraModel();
|
||||||
iter->second *= data.cameraModels()[0].localTransform();
|
}
|
||||||
}
|
else if(_dbDriver)
|
||||||
else if(!data.stereoCameraModel().localTransform().isNull())
|
{
|
||||||
{
|
_dbDriver->getCalibration(iter->first, models, stereoModel);
|
||||||
iter->second *= data.stereoCameraModel().localTransform();
|
}
|
||||||
}
|
|
||||||
|
if(models.size() && !models[0].localTransform().isNull())
|
||||||
|
{
|
||||||
|
iter->second *= models[0].localTransform();
|
||||||
|
}
|
||||||
|
else if(!stereoModel.localTransform().isNull())
|
||||||
|
{
|
||||||
|
iter->second *= stereoModel.localTransform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1194,22 +1218,33 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
if(iter->second->size())
|
if(iter->second->size())
|
||||||
{
|
{
|
||||||
Eigen::Vector3f viewpoint(0.0f,0.0f,0.0f);
|
Eigen::Vector3f viewpoint(0.0f,0.0f,0.0f);
|
||||||
|
|
||||||
|
std::vector<CameraModel> models;
|
||||||
|
StereoCameraModel stereoModel;
|
||||||
if(cachedSignatures.contains(iter->first))
|
if(cachedSignatures.contains(iter->first))
|
||||||
{
|
{
|
||||||
const SensorData & data = cachedSignatures.find(iter->first)->sensorData();
|
const SensorData & data = cachedSignatures.find(iter->first)->sensorData();
|
||||||
if(data.cameraModels().size() && !data.cameraModels()[0].localTransform().isNull())
|
models = data.cameraModels();
|
||||||
{
|
stereoModel = data.stereoCameraModel();
|
||||||
viewpoint[0] = data.cameraModels()[0].localTransform().x();
|
|
||||||
viewpoint[1] = data.cameraModels()[0].localTransform().y();
|
|
||||||
viewpoint[2] = data.cameraModels()[0].localTransform().z();
|
|
||||||
}
|
|
||||||
else if(!data.stereoCameraModel().localTransform().isNull())
|
|
||||||
{
|
|
||||||
viewpoint[0] = data.stereoCameraModel().localTransform().x();
|
|
||||||
viewpoint[1] = data.stereoCameraModel().localTransform().y();
|
|
||||||
viewpoint[2] = data.stereoCameraModel().localTransform().z();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if(_dbDriver)
|
||||||
|
{
|
||||||
|
_dbDriver->getCalibration(iter->first, models, stereoModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(models.size() && !models[0].localTransform().isNull())
|
||||||
|
{
|
||||||
|
viewpoint[0] = models[0].localTransform().x();
|
||||||
|
viewpoint[1] = models[0].localTransform().y();
|
||||||
|
viewpoint[2] = models[0].localTransform().z();
|
||||||
|
}
|
||||||
|
else if(!stereoModel.localTransform().isNull())
|
||||||
|
{
|
||||||
|
viewpoint[0] = stereoModel.localTransform().x();
|
||||||
|
viewpoint[1] = stereoModel.localTransform().y();
|
||||||
|
viewpoint[2] = stereoModel.localTransform().z();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<pcl::Vertices> polygons = util3d::organizedFastMesh(
|
std::vector<pcl::Vertices> polygons = util3d::organizedFastMesh(
|
||||||
iter->second,
|
iter->second,
|
||||||
_ui->doubleSpinBox_mesh_angleTolerance->value()*M_PI/180.0,
|
_ui->doubleSpinBox_mesh_angleTolerance->value()*M_PI/180.0,
|
||||||
@@ -1766,29 +1801,52 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
std::map<int, CameraModel> cameraModels;
|
std::map<int, CameraModel> cameraModels;
|
||||||
for(std::map<int, Transform>::iterator jter=cameras.begin(); jter!=cameras.end(); ++jter)
|
for(std::map<int, Transform>::iterator jter=cameras.begin(); jter!=cameras.end(); ++jter)
|
||||||
{
|
{
|
||||||
|
std::vector<CameraModel> models;
|
||||||
|
StereoCameraModel stereoModel;
|
||||||
|
bool cacheHasCompressedImage = false;
|
||||||
if(cachedSignatures.contains(jter->first))
|
if(cachedSignatures.contains(jter->first))
|
||||||
{
|
{
|
||||||
const Signature & s = cachedSignatures.value(jter->first);
|
const SensorData & data = cachedSignatures.find(jter->first)->sensorData();
|
||||||
CameraModel model;
|
models = data.cameraModels();
|
||||||
if(s.sensorData().stereoCameraModel().isValidForProjection())
|
stereoModel = data.stereoCameraModel();
|
||||||
{
|
cacheHasCompressedImage = !data.imageCompressed().empty();
|
||||||
model = s.sensorData().stereoCameraModel().left();
|
}
|
||||||
}
|
else if(_dbDriver)
|
||||||
else if(s.sensorData().cameraModels().size() == 1 && s.sensorData().cameraModels()[0].isValidForProjection())
|
{
|
||||||
{
|
_dbDriver->getCalibration(jter->first, models, stereoModel);
|
||||||
model = s.sensorData().cameraModels()[0];
|
}
|
||||||
}
|
|
||||||
if(!jter->second.isNull() && model.isValidForProjection() && !s.sensorData().imageCompressed().empty())
|
|
||||||
{
|
|
||||||
if(model.imageWidth() == 0 || model.imageHeight() == 0)
|
|
||||||
{
|
|
||||||
// we are using an old database format (image size not saved in calibrations), we should
|
|
||||||
// uncompress images to get their size
|
|
||||||
cv::Mat img;
|
|
||||||
s.sensorData().uncompressDataConst(&img, 0);
|
|
||||||
model.setImageSize(img.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
CameraModel model;
|
||||||
|
if(stereoModel.isValidForProjection())
|
||||||
|
{
|
||||||
|
model = stereoModel.left();
|
||||||
|
}
|
||||||
|
else if(models.size() == 1 && models[0].isValidForProjection())
|
||||||
|
{
|
||||||
|
model = models[0];
|
||||||
|
}
|
||||||
|
if(!jter->second.isNull() && model.isValidForProjection())
|
||||||
|
{
|
||||||
|
if(model.imageWidth() == 0 || model.imageHeight() == 0)
|
||||||
|
{
|
||||||
|
// we are using an old database format (image size not saved in calibrations), we should
|
||||||
|
// uncompress images to get their size
|
||||||
|
cv::Mat img;
|
||||||
|
if(cacheHasCompressedImage)
|
||||||
|
{
|
||||||
|
cachedSignatures.find(jter->first)->sensorData().uncompressDataConst(&img, 0);
|
||||||
|
}
|
||||||
|
else if(_dbDriver)
|
||||||
|
{
|
||||||
|
SensorData data;
|
||||||
|
_dbDriver->getNodeData(jter->first, data, true, false, false, false);
|
||||||
|
data.uncompressDataConst(&img, 0);
|
||||||
|
}
|
||||||
|
model.setImageSize(img.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(model.imageWidth() != 0 && model.imageHeight() != 0)
|
||||||
|
{
|
||||||
cameraPoses.insert(std::make_pair(jter->first, jter->second));
|
cameraPoses.insert(std::make_pair(jter->first, jter->second));
|
||||||
cameraModels.insert(std::make_pair(jter->first, model));
|
cameraModels.insert(std::make_pair(jter->first, model));
|
||||||
}
|
}
|
||||||
@@ -2096,118 +2154,125 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
|||||||
pcl::IndicesPtr indices(new std::vector<int>);
|
pcl::IndicesPtr indices(new std::vector<int>);
|
||||||
if(_ui->checkBox_regenerate->isChecked())
|
if(_ui->checkBox_regenerate->isChecked())
|
||||||
{
|
{
|
||||||
|
SensorData data;
|
||||||
|
cv::Mat image, depth;
|
||||||
if(cachedSignatures.contains(iter->first))
|
if(cachedSignatures.contains(iter->first))
|
||||||
{
|
{
|
||||||
const Signature & s = cachedSignatures.find(iter->first).value();
|
const Signature & s = cachedSignatures.find(iter->first).value();
|
||||||
SensorData d = s.sensorData();
|
data = s.sensorData();
|
||||||
cv::Mat image, depth;
|
data.uncompressData(&image, &depth, 0);
|
||||||
d.uncompressData(&image, &depth, 0);
|
}
|
||||||
if(!image.empty() && !depth.empty())
|
else if(_dbDriver)
|
||||||
|
{
|
||||||
|
_dbDriver->getNodeData(iter->first, data, true, false, false, false);
|
||||||
|
data.uncompressData(&image, &depth, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!image.empty() && !depth.empty())
|
||||||
|
{
|
||||||
|
if(_ui->spinBox_fillDepthHoles->value() > 0)
|
||||||
{
|
{
|
||||||
if(_ui->spinBox_fillDepthHoles->value() > 0)
|
depth = util2d::fillDepthHoles(depth, _ui->spinBox_fillDepthHoles->value(), float(_ui->spinBox_fillDepthHolesError->value())/100.f);
|
||||||
{
|
}
|
||||||
depth = util2d::fillDepthHoles(depth, _ui->spinBox_fillDepthHoles->value(), float(_ui->spinBox_fillDepthHolesError->value())/100.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!_ui->lineEdit_distortionModel->text().isEmpty() &&
|
if(!_ui->lineEdit_distortionModel->text().isEmpty() &&
|
||||||
QFileInfo(_ui->lineEdit_distortionModel->text()).exists())
|
QFileInfo(_ui->lineEdit_distortionModel->text()).exists())
|
||||||
{
|
{
|
||||||
clams::DiscreteDepthDistortionModel model;
|
clams::DiscreteDepthDistortionModel model;
|
||||||
model.load(_ui->lineEdit_distortionModel->text().toStdString());
|
model.load(_ui->lineEdit_distortionModel->text().toStdString());
|
||||||
depth = depth.clone();// make sure we are not modifying data in cached signatures.
|
depth = depth.clone();// make sure we are not modifying data in cached signatures.
|
||||||
model.undistort(depth);
|
model.undistort(depth);
|
||||||
d.setDepthOrRightRaw(depth);
|
data.setDepthOrRightRaw(depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bilateral filtering
|
// bilateral filtering
|
||||||
if(_ui->checkBox_bilateral->isChecked())
|
if(_ui->checkBox_bilateral->isChecked())
|
||||||
{
|
{
|
||||||
depth = util2d::fastBilateralFiltering(depth,
|
depth = util2d::fastBilateralFiltering(depth,
|
||||||
_ui->doubleSpinBox_bilateral_sigmaS->value(),
|
_ui->doubleSpinBox_bilateral_sigmaS->value(),
|
||||||
_ui->doubleSpinBox_bilateral_sigmaR->value());
|
_ui->doubleSpinBox_bilateral_sigmaR->value());
|
||||||
d.setDepthOrRightRaw(depth);
|
data.setDepthOrRightRaw(depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
UASSERT(iter->first == d.id());
|
UASSERT(iter->first == data.id());
|
||||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudWithoutNormals;
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudWithoutNormals;
|
||||||
std::vector<float> roiRatios;
|
std::vector<float> roiRatios;
|
||||||
if(!_ui->lineEdit_roiRatios->text().isEmpty())
|
if(!_ui->lineEdit_roiRatios->text().isEmpty())
|
||||||
|
{
|
||||||
|
QStringList values = _ui->lineEdit_roiRatios->text().split(' ');
|
||||||
|
if(values.size() == 4)
|
||||||
{
|
{
|
||||||
QStringList values = _ui->lineEdit_roiRatios->text().split(' ');
|
roiRatios.resize(4);
|
||||||
if(values.size() == 4)
|
for(int i=0; i<values.size(); ++i)
|
||||||
{
|
{
|
||||||
roiRatios.resize(4);
|
roiRatios[i] = uStr2Float(values[i].toStdString().c_str());
|
||||||
for(int i=0; i<values.size(); ++i)
|
|
||||||
{
|
|
||||||
roiRatios[i] = uStr2Float(values[i].toStdString().c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cloudWithoutNormals = util3d::cloudRGBFromSensorData(
|
}
|
||||||
d,
|
cloudWithoutNormals = util3d::cloudRGBFromSensorData(
|
||||||
_ui->spinBox_decimation->value() == 0?1:_ui->spinBox_decimation->value(),
|
data,
|
||||||
_ui->doubleSpinBox_maxDepth->value(),
|
_ui->spinBox_decimation->value() == 0?1:_ui->spinBox_decimation->value(),
|
||||||
_ui->doubleSpinBox_minDepth->value(),
|
_ui->doubleSpinBox_maxDepth->value(),
|
||||||
indices.get(),
|
_ui->doubleSpinBox_minDepth->value(),
|
||||||
parameters,
|
indices.get(),
|
||||||
roiRatios);
|
parameters,
|
||||||
|
roiRatios);
|
||||||
|
|
||||||
if(cloudWithoutNormals->size())
|
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)
|
||||||
{
|
{
|
||||||
// Don't voxelize if we create organized mesh
|
cloudWithoutNormals = util3d::voxelize(cloudWithoutNormals, indices, _ui->doubleSpinBox_voxelSize_assembled->value());
|
||||||
if(!(_ui->comboBox_pipeline->currentIndex()==0 && _ui->checkBox_meshing->isChecked()) && _ui->doubleSpinBox_voxelSize_assembled->value()>0.0)
|
indices->resize(cloudWithoutNormals->size());
|
||||||
|
for(unsigned int i=0; i<indices->size(); ++i)
|
||||||
{
|
{
|
||||||
cloudWithoutNormals = util3d::voxelize(cloudWithoutNormals, indices, _ui->doubleSpinBox_voxelSize_assembled->value());
|
indices->at(i) = i;
|
||||||
indices->resize(cloudWithoutNormals->size());
|
|
||||||
for(unsigned int i=0; i<indices->size(); ++i)
|
|
||||||
{
|
|
||||||
indices->at(i) = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// view point
|
// view point
|
||||||
Eigen::Vector3f viewPoint(0.0f,0.0f,0.0f);
|
Eigen::Vector3f viewPoint(0.0f,0.0f,0.0f);
|
||||||
if(d.cameraModels().size() && !d.cameraModels()[0].localTransform().isNull())
|
if(data.cameraModels().size() && !data.cameraModels()[0].localTransform().isNull())
|
||||||
{
|
{
|
||||||
viewPoint[0] = d.cameraModels()[0].localTransform().x();
|
viewPoint[0] = data.cameraModels()[0].localTransform().x();
|
||||||
viewPoint[1] = d.cameraModels()[0].localTransform().y();
|
viewPoint[1] = data.cameraModels()[0].localTransform().y();
|
||||||
viewPoint[2] = d.cameraModels()[0].localTransform().z();
|
viewPoint[2] = data.cameraModels()[0].localTransform().z();
|
||||||
}
|
}
|
||||||
else if(!d.stereoCameraModel().localTransform().isNull())
|
else if(!data.stereoCameraModel().localTransform().isNull())
|
||||||
{
|
{
|
||||||
viewPoint[0] = d.stereoCameraModel().localTransform().x();
|
viewPoint[0] = data.stereoCameraModel().localTransform().x();
|
||||||
viewPoint[1] = d.stereoCameraModel().localTransform().y();
|
viewPoint[1] = data.stereoCameraModel().localTransform().y();
|
||||||
viewPoint[2] = d.stereoCameraModel().localTransform().z();
|
viewPoint[2] = data.stereoCameraModel().localTransform().z();
|
||||||
}
|
}
|
||||||
|
|
||||||
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value(), viewPoint);
|
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value(), viewPoint);
|
||||||
pcl::concatenateFields(*cloudWithoutNormals, *normals, *cloud);
|
pcl::concatenateFields(*cloudWithoutNormals, *normals, *cloud);
|
||||||
|
|
||||||
if(_ui->checkBox_subtraction->isChecked() &&
|
if(_ui->checkBox_subtraction->isChecked() &&
|
||||||
_ui->doubleSpinBox_subtractPointFilteringRadius->value() > 0.0)
|
_ui->doubleSpinBox_subtractPointFilteringRadius->value() > 0.0)
|
||||||
|
{
|
||||||
|
pcl::IndicesPtr beforeSubtractionIndices = indices;
|
||||||
|
if( cloud->size() &&
|
||||||
|
previousCloud.get() != 0 &&
|
||||||
|
previousIndices.get() != 0 &&
|
||||||
|
previousIndices->size() &&
|
||||||
|
!previousPose.isNull())
|
||||||
{
|
{
|
||||||
pcl::IndicesPtr beforeSubtractionIndices = indices;
|
rtabmap::Transform t = iter->second.inverse() * previousPose;
|
||||||
if( cloud->size() &&
|
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr transformedCloud = rtabmap::util3d::transformPointCloud(previousCloud, t);
|
||||||
previousCloud.get() != 0 &&
|
indices = rtabmap::util3d::subtractFiltering(
|
||||||
previousIndices.get() != 0 &&
|
cloud,
|
||||||
previousIndices->size() &&
|
indices,
|
||||||
!previousPose.isNull())
|
transformedCloud,
|
||||||
{
|
previousIndices,
|
||||||
rtabmap::Transform t = iter->second.inverse() * previousPose;
|
_ui->doubleSpinBox_subtractPointFilteringRadius->value(),
|
||||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr transformedCloud = rtabmap::util3d::transformPointCloud(previousCloud, t);
|
_ui->doubleSpinBox_subtractPointFilteringAngle->value(),
|
||||||
indices = rtabmap::util3d::subtractFiltering(
|
_ui->spinBox_subtractFilteringMinPts->value());
|
||||||
cloud,
|
|
||||||
indices,
|
|
||||||
transformedCloud,
|
|
||||||
previousIndices,
|
|
||||||
_ui->doubleSpinBox_subtractPointFilteringRadius->value(),
|
|
||||||
_ui->doubleSpinBox_subtractPointFilteringAngle->value(),
|
|
||||||
_ui->spinBox_subtractFilteringMinPts->value());
|
|
||||||
}
|
|
||||||
previousCloud = cloud;
|
|
||||||
previousIndices = beforeSubtractionIndices;
|
|
||||||
previousPose = iter->second;
|
|
||||||
}
|
}
|
||||||
|
previousCloud = cloud;
|
||||||
|
previousIndices = beforeSubtractionIndices;
|
||||||
|
previousPose = iter->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2242,22 +2307,30 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
|||||||
|
|
||||||
// view point
|
// view point
|
||||||
Eigen::Vector3f viewPoint(0.0f,0.0f,0.0f);
|
Eigen::Vector3f viewPoint(0.0f,0.0f,0.0f);
|
||||||
|
std::vector<CameraModel> models;
|
||||||
|
StereoCameraModel stereoModel;
|
||||||
if(cachedSignatures.contains(iter->first))
|
if(cachedSignatures.contains(iter->first))
|
||||||
{
|
{
|
||||||
const Signature & s = cachedSignatures.find(iter->first).value();
|
const Signature & s = cachedSignatures.find(iter->first).value();
|
||||||
SensorData d = s.sensorData();
|
models = s.sensorData().cameraModels();
|
||||||
if(d.cameraModels().size() && !d.cameraModels()[0].localTransform().isNull())
|
stereoModel = s.sensorData().stereoCameraModel();
|
||||||
{
|
}
|
||||||
viewPoint[0] = d.cameraModels()[0].localTransform().x();
|
else if(_dbDriver)
|
||||||
viewPoint[1] = d.cameraModels()[0].localTransform().y();
|
{
|
||||||
viewPoint[2] = d.cameraModels()[0].localTransform().z();
|
_dbDriver->getCalibration(iter->first, models, stereoModel);
|
||||||
}
|
}
|
||||||
else if(!d.stereoCameraModel().localTransform().isNull())
|
|
||||||
{
|
if(models.size() && !models[0].localTransform().isNull())
|
||||||
viewPoint[0] = d.stereoCameraModel().localTransform().x();
|
{
|
||||||
viewPoint[1] = d.stereoCameraModel().localTransform().y();
|
viewPoint[0] = models[0].localTransform().x();
|
||||||
viewPoint[2] = d.stereoCameraModel().localTransform().z();
|
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();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2605,7 +2678,7 @@ cv::Mat ExportCloudsDialog::mergeTextures(pcl::TextureMesh & mesh, const QMap<in
|
|||||||
{
|
{
|
||||||
std::vector<int> textures(mesh.tex_materials.size(), -1);
|
std::vector<int> textures(mesh.tex_materials.size(), -1);
|
||||||
cv::Size imageSize;
|
cv::Size imageSize;
|
||||||
int imageType=CV_8UC1;
|
const int imageType=CV_8UC3;
|
||||||
UDEBUG("");
|
UDEBUG("");
|
||||||
bool mergeTextures = true;
|
bool mergeTextures = true;
|
||||||
for(unsigned int i=0; i<mesh.tex_materials.size(); ++i)
|
for(unsigned int i=0; i<mesh.tex_materials.size(); ++i)
|
||||||
@@ -2617,42 +2690,57 @@ cv::Mat ExportCloudsDialog::mergeTextures(pcl::TextureMesh & mesh, const QMap<in
|
|||||||
int textureId = uStr2Int(mesh.tex_materials[i].tex_file);
|
int textureId = uStr2Int(mesh.tex_materials[i].tex_file);
|
||||||
textures[i] = textureId;
|
textures[i] = textureId;
|
||||||
|
|
||||||
QMap<int, Signature>::const_iterator iter = cachedSignatures.find(textureId);
|
if(imageSize.width == 0 || imageSize.height == 0)
|
||||||
UASSERT(iter!=cachedSignatures.end() && !iter->sensorData().imageCompressed().empty());
|
|
||||||
|
|
||||||
cv::Size tmpImageSize;
|
|
||||||
if(iter->sensorData().cameraModels().size()==1 &&
|
|
||||||
iter->sensorData().cameraModels()[0].imageHeight()>0 &&
|
|
||||||
iter->sensorData().cameraModels()[0].imageWidth()>0)
|
|
||||||
{
|
{
|
||||||
tmpImageSize = iter->sensorData().cameraModels()[0].imageSize();
|
if(cachedSignatures.find(textureId)!=cachedSignatures.end() && !cachedSignatures.find(textureId)->sensorData().imageCompressed().empty())
|
||||||
if(imageSize.height == 0 && imageSize.width == 0)
|
|
||||||
{
|
{
|
||||||
// just for the first image, get the type, assuming all others have the same type
|
SensorData data = cachedSignatures.find(textureId).value().sensorData();
|
||||||
cv::Mat image;
|
if(data.cameraModels().size()==1 &&
|
||||||
iter->sensorData().uncompressDataConst(&image, 0);
|
data.cameraModels()[0].imageHeight()>0 &&
|
||||||
UASSERT(!image.empty());
|
data.cameraModels()[0].imageWidth()>0)
|
||||||
imageType = image.type();
|
{
|
||||||
|
imageSize = data.cameraModels()[0].imageSize();
|
||||||
|
}
|
||||||
|
else if(data.stereoCameraModel().left().imageHeight() > 0 &&
|
||||||
|
data.stereoCameraModel().left().imageWidth() > 0)
|
||||||
|
{
|
||||||
|
imageSize = data.stereoCameraModel().left().imageSize();
|
||||||
|
}
|
||||||
|
else // backward compatibility for image size not set in CameraModel
|
||||||
|
{
|
||||||
|
cv::Mat image;
|
||||||
|
data.uncompressDataConst(&image, 0);
|
||||||
|
UASSERT(!image.empty());
|
||||||
|
imageSize = image.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(_dbDriver)
|
||||||
|
{
|
||||||
|
std::vector<CameraModel> models;
|
||||||
|
StereoCameraModel stereoModel;
|
||||||
|
_dbDriver->getCalibration(textureId, models, stereoModel);
|
||||||
|
if(models.size()==1 &&
|
||||||
|
models[0].imageHeight()>0 &&
|
||||||
|
models[0].imageWidth()>0)
|
||||||
|
{
|
||||||
|
imageSize = models[0].imageSize();
|
||||||
|
}
|
||||||
|
else if(stereoModel.left().imageHeight() > 0 &&
|
||||||
|
stereoModel.left().imageWidth() > 0)
|
||||||
|
{
|
||||||
|
imageSize = stereoModel.left().imageSize();
|
||||||
|
}
|
||||||
|
else // backward compatibility for image size not set in CameraModel
|
||||||
|
{
|
||||||
|
SensorData data;
|
||||||
|
_dbDriver->getNodeData(textureId, data, true, false, false, false);
|
||||||
|
cv::Mat image;
|
||||||
|
data.uncompressDataConst(&image, 0);
|
||||||
|
UASSERT(!image.empty());
|
||||||
|
imageSize = image.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // backward compatibility for image size not set in CameraModel
|
|
||||||
{
|
|
||||||
cv::Mat image;
|
|
||||||
iter->sensorData().uncompressDataConst(&image, 0);
|
|
||||||
UASSERT(!image.empty());
|
|
||||||
tmpImageSize = image.size();
|
|
||||||
if(imageSize.height == 0 && imageSize.width == 0)
|
|
||||||
{
|
|
||||||
imageType = image.type();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(imageSize.width>0 && imageSize.height>0 && imageSize.width != tmpImageSize.width)
|
|
||||||
{
|
|
||||||
UWARN("All images should have the same dimensions to merge the textures!");
|
|
||||||
mergeTextures = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
imageSize = tmpImageSize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mergeTextures && textures.size() && imageSize.height>0 && imageSize.width>0)
|
if(mergeTextures && textures.size() && imageSize.height>0 && imageSize.width>0)
|
||||||
@@ -2680,13 +2768,30 @@ cv::Mat ExportCloudsDialog::mergeTextures(pcl::TextureMesh & mesh, const QMap<in
|
|||||||
UASSERT(v < textureSize-emptyImage.rows);
|
UASSERT(v < textureSize-emptyImage.rows);
|
||||||
if(textures[t]>=0)
|
if(textures[t]>=0)
|
||||||
{
|
{
|
||||||
QMap<int, Signature>::const_iterator iter = cachedSignatures.find(textures[t]);
|
|
||||||
UASSERT(iter!=cachedSignatures.end() && !iter->sensorData().imageCompressed().empty());
|
|
||||||
cv::Mat image;
|
cv::Mat image;
|
||||||
iter->sensorData().uncompressDataConst(&image, 0);
|
|
||||||
|
if(cachedSignatures.find(textures[t]) != cachedSignatures.end() &&
|
||||||
|
!cachedSignatures.find(textures[t])->sensorData().imageCompressed().empty())
|
||||||
|
{
|
||||||
|
cachedSignatures.find(textures[t])->sensorData().uncompressDataConst(&image, 0);
|
||||||
|
}
|
||||||
|
else if(_dbDriver)
|
||||||
|
{
|
||||||
|
SensorData data;
|
||||||
|
_dbDriver->getNodeData(textures[t], data, true, false, false, false);
|
||||||
|
data.uncompressDataConst(&image, 0);
|
||||||
|
}
|
||||||
|
|
||||||
UASSERT(!image.empty());
|
UASSERT(!image.empty());
|
||||||
cv::Mat resizedImage;
|
cv::Mat resizedImage;
|
||||||
cv::resize(image, resizedImage, emptyImage.size(), 0.0f, 0.0f, cv::INTER_AREA);
|
cv::resize(image, resizedImage, emptyImage.size(), 0.0f, 0.0f, cv::INTER_AREA);
|
||||||
|
UASSERT(resizedImage.type() == CV_8UC1 || resizedImage.type() == CV_8UC3);
|
||||||
|
if(resizedImage.type() == CV_8UC1)
|
||||||
|
{
|
||||||
|
cv::Mat resizedImageColor;
|
||||||
|
cv::cvtColor(resizedImage, resizedImageColor, CV_GRAY2BGR);
|
||||||
|
resizedImage = resizedImageColor;
|
||||||
|
}
|
||||||
if(_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textures[t]) >= 0)
|
if(_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textures[t]) >= 0)
|
||||||
{
|
{
|
||||||
_compensator->apply(textures[t], resizedImage);
|
_compensator->apply(textures[t], resizedImage);
|
||||||
@@ -2766,9 +2871,17 @@ void ExportCloudsDialog::saveTextureMeshes(
|
|||||||
if(uIsInteger(mesh->tex_materials[i].tex_file, false))
|
if(uIsInteger(mesh->tex_materials[i].tex_file, false))
|
||||||
{
|
{
|
||||||
int textureId = uStr2Int(mesh->tex_materials[i].tex_file);
|
int textureId = uStr2Int(mesh->tex_materials[i].tex_file);
|
||||||
UASSERT(cachedSignatures.contains(textureId) && !cachedSignatures.value(textureId).sensorData().imageCompressed().empty());
|
|
||||||
cv::Mat image;
|
cv::Mat image;
|
||||||
cachedSignatures.value(textureId).sensorData().uncompressDataConst(&image, 0);
|
if(cachedSignatures.contains(textureId) && !cachedSignatures.value(textureId).sensorData().imageCompressed().empty())
|
||||||
|
{
|
||||||
|
cachedSignatures.value(textureId).sensorData().uncompressDataConst(&image, 0);
|
||||||
|
}
|
||||||
|
else if(_dbDriver)
|
||||||
|
{
|
||||||
|
SensorData data;
|
||||||
|
_dbDriver->getNodeData(textureId, data, true, false, false, false);
|
||||||
|
data.uncompressDataConst(&image, 0);
|
||||||
|
}
|
||||||
UASSERT(!image.empty());
|
UASSERT(!image.empty());
|
||||||
imageSize = image.size();
|
imageSize = image.size();
|
||||||
if(_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textureId) >= 0)
|
if(_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textureId) >= 0)
|
||||||
@@ -2886,9 +2999,18 @@ void ExportCloudsDialog::saveTextureMeshes(
|
|||||||
if(uIsInteger(mesh->tex_materials[i].tex_file, false))
|
if(uIsInteger(mesh->tex_materials[i].tex_file, false))
|
||||||
{
|
{
|
||||||
int textureId = uStr2Int(mesh->tex_materials[i].tex_file);
|
int textureId = uStr2Int(mesh->tex_materials[i].tex_file);
|
||||||
UASSERT(cachedSignatures.contains(textureId) && !cachedSignatures.value(textureId).sensorData().imageCompressed().empty());
|
|
||||||
cv::Mat image;
|
cv::Mat image;
|
||||||
cachedSignatures.value(textureId).sensorData().uncompressDataConst(&image, 0);
|
if(cachedSignatures.contains(textureId) && !cachedSignatures.value(textureId).sensorData().imageCompressed().empty())
|
||||||
|
{
|
||||||
|
cachedSignatures.value(textureId).sensorData().uncompressDataConst(&image, 0);
|
||||||
|
}
|
||||||
|
else if(_dbDriver)
|
||||||
|
{
|
||||||
|
SensorData data;
|
||||||
|
_dbDriver->getNodeData(textureId, data, true, false, false, false);
|
||||||
|
data.uncompressDataConst(&image, 0);
|
||||||
|
}
|
||||||
|
|
||||||
UASSERT(!image.empty());
|
UASSERT(!image.empty());
|
||||||
imageSize = image.size();
|
imageSize = image.size();
|
||||||
if(_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textureId) >= 0)
|
if(_ui->checkBox_gainCompensation->isChecked() && _compensator && _compensator->getIndex(textureId) >= 0)
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class QAbstractButton;
|
|||||||
namespace rtabmap {
|
namespace rtabmap {
|
||||||
class ProgressDialog;
|
class ProgressDialog;
|
||||||
class GainCompensator;
|
class GainCompensator;
|
||||||
|
class DBDriver;
|
||||||
|
|
||||||
class ExportCloudsDialog : public QDialog
|
class ExportCloudsDialog : public QDialog
|
||||||
{
|
{
|
||||||
@@ -60,6 +61,8 @@ public:
|
|||||||
void saveSettings(QSettings & settings, const QString & group = "") const;
|
void saveSettings(QSettings & settings, const QString & group = "") const;
|
||||||
void loadSettings(QSettings & settings, const QString & group = "");
|
void loadSettings(QSettings & settings, const QString & group = "");
|
||||||
|
|
||||||
|
void setDBDriver(const DBDriver * dbDriver) {_dbDriver = dbDriver;}
|
||||||
|
|
||||||
void exportClouds(
|
void exportClouds(
|
||||||
const std::map<int, Transform> & poses,
|
const std::map<int, Transform> & poses,
|
||||||
const std::multimap<int, Link> & links,
|
const std::multimap<int, Link> & links,
|
||||||
@@ -124,6 +127,7 @@ private:
|
|||||||
QString _workingDirectory;
|
QString _workingDirectory;
|
||||||
bool _canceled;
|
bool _canceled;
|
||||||
GainCompensator * _compensator;
|
GainCompensator * _compensator;
|
||||||
|
const DBDriver * _dbDriver;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1285</width>
|
<width>1392</width>
|
||||||
<height>965</height>
|
<height>965</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>253</width>
|
<width>339</width>
|
||||||
<height>208</height>
|
<height>208</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -210,7 +210,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>253</width>
|
<width>339</width>
|
||||||
<height>208</height>
|
<height>208</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -483,7 +483,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1285</width>
|
<width>1392</width>
|
||||||
<height>22</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -987,7 +987,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QToolBox" name="toolBox">
|
<widget class="QToolBox" name="toolBox">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>3</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="page_3">
|
<widget class="QWidget" name="page_3">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
@@ -1131,7 +1131,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>280</width>
|
<width>280</width>
|
||||||
<height>584</height>
|
<height>608</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -1174,7 +1174,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLabel" name="label_51">
|
<widget class="QLabel" name="label_51">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Gain compensation radius (Constraints view)</string>
|
<string>Gain compensation radius (Constraints view)</string>
|
||||||
@@ -1184,7 +1184,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_gainCompensationRadius">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_gainCompensationRadius">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string> m</string>
|
<string> m</string>
|
||||||
@@ -1206,6 +1206,20 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="label_53">
|
||||||
|
<property name="text">
|
||||||
|
<string>OctoMap</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="checkBox_octomap">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -1547,8 +1561,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>333</width>
|
<width>186</width>
|
||||||
<height>256</height>
|
<height>496</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -1911,6 +1925,94 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QDockWidget" name="dockWidget_occupancyGridView">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Occupancy Grid</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="dockWidgetArea">
|
||||||
|
<number>4</number>
|
||||||
|
</attribute>
|
||||||
|
<widget class="QWidget" name="dockWidgetContents_occupancyGrid">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_14" stretch="1,0">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="layout_occupancyGridView">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_grid_2d">
|
||||||
|
<property name="text">
|
||||||
|
<string>2d Map</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_grid_cubes">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cubes Rendering</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_grid_empty">
|
||||||
|
<property name="text">
|
||||||
|
<string>Empty Space</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_grid_depth">
|
||||||
|
<property name="prefix">
|
||||||
|
<string>Depth </string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
<action name="actionOpen_database">
|
<action name="actionOpen_database">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open database</string>
|
<string>Open database</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user