0.19.6: Added auto brightness/contrast and texture format options to multiband approach. rtabmap-export moved from examples to tools directory.

This commit is contained in:
matlabbe
2019-11-03 14:10:02 -05:00
parent 5d789f75a9
commit 179f17d267
17 changed files with 337 additions and 190 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
#######################
SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 19)
SET(RTABMAP_PATCH_VERSION 5)
SET(RTABMAP_PATCH_VERSION 6)
SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
+3 -1
View File
@@ -147,7 +147,9 @@ cv::Mat RTABMAP_EXP brightnessAndContrastAuto(
const cv::Mat & src,
const cv::Mat & mask,
float clipLowHistPercent=0,
float clipHighHistPercent=0);
float clipHighHistPercent=0,
float * alphaOut = 0,
float * betaOut = 0);
cv::Mat RTABMAP_EXP exposureFusion(
const std::vector<cv::Mat> & images);
@@ -223,7 +223,8 @@ cv::Mat RTABMAP_EXP mergeTextures(
const ProgressState * state = 0,
unsigned char blankValue = 255, //Gray value for blank polygons (without texture)
std::map<int, std::map<int, cv::Vec4d> > * gains = 0, // <Camera ID, Camera Sub Index (multi-cameras), gains Gray-R-G-B>
std::map<int, std::map<int, cv::Mat> > * blendingGains = 0); // <Camera ID, Camera Sub Index (multi-cameras), gains>
std::map<int, std::map<int, cv::Mat> > * blendingGains = 0, // <Camera ID, Camera Sub Index (multi-cameras), gains>
std::pair<float, float> * contrastValues = 0); // Alpha/beta contrast values
cv::Mat RTABMAP_EXP mergeTextures(
pcl::TextureMesh & mesh,
const std::map<int, cv::Mat> & images, // raw or compressed, can be empty if memory or dbDriver should be used
@@ -244,13 +245,15 @@ cv::Mat RTABMAP_EXP mergeTextures(
const ProgressState * state = 0,
unsigned char blankValue = 255, //Gray value for blank polygons (without texture)
std::map<int, std::map<int, cv::Vec4d> > * gains = 0, // <Camera ID, Camera Sub Index (multi-cameras), gains Gray-R-G-B>
std::map<int, std::map<int, cv::Mat> > * blendingGains = 0); // <Camera ID, Camera Sub Index (multi-cameras), gains>
std::map<int, std::map<int, cv::Mat> > * blendingGains = 0, // <Camera ID, Camera Sub Index (multi-cameras), gains>
std::pair<float, float> * contrastValues = 0); // Alpha/beta contrast values
void RTABMAP_EXP fixTextureMeshForVisualization(pcl::TextureMesh & textureMesh);
bool RTABMAP_EXP multiBandTexturing(
const std::string & outputOBJPath,
const pcl::PolygonMesh & mesh,
const pcl::PCLPointCloud2 & cloud,
const std::vector<pcl::Vertices> & polygons,
const std::map<int, Transform> & cameraPoses,
const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels, // required output of util3d::createTextureMesh()
const std::map<int, cv::Mat> & images, // raw or compressed, can be empty if memory or dbDriver should be used
@@ -258,8 +261,10 @@ bool RTABMAP_EXP multiBandTexturing(
const Memory * memory = 0, // Should be set if images are not set
const DBDriver * dbDriver = 0, // Should be set if images and memory are not set
int textureSize = 8192,
const std::string & textureFormat = "jpg", // png, jpg
const std::map<int, std::map<int, cv::Vec4d> > & gains = std::map<int, std::map<int, cv::Vec4d> >(), // optional output of util3d::mergeTextures()
const std::map<int, std::map<int, cv::Mat> > & blendingGains = std::map<int, std::map<int, cv::Mat> >()); // optional output of util3d::mergeTextures()
const std::map<int, std::map<int, cv::Mat> > & blendingGains = std::map<int, std::map<int, cv::Mat> >(), // optional output of util3d::mergeTextures()
const std::pair<float, float> & contrastValues = std::pair<float, float>(0,0)); // optional output of util3d::mergeTextures()
cv::Mat RTABMAP_EXP computeNormals(
const cv::Mat & laserScan,
+1 -1
View File
@@ -604,7 +604,7 @@ void Optimizer::computeBACorrespondences(
ParametersMap regParam;
regParam.insert(ParametersPair(Parameters::kVisEstimationType(), "1"));
regParam.insert(ParametersPair(Parameters::kVisPnPReprojError(), "5"));
regParam.insert(ParametersPair(Parameters::kVisMinInliers(), "5"));
regParam.insert(ParametersPair(Parameters::kVisMinInliers(), "6"));
regParam.insert(ParametersPair(Parameters::kVisCorNNDR(), "0.6"));
RegistrationVis reg(regParam);
+5 -1
View File
@@ -119,7 +119,11 @@ void RegistrationVis::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kVisMeanInliersDistance(), _maxInliersMeanDistance);
uInsert(_bundleParameters, parameters);
UASSERT_MSG(_minInliers >= 1, uFormat("value=%d", _minInliers).c_str());
if(_minInliers < 6)
{
UWARN("%s should be >= 6 but it is set to %d, setting to 6.", Parameters::kVisMinInliers().c_str(), _minInliers);
_minInliers = 6;
}
UASSERT_MSG(_inlierDistance > 0.0f, uFormat("value=%f", _inlierDistance).c_str());
UASSERT_MSG(_iterations > 0, uFormat("value=%d", _iterations).c_str());
+16 -8
View File
@@ -4468,15 +4468,12 @@ int Rtabmap::detectMoreLoopClosures(
std::map<int, int> mapIds;
UDEBUG("remove all invalid or intermediate nodes, fill mapIds");
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end();++iter)
for(std::map<int, Transform>::iterator iter=poses.upper_bound(0); iter!=poses.end();++iter)
{
if(iter->first > 0)
if(signatures.at(iter->first).getWeight() >= 0)
{
if(signatures.at(iter->first).getWeight() >= 0)
{
posesToCheckLoopClosures.insert(*iter);
mapIds.insert(std::make_pair(iter->first, signatures.at(iter->first).mapId()));
}
posesToCheckLoopClosures.insert(*iter);
mapIds.insert(std::make_pair(iter->first, signatures.at(iter->first).mapId()));
}
}
@@ -4517,7 +4514,18 @@ int Rtabmap::detectMoreLoopClosures(
(intraSession && mapIdFrom == mapIdTo))
{
if(rtabmap::graph::findLink(checkedLoopClosures, from, to) == checkedLoopClosures.end())
bool alreadyChecked = false;
for(std::multimap<int, int>::iterator jter = checkedLoopClosures.lower_bound(from);
!alreadyChecked && jter!=checkedLoopClosures.end() && jter->first == from;
++jter)
{
if(to == jter->second)
{
alreadyChecked = true;
}
}
if(!alreadyChecked)
{
// only add new links and one per cluster per iteration
if(addedLinks.find(from) == addedLinks.end() &&
+11 -1
View File
@@ -1939,7 +1939,7 @@ cv::Mat fastBilateralFiltering(const cv::Mat & depth, float sigmaS, float sigmaR
* \note In case of BGRA image, we won't touch the transparency
* See http://answers.opencv.org/question/75510/how-to-make-auto-adjustmentsbrightness-and-contrast-for-image-android-opencv-image-correction/
*/
cv::Mat brightnessAndContrastAuto(const cv::Mat &src, const cv::Mat & mask, float clipLowHistPercent, float clipHighHistPercent)
cv::Mat brightnessAndContrastAuto(const cv::Mat &src, const cv::Mat & mask, float clipLowHistPercent, float clipHighHistPercent, float * alphaOut, float * betaOut)
{
CV_Assert(clipLowHistPercent >= 0 && clipHighHistPercent>=0);
@@ -2011,6 +2011,16 @@ cv::Mat brightnessAndContrastAuto(const cv::Mat &src, const cv::Mat & mask, floa
int from_to[] = { 3, 3};
cv::mixChannels(&src, 4, &dst,1, from_to, 1);
}
if(alphaOut)
{
*alphaOut = alpha;
}
if(betaOut)
{
*betaOut = beta;
}
return dst;
}
+105 -50
View File
@@ -53,6 +53,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <aliceVision/mesh/Mesh.hpp>
#include <aliceVision/mesh/Texturing.hpp>
#include <aliceVision/camera/Pinhole.hpp>
#include <boost/algorithm/string.hpp>
using namespace aliceVision;
#endif
@@ -1439,7 +1440,8 @@ cv::Mat mergeTextures(
const ProgressState * state,
unsigned char blankValue,
std::map<int, std::map<int, cv::Vec4d> > * gains,
std::map<int, std::map<int, cv::Mat> > * blendingGains)
std::map<int, std::map<int, cv::Mat> > * blendingGains,
std::pair<float, float> * contrastValues)
{
std::map<int, std::vector<CameraModel> > calibVectors;
for(std::map<int, CameraModel>::const_iterator iter=calibrations.begin(); iter!=calibrations.end(); ++iter)
@@ -1467,7 +1469,8 @@ cv::Mat mergeTextures(
state,
blankValue,
gains,
blendingGains);
blendingGains,
contrastValues);
}
cv::Mat mergeTextures(
pcl::TextureMesh & mesh,
@@ -1489,7 +1492,8 @@ cv::Mat mergeTextures(
const ProgressState * state,
unsigned char blankValue,
std::map<int, std::map<int, cv::Vec4d> > * gainsOut,
std::map<int, std::map<int, cv::Mat> > * blendingGainsOut)
std::map<int, std::map<int, cv::Mat> > * blendingGainsOut,
std::pair<float, float> * contrastValuesOut)
{
//get texture size, if disabled use default 1024
UASSERT(textureSize%256 == 0);
@@ -2109,40 +2113,43 @@ cv::Mat mergeTextures(
if(brightnessContrastRatioLow > 0 || brightnessContrastRatioHigh > 0)
{
for(int i=0; i<materials; ++i)
if(exposureFusion)
{
cv::Mat globalTexturesROI = globalTextures(cv::Range::all(), cv::Range(i*globalTextures.rows, (i+1)*globalTextures.rows));
cv::Mat globalTextureMasksROI = globalTextureMasks(cv::Range::all(), cv::Range(i*globalTextureMasks.rows, (i+1)*globalTextureMasks.rows));
if(exposureFusion)
std::vector<cv::Mat> images;
images.push_back(globalTextures);
if (brightnessContrastRatioLow > 0)
{
std::vector<cv::Mat> images;
images.push_back(globalTexturesROI);
if (brightnessContrastRatioLow > 0)
{
images.push_back(util2d::brightnessAndContrastAuto(
globalTexturesROI,
globalTextureMasksROI,
images.push_back(util2d::brightnessAndContrastAuto(
globalTextures,
globalTextureMasks,
(float)brightnessContrastRatioLow,
0.0f));
}
if (brightnessContrastRatioHigh > 0)
{
images.push_back(util2d::brightnessAndContrastAuto(
globalTexturesROI,
globalTextureMasksROI,
}
if (brightnessContrastRatioHigh > 0)
{
images.push_back(util2d::brightnessAndContrastAuto(
globalTextures,
globalTextureMasks,
0.0f,
(float)brightnessContrastRatioHigh));
}
util2d::exposureFusion(images).copyTo(globalTexturesROI);
}
else
{
util2d::brightnessAndContrastAuto(
globalTexturesROI,
globalTextureMasksROI,
globalTextures = util2d::exposureFusion(images);
}
else
{
float alpha, beta;
globalTextures = util2d::brightnessAndContrastAuto(
globalTextures,
globalTextureMasks,
(float)brightnessContrastRatioLow,
(float)brightnessContrastRatioHigh).copyTo(globalTexturesROI);
(float)brightnessContrastRatioHigh,
&alpha,
&beta);
if(contrastValuesOut)
{
contrastValuesOut->first = alpha;
contrastValuesOut->second = beta;
}
}
if(state) state->callback(uFormat("Brightness and contrast auto %fs", timer.ticks()));
@@ -2195,7 +2202,8 @@ void fixTextureMeshForVisualization(pcl::TextureMesh & textureMesh)
bool multiBandTexturing(
const std::string & outputOBJPath,
const pcl::PolygonMesh & mesh,
const pcl::PCLPointCloud2 & cloud,
const std::vector<pcl::Vertices> & polygons,
const std::map<int, Transform> & cameraPoses,
const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels, // required output of util3d::createTextureMesh()
const std::map<int, cv::Mat> & images, // raw or compressed, can be empty if memory or dbDriver should be used
@@ -2203,8 +2211,10 @@ bool multiBandTexturing(
const Memory * memory, // Should be set if images are not set
const DBDriver * dbDriver, // Should be set if images and memory are not set
int textureSize,
const std::string & textureFormat,
const std::map<int, std::map<int, cv::Vec4d> > & gains, // optional output of util3d::mergeTextures()
const std::map<int, std::map<int, cv::Mat> > & blendingGains)// optional output of util3d::mergeTextures()
const std::map<int, std::map<int, cv::Mat> > & blendingGains, // optional output of util3d::mergeTextures()
const std::pair<float, float> & contrastValues) // optional output of util3d::mergeTextures()
{
#ifdef RTABMAP_ALICE_VISION
if(ULogger::level() == ULogger::kDebug)
@@ -2226,15 +2236,16 @@ bool multiBandTexturing(
sfmData::SfMData sfmData;
pcl::PointCloud<pcl::PointXYZRGB> cloud2;
pcl::fromPCLPointCloud2(mesh.cloud, cloud2);
pcl::fromPCLPointCloud2(cloud, cloud2);
UASSERT(vertexToPixels.size() == cloud2.size());
UINFO("Input mesh: %d points %d polygons", (int)cloud2.size(), (int)mesh.polygons.size());
UINFO("Input mesh: %d points %d polygons", (int)cloud2.size(), (int)polygons.size());
mesh::Texturing texturing;
texturing.me = new mesh::Mesh();
texturing.me->pts = new StaticVector<Point3d>(cloud2.size());
texturing.pointsVisibilities = new mesh::PointsVisibility();
texturing.pointsVisibilities->reserve(cloud2.size());
texturing.texParams.textureSide = textureSize;
texturing.texParams.textureSide = 8192;
texturing.texParams.downscale = 8192/textureSize;
std::vector<int> camIndexToId(uKeys(cameraModels));
for(size_t i=0;i<cloud2.size();++i)
@@ -2250,14 +2261,14 @@ bool multiBandTexturing(
(*texturing.me->pts)[i] = Point3d(pt.x, pt.y, pt.z);
}
texturing.me->tris = new StaticVector<mesh::Mesh::triangle>(mesh.polygons.size());
for(size_t i=0;i<mesh.polygons.size();++i)
texturing.me->tris = new StaticVector<mesh::Mesh::triangle>(polygons.size());
for(size_t i=0;i<polygons.size();++i)
{
UASSERT(mesh.polygons[i].vertices.size() == 3);
UASSERT(polygons[i].vertices.size() == 3);
(*texturing.me->tris)[i] = mesh::Mesh::triangle(
mesh.polygons[i].vertices[0],
mesh.polygons[i].vertices[1],
mesh.polygons[i].vertices[2]);
polygons[i].vertices[0],
polygons[i].vertices[1],
polygons[i].vertices[2]);
}
UTimer timer;
std::string outputDirectory = UDirectory::getDir(outputOBJPath);
@@ -2274,6 +2285,7 @@ bool multiBandTexturing(
!images.find(camId)->second.empty() &&
cameraModels.find(camId) != cameraModels.end())
{
image = images.find(camId)->second;
models = cameraModels.find(camId)->second;
}
else if(memory)
@@ -2315,18 +2327,18 @@ bool multiBandTexturing(
}
if(models.empty())
{
UERROR("No camera models found for camera %d", iter->first);
continue;
UERROR("No camera models found for camera %d. Aborting multiband texturing...", iter->first);
return false;
}
else if(models.size() != 1)
{
UERROR("Unwrapping not supporting multi-camera yet... ignoring %d", iter->first);
continue;
UERROR("Unwrapping not supporting multi-camera yet... ignoring %d. Aborting multiband texturing...", iter->first);
return false;
}
if(image.empty())
{
UERROR("No image found for camera %d", iter->first);
continue;
UERROR("No image found for camera %d. Aborting multiband texturing...", iter->first);
return false;
}
if(image.rows == 1 && image.type() == CV_8UC1)
@@ -2400,13 +2412,14 @@ bool multiBandTexturing(
UINFO("Unwrapping done. %fs", timer.ticks());
// save final obj file
texturing.saveAsOBJ(outputDirectory, uSplit(UFile::getName(outputOBJPath), '.').front());
UINFO("Saved %s. %fs\n", outputOBJPath, timer.ticks());
std::string baseName = uSplit(UFile::getName(outputOBJPath), '.').front();
texturing.saveAsOBJ(outputDirectory, baseName);
UINFO("Saved %s. %fs", outputOBJPath, timer.ticks());
// generate textures
UINFO("Generating textures...\n");
UINFO("Generating textures...");
texturing.generateTextures(mp, outputDirectory);
UINFO("Generating textures done. %fs\n", timer.ticks());
UINFO("Generating textures done. %fs", timer.ticks());
UINFO("Cleanup temporary directory \"%s\"...", tmpImageDirectory.c_str());
UDirectory dir(tmpImageDirectory);
@@ -2419,6 +2432,48 @@ bool multiBandTexturing(
UDirectory::removeDir(tmpImageDirectory);
UINFO("Cleanup temporary directory \"%s\"... done.", tmpImageDirectory.c_str());
UINFO("Rename/convert textures...");
dir.setPath(outputDirectory, "png");
std::map<std::string, std::string> texNames; // <old, new>
std::string outputFormat = textureFormat;
if(outputFormat.front() == '.')
{
outputFormat = outputFormat.substr(1, std::string::npos);
}
for(std::list<std::string>::const_iterator iter=dir.getFileNames().begin(); iter!=dir.getFileNames().end(); ++iter)
{
// Textures are called "texture_1001.png", "texture_1002.png", ...
if(uStrContains(*iter, "texture_10"))
{
cv::Mat img = cv::imread(outputDirectory+"/"+*iter);
if(contrastValues.first != 0.0f || contrastValues.second != 0.0f)
{
UASSERT(img.channels() == 3);
// Re-use same contrast values with all images
img.convertTo(img, -1, contrastValues.first, contrastValues.second);
}
std::string newName = *iter;
boost::replace_all(newName, "png", outputFormat);
boost::replace_all(newName, "texture", baseName);
texNames.insert(std::make_pair(*iter, newName));
cv::imwrite(outputDirectory+"/"+newName, img);
UFile::erase(outputDirectory+"/"+*iter);
}
}
std::ifstream fi(outputDirectory+"/"+baseName+".mtl");
std::string mtlStr((std::istreambuf_iterator<char>(fi)),
std::istreambuf_iterator<char>());
fi.close();
UFile::erase(outputDirectory+"/"+baseName);
for(std::map<std::string, std::string>::iterator iter=texNames.begin(); iter!=texNames.end(); ++iter)
{
boost::replace_all(mtlStr, iter->first, iter->second);
}
std::ofstream fo(outputDirectory+"/"+baseName+".mtl");
fo.write(mtlStr.c_str(), mtlStr.size());
fo.close();
UINFO("Rename/convert textures... done. %fs", timer.ticks());
return true;
#else
UERROR("Cannot unwrap texture mesh. RTAB-Map is not built with Alice Vision support! Returning false.");
-1
View File
@@ -1,6 +1,5 @@
ADD_SUBDIRECTORY( BOWMapping )
ADD_SUBDIRECTORY( Export )
IF(TARGET rtabmap_gui)
ADD_SUBDIRECTORY( RGBDMapping )
-58
View File
@@ -1,58 +0,0 @@
cmake_minimum_required(VERSION 2.8)
IF(DEFINED PROJECT_NAME)
set(internal TRUE)
ENDIF(DEFINED PROJECT_NAME)
if(internal)
# inside rtabmap project (see below for external build)
SET(RTABMap_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include
)
SET(RTABMap_LIBRARIES
rtabmap_core
rtabmap_utilite
)
else()
# external build
PROJECT( MyProject )
FIND_PACKAGE(RTABMap REQUIRED)
FIND_PACKAGE(OpenCV REQUIRED)
FIND_PACKAGE(PCL 1.7 REQUIRED)
endif()
if(POLICY CMP0020)
cmake_policy(SET CMP0020 OLD)
endif()
SET(INCLUDE_DIRS
${RTABMap_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${PCL_INCLUDE_DIRS}
)
SET(LIBRARIES
${RTABMap_LIBRARIES}
${OpenCV_LIBRARIES}
${PCL_LIBRARIES}
)
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
ADD_EXECUTABLE(export main.cpp)
TARGET_LINK_LIBRARIES(export ${LIBRARIES})
if(internal)
SET_TARGET_PROPERTIES( export
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-export)
endif(internal)
INSTALL(TARGETS export
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
+25 -10
View File
@@ -653,7 +653,7 @@ void ExportCloudsDialog::restoreDefaults()
_ui->doubleSpinBox_cameraFilterVelRad->setValue(0);
_ui->doubleSpinBox_laplacianVariance->setValue(0);
_ui->spinBox_textureBrightnessContrastRatioLow->setValue(0);
_ui->spinBox_textureBrightnessContrastRatioHigh->setValue(0);
_ui->spinBox_textureBrightnessContrastRatioHigh->setValue(5);
_ui->checkBox_exposureFusion->setChecked(false);
_ui->checkBox_blending->setChecked(true);
_ui->comboBox_blendingDecimation->setCurrentIndex(0);
@@ -3840,10 +3840,15 @@ void ExportCloudsDialog::saveTextureMeshes(
cv::Mat globalTextures;
bool texturesMerged = _ui->comboBox_meshingTextureSize->isEnabled() && _ui->comboBox_meshingTextureSize->currentIndex() > 0;
if(texturesMerged && mesh->tex_materials.size()>1)
{
{
_progressDialog->appendText(tr("Merging textures..."));
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
std::map<int, std::map<int, cv::Vec4d> > gains;
std::map<int, std::map<int, cv::Mat> > blendingGains;
std::pair<float, float> contrastValues(0,0);
globalTextures = util3d::mergeTextures(
*mesh,
images,
@@ -3851,7 +3856,7 @@ void ExportCloudsDialog::saveTextureMeshes(
0,
_dbDriver,
textureSize,
_ui->spinBox_mesh_maxTextures->value(),
_ui->checkBox_multiband->isEnabled() && _ui->checkBox_multiband->isChecked()?1:_ui->spinBox_mesh_maxTextures->value(),
textureVertexToPixels,
_ui->checkBox_gainCompensation->isChecked(),
_ui->doubleSpinBox_gainBeta->value(),
@@ -3864,17 +3869,25 @@ void ExportCloudsDialog::saveTextureMeshes(
0,
0,
&gains,
&blendingGains);
&blendingGains,
&contrastValues);
_progressDialog->appendText(tr("Merging textures... done."));
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
if(_ui->checkBox_multiband->isEnabled() && _ui->checkBox_multiband->isChecked() && mesh->tex_polygons.size() == 1)
{
pcl::PolygonMesh multibandMesh;
multibandMesh.cloud = mesh->cloud;
multibandMesh.polygons = mesh->tex_polygons[0];
_progressDialog->appendText(tr("Multiband texturing... (this may take a couple of minutes!)"));
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
success = util3d::multiBandTexturing(
path.toStdString(),
multibandMesh,
mesh->cloud,
mesh->tex_polygons[0],
poses,
textureVertexToPixels,
images,
@@ -3882,8 +3895,10 @@ void ExportCloudsDialog::saveTextureMeshes(
0,
_dbDriver,
textureSize,
_ui->comboBox_meshingTextureFormat->currentText().toStdString(),
gains,
blendingGains);
blendingGains,
contrastValues);
if(success)
{
_progressDialog->incrementStep();
+7
View File
@@ -4741,6 +4741,13 @@ void MainWindow::openDatabase(const QString & path, const ParametersMap & overri
different = false;
}
}
else if(Parameters::getType(iter->first).compare("bool") == 0)
{
if(uStr2Bool(iter->second) == uStr2Bool(jter->second))
{
different = false;
}
}
if(different)
{
differentParameters.insert(*iter);
+3 -3
View File
@@ -63,7 +63,7 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-1371</y>
<y>0</y>
<width>680</width>
<height>3083</height>
</rect>
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex">
<number>5</number>
<number>21</number>
</property>
<widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -16606,7 +16606,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<item row="1" column="0">
<widget class="QSpinBox" name="loopClosure_bowMinInliers">
<property name="minimum">
<number>1</number>
<number>6</number>
</property>
<property name="maximum">
<number>1000</number>
+1
View File
@@ -10,6 +10,7 @@ ADD_SUBDIRECTORY( EurocDataset )
ADD_SUBDIRECTORY( Recovery )
ADD_SUBDIRECTORY( Reprocess )
ADD_SUBDIRECTORY( DetectMoreLoopClosures )
ADD_SUBDIRECTORY( Export )
IF(OPENCV_NONFREE_FOUND)
ADD_SUBDIRECTORY( VocabularyComparison )
+9 -2
View File
@@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UMath.h>
#include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UStl.h>
#include <pcl/filters/filter.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/obj_io.h>
@@ -54,7 +55,7 @@ void showUsage()
" -i # Iterations (default 1).\n"
" --intra Add only intra-session loop closures.\n"
" --inter Add only inter-session loop closures.\n"
"\n");
"\n%s", Parameters::showUsage());
exit(1);
}
@@ -98,7 +99,11 @@ int main(int argc, char * argv[])
bool interSession = false;
for(int i=1; i<argc-1; ++i)
{
if(std::strcmp(argv[i], "--intra") == 0)
if(std::strcmp(argv[i], "--help") == 0)
{
showUsage();
}
else if(std::strcmp(argv[i], "--intra") == 0)
{
intraSession = true;
if(interSession)
@@ -151,6 +156,7 @@ int main(int argc, char * argv[])
}
}
}
ParametersMap inputParams = Parameters::parseArguments(argc, argv);
std::string dbPath = argv[argc-1];
if(!UFile::exists(dbPath))
@@ -193,6 +199,7 @@ int main(int argc, char * argv[])
// Get the global optimized map
Rtabmap rtabmap;
printf("Initialization...\n");
uInsert(parameters, inputParams);
rtabmap.init(parameters, dbPath);
PrintProgressState progress;
+36
View File
@@ -0,0 +1,36 @@
SET(RTABMap_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include
)
SET(RTABMap_LIBRARIES
rtabmap_core
rtabmap_utilite
)
SET(INCLUDE_DIRS
${RTABMap_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${PCL_INCLUDE_DIRS}
)
SET(LIBRARIES
${RTABMap_LIBRARIES}
${OpenCV_LIBRARIES}
${PCL_LIBRARIES}
)
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
ADD_EXECUTABLE(export main.cpp)
TARGET_LINK_LIBRARIES(export ${LIBRARIES})
SET_TARGET_PROPERTIES( export
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-export)
INSTALL(TARGETS export
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
@@ -52,18 +52,20 @@ void showUsage()
"Options:\n"
" --mesh Create a mesh.\n"
" --texture Create a mesh with texture.\n"
" --texture_size Texture size (default 4096.\n"
" --texture_count Maximum textures generated (default 1).\n"
" --texture_size # Texture size (default 4096).\n"
" --texture_count # Maximum textures generated (default 1).\n"
" --texture_range # Maximum camera range for texturing a polygon (default 0 meters: no limit).\n"
" --ba Do global bundle adjustment before assembling the clouds.\n"
" --no_gain Disable gain compensation when texturing.\n"
" --no_blending Disable blending when texturing.\n"
" --no_clean Disable cleaning colorless polygons.\n"
" --multiband Enable multiband texturing (AliceVision dependency required).\n"
" --poisson_depth # Set Poisson depth for mesh reconstruction.\n"
" --max_polygons # Maximum polygons when creating a mesh (default 1000000, set 0 for no limit).\n"
" --max_polygons # Maximum polygons when creating a mesh (default 500000, set 0 for no limit).\n"
" --max_range # Maximum range of the created clouds (default 4 m).\n"
" --decimation # Image decimation before creating the clouds (default 4).\n"
" --decimation # Depth image decimation before creating the clouds (default 4).\n"
" --voxel # Voxel size of the created clouds (default 0.01 m).\n"
" --color_radius # Radius used to colorize polygons (default 0.05 m, set 0 for nearest color).\n"
"\n%s", Parameters::showUsage());
;
exit(1);
@@ -86,17 +88,22 @@ int main(int argc, char * argv[])
bool doBlending = true;
bool doClean = true;
int poissonDepth = 0;
int maxPolygons = 1000000;
int maxPolygons = 500000;
int decimation = 4;
float maxRange = 4.0f;
float voxelSize = 0.01f;
int textureSize = 8192;
int textureSize = 4096;
int textureCount = 8;
int textureRange = 0;
bool multiband = false;
ParametersMap params = Parameters::parseArguments(argc, argv, false);
float colorRadius = 0.05;
for(int i=1; i<argc-1; ++i)
{
if(std::strcmp(argv[i], "--mesh") == 0)
if(std::strcmp(argv[i], "--help") == 0)
{
showUsage();
}
else if(std::strcmp(argv[i], "--mesh") == 0)
{
mesh = true;
}
@@ -129,6 +136,18 @@ int main(int argc, char * argv[])
showUsage();
}
}
else if(std::strcmp(argv[i], "--texture_range") == 0)
{
++i;
if(i<argc-1)
{
textureRange = uStr2Int(argv[i]);
}
else
{
showUsage();
}
}
else if(std::strcmp(argv[i], "--ba") == 0)
{
ba = true;
@@ -147,7 +166,11 @@ int main(int argc, char * argv[])
}
else if(std::strcmp(argv[i], "--multiband") == 0)
{
#ifdef RTABMAP_ALICE_VISION
multiband = true;
#else
printf("\"--multiband\" option cannot be used vecause RTAB-Map is not built with AliceVision support. Ignoring multiband...\n");
#endif
}
else if(std::strcmp(argv[i], "--poisson_depth") == 0)
{
@@ -209,7 +232,20 @@ int main(int argc, char * argv[])
showUsage();
}
}
else if(std::strcmp(argv[i], "--color_radius") == 0)
{
++i;
if(i<argc-1)
{
colorRadius = uStr2Float(argv[i]);
}
else
{
showUsage();
}
}
}
ParametersMap params = Parameters::parseArguments(argc, argv, false);
std::string dbPath = argv[argc-1];
@@ -224,6 +260,7 @@ int main(int argc, char * argv[])
else
{
UERROR("Cannot open database %s!", dbPath.c_str());
return -1;
}
delete driver;
@@ -232,19 +269,24 @@ int main(int argc, char * argv[])
printf("Added custom parameter %s=%s\n",iter->first.c_str(), iter->second.c_str());
}
UTimer timer;
printf("Loading database \"%s\"...\n", dbPath.c_str());
// Get the global optimized map
Rtabmap rtabmap;
uInsert(parameters, params);
rtabmap.init(parameters, dbPath);
printf("Loading database \"%s\"... done.\n", dbPath.c_str());
printf("Loading database \"%s\"... done (%fs).\n", dbPath.c_str(), timer.ticks());
std::map<int, Signature> nodes;
std::map<int, Transform> optimizedPoses;
std::multimap<int, Link> links;
printf("Optimizing the map...\n");
rtabmap.get3DMap(nodes, optimizedPoses, links, true, true);
printf("Optimizing the map... done.\n");
printf("Optimizing the map... done (%fs).\n", timer.ticks());
std::string outputDirectory = UDirectory::getDir(dbPath);
std::string baseName = uSplit(UFile::getName(dbPath), '.').front();
if(ba)
{
@@ -261,7 +303,7 @@ int main(int argc, char * argv[])
cameraSingleModels.insert(std::make_pair(iter->first, node.sensorData().cameraModels().front()));
}
optimizedPoses = g2o.optimizeBA(optimizedPoses.begin()->first, optimizedPoses, links, cameraSingleModels, points3DMap, wordReferences);
printf("Global bundle adjustment... done.\n");
printf("Global bundle adjustment... done (%fs).\n", timer.ticks());
}
// Construct the cloud
@@ -317,7 +359,7 @@ int main(int argc, char * argv[])
cameraDepths.insert(std::make_pair(iter->first, depth));
}
}
printf("Create and assemble the clouds... done.\n");
printf("Create and assemble the clouds... done (%fs, %d points).\n", timer.ticks(), (int)mergedClouds->size());
if(mergedClouds->size())
{
@@ -326,9 +368,10 @@ int main(int argc, char * argv[])
printf("Voxel grid filtering of the assembled cloud (voxel=%f, %d points)\n", 0.01f, (int)mergedClouds->size());
mergedClouds = util3d::voxelize(mergedClouds, voxelSize);
printf("Saving cloud.ply... (%d points)\n", (int)mergedClouds->size());
pcl::io::savePLYFile("cloud.ply", *mergedClouds);
printf("Saving cloud.ply... done!\n");
std::string outputPath=outputDirectory+"/"+baseName+"_cloud.ply";
printf("Saving %s... (%d points)\n", outputPath.c_str(), (int)mergedClouds->size());
pcl::io::savePLYFile(outputPath, *mergedClouds);
printf("Saving %s... done!\n", outputPath.c_str());
}
else
{
@@ -355,9 +398,8 @@ int main(int argc, char * argv[])
pcl::Poisson<pcl::PointXYZRGBNormal> poisson;
poisson.setDepth(optimizedDepth);
poisson.setInputCloud(mergedClouds);
UTimer timer;
poisson.reconstruct(*mesh);
printf("Mesh reconstruction... done! %fs (%d polygons)\n", timer.ticks(), (int)mesh->polygons.size());
printf("Mesh reconstruction... done (%fs, %d polygons).\n", timer.ticks(), (int)mesh->polygons.size());
if(mesh->polygons.size())
{
@@ -366,15 +408,17 @@ int main(int argc, char * argv[])
0.0f,
maxPolygons,
mergedClouds,
doClean?0.05:0,
colorRadius,
!texture,
doClean);
doClean,
200);
if(!texture)
{
printf("Saving mesh.ply...\n");
pcl::io::savePLYFile("mesh.ply", *mesh);
printf("Saving mesh.ply... done!\n");
std::string outputPath=outputDirectory+"/"+baseName+"_mesh.ply";
printf("Saving %s...\n", outputPath.c_str());
pcl::io::savePLYFile(outputPath, *mesh);
printf("Saving %s... done!\n", outputPath.c_str());
}
else
{
@@ -385,28 +429,36 @@ int main(int argc, char * argv[])
cameraPoses,
cameraModels,
cameraDepths,
3,
textureRange,
0.0f,
0.0f,
50,
multiband?0:50, // Min polygons in camera view to be textured by this camera
std::vector<float>(),
0,
&vertexToPixels);
printf("Texturing... done! %fs\n", timer.ticks());
printf("Texturing... done (%fs).\n", timer.ticks());
// Remove occluded polygons (polygons with no texture)
if(doClean && textureMesh->tex_coordinates.size())
{
printf("Cleanup mesh...\n");
rtabmap::util3d::cleanTextureMesh(*textureMesh, 0);
printf("Cleanup mesh... done! %fs\n", timer.ticks());
rtabmap::util3d::cleanTextureMesh(*textureMesh, 100); // Min polygons in a cluster to keep them
printf("Cleanup mesh... done (%fs).\n", timer.ticks());
}
if(textureMesh->tex_materials.size())
{
printf("Merging %d textures...\n", (int)textureMesh->tex_materials.size());
if(multiband)
{
printf("Merging %d texture(s) to single one (multiband enabled)...\n", (int)textureMesh->tex_materials.size());
}
else
{
printf("Merging %d texture(s)... (%d max textures)\n", (int)textureMesh->tex_materials.size(), textureCount);
}
std::map<int, std::map<int, cv::Vec4d> > gains;
std::map<int, std::map<int, cv::Mat> > blendingGains;
std::pair<float, float> contrastValues(0,0);
cv::Mat textures = rtabmap::util3d::mergeTextures(
*textureMesh,
std::map<int, cv::Mat>(),
@@ -414,14 +466,18 @@ int main(int argc, char * argv[])
rtabmap.getMemory(),
0,
textureSize,
textureCount,
multiband?1:textureCount, // to get contrast values based on all images in multiband mode
vertexToPixels,
doGainCompensation, 10.0f, true ,doBlending, 0, 0, 0, false,
0,
0,
doGainCompensation, 1.0f, true,
doBlending, 0,
0, 10, // low-high brightness/contrast balance
false, // exposure fusion
0, // state
0, // blank value (0=black)
&gains,
&blendingGains);
printf("Merging %d textures... done. %fs\n", (int)textureMesh->tex_materials.size(), timer.ticks());
&blendingGains,
&contrastValues);
printf("Merging to %d texture(s)... done (%fs).\n", (int)textureMesh->tex_materials.size(), timer.ticks());
// TextureMesh OBJ
bool success = false;
@@ -444,29 +500,28 @@ int main(int argc, char * argv[])
if(success)
{
std::string filePath = "mesh.obj";
printf("Saving obj (%d vertices) to %s.\n", (int)textureMesh->cloud.data.size()/textureMesh->cloud.point_step, filePath.c_str());
success = pcl::io::saveOBJFile(filePath, *textureMesh) == 0;
std::string outputPath=outputDirectory+"/"+baseName+"_mesh.obj";
printf("Saving obj (%d vertices) to %s.\n", (int)textureMesh->cloud.data.size()/textureMesh->cloud.point_step, outputPath.c_str());
success = pcl::io::saveOBJFile(outputPath, *textureMesh) == 0;
if(success)
{
printf("Saved obj to %s!\n", filePath.c_str());
printf("Saved obj to %s!\n", outputPath.c_str());
}
else
{
UERROR("Failed saving obj to %s!", filePath.c_str());
UERROR("Failed saving obj to %s!", outputPath.c_str());
}
}
if(multiband)
{
#ifndef RTABMAP_ALICE_VISION
UERROR("Cannot use --unwrap option, RTAB-Map is not built with AliceVision support.");
#else
timer.restart();
printf("MultiBand texturing... \"mesh_multiband.obj\"\n");
if(util3d::multiBandTexturing("mesh_multiband.obj",
*mesh,
std::string outputPath=outputDirectory+"/"+baseName+"_mesh_multiband.obj";
printf("MultiBand texturing... \"%s\"\n", outputPath.c_str());
if(util3d::multiBandTexturing(outputPath,
textureMesh->cloud,
textureMesh->tex_polygons[0],
cameraPoses,
vertexToPixels,
std::map<int, cv::Mat >(),
@@ -474,16 +529,17 @@ int main(int argc, char * argv[])
rtabmap.getMemory(),
0,
textureSize,
"jpg",
gains,
blendingGains))
blendingGains,
contrastValues))
{
printf("MultiBand texturing...done. %fs\n", timer.ticks());
printf("MultiBand texturing...done (%fs).\n", timer.ticks());
}
else
{
printf("MultiBand texturing...failed! %fs\n", timer.ticks());
printf("MultiBand texturing...failed! (%fs)\n", timer.ticks());
}
#endif
}
}
}