diff --git a/CMakeLists.txt b/CMakeLists.txt index 709668f6..82349038 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,10 @@ FIND_PACKAGE(OpenCV REQUIRED) # tested on 2.3.1 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) + ####### OSX BUNDLE CMAKE_INSTALL_PREFIX ####### IF(APPLE) OPTION(BUILD_AS_BUNDLE "Set to ON to build as bundle (DragNDrop)" OFF) @@ -218,6 +222,11 @@ MESSAGE(STATUS "--------------------------------------------") MESSAGE(STATUS "Info :") MESSAGE(STATUS " CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}") MESSAGE(STATUS " CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}") +IF(OPENCV_NONFREE_FOUND) +MESSAGE(STATUS " With OpenCV nonfree module (SIFT/SURF) = YES") +ELSE() +MESSAGE(STATUS " With OpenCV nonfree module (SIFT/SURF) = NO (not found)") +ENDIF() IF(APPLE) MESSAGE(STATUS " BUILD_AS_BUNDLE = ${BUILD_AS_BUNDLE}") ENDIF(APPLE) diff --git a/include/find_object/Settings.h b/include/find_object/Settings.h index ca9a0488..5dcef704 100644 --- a/include/find_object/Settings.h +++ b/include/find_object/Settings.h @@ -94,8 +94,13 @@ 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(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."); @@ -142,18 +147,13 @@ class FINDOBJECT_EXP Settings PARAMETER(Feature2D, MSER_minMargin, double, 0.003, ""); PARAMETER(Feature2D, MSER_edgeBlurSize, int, 5, ""); +#ifdef WITH_NONFREE 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."); PARAMETER(Feature2D, SIFT_edgeThreshold, double, 10, "The threshold used to filter out edge-like features. Note that the its meaning is different from the contrastThreshold, i.e. the larger the edgeThreshold, the less features are filtered out (more features are retained)."); PARAMETER(Feature2D, SIFT_sigma, double, 1.6, "The sigma of the Gaussian applied to the input image at the octave #0. If your image is captured with a weak camera with soft lenses, you might want to reduce the number."); - PARAMETER(Feature2D, Star_maxSize, int, 45, ""); - PARAMETER(Feature2D, Star_responseThreshold, int, 30, ""); - PARAMETER(Feature2D, Star_lineThresholdProjected, int, 10, ""); - PARAMETER(Feature2D, Star_lineThresholdBinarized, int, 8, ""); - PARAMETER(Feature2D, Star_suppressNonmaxSize, int, 5, ""); - PARAMETER(Feature2D, SURF_hessianThreshold, double, 600.0, "Threshold for hessian keypoint detector used in SURF."); PARAMETER(Feature2D, SURF_nOctaves, int, 4, "Number of pyramid octaves the keypoint detector will use."); PARAMETER(Feature2D, SURF_nOctaveLayers, int, 2, "Number of octave layers within each octave."); @@ -161,6 +161,13 @@ class FINDOBJECT_EXP Settings PARAMETER(Feature2D, SURF_upright, bool, false, "Up-right or rotated features flag (true - do not compute orientation of features; false - compute orientation)."); PARAMETER(Feature2D, SURF_gpu, bool, false, "GPU-SURF: Use GPU version of SURF. This option is enabled only if OpenCV is built with CUDA and GPUs are detected."); PARAMETER(Feature2D, SURF_keypointsRatio, float, 0.01f, "Used with SURF GPU."); +#endif + + PARAMETER(Feature2D, Star_maxSize, int, 45, ""); + PARAMETER(Feature2D, Star_responseThreshold, int, 30, ""); + PARAMETER(Feature2D, Star_lineThresholdProjected, int, 10, ""); + PARAMETER(Feature2D, Star_lineThresholdBinarized, int, 8, ""); + PARAMETER(Feature2D, Star_suppressNonmaxSize, int, 5, ""); PARAMETER(Feature2D, BRISK_thresh, int, 30, "FAST/AGAST detection threshold score."); PARAMETER(Feature2D, BRISK_octaves, int, 3, "Detection octaves. Use 0 to do single scale."); @@ -171,16 +178,23 @@ 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."); - PARAMETER(NearestNeighbor, 1Strategy, QString, "1:Linear;KDTree;KMeans;Composite;Autotuned;Lsh", "Nearest neighbor strategy."); +#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(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."); PARAMETER(NearestNeighbor, 6minDistance, float, 1.6f, "Minimum distance. You can look at top of this panel where minimum and maximum distances are shown to properly set this parameter depending of the descriptor used."); - PARAMETER(NearestNeighbor, 7search_checks, int, 32, "The number of times the tree(s) in the index should be recursively traversed. A higher value for this parameter would give better search precision, but also take more time. If automatic configuration was used when the index was created, the number of checks required to achieve the specified precision was also computed, in which case this parameter is ignored."); - PARAMETER(NearestNeighbor, 8search_eps, float, 0, ""); - PARAMETER(NearestNeighbor, 9search_sorted, bool, true, ""); + PARAMETER(NearestNeighbor, BruteForce_gpu, bool, false, "Brute force GPU"); + + PARAMETER(NearestNeighbor, search_checks, int, 32, "The number of times the tree(s) in the index should be recursively traversed. A higher value for this parameter would give better search precision, but also take more time. If automatic configuration was used when the index was created, the number of checks required to achieve the specified precision was also computed, in which case this parameter is ignored."); + PARAMETER(NearestNeighbor, search_eps, float, 0, ""); + PARAMETER(NearestNeighbor, search_sorted, bool, true, ""); PARAMETER(NearestNeighbor, KDTree_trees, int, 4, "The number of parallel kd-trees to use. Good values are in the range [1..16]."); @@ -261,6 +275,7 @@ public: static QString currentDetectorType(); static QString currentNearestNeighborType(); + static bool isBruteForceNearestNeighbor(); static cv::flann::IndexParams * createFlannIndexParams(); static cvflann::flann_distance_t getFlannDistanceType(); static cv::flann::SearchParams getFlannSearchParams(); diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index e846503c..a91914f3 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -135,14 +135,18 @@ MainWindow::MainWindow(FindObject * findObject, Camera * camera, QWidget * paren if(cv::gpu::getCudaEnabledDeviceCount() == 0) { +#ifdef WITH_NONFREE ui_->toolBox->updateParameter(Settings::kFeature2D_SURF_gpu()); - ui_->toolBox->updateParameter(Settings::kFeature2D_Fast_gpu()); - ui_->toolBox->updateParameter(Settings::kFeature2D_ORB_gpu()); ui_->toolBox->getParameterWidget(Settings::kFeature2D_SURF_gpu())->setEnabled(false); ui_->toolBox->getParameterWidget(Settings::kFeature2D_SURF_keypointsRatio())->setEnabled(false); +#endif + ui_->toolBox->updateParameter(Settings::kFeature2D_Fast_gpu()); + ui_->toolBox->updateParameter(Settings::kFeature2D_ORB_gpu()); + ui_->toolBox->updateParameter(Settings::kNearestNeighbor_BruteForce_gpu()); ui_->toolBox->getParameterWidget(Settings::kFeature2D_Fast_gpu())->setEnabled(false); ui_->toolBox->getParameterWidget(Settings::kFeature2D_Fast_keypointsRatio())->setEnabled(false); ui_->toolBox->getParameterWidget(Settings::kFeature2D_ORB_gpu())->setEnabled(false); + ui_->toolBox->getParameterWidget(Settings::kNearestNeighbor_BruteForce_gpu())->setEnabled(false); } connect((QDoubleSpinBox*)ui_->toolBox->getParameterWidget(Settings::kCamera_4imageRate()), diff --git a/src/ParametersToolBox.cpp b/src/ParametersToolBox.cpp index 58e6aaa0..1bdc657d 100644 --- a/src/ParametersToolBox.cpp +++ b/src/ParametersToolBox.cpp @@ -204,6 +204,16 @@ void ParametersToolBox::updateParametersVisibility() else if(!objects[i]->objectName().split('/').at(1).at(0).isDigit()) { ((QWidget*)objects[i])->setVisible(false); + if(nnBox->currentIndex() < 6 && objects[i]->objectName().split('/').at(1).contains("search")) + { + //show flann search parameters + ((QWidget*)objects[i])->setVisible(true); + } + } + else if(objects[i]->objectName().split('/').at(1).contains("Distance_type")) + { + // don't show distance when bruteforce is selected + ((QWidget*)objects[i])->setVisible(nnBox->currentIndex() != 6); } } } @@ -494,16 +504,16 @@ void ParametersToolBox::changeParameter(const int & value) descriptorBox->currentText().compare("Brief") == 0 || descriptorBox->currentText().compare("BRISK") == 0 || descriptorBox->currentText().compare("FREAK") == 0; - if(isBinaryDescriptor && nnBox->currentText().compare("Lsh") != 0) + if(isBinaryDescriptor && nnBox->currentText().compare("Lsh") != 0 && nnBox->currentText().compare("BruteForce") != 0) { QMessageBox::warning(this, tr("Warning"), tr("Current selected descriptor type (\"%1\") is binary while nearest neighbor strategy is not (\"%2\").\n" - "Falling back to \"Lsh\" nearest neighbor strategy with Hamming distance (by default).") + "Falling back to \"BruteForce\" nearest neighbor strategy with Hamming distance (by default).") .arg(descriptorBox->currentText()) .arg(nnBox->currentText())); QString tmp = Settings::getNearestNeighbor_1Strategy(); - *tmp.begin() = '5'; // set LSH + *tmp.begin() = '6'; // set BruteForce Settings::setNearestNeighbor_1Strategy(tmp); tmp = Settings::getNearestNeighbor_2Distance_type(); *tmp.begin() = '8'; // set HAMMING @@ -561,7 +571,7 @@ void ParametersToolBox::changeParameter(const int & value) { QComboBox * nnBox = (QComboBox*)this->getParameterWidget(Settings::kNearestNeighbor_1Strategy()); QComboBox * distBox = (QComboBox*)this->getParameterWidget(Settings::kNearestNeighbor_2Distance_type()); - if(nnBox->currentText().compare("Lsh") != 0 && distBox->currentIndex() > 1) + if(nnBox->currentText().compare("BruteForce") != 0 && nnBox->currentText().compare("Lsh") != 0 && distBox->currentIndex() > 1) { QMessageBox::warning(this, tr("Warning"), diff --git a/src/Settings.cpp b/src/Settings.cpp index 2b814e46..230dc6fc 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -33,9 +33,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include +#ifdef WITH_NONFREE +#include #include +#endif #include namespace find_object { @@ -120,9 +122,12 @@ void Settings::loadSettings(const QString & fileName) if(cv::gpu::getCudaEnabledDeviceCount() == 0) { +#ifdef WITH_NONFREE Settings::setFeature2D_SURF_gpu(false); +#endif Settings::setFeature2D_Fast_gpu(false); Settings::setFeature2D_ORB_gpu(false); + Settings::setNearestNeighbor_BruteForce_gpu(false); } } @@ -217,6 +222,7 @@ public: cv::Mat & descriptors) = 0; }; +#ifdef WITH_NONFREE class GPUSURF : public GPUFeature2D { public: @@ -291,6 +297,7 @@ public: private: cv::gpu::SURF_GPU surf_; // HACK: static because detectImpl() is const! }; +#endif class GPUFAST : public GPUFeature2D { @@ -416,168 +423,151 @@ 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 { - switch(index) + if(strategies.at(index).compare("Dense") == 0) { - case 0: - if(strategies.at(index).compare("Dense") == 0) + detector = new cv::DenseFeatureDetector( + getFeature2D_Dense_initFeatureScale(), + getFeature2D_Dense_featureScaleLevels(), + getFeature2D_Dense_featureScaleMul(), + getFeature2D_Dense_initXyStep(), + getFeature2D_Dense_initImgBound(), + getFeature2D_Dense_varyXyStepWithScale(), + getFeature2D_Dense_varyImgBoundWithScale()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + else if(strategies.at(index).compare("Fast") == 0) + { + if(getFeature2D_Fast_gpu() && cv::gpu::getCudaEnabledDeviceCount()) { - detector = new cv::DenseFeatureDetector( - getFeature2D_Dense_initFeatureScale(), - getFeature2D_Dense_featureScaleLevels(), - getFeature2D_Dense_featureScaleMul(), - getFeature2D_Dense_initXyStep(), - getFeature2D_Dense_initImgBound(), - getFeature2D_Dense_varyXyStepWithScale(), - getFeature2D_Dense_varyImgBoundWithScale()); + detectorGPU = new GPUFAST( + getFeature2D_Fast_threshold(), + getFeature2D_Fast_nonmaxSuppression()); + UDEBUG("type=%s GPU", strategies.at(index).toStdString().c_str()); + } + else + { + detector = new cv::FastFeatureDetector( + getFeature2D_Fast_threshold(), + getFeature2D_Fast_nonmaxSuppression()); UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); } - break; - case 1: - if(strategies.at(index).compare("Fast") == 0) + } + else if(strategies.at(index).compare("GFTT") == 0) + { + detector = new cv::GFTTDetector( + getFeature2D_GFTT_maxCorners(), + getFeature2D_GFTT_qualityLevel(), + getFeature2D_GFTT_minDistance(), + getFeature2D_GFTT_blockSize(), + getFeature2D_GFTT_useHarrisDetector(), + getFeature2D_GFTT_k()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + else if(strategies.at(index).compare("MSER") == 0) + { + detector = new cv::MSER( + getFeature2D_MSER_delta(), + getFeature2D_MSER_minArea(), + getFeature2D_MSER_maxArea(), + getFeature2D_MSER_maxVariation(), + getFeature2D_MSER_minDiversity(), + getFeature2D_MSER_maxEvolution(), + getFeature2D_MSER_areaThreshold(), + getFeature2D_MSER_minMargin(), + getFeature2D_MSER_edgeBlurSize()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + else if(strategies.at(index).compare("ORB") == 0) + { + if(getFeature2D_ORB_gpu() && cv::gpu::getCudaEnabledDeviceCount()) { - if(getFeature2D_Fast_gpu() && cv::gpu::getCudaEnabledDeviceCount()) - { - detectorGPU = new GPUFAST( - getFeature2D_Fast_threshold(), - getFeature2D_Fast_nonmaxSuppression()); - UDEBUG("type=%s GPU", strategies.at(index).toStdString().c_str()); - } - else - { - detector = new cv::FastFeatureDetector( - getFeature2D_Fast_threshold(), - getFeature2D_Fast_nonmaxSuppression()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } + detectorGPU = new GPUORB( + getFeature2D_ORB_nFeatures(), + getFeature2D_ORB_scaleFactor(), + getFeature2D_ORB_nLevels(), + getFeature2D_ORB_edgeThreshold(), + getFeature2D_ORB_firstLevel(), + getFeature2D_ORB_WTA_K(), + getFeature2D_ORB_scoreType(), + getFeature2D_ORB_patchSize(), + getFeature2D_Fast_threshold(), + getFeature2D_Fast_nonmaxSuppression()); + UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); } - break; - case 2: - if(strategies.at(index).compare("GFTT") == 0) + else { - detector = new cv::GFTTDetector( - getFeature2D_GFTT_maxCorners(), - getFeature2D_GFTT_qualityLevel(), - getFeature2D_GFTT_minDistance(), - getFeature2D_GFTT_blockSize(), - getFeature2D_GFTT_useHarrisDetector(), - getFeature2D_GFTT_k()); + detector = new cv::ORB( + getFeature2D_ORB_nFeatures(), + getFeature2D_ORB_scaleFactor(), + getFeature2D_ORB_nLevels(), + getFeature2D_ORB_edgeThreshold(), + getFeature2D_ORB_firstLevel(), + getFeature2D_ORB_WTA_K(), + getFeature2D_ORB_scoreType(), + getFeature2D_ORB_patchSize()); UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); } - break; - case 3: - if(strategies.at(index).compare("MSER") == 0) + } + else if(strategies.at(index).compare("Star") == 0) + { + detector = new cv::StarFeatureDetector( + getFeature2D_Star_maxSize(), + getFeature2D_Star_responseThreshold(), + getFeature2D_Star_lineThresholdProjected(), + getFeature2D_Star_lineThresholdBinarized(), + getFeature2D_Star_suppressNonmaxSize()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + else if(strategies.at(index).compare("BRISK") == 0) + { + detector = new cv::BRISK( + getFeature2D_BRISK_thresh(), + getFeature2D_BRISK_octaves(), + getFeature2D_BRISK_patternScale()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } +#ifdef WITH_NONFREE + else if(strategies.at(index).compare("SIFT") == 0) + { + detector = new cv::SIFT( + getFeature2D_SIFT_nfeatures(), + getFeature2D_SIFT_nOctaveLayers(), + getFeature2D_SIFT_contrastThreshold(), + getFeature2D_SIFT_edgeThreshold(), + getFeature2D_SIFT_sigma()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + else if(strategies.at(index).compare("SURF") == 0) + { + if(getFeature2D_SURF_gpu() && cv::gpu::getCudaEnabledDeviceCount()) { - detector = new cv::MSER( - getFeature2D_MSER_delta(), - getFeature2D_MSER_minArea(), - getFeature2D_MSER_maxArea(), - getFeature2D_MSER_maxVariation(), - getFeature2D_MSER_minDiversity(), - getFeature2D_MSER_maxEvolution(), - getFeature2D_MSER_areaThreshold(), - getFeature2D_MSER_minMargin(), - getFeature2D_MSER_edgeBlurSize()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - break; - case 4: - if(strategies.at(index).compare("ORB") == 0) - { - if(getFeature2D_ORB_gpu() && cv::gpu::getCudaEnabledDeviceCount()) - { - detectorGPU = new GPUORB( - getFeature2D_ORB_nFeatures(), - getFeature2D_ORB_scaleFactor(), - getFeature2D_ORB_nLevels(), - getFeature2D_ORB_edgeThreshold(), - getFeature2D_ORB_firstLevel(), - getFeature2D_ORB_WTA_K(), - getFeature2D_ORB_scoreType(), - getFeature2D_ORB_patchSize(), - getFeature2D_Fast_threshold(), - getFeature2D_Fast_nonmaxSuppression()); - UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); - } - else - { - detector = new cv::ORB( - getFeature2D_ORB_nFeatures(), - getFeature2D_ORB_scaleFactor(), - getFeature2D_ORB_nLevels(), - getFeature2D_ORB_edgeThreshold(), - getFeature2D_ORB_firstLevel(), - getFeature2D_ORB_WTA_K(), - getFeature2D_ORB_scoreType(), - getFeature2D_ORB_patchSize()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - } - break; - case 5: - if(strategies.at(index).compare("SIFT") == 0) - { - detector = new cv::SIFT( - getFeature2D_SIFT_nfeatures(), - getFeature2D_SIFT_nOctaveLayers(), - getFeature2D_SIFT_contrastThreshold(), - getFeature2D_SIFT_edgeThreshold(), - getFeature2D_SIFT_sigma()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - break; - case 6: - if(strategies.at(index).compare("Star") == 0) - { - detector = new cv::StarFeatureDetector( - getFeature2D_Star_maxSize(), - getFeature2D_Star_responseThreshold(), - getFeature2D_Star_lineThresholdProjected(), - getFeature2D_Star_lineThresholdBinarized(), - getFeature2D_Star_suppressNonmaxSize()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - break; - case 7: - if(strategies.at(index).compare("SURF") == 0) - { - if(getFeature2D_SURF_gpu() && cv::gpu::getCudaEnabledDeviceCount()) - { - detectorGPU = new GPUSURF( - getFeature2D_SURF_hessianThreshold(), - getFeature2D_SURF_nOctaves(), - getFeature2D_SURF_nOctaveLayers(), - getFeature2D_SURF_extended(), - getFeature2D_SURF_keypointsRatio(), - getFeature2D_SURF_upright()); - UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); - } - else - { - detector = new cv::SURF( + detectorGPU = new GPUSURF( getFeature2D_SURF_hessianThreshold(), getFeature2D_SURF_nOctaves(), getFeature2D_SURF_nOctaveLayers(), getFeature2D_SURF_extended(), + getFeature2D_SURF_keypointsRatio(), getFeature2D_SURF_upright()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } + UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); } - break; - case 8: - if(strategies.at(index).compare("BRISK") == 0) + else { - detector = new cv::BRISK( - getFeature2D_BRISK_thresh(), - getFeature2D_BRISK_octaves(), - getFeature2D_BRISK_patternScale()); + detector = new cv::SURF( + getFeature2D_SURF_hessianThreshold(), + getFeature2D_SURF_nOctaves(), + getFeature2D_SURF_nOctaveLayers(), + getFeature2D_SURF_extended(), + getFeature2D_SURF_upright()); UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); } - break; - default: - break; } +#endif } } } @@ -606,113 +596,102 @@ 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 { - switch(index) + if(strategies.at(index).compare("Brief") == 0) { - case 0: - if(strategies.at(index).compare("Brief") == 0) - { - extractor = new cv::BriefDescriptorExtractor( - getFeature2D_Brief_bytes()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - break; - case 1: - if(strategies.at(index).compare("ORB") == 0) - { - if(getFeature2D_ORB_gpu() && cv::gpu::getCudaEnabledDeviceCount()) - { - extractorGPU = new GPUORB( - getFeature2D_ORB_nFeatures(), - getFeature2D_ORB_scaleFactor(), - getFeature2D_ORB_nLevels(), - getFeature2D_ORB_edgeThreshold(), - getFeature2D_ORB_firstLevel(), - getFeature2D_ORB_WTA_K(), - getFeature2D_ORB_scoreType(), - getFeature2D_ORB_patchSize(), - getFeature2D_Fast_threshold(), - getFeature2D_Fast_nonmaxSuppression()); - UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); - } - else - { - extractor = new cv::ORB( - getFeature2D_ORB_nFeatures(), - getFeature2D_ORB_scaleFactor(), - getFeature2D_ORB_nLevels(), - getFeature2D_ORB_edgeThreshold(), - getFeature2D_ORB_firstLevel(), - getFeature2D_ORB_WTA_K(), - getFeature2D_ORB_scoreType(), - getFeature2D_ORB_patchSize()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - } - break; - case 2: - if(strategies.at(index).compare("SIFT") == 0) - { - extractor = new cv::SIFT( - getFeature2D_SIFT_nfeatures(), - getFeature2D_SIFT_nOctaveLayers(), - getFeature2D_SIFT_contrastThreshold(), - getFeature2D_SIFT_edgeThreshold(), - getFeature2D_SIFT_sigma()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - break; - case 3: - if(strategies.at(index).compare("SURF") == 0) - { - if(getFeature2D_SURF_gpu() && cv::gpu::getCudaEnabledDeviceCount()) - { - extractorGPU = new GPUSURF( - getFeature2D_SURF_hessianThreshold(), - getFeature2D_SURF_nOctaves(), - getFeature2D_SURF_nOctaveLayers(), - getFeature2D_SURF_extended(), - getFeature2D_SURF_keypointsRatio(), - getFeature2D_SURF_upright()); - UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); - } - else - { - extractor = new cv::SURF( - getFeature2D_SURF_hessianThreshold(), - getFeature2D_SURF_nOctaves(), - getFeature2D_SURF_nOctaveLayers(), - getFeature2D_SURF_extended(), - getFeature2D_SURF_upright()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - } - break; - case 4: - if(strategies.at(index).compare("BRISK") == 0) - { - extractor = new cv::BRISK( - getFeature2D_BRISK_thresh(), - getFeature2D_BRISK_octaves(), - getFeature2D_BRISK_patternScale()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - break; - case 5: - if(strategies.at(index).compare("FREAK") == 0) - { - extractor = new cv::FREAK( - getFeature2D_FREAK_orientationNormalized(), - getFeature2D_FREAK_scaleNormalized(), - getFeature2D_FREAK_patternScale(), - getFeature2D_FREAK_nOctaves()); - UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); - } - break; - default: - break; + extractor = new cv::BriefDescriptorExtractor( + getFeature2D_Brief_bytes()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); } + else if(strategies.at(index).compare("ORB") == 0) + { + if(getFeature2D_ORB_gpu() && cv::gpu::getCudaEnabledDeviceCount()) + { + extractorGPU = new GPUORB( + getFeature2D_ORB_nFeatures(), + getFeature2D_ORB_scaleFactor(), + getFeature2D_ORB_nLevels(), + getFeature2D_ORB_edgeThreshold(), + getFeature2D_ORB_firstLevel(), + getFeature2D_ORB_WTA_K(), + getFeature2D_ORB_scoreType(), + getFeature2D_ORB_patchSize(), + getFeature2D_Fast_threshold(), + getFeature2D_Fast_nonmaxSuppression()); + UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); + } + else + { + extractor = new cv::ORB( + getFeature2D_ORB_nFeatures(), + getFeature2D_ORB_scaleFactor(), + getFeature2D_ORB_nLevels(), + getFeature2D_ORB_edgeThreshold(), + getFeature2D_ORB_firstLevel(), + getFeature2D_ORB_WTA_K(), + getFeature2D_ORB_scoreType(), + getFeature2D_ORB_patchSize()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + } + else if(strategies.at(index).compare("BRISK") == 0) + { + extractor = new cv::BRISK( + getFeature2D_BRISK_thresh(), + getFeature2D_BRISK_octaves(), + getFeature2D_BRISK_patternScale()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + else if(strategies.at(index).compare("FREAK") == 0) + { + extractor = new cv::FREAK( + getFeature2D_FREAK_orientationNormalized(), + getFeature2D_FREAK_scaleNormalized(), + getFeature2D_FREAK_patternScale(), + getFeature2D_FREAK_nOctaves()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } +#ifdef WITH_NONFREE + else if(strategies.at(index).compare("SIFT") == 0) + { + extractor = new cv::SIFT( + getFeature2D_SIFT_nfeatures(), + getFeature2D_SIFT_nOctaveLayers(), + getFeature2D_SIFT_contrastThreshold(), + getFeature2D_SIFT_edgeThreshold(), + getFeature2D_SIFT_sigma()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + else if(strategies.at(index).compare("SURF") == 0) + { + if(getFeature2D_SURF_gpu() && cv::gpu::getCudaEnabledDeviceCount()) + { + extractorGPU = new GPUSURF( + getFeature2D_SURF_hessianThreshold(), + getFeature2D_SURF_nOctaves(), + getFeature2D_SURF_nOctaveLayers(), + getFeature2D_SURF_extended(), + getFeature2D_SURF_keypointsRatio(), + getFeature2D_SURF_upright()); + UDEBUG("type=%s (GPU)", strategies.at(index).toStdString().c_str()); + } + else + { + extractor = new cv::SURF( + getFeature2D_SURF_hessianThreshold(), + getFeature2D_SURF_nOctaves(), + getFeature2D_SURF_nOctaveLayers(), + getFeature2D_SURF_extended(), + getFeature2D_SURF_upright()); + UDEBUG("type=%s", strategies.at(index).toStdString().c_str()); + } + } +#endif } } } @@ -746,6 +725,27 @@ QString Settings::currentNearestNeighborType() return getNearestNeighbor_1Strategy().split(':').last().split(';').at(index); } +bool Settings::isBruteForceNearestNeighbor() +{ + bool bruteForce = false; + QString str = getNearestNeighbor_1Strategy(); + QStringList split = str.split(':'); + if(split.size()==2) + { + bool ok = false; + int index = split.first().toInt(&ok); + if(ok) + { + QStringList strategies = split.last().split(';'); + if(strategies.size() >= 7 && index == 6) + { + bruteForce = true; + } + } + } + return bruteForce; +} + cv::flann::IndexParams * Settings::createFlannIndexParams() { cv::flann::IndexParams * params = 0; @@ -758,7 +758,7 @@ cv::flann::IndexParams * Settings::createFlannIndexParams() if(ok) { QStringList strategies = split.last().split(';'); - if(strategies.size() == 6 && index>=0 && index<6) + if(strategies.size() >= 6 && index>=0 && index<6) { switch(index) { @@ -884,9 +884,9 @@ cvflann::flann_distance_t Settings::getFlannDistanceType() cv::flann::SearchParams Settings::getFlannSearchParams() { return cv::flann::SearchParams( - getNearestNeighbor_7search_checks(), - getNearestNeighbor_8search_eps(), - getNearestNeighbor_9search_sorted()); + getNearestNeighbor_search_checks(), + getNearestNeighbor_search_eps(), + getNearestNeighbor_search_sorted()); } int Settings::getHomographyMethod() diff --git a/src/Vocabulary.cpp b/src/Vocabulary.cpp index 92186610..6dcd269d 100644 --- a/src/Vocabulary.cpp +++ b/src/Vocabulary.cpp @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Vocabulary.h" #include #include +#include namespace find_object { @@ -67,7 +68,7 @@ QMultiMap Vocabulary::addWords(const cv::Mat & descriptors, int object if(!indexedDescriptors_.empty() && indexedDescriptors_.rows >= (int)k) { Q_ASSERT(indexedDescriptors_.type() == descriptors.type() && indexedDescriptors_.cols == descriptors.cols); - flannIndex_.knnSearch(descriptors, results, dists, k, Settings::getFlannSearchParams() ); + this->search(descriptors, results, dists, k); if( dists.type() == CV_32S ) { @@ -207,7 +208,7 @@ void Vocabulary::update() notIndexedWordIds_.clear(); } - if(!indexedDescriptors_.empty()) + if(!indexedDescriptors_.empty() && !Settings::isBruteForceNearestNeighbor()) { cv::flann::IndexParams * params = Settings::createFlannIndexParams(); flannIndex_.build(indexedDescriptors_, *params, Settings::getFlannDistanceType()); @@ -223,7 +224,46 @@ void Vocabulary::search(const cv::Mat & descriptors, cv::Mat & results, cv::Mat { Q_ASSERT(descriptors.type() == indexedDescriptors_.type() && descriptors.cols == indexedDescriptors_.cols); - flannIndex_.knnSearch(descriptors, results, dists, k, Settings::getFlannSearchParams()); + if(Settings::isBruteForceNearestNeighbor()) + { + std::vector > matches; + if(Settings::getNearestNeighbor_BruteForce_gpu() && cv::gpu::getCudaEnabledDeviceCount()) + { + cv::gpu::GpuMat newDescriptorsGpu(descriptors); + cv::gpu::GpuMat lastDescriptorsGpu(indexedDescriptors_); + if(indexedDescriptors_.type()==CV_8U) + { + cv::gpu::BruteForceMatcher_GPU gpuMatcher; + gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k); + } + else + { + cv::gpu::BruteForceMatcher_GPU > gpuMatcher; + gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k); + } + } + else + { + cv::BFMatcher matcher(indexedDescriptors_.type()==CV_8U?cv::NORM_HAMMING:cv::NORM_L2); + matcher.knnMatch(descriptors, indexedDescriptors_, matches, k); + } + + //convert back to matrix style + results = cv::Mat(matches.size(), k, CV_32SC1); + dists = cv::Mat(matches.size(), k, CV_32FC1); + for(unsigned int i=0; i(i, j) = matches[i].at(j).trainIdx; + dists.at(i, j) = matches[i].at(j).distance; + } + } + } + else + { + flannIndex_.knnSearch(descriptors, results, dists, k, Settings::getFlannSearchParams()); + } if( dists.type() == CV_32S ) {