diff --git a/CMakeLists.txt b/CMakeLists.txt index 82349038..2948c415 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,8 +85,11 @@ FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) # tested on Qt4.8 ADD_DEFINITIONS(-DQT_NO_KEYWORDS) # To avoid conflicts with boost signals used in ROS IF(OPENCV_NONFREE_FOUND) - ADD_DEFINITIONS(-DWITH_NONFREE) -ENDIF(OPENCV_NONFREE_FOUND) + SET(NONFREE 1) +ELSE() + SET(NONFREE 0) +ENDIF() +CONFIGURE_FILE(Version.h.in ${PROJECT_SOURCE_DIR}/include/${PROJECT_PREFIX}/Version.h) ####### OSX BUNDLE CMAKE_INSTALL_PREFIX ####### IF(APPLE) diff --git a/Version.h.in b/Version.h.in new file mode 100644 index 00000000..6f813509 --- /dev/null +++ b/Version.h.in @@ -0,0 +1,43 @@ +/* +Copyright (c) 2010-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Universite de Sherbrooke nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef VERSION_H_ +#define VERSION_H_ + +// This is auto-generated! +#define FINDOBJECT_VERSION "@PROJECT_VERSION@" + +#define FINDOBJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define FINDOBJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define FINDOBJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@ + +#define FINDOBJECT_VERSION_COMPARE(major, minor, patch) (major>=@PROJECT_VERSION_MAJOR@ || (major==@PROJECT_VERSION_MAJOR@ && minor>=@PROJECT_VERSION_MINOR@) || (major==@PROJECT_VERSION_MAJOR@ && minor==@PROJECT_VERSION_MINOR@ && patch >=@PROJECT_VERSION_PATCH@)) + +#define FINDOBJECT_NONFREE @NONFREE@ + +#endif /* VERSION_H_ */ + diff --git a/include/find_object/Settings.h b/include/find_object/Settings.h index 5dcef704..04da5c2e 100644 --- a/include/find_object/Settings.h +++ b/include/find_object/Settings.h @@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define SETTINGS_H_ #include "find_object/FindObjectExp.h" // DLL export/import defines +#include "find_object/Version.h" // DLL export/import defines #include #include @@ -80,6 +81,25 @@ typedef unsigned int uint; descriptions_.insert(#PREFIX "/" #NAME, DESCRIPTION);} \ }; \ Dummy##PREFIX##_##NAME dummy##PREFIX##_##NAME; + +#define PARAMETER_COND(PREFIX, NAME, TYPE, COND, DEFAULT_VALUE1, DEFAULT_VALUE2, DESCRIPTION) \ + public: \ + static QString k##PREFIX##_##NAME() {return QString(#PREFIX "/" #NAME);} \ + static TYPE default##PREFIX##_##NAME() {return COND?DEFAULT_VALUE1:DEFAULT_VALUE2;} \ + static QString type##PREFIX##_##NAME() {return QString(#TYPE);} \ + static QString description##PREFIX##_##NAME() {return QString(DESCRIPTION);} \ + PARAMETER_GETTER_##TYPE(PREFIX, NAME) \ + static void set##PREFIX##_##NAME(const TYPE & value) {parameters_[#PREFIX "/" #NAME] = value;} \ + private: \ + class Dummy##PREFIX##_##NAME { \ + public: \ + Dummy##PREFIX##_##NAME() { \ + defaultParameters_.insert(#PREFIX "/" #NAME, QVariant(COND?DEFAULT_VALUE1:DEFAULT_VALUE2)); \ + parameters_.insert(#PREFIX "/" #NAME, COND?DEFAULT_VALUE1:DEFAULT_VALUE2); \ + parametersType_.insert(#PREFIX "/" #NAME, #TYPE); \ + descriptions_.insert(#PREFIX "/" #NAME, DESCRIPTION);} \ + }; \ + Dummy##PREFIX##_##NAME dummy##PREFIX##_##NAME; // MACRO END class FINDOBJECT_EXP Settings @@ -94,13 +114,9 @@ class FINDOBJECT_EXP Settings PARAMETER(Camera, 9queueSize, int, 1, "Maximum images buffered from TCP. If 0, all images are buffered."); //List format : [Index:item0;item1;item3;...] -#ifdef WITH_NONFREE - PARAMETER(Feature2D, 1Detector, QString, "7:Dense;Fast;GFTT;MSER;ORB;SIFT;Star;SURF;BRISK" , "Keypoint detector."); - PARAMETER(Feature2D, 2Descriptor, QString, "3:Brief;ORB;SIFT;SURF;BRISK;FREAK", "Keypoint descriptor."); -#else - PARAMETER(Feature2D, 1Detector, QString, "1:Dense;Fast;GFTT;MSER;ORB;Star;BRISK" , "Keypoint detector."); - PARAMETER(Feature2D, 2Descriptor, QString, "0:Brief;ORB;BRISK;FREAK", "Keypoint descriptor."); -#endif + + PARAMETER_COND(Feature2D, 1Detector, QString, FINDOBJECT_NONFREE, "7:Dense;Fast;GFTT;MSER;ORB;SIFT;Star;SURF;BRISK" , "1:Dense;Fast;GFTT;MSER;ORB;SIFT;Star;SURF;BRISK", "Keypoint detector."); + PARAMETER_COND(Feature2D, 2Descriptor, QString, FINDOBJECT_NONFREE, "3:Brief;ORB;SIFT;SURF;BRISK;FREAK", "0:Brief;ORB;SIFT;SURF;BRISK;FREAK", "Keypoint descriptor."); PARAMETER(Feature2D, 3MaxFeatures, int, 0, "Maximum features per image. If the number of features extracted is over this threshold, only X features with the highest response are kept. 0 means all features are kept."); PARAMETER(Feature2D, 4Affine, bool, false, "(ASIFT) Extract features on multiple affine transformations of the image."); PARAMETER(Feature2D, 5AffineCount, int, 6, "(ASIFT) Higher the value, more affine transformations will be done."); @@ -147,7 +163,7 @@ class FINDOBJECT_EXP Settings PARAMETER(Feature2D, MSER_minMargin, double, 0.003, ""); PARAMETER(Feature2D, MSER_edgeBlurSize, int, 5, ""); -#ifdef WITH_NONFREE +#if FINDOBJECT_NONFREE == 1 PARAMETER(Feature2D, SIFT_nfeatures, int, 0, "The number of best features to retain. The features are ranked by their scores (measured in SIFT algorithm as the local contrast)."); PARAMETER(Feature2D, SIFT_nOctaveLayers, int, 3, "The number of layers in each octave. 3 is the value used in D. Lowe paper. The number of octaves is computed automatically from the image resolution."); PARAMETER(Feature2D, SIFT_contrastThreshold, double, 0.04, "The contrast threshold used to filter out weak features in semi-uniform (low-contrast) regions. The larger the threshold, the less features are produced by the detector."); @@ -178,13 +194,8 @@ class FINDOBJECT_EXP Settings PARAMETER(Feature2D, FREAK_patternScale, float, 22.0f, "Scaling of the description pattern."); PARAMETER(Feature2D, FREAK_nOctaves, int, 4, "Number of octaves covered by the detected keypoints."); -#ifdef WITH_NONFREE - PARAMETER(NearestNeighbor, 1Strategy, QString, "1:Linear;KDTree;KMeans;Composite;Autotuned;Lsh;BruteForce", "Nearest neighbor strategy."); - PARAMETER(NearestNeighbor, 2Distance_type, QString, "0:EUCLIDEAN_L2;MANHATTAN_L1;MINKOWSKI;MAX;HIST_INTERSECT;HELLINGER;CHI_SQUARE_CS;KULLBACK_LEIBLER_KL;HAMMING", "Distance type."); -#else - PARAMETER(NearestNeighbor, 1Strategy, QString, "6:Linear;KDTree;KMeans;Composite;Autotuned;Lsh;BruteForce", "Nearest neighbor strategy."); - PARAMETER(NearestNeighbor, 2Distance_type, QString, "1:EUCLIDEAN_L2;MANHATTAN_L1;MINKOWSKI;MAX;HIST_INTERSECT;HELLINGER;CHI_SQUARE_CS;KULLBACK_LEIBLER_KL;HAMMING", "Distance type."); -#endif + PARAMETER_COND(NearestNeighbor, 1Strategy, QString, FINDOBJECT_NONFREE, "1:Linear;KDTree;KMeans;Composite;Autotuned;Lsh;BruteForce", "6:Linear;KDTree;KMeans;Composite;Autotuned;Lsh;BruteForce", "Nearest neighbor strategy."); + PARAMETER_COND(NearestNeighbor, 2Distance_type, QString, FINDOBJECT_NONFREE, "0:EUCLIDEAN_L2;MANHATTAN_L1;MINKOWSKI;MAX;HIST_INTERSECT;HELLINGER;CHI_SQUARE_CS;KULLBACK_LEIBLER_KL;HAMMING", "1:EUCLIDEAN_L2;MANHATTAN_L1;MINKOWSKI;MAX;HIST_INTERSECT;HELLINGER;CHI_SQUARE_CS;KULLBACK_LEIBLER_KL;HAMMING", "Distance type."); PARAMETER(NearestNeighbor, 3nndrRatioUsed, bool, true, "Nearest neighbor distance ratio approach to accept the best match."); PARAMETER(NearestNeighbor, 4nndrRatio, float, 0.8f, "Nearest neighbor distance ratio."); PARAMETER(NearestNeighbor, 5minDistanceUsed, bool, false, "Minimum distance with the nearest descriptor to accept a match."); diff --git a/src/AboutDialog.cpp b/src/AboutDialog.cpp index 5958fe5c..dd7d601f 100644 --- a/src/AboutDialog.cpp +++ b/src/AboutDialog.cpp @@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AboutDialog.h" #include "ui_aboutDialog.h" #include +#include "find_object/Version.h" namespace find_object { @@ -37,7 +38,15 @@ AboutDialog::AboutDialog(QWidget * parent) : ui_ = new Ui_aboutDialog(); ui_->setupUi(this); ui_->label_version->setText(PROJECT_VERSION); - ui_->label_version_opencv->setText(CV_VERSION); + + QString cv_version = CV_VERSION; + #if RTABMAP_NONFREE == 1 + cv_version.append(" [With nonfree]"); + #else + cv_version.append(" [Without nonfree]"); + #endif + + ui_->label_version_opencv->setText(cv_version); } AboutDialog::~AboutDialog() diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index a91914f3..e1fb8471 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -135,7 +135,7 @@ MainWindow::MainWindow(FindObject * findObject, Camera * camera, QWidget * paren if(cv::gpu::getCudaEnabledDeviceCount() == 0) { -#ifdef WITH_NONFREE +#if FINDOBJECT_NONFREE == 1 ui_->toolBox->updateParameter(Settings::kFeature2D_SURF_gpu()); ui_->toolBox->getParameterWidget(Settings::kFeature2D_SURF_gpu())->setEnabled(false); ui_->toolBox->getParameterWidget(Settings::kFeature2D_SURF_keypointsRatio())->setEnabled(false); diff --git a/src/ParametersToolBox.cpp b/src/ParametersToolBox.cpp index 1bdc657d..f4ff92fd 100644 --- a/src/ParametersToolBox.cpp +++ b/src/ParametersToolBox.cpp @@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include "find_object/utilite/ULogger.h" namespace find_object { @@ -336,6 +337,27 @@ void ParametersToolBox::addParameter(QVBoxLayout * layout, widget->setObjectName(key); QStringList splitted = value.split(':'); widget->addItems(splitted.last().split(';')); +#if FINDOBJECT_NONFREE == 0 + if(key.compare(Settings::kFeature2D_1Detector()) == 0) + { + widget->setItemData(5, 0, Qt::UserRole - 1); // disable SIFT + widget->setItemData(7, 0, Qt::UserRole - 1); // disable SURF + } + if(key.compare(Settings::kFeature2D_2Descriptor()) == 0) + { + widget->setItemData(2, 0, Qt::UserRole - 1); // disable SIFT + widget->setItemData(3, 0, Qt::UserRole - 1); // disable SURF + } + if(key.compare(Settings::kNearestNeighbor_1Strategy()) == 0) + { + // disable FLANN approaches (cannot be used with binary descriptors) + widget->setItemData(0, 0, Qt::UserRole - 1); + widget->setItemData(1, 0, Qt::UserRole - 1); + widget->setItemData(2, 0, Qt::UserRole - 1); + widget->setItemData(3, 0, Qt::UserRole - 1); + widget->setItemData(4, 0, Qt::UserRole - 1); + } +#endif widget->setCurrentIndex(splitted.first().toInt()); connect(widget, SIGNAL(currentIndexChanged(int)), this, SLOT(changeParameter(int))); addParameter(layout, key, widget); diff --git a/src/Settings.cpp b/src/Settings.cpp index 230dc6fc..055f729f 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -34,7 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#ifdef WITH_NONFREE +#if FINDOBJECT_NONFREE == 1 #include #include #endif @@ -109,6 +109,49 @@ void Settings::loadSettings(const QString & fileName) value = QVariant(str); UINFO("Updated list of parameter \"%s\"", key.toStdString().c_str()); } +#if FINDOBJECT_NONFREE == 0 + QChar index = str.at(0); + if(key.compare(Settings::kFeature2D_1Detector()) == 0) + { + if(index == '5' || index == '7') + { + index = Settings::defaultFeature2D_1Detector().at(0); + int indexInt = Settings::defaultFeature2D_1Detector().split(':').first().toInt(); + UWARN("Trying to set \"%s\" to SIFT/SURF but Find-Object isn't built " + "with the nonfree module from OpenCV. Keeping default combo value: %s.", + Settings::kFeature2D_1Detector().toStdString().c_str(), + Settings::defaultFeature2D_1Detector().split(':').last().split(";").at(indexInt).toStdString().c_str()); + } + } + if(key.compare(Settings::kFeature2D_2Descriptor()) == 0) + { + if(index == '2' || index == '3') + { + index = Settings::defaultFeature2D_2Descriptor().at(0); + int indexInt = Settings::defaultFeature2D_2Descriptor().split(':').first().toInt(); + UWARN("Trying to set \"%s\" to SIFT/SURF but Find-Object isn't built " + "with the nonfree module from OpenCV. Keeping default combo value: %s.", + Settings::kFeature2D_2Descriptor().toStdString().c_str(), + Settings::defaultFeature2D_2Descriptor().split(':').last().split(";").at(indexInt).toStdString().c_str()); + } + } + if(key.compare(Settings::kNearestNeighbor_1Strategy()) == 0) + { + if(index <= '4') + { + index = Settings::defaultNearestNeighbor_1Strategy().at(0); + int indexInt = Settings::defaultNearestNeighbor_1Strategy().split(':').first().toInt(); + UWARN("Trying to set \"%s\" to one FLANN approach but Find-Object isn't built " + "with the nonfree module from OpenCV and FLANN cannot be used " + "with binary descriptors. Keeping default combo value: %s.", + Settings::kNearestNeighbor_1Strategy().toStdString().c_str(), + Settings::defaultNearestNeighbor_1Strategy().split(':').last().split(";").at(indexInt).toStdString().c_str()); + } + } + str = getParameter(key).toString(); + str[0] = index.toAscii(); + value = QVariant(str); +#endif setParameter(key, value); } } @@ -122,7 +165,7 @@ void Settings::loadSettings(const QString & fileName) if(cv::gpu::getCudaEnabledDeviceCount() == 0) { -#ifdef WITH_NONFREE +#if FINDOBJECT_NONFREE == 1 Settings::setFeature2D_SURF_gpu(false); #endif Settings::setFeature2D_Fast_gpu(false); @@ -222,7 +265,7 @@ public: cv::Mat & descriptors) = 0; }; -#ifdef WITH_NONFREE +#if FINDOBJECT_NONFREE == 1 class GPUSURF : public GPUFeature2D { public: @@ -423,12 +466,23 @@ KeypointDetector * Settings::createKeypointDetector() if(ok) { QStringList strategies = split.last().split(';'); -#ifdef WITH_NONFREE + if(strategies.size() == 9 && index>=0 && index<9) -#else - if(strategies.size() == 7 && index>=0 && index<7) -#endif { + +#if FINDOBJECT_NONFREE == 0 + //check for nonfree stuff + if(strategies.at(index).compare("SIFT") == 0 || + strategies.at(index).compare("SURF") == 0) + { + index = Settings::defaultFeature2D_1Detector().split(':').first().toInt(); + UERROR("Find-Object is not built with OpenCV nonfree module so " + "SIFT/SURF cannot be used! Using default \"%s\" instead.", + strategies.at(index).toStdString().c_str()); + + } +#endif + if(strategies.at(index).compare("Dense") == 0) { detector = new cv::DenseFeatureDetector( @@ -532,7 +586,7 @@ KeypointDetector * Settings::createKeypointDetector() getFeature2D_BRISK_patternScale()); UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); } -#ifdef WITH_NONFREE +#if FINDOBJECT_NONFREE == 1 else if(strategies.at(index).compare("SIFT") == 0) { detector = new cv::SIFT( @@ -596,12 +650,22 @@ DescriptorExtractor * Settings::createDescriptorExtractor() if(ok) { QStringList strategies = split.last().split(';'); -#ifdef WITH_NONFREE if(strategies.size() == 6 && index>=0 && index<6) -#else - if(strategies.size() == 4 && index>=0 && index<4) -#endif { + +#if FINDOBJECT_NONFREE == 0 + //check for nonfree stuff + if(strategies.at(index).compare("SIFT") == 0 || + strategies.at(index).compare("SURF") == 0) + { + index = Settings::defaultFeature2D_2Descriptor().split(':').first().toInt(); + UERROR("Find-Object is not built with OpenCV nonfree module so " + "SIFT/SURF cannot be used! Using default \"%s\" instead.", + strategies.at(index).toStdString().c_str()); + + } +#endif + if(strategies.at(index).compare("Brief") == 0) { extractor = new cv::BriefDescriptorExtractor( @@ -656,7 +720,7 @@ DescriptorExtractor * Settings::createDescriptorExtractor() getFeature2D_FREAK_nOctaves()); UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); } -#ifdef WITH_NONFREE +#if FINDOBJECT_NONFREE == 1 else if(strategies.at(index).compare("SIFT") == 0) { extractor = new cv::SIFT(