DatabaseViewer: Added ExportCloudsDialog, added Occupancy Grid View

This commit is contained in:
matlabbe
2017-03-21 21:51:39 -04:00
parent 622352b411
commit 2574f3a8ee
8 changed files with 892 additions and 522 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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_;

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
}; };
} }

View File

@@ -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>