From d7247fba704755e73fe6d2cfa79725dd8245e07a Mon Sep 17 00:00:00 2001 From: matlabbe Date: Wed, 4 Jan 2012 17:30:36 +0000 Subject: [PATCH] Simplified Parameter getters to return directly the related type instead of QVariant Added Nearest neighbor min distance + statistics git-svn-id: http://find-object.googlecode.com/svn/trunk/find_object@60 620bd6b2-0a58-f614-fd9a-1bd335dccda9 --- src/Camera.cpp | 22 +++---- src/MainWindow.cpp | 59 +++++++++++++---- src/ParametersToolBox.cpp | 4 +- src/Settings.cpp | 132 +++++++++++++++++++------------------- src/Settings.h | 35 +++++++--- src/ui/mainWindow.ui | 30 ++++++++- 6 files changed, 182 insertions(+), 100 deletions(-) diff --git a/src/Camera.cpp b/src/Camera.cpp index 1f9f0faf..74d0ae0f 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -46,15 +46,15 @@ void Camera::takeImage() //resize if(img && - Settings::getCamera_imageWidth().toInt() && - Settings::getCamera_imageHeight().toInt() && - Settings::getCamera_imageWidth().toInt() != img->width && - Settings::getCamera_imageHeight().toInt() != img->height) + Settings::getCamera_imageWidth() && + Settings::getCamera_imageHeight() && + Settings::getCamera_imageWidth() != img->width && + Settings::getCamera_imageHeight() != img->height) { // declare a destination IplImage object with correct size, depth and channels cv::Mat headerImg = img; - cv::Mat imgMat(Settings::getCamera_imageHeight().toInt(), - Settings::getCamera_imageWidth().toInt(), + cv::Mat imgMat(Settings::getCamera_imageHeight(), + Settings::getCamera_imageWidth(), headerImg.type()); //use cvResize to resize source to a destination image (linear interpolation) @@ -73,11 +73,11 @@ bool Camera::start() { if(!capture_) { - capture_ = cvCaptureFromCAM(Settings::getCamera_deviceId().toInt()); + capture_ = cvCaptureFromCAM(Settings::getCamera_deviceId()); if(capture_) { - cvSetCaptureProperty(capture_, CV_CAP_PROP_FRAME_WIDTH, double(Settings::getCamera_imageWidth().toInt())); - cvSetCaptureProperty(capture_, CV_CAP_PROP_FRAME_HEIGHT, double(Settings::getCamera_imageHeight().toInt())); + cvSetCaptureProperty(capture_, CV_CAP_PROP_FRAME_WIDTH, double(Settings::getCamera_imageWidth())); + cvSetCaptureProperty(capture_, CV_CAP_PROP_FRAME_HEIGHT, double(Settings::getCamera_imageHeight())); } } if(!capture_) @@ -103,9 +103,9 @@ void Camera::stopTimer() void Camera::updateImageRate() { - if(Settings::getCamera_imageRate().toInt()) + if(Settings::getCamera_imageRate()) { - cameraTimer_.setInterval(1000/Settings::getCamera_imageRate().toInt()); + cameraTimer_.setInterval(1000/Settings::getCamera_imageRate()); } else { diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index fc163ac6..231262d2 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // Camera ownership transferred MainWindow::MainWindow(Camera * camera, QWidget * parent) : @@ -199,7 +200,7 @@ void MainWindow::showObject(ObjWidget * obj) QList objs = ui_->objects_area->findChildren(); QVBoxLayout * vLayout = new QVBoxLayout(); obj->setMinimumSize(obj->image().width(), obj->image().height()); - int id = Settings::getGeneral_nextObjID().toInt(); + int id = Settings::getGeneral_nextObjID(); if(obj->id() == 0) { obj->setId(id++); @@ -298,7 +299,7 @@ void MainWindow::startProcessing() else { this->statusBar()->clearMessage(); - QMessageBox::critical(this, tr("Camera error"), tr("Camera initialization failed! (with device %1)").arg(Settings::getCamera_deviceId().toInt())); + QMessageBox::critical(this, tr("Camera error"), tr("Camera initialization failed! (with device %1)").arg(Settings::getCamera_deviceId())); } } @@ -369,7 +370,7 @@ void MainWindow::update(const cv::Mat & image) // COMPARE int alpha = 20*255/100; - if(!dataTree_.empty()) + if(!dataTree_.empty() && (Settings::getNearestNeighbor_nndrRatioUsed() || Settings::getNearestNeighbor_minDistanceUsed())) { // CREATE INDEX cv::Mat environment(descriptors.rows, descriptors.cols, CV_32F); @@ -378,7 +379,11 @@ void MainWindow::update(const cv::Mat & image) ui_->label_timeIndexing->setText(QString::number(time.restart())); // DO NEAREST NEIGHBOR - int k = 2; + int k = 1; + if(Settings::getNearestNeighbor_nndrRatioUsed()) + { + k = 2; + } int emax = 64; cv::Mat results(dataTree_.rows, k, CV_32SC1); // results index cv::Mat dists(dataTree_.rows, k, CV_32FC1); // Distance results are CV_32FC1 @@ -396,11 +401,39 @@ void MainWindow::update(const cv::Mat & image) std::vector indexes_1, indexes_2; std::vector outlier_mask; QMap objectsPos; + float minMatchedDistance = -1.0f; + float maxMatchedDistance = -1.0f; for(int i=0; i(i,0) <= Settings::getNearestNeighbor_nndrRatio().toFloat() * dists.at(i,1)) + if(Settings::getNearestNeighbor_nndrRatioUsed() && + dists.at(i,0) <= Settings::getNearestNeighbor_nndrRatio() * dists.at(i,1)) + { + matched = true; + } + if((matched || !Settings::getNearestNeighbor_nndrRatioUsed()) && + Settings::getNearestNeighbor_minDistanceUsed()) + { + if(dists.at(i,0) <= Settings::getNearestNeighbor_minDistance()) + { + matched = true; + } + else + { + matched = false; + } + } + if(minMatchedDistance == -1 || minMatchedDistance>dists.at(i,0)) + { + minMatchedDistance = dists.at(i,0); + } + if(maxMatchedDistance == -1 || maxMatchedDistance(i,0)) + { + maxMatchedDistance = dists.at(i,0); + } + + if(matched) { if(j>0) { @@ -419,14 +452,14 @@ void MainWindow::update(const cv::Mat & image) if(i+1 >= dataRange_.at(j)) { QLabel * label = ui_->dockWidget_objects->findChild(QString("%1detection").arg(objects_.at(j)->id())); - if(mpts_1.size() >= Settings::getHomography_minimumInliers().toUInt()) + if(mpts_1.size() >= Settings::getHomography_minimumInliers()) { cv::Mat H = findHomography(mpts_1, mpts_2, cv::RANSAC, - Settings::getHomography_ransacReprojThr().toDouble(), + Settings::getHomography_ransacReprojThr(), outlier_mask); - int inliers=0, outliers=0; + uint inliers=0, outliers=0; QColor color((Qt::GlobalColor)(j % 12 + 7 )); color.setAlpha(alpha); for(unsigned int k=0; k= Settings::getHomography_minimumInliers().toInt()) + if(inliers >= Settings::getHomography_minimumInliers()) { if(this->isVisible()) { @@ -499,6 +532,8 @@ void MainWindow::update(const cv::Mat & image) ++j; } } + ui_->label_minMatchedDistance->setNum(minMatchedDistance); + ui_->label_maxMatchedDistance->setNum(maxMatchedDistance); if(objectsPos.size()) { @@ -533,9 +568,9 @@ void MainWindow::update(const cv::Mat & image) // Refresh the label only after each 1000 ms if(refreshStartTime_.elapsed() > 1000) { - if(Settings::getCamera_imageRate().toInt()>0) + if(Settings::getCamera_imageRate()>0) { - ui_->label_timeRefreshRate->setText(QString("(%1 Hz - %2 Hz)").arg(QString::number(Settings::getCamera_imageRate().toInt())).arg(QString::number(lowestRefreshRate_))); + ui_->label_timeRefreshRate->setText(QString("(%1 Hz - %2 Hz)").arg(QString::number(Settings::getCamera_imageRate())).arg(QString::number(lowestRefreshRate_))); } else { diff --git a/src/ParametersToolBox.cpp b/src/ParametersToolBox.cpp index eb697af7..f8a1751b 100644 --- a/src/ParametersToolBox.cpp +++ b/src/ParametersToolBox.cpp @@ -157,11 +157,11 @@ void ParametersToolBox::addParameter(QVBoxLayout * layout, if(def>0.0) { - widget->setMaximum(def*10.0); + widget->setMaximum(def*1000000.0); } else if(def<0.0) { - widget->setMinimum(def*10.0); + widget->setMinimum(def*1000000.0); widget->setMaximum(0.0); } widget->setValue(value); diff --git a/src/Settings.cpp b/src/Settings.cpp index 67eee329..e9ffcf8b 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -92,7 +92,7 @@ void Settings::saveSettings(const QString & fileName, const QByteArray & windowG cv::FeatureDetector * Settings::createFeaturesDetector() { cv::FeatureDetector * detector = 0; - QString str = getDetector_Type().toString(); + QString str = getDetector_Type(); QStringList split = str.split(':'); if(split.size()==2) { @@ -109,13 +109,13 @@ cv::FeatureDetector * Settings::createFeaturesDetector() if(strategies.at(index).compare("Dense") == 0) { cv::DenseFeatureDetector::Params params; - params.initFeatureScale = getDense_initFeatureScale().toFloat(); - params.featureScaleLevels = getDense_featureScaleLevels().toInt(); - params.featureScaleMul = getDense_featureScaleMul().toFloat(); - params.initXyStep = getDense_initXyStep().toInt(); - params.initImgBound = getDense_initImgBound().toInt(); - params.varyXyStepWithScale = getDense_varyXyStepWithScale().toBool(); - params.varyImgBoundWithScale = getDense_varyImgBoundWithScale().toBool(); + params.initFeatureScale = getDense_initFeatureScale(); + params.featureScaleLevels = getDense_featureScaleLevels(); + params.featureScaleMul = getDense_featureScaleMul(); + params.initXyStep = getDense_initXyStep(); + params.initImgBound = getDense_initImgBound(); + params.varyXyStepWithScale = getDense_varyXyStepWithScale(); + params.varyImgBoundWithScale = getDense_varyImgBoundWithScale(); detector = new cv::DenseFeatureDetector(params); } break; @@ -123,20 +123,20 @@ cv::FeatureDetector * Settings::createFeaturesDetector() if(strategies.at(index).compare("Fast") == 0) { detector = new cv::FastFeatureDetector( - getFast_threshold().toInt(), - getFast_nonmaxSuppression().toBool()); + getFast_threshold(), + getFast_nonmaxSuppression()); } break; case 2: if(strategies.at(index).compare("GoodFeaturesToTrack") == 0) { cv::GoodFeaturesToTrackDetector::Params params; - params.maxCorners = getGoodFeaturesToTrack_maxCorners().toInt(); - params.qualityLevel = getGoodFeaturesToTrack_qualityLevel().toDouble(); - params.minDistance = getGoodFeaturesToTrack_minDistance().toDouble(); - params.blockSize = getGoodFeaturesToTrack_blockSize().toInt(); - params.useHarrisDetector = getGoodFeaturesToTrack_useHarrisDetector().toBool(); - params.k = getGoodFeaturesToTrack_k().toDouble(); + params.maxCorners = getGoodFeaturesToTrack_maxCorners(); + params.qualityLevel = getGoodFeaturesToTrack_qualityLevel(); + params.minDistance = getGoodFeaturesToTrack_minDistance(); + params.blockSize = getGoodFeaturesToTrack_blockSize(); + params.useHarrisDetector = getGoodFeaturesToTrack_useHarrisDetector(); + params.k = getGoodFeaturesToTrack_k(); detector = new cv::GoodFeaturesToTrackDetector(params); } break; @@ -144,15 +144,15 @@ cv::FeatureDetector * Settings::createFeaturesDetector() if(strategies.at(index).compare("Mser") == 0) { CvMSERParams params = cvMSERParams(); - params.delta = getMser_delta().toInt(); - params.maxArea = getMser_maxArea().toInt(); - params.minArea = getMser_minArea().toInt(); - params.maxVariation = getMser_maxVariation().toFloat(); - params.minDiversity = getMser_minDiversity().toFloat(); - params.maxEvolution = getMser_maxEvolution().toInt(); - params.areaThreshold = getMser_areaThreshold().toDouble(); - params.minMargin = getMser_minMargin().toDouble(); - params.edgeBlurSize = getMser_edgeBlurSize().toInt(); + params.delta = getMser_delta(); + params.maxArea = getMser_maxArea(); + params.minArea = getMser_minArea(); + params.maxVariation = getMser_maxVariation(); + params.minDiversity = getMser_minDiversity(); + params.maxEvolution = getMser_maxEvolution(); + params.areaThreshold = getMser_areaThreshold(); + params.minMargin = getMser_minMargin(); + params.edgeBlurSize = getMser_edgeBlurSize(); detector = new cv::MserFeatureDetector(params); } break; @@ -160,12 +160,12 @@ cv::FeatureDetector * Settings::createFeaturesDetector() if(strategies.at(index).compare("Orb") == 0) { cv::ORB::CommonParams params; - params.scale_factor_ = getOrb_scaleFactor().toFloat(); - params.n_levels_ = getOrb_nLevels().toUInt(); - params.first_level_ = getOrb_firstLevel().toUInt(); - params.edge_threshold_ = getOrb_edgeThreshold().toInt(); + params.scale_factor_ = getOrb_scaleFactor(); + params.n_levels_ = getOrb_nLevels(); + params.first_level_ = getOrb_firstLevel(); + params.edge_threshold_ = getOrb_edgeThreshold(); detector = new cv::OrbFeatureDetector( - getOrb_nFeatures().toUInt(), + getOrb_nFeatures(), params); } break; @@ -173,13 +173,13 @@ cv::FeatureDetector * Settings::createFeaturesDetector() if(strategies.at(index).compare("Sift") == 0) { cv::SIFT::DetectorParams detectorParams; - detectorParams.edgeThreshold = getSift_edgeThreshold().toDouble(); - detectorParams.threshold = getSift_threshold().toDouble(); + detectorParams.edgeThreshold = getSift_edgeThreshold(); + detectorParams.threshold = getSift_threshold(); cv::SIFT::CommonParams commonParams; - commonParams.angleMode = getSift_angleMode().toInt(); - commonParams.firstOctave = getSift_firstOctave().toInt(); - commonParams.nOctaveLayers = getSift_nOctaveLayers().toInt(); - commonParams.nOctaves = getSift_nOctaves().toInt(); + commonParams.angleMode = getSift_angleMode(); + commonParams.firstOctave = getSift_firstOctave(); + commonParams.nOctaveLayers = getSift_nOctaveLayers(); + commonParams.nOctaves = getSift_nOctaves(); detector = new cv::SiftFeatureDetector( detectorParams, commonParams); @@ -189,11 +189,11 @@ cv::FeatureDetector * Settings::createFeaturesDetector() if(strategies.at(index).compare("Star") == 0) { CvStarDetectorParams params = cvStarDetectorParams(); - params.lineThresholdBinarized = getStar_lineThresholdBinarized().toInt(); - params.lineThresholdProjected = getStar_lineThresholdProjected().toInt(); - params.maxSize = getStar_maxSize().toInt(); - params.responseThreshold = getStar_responseThreshold().toInt(); - params.suppressNonmaxSize = getStar_suppressNonmaxSize().toInt(); + params.lineThresholdBinarized = getStar_lineThresholdBinarized(); + params.lineThresholdProjected = getStar_lineThresholdProjected(); + params.maxSize = getStar_maxSize(); + params.responseThreshold = getStar_responseThreshold(); + params.suppressNonmaxSize = getStar_suppressNonmaxSize(); detector = new cv::StarFeatureDetector(params); } break; @@ -201,10 +201,10 @@ cv::FeatureDetector * Settings::createFeaturesDetector() if(strategies.at(index).compare("Surf") == 0) { detector = new cv::SurfFeatureDetector( - getSurf_hessianThreshold().toDouble(), - getSurf_octaves().toInt(), - getSurf_octaveLayers().toInt(), - getSurf_upright().toBool()); + getSurf_hessianThreshold(), + getSurf_octaves(), + getSurf_octaveLayers(), + getSurf_upright()); } break; default: @@ -219,7 +219,7 @@ cv::FeatureDetector * Settings::createFeaturesDetector() cv::DescriptorExtractor * Settings::createDescriptorsExtractor() { cv::DescriptorExtractor * extractor = 0; - QString str = getDescriptor_Type().toString(); + QString str = getDescriptor_Type(); QStringList split = str.split(':'); if(split.size()==2) { @@ -236,17 +236,17 @@ cv::DescriptorExtractor * Settings::createDescriptorsExtractor() if(strategies.at(index).compare("Brief") == 0) { extractor = new cv::BriefDescriptorExtractor( - getBrief_bytes().toInt()); + getBrief_bytes()); } break; case 1: if(strategies.at(index).compare("Orb") == 0) { cv::ORB::CommonParams params; - params.scale_factor_ = getOrb_scaleFactor().toFloat(); - params.n_levels_ = getOrb_nLevels().toUInt(); - params.first_level_ = getOrb_firstLevel().toUInt(); - params.edge_threshold_ = getOrb_edgeThreshold().toInt(); + params.scale_factor_ = getOrb_scaleFactor(); + params.n_levels_ = getOrb_nLevels(); + params.first_level_ = getOrb_firstLevel(); + params.edge_threshold_ = getOrb_edgeThreshold(); extractor = new cv::OrbDescriptorExtractor(params); } break; @@ -254,14 +254,14 @@ cv::DescriptorExtractor * Settings::createDescriptorsExtractor() if(strategies.at(index).compare("Sift") == 0) { cv::SIFT::DescriptorParams descriptorParams; - descriptorParams.isNormalize = getSift_isNormalize().toBool(); - descriptorParams.magnification = getSift_magnification().toDouble(); - descriptorParams.recalculateAngles = getSift_recalculateAngles().toBool(); + descriptorParams.isNormalize = getSift_isNormalize(); + descriptorParams.magnification = getSift_magnification(); + descriptorParams.recalculateAngles = getSift_recalculateAngles(); cv::SIFT::CommonParams commonParams; - commonParams.angleMode = getSift_angleMode().toInt(); - commonParams.firstOctave = getSift_firstOctave().toInt(); - commonParams.nOctaveLayers = getSift_nOctaveLayers().toInt(); - commonParams.nOctaves = getSift_nOctaves().toInt(); + commonParams.angleMode = getSift_angleMode(); + commonParams.firstOctave = getSift_firstOctave(); + commonParams.nOctaveLayers = getSift_nOctaveLayers(); + commonParams.nOctaves = getSift_nOctaves(); extractor = new cv::SiftDescriptorExtractor( descriptorParams, commonParams); @@ -271,10 +271,10 @@ cv::DescriptorExtractor * Settings::createDescriptorsExtractor() if(strategies.at(index).compare("Surf") == 0) { extractor = new cv::SurfDescriptorExtractor( - getSurf_octaves().toInt(), - getSurf_octaveLayers().toInt(), - getSurf_extended().toBool(), - getSurf_upright().toBool()); + getSurf_octaves(), + getSurf_octaveLayers(), + getSurf_extended(), + getSurf_upright()); } break; default: @@ -289,13 +289,13 @@ cv::DescriptorExtractor * Settings::createDescriptorsExtractor() QString Settings::currentDetectorType() { - int index = Settings::getDetector_Type().toString().split(':').first().toInt(); - return getDetector_Type().toString().split(':').last().split(';').at(index); + int index = Settings::getDetector_Type().split(':').first().toInt(); + return getDetector_Type().split(':').last().split(';').at(index); } QString Settings::currentDescriptorType() { - int index = Settings::getDescriptor_Type().toString().split(':').first().toInt(); - return getDescriptor_Type().toString().split(':').last().split(';').at(index); + int index = Settings::getDescriptor_Type().split(':').first().toInt(); + return getDescriptor_Type().split(':').last().split(';').at(index); } diff --git a/src/Settings.h b/src/Settings.h index f0715608..b3ab9c4e 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -15,13 +15,29 @@ class Camera; typedef QMap ParametersMap; // Key, value typedef QMap ParametersType; // Key, type +typedef unsigned int uint; + // MACRO BEGIN + +#define PARAMETER_GETTER_bool(PREFIX, NAME) \ + static bool get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME).toBool();} +#define PARAMETER_GETTER_int(PREFIX, NAME) \ + static int get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME).toInt();} +#define PARAMETER_GETTER_uint(PREFIX, NAME) \ + static uint get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME).toUInt();} +#define PARAMETER_GETTER_float(PREFIX, NAME) \ + static float get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME).toFloat();} +#define PARAMETER_GETTER_double(PREFIX, NAME) \ + static double get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME).toDouble();} +#define PARAMETER_GETTER_QString(PREFIX, NAME) \ + static QString get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME).toString();} + #define PARAMETER(PREFIX, NAME, TYPE, DEFAULT_VALUE) \ public: \ static QString k##PREFIX##_##NAME() {return QString(#PREFIX "/" #NAME);} \ static TYPE default##PREFIX##_##NAME() {return DEFAULT_VALUE;} \ static QString type##PREFIX##_##NAME() {return QString(#TYPE);} \ - static QVariant get##PREFIX##_##NAME() {return parameters_.value(#PREFIX "/" #NAME);} \ + PARAMETER_GETTER_##TYPE(PREFIX, NAME) \ static void set##PREFIX##_##NAME(const TYPE & value) {parameters_[#PREFIX "/" #NAME] = value;} \ private: \ class Dummy##PREFIX##_##NAME { \ @@ -65,11 +81,11 @@ class Settings PARAMETER(GoodFeaturesToTrack, useHarrisDetector, bool, cv::GoodFeaturesToTrackDetector::Params().useHarrisDetector); PARAMETER(GoodFeaturesToTrack, k, double, cv::GoodFeaturesToTrackDetector::Params().k); - PARAMETER(Orb, nFeatures, unsigned int, 700); + PARAMETER(Orb, nFeatures, uint, 700); PARAMETER(Orb, scaleFactor, float, cv::ORB::CommonParams().scale_factor_); - PARAMETER(Orb, nLevels, unsigned int, cv::ORB::CommonParams().n_levels_); - PARAMETER(Orb, firstLevel, unsigned int, cv::ORB::CommonParams().first_level_); - PARAMETER(Orb, edgeThreshold, int, cv::ORB::CommonParams().edge_threshold_); + PARAMETER(Orb, nLevels, uint, cv::ORB::CommonParams().n_levels_); + PARAMETER(Orb, firstLevel, uint, cv::ORB::CommonParams().first_level_); + PARAMETER(Orb, edgeThreshold, uint, cv::ORB::CommonParams().edge_threshold_); PARAMETER(Mser, delta, int, cvMSERParams().delta); PARAMETER(Mser, minArea, int, cvMSERParams().minArea); @@ -103,12 +119,15 @@ class Settings PARAMETER(Surf, upright, bool, false); PARAMETER(Surf, extended, bool, false); - PARAMETER(NearestNeighbor, nndrRatio, float, 0.8f); // NNDR RATIO + PARAMETER(NearestNeighbor, nndrRatioUsed, bool, true); + PARAMETER(NearestNeighbor, nndrRatio, float, 0.8f); + PARAMETER(NearestNeighbor, minDistanceUsed, bool, false); + PARAMETER(NearestNeighbor, minDistance, float, 1.6f); - PARAMETER(General, nextObjID, unsigned int, 1); + PARAMETER(General, nextObjID, uint, 1); PARAMETER(Homography, ransacReprojThr, double, 1.0); - PARAMETER(Homography, minimumInliers, int, 10); + PARAMETER(Homography, minimumInliers, uint, 10); public: virtual ~Settings(){} diff --git a/src/ui/mainWindow.ui b/src/ui/mainWindow.ui index 939d4167..c21cfc65 100644 --- a/src/ui/mainWindow.ui +++ b/src/ui/mainWindow.ui @@ -200,7 +200,7 @@ - Timings + Statistics @@ -316,6 +316,34 @@ + + + + 000 + + + + + + + Min matched distance + + + + + + + Max matched distance + + + + + + + 000 + + +