Added Load/Save vocabulary actions in File menu (in console mode, see "--vocabulary" option) (issue #2)
This commit is contained in:
parent
a4a9b8ca5f
commit
dd14e5e1ca
119
app/main.cpp
119
app/main.cpp
@ -99,15 +99,19 @@ void showUsage()
|
||||
" --console Don't use the GUI (by default the camera will be\n"
|
||||
" started automatically). Option --objects must also be\n"
|
||||
" used with valid objects.\n"
|
||||
" --session \"path\" Path to a session to load (*.bin).\n"
|
||||
" --session \"path\" Path to a session to load (*.bin). Use \"--session_new\" to\n"
|
||||
" create a session instead (will be saved to \"path\" on exit, only\n"
|
||||
" on console mode).\n"
|
||||
" --object \"path\" Path to an object to detect.\n"
|
||||
" --objects \"path\" Directory of the objects to detect (--object is ignored).\n"
|
||||
" --config \"path\" Path to configuration file (default: %s).\n"
|
||||
" If set to \"\", default parameters are used "
|
||||
" If set to \"\", default parameters are used\n"
|
||||
" without saving modified parameters on closing.\n"
|
||||
" --scene \"path\" Path to a scene image file.\n"
|
||||
" --vocabulary \"path\" Path to a vocabulary file (*.yaml *.xml). Parameters \"General/invertedSearch\"\n"
|
||||
" and \"General/vocabularyFixed\" will be also enabled. Ignored if \"--session\" is set.\n"
|
||||
" --images_not_saved Don't keep images in RAM after the features are extracted (only\n"
|
||||
" in console mode). Images won't be saved if an output session is set.\n"
|
||||
" in console mode). Images won't be saved if an output session is set.\n"
|
||||
" --debug Show debug log.\n"
|
||||
" --debug-time Show debug log with time.\n"
|
||||
" --params Show all parameters.\n"
|
||||
@ -133,10 +137,12 @@ int main(int argc, char* argv[])
|
||||
//////////////////////////
|
||||
bool guiMode = true;
|
||||
QString sessionPath = "";
|
||||
bool sessionNew = false;
|
||||
QString objectsPath = "";
|
||||
QString objectPath = "";
|
||||
QString scenePath = "";
|
||||
QString configPath = find_object::Settings::iniDefaultPath();
|
||||
QString vocabularyPath = "";
|
||||
QString jsonPath;
|
||||
find_object::ParametersMap customParameters;
|
||||
bool imagesSaved = true;
|
||||
@ -176,8 +182,15 @@ int main(int argc, char* argv[])
|
||||
continue;
|
||||
}
|
||||
if(strcmp(argv[i], "-session") == 0 ||
|
||||
strcmp(argv[i], "--session") == 0)
|
||||
strcmp(argv[i], "--session") == 0 ||
|
||||
strcmp(argv[i], "-session_new") == 0 ||
|
||||
strcmp(argv[i], "--session_new") == 0)
|
||||
{
|
||||
if(strcmp(argv[i], "-session_new") == 0 ||
|
||||
strcmp(argv[i], "--session_new") == 0)
|
||||
{
|
||||
sessionNew = true;
|
||||
}
|
||||
++i;
|
||||
if(i < argc)
|
||||
{
|
||||
@ -186,9 +199,10 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
sessionPath.replace('~', QDir::homePath());
|
||||
}
|
||||
if(!QFile(sessionPath).exists())
|
||||
|
||||
if(!sessionNew && !QFile(sessionPath).exists())
|
||||
{
|
||||
UERROR("Session path not valid : %s", sessionPath.toStdString().c_str());
|
||||
UERROR("Session path not valid : %s (if you want to create a new session, use \"--session_new\")", sessionPath.toStdString().c_str());
|
||||
showUsage();
|
||||
}
|
||||
}
|
||||
@ -244,6 +258,29 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(strcmp(argv[i], "-vocabulary") == 0 ||
|
||||
strcmp(argv[i], "--vocabulary") == 0)
|
||||
{
|
||||
++i;
|
||||
if(i < argc)
|
||||
{
|
||||
vocabularyPath = argv[i];
|
||||
if(vocabularyPath.contains('~'))
|
||||
{
|
||||
vocabularyPath.replace('~', QDir::homePath());
|
||||
}
|
||||
if(!QFile(vocabularyPath).exists())
|
||||
{
|
||||
UERROR("Vocabulary path not valid : %s", vocabularyPath.toStdString().c_str());
|
||||
showUsage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
showUsage();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(strcmp(argv[i], "-config") == 0 ||
|
||||
strcmp(argv[i], "--config") == 0)
|
||||
{
|
||||
@ -365,7 +402,14 @@ int main(int argc, char* argv[])
|
||||
UINFO(" GUI mode = %s", guiMode?"true":"false");
|
||||
if(!sessionPath.isEmpty())
|
||||
{
|
||||
UINFO(" Session path: \"%s\"", sessionPath.toStdString().c_str());
|
||||
if(sessionNew)
|
||||
{
|
||||
UINFO(" Session path: \"%s\" [NEW]", sessionPath.toStdString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
UINFO(" Session path: \"%s\"", sessionPath.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
else if(!objectsPath.isEmpty())
|
||||
{
|
||||
@ -381,6 +425,21 @@ int main(int argc, char* argv[])
|
||||
UINFO(" JSON path: \"%s\"", jsonPath.toStdString().c_str());
|
||||
}
|
||||
UINFO(" Settings path: \"%s\"", configPath.toStdString().c_str());
|
||||
UINFO(" Vocabulary path: \"%s\"", vocabularyPath.toStdString().c_str());
|
||||
|
||||
if(!vocabularyPath.isEmpty())
|
||||
{
|
||||
if(customParameters.contains(find_object::Settings::kGeneral_vocabularyFixed()))
|
||||
{
|
||||
UWARN("\"General/vocabularyFixed\" custom parameter overwritten as a fixed vocabulary is used.");
|
||||
}
|
||||
if(customParameters.contains(find_object::Settings::kGeneral_invertedSearch()))
|
||||
{
|
||||
UWARN("\"General/invertedSearch\" custom parameter overwritten as a fixed vocabulary is used.");
|
||||
}
|
||||
customParameters[find_object::Settings::kGeneral_vocabularyFixed()] = true;
|
||||
customParameters[find_object::Settings::kGeneral_invertedSearch()] = true;
|
||||
}
|
||||
|
||||
for(find_object::ParametersMap::iterator iter= customParameters.begin(); iter!=customParameters.end(); ++iter)
|
||||
{
|
||||
@ -405,8 +464,14 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Load objects if path is set
|
||||
int objectsLoaded = 0;
|
||||
if(!sessionPath.isEmpty())
|
||||
if(!sessionPath.isEmpty() && !sessionNew)
|
||||
{
|
||||
if(!vocabularyPath.isEmpty() && !findObject->loadVocabulary(vocabularyPath))
|
||||
{
|
||||
UWARN("Vocabulary \"%s\" is not loaded as a session \"%s\" is already loaded",
|
||||
vocabularyPath.toStdString().c_str(),
|
||||
sessionPath.toStdString().c_str());
|
||||
}
|
||||
if(!findObject->loadSession(sessionPath))
|
||||
{
|
||||
UERROR("Could not load session \"%s\"", sessionPath.toStdString().c_str());
|
||||
@ -418,6 +483,10 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
else if(!objectsPath.isEmpty())
|
||||
{
|
||||
if(!vocabularyPath.isEmpty() && !findObject->loadVocabulary(vocabularyPath))
|
||||
{
|
||||
UERROR("Failed to load vocabulary \"%s\"", vocabularyPath.toStdString().c_str());
|
||||
}
|
||||
objectsLoaded = findObject->loadObjects(objectsPath);
|
||||
if(!objectsLoaded)
|
||||
{
|
||||
@ -426,6 +495,11 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
else if(!objectPath.isEmpty())
|
||||
{
|
||||
if(!vocabularyPath.isEmpty() && !findObject->loadVocabulary(vocabularyPath))
|
||||
{
|
||||
UERROR("Failed to load vocabulary \"%s\"", vocabularyPath.toStdString().c_str());
|
||||
}
|
||||
|
||||
const find_object::ObjSignature * obj = findObject->addObject(objectPath);
|
||||
if(obj)
|
||||
{
|
||||
@ -438,6 +512,11 @@ int main(int argc, char* argv[])
|
||||
UWARN("No object loaded from \"%s\"", objectsPath.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
else if(!vocabularyPath.isEmpty() && !findObject->loadVocabulary(vocabularyPath))
|
||||
{
|
||||
UERROR("Failed to load vocabulary \"%s\"", vocabularyPath.toStdString().c_str());
|
||||
}
|
||||
|
||||
cv::Mat scene;
|
||||
if(!scenePath.isEmpty())
|
||||
{
|
||||
@ -468,13 +547,6 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
if(objectsLoaded == 0)
|
||||
{
|
||||
UERROR("In console mode, at least one object must be loaded! See -console option.");
|
||||
delete findObject;
|
||||
showUsage();
|
||||
}
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
if(!scene.empty())
|
||||
@ -535,13 +607,20 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
app.exec();
|
||||
|
||||
if(!sessionPath.isEmpty() && findObject->isSessionModified())
|
||||
if(!sessionPath.isEmpty())
|
||||
{
|
||||
UINFO("The session has been modified, updating the session file...");
|
||||
if(findObject->saveSession(sessionPath))
|
||||
if(findObject->isSessionModified())
|
||||
{
|
||||
UINFO("Session \"%s\" successfully saved (%d objects)!",
|
||||
sessionPath.toStdString().c_str(), findObject->objects().size());
|
||||
UINFO("The session has been modified, updating the session file...");
|
||||
if(findObject->saveSession(sessionPath))
|
||||
{
|
||||
UINFO("Session \"%s\" successfully saved (%d objects)!",
|
||||
sessionPath.toStdString().c_str(), findObject->objects().size());
|
||||
}
|
||||
}
|
||||
else if(sessionNew)
|
||||
{
|
||||
UINFO("The session has not been modified, session file not created...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +69,9 @@ public:
|
||||
bool saveSession(const QString & path);
|
||||
bool isSessionModified() const {return sessionModified_;}
|
||||
|
||||
bool saveVocabulary(const QString & filePath) const;
|
||||
bool loadVocabulary(const QString & filePath);
|
||||
|
||||
int loadObjects(const QString & dirPath, bool recursive = false); // call updateObjects()
|
||||
const ObjSignature * addObject(const QString & filePath);
|
||||
const ObjSignature * addObject(const cv::Mat & image, int id=0, const QString & filePath = QString());
|
||||
|
||||
@ -87,6 +87,8 @@ private Q_SLOTS:
|
||||
void saveSettings();
|
||||
void loadObjects();
|
||||
bool saveObjects();
|
||||
void loadVocabulary();
|
||||
void saveVocabulary();
|
||||
void addObjectFromScene();
|
||||
void addObjectsFromFiles(const QStringList & fileNames);
|
||||
void addObjectsFromFiles();
|
||||
@ -104,7 +106,7 @@ private Q_SLOTS:
|
||||
void showHideControls();
|
||||
void showObjectsFeatures();
|
||||
void hideObjectsFeatures();
|
||||
void updateObjects(const QList<int> & ids = QList<int>());
|
||||
void updateObjects();
|
||||
void notifyParametersChanged(const QStringList & param);
|
||||
void moveCameraFrame(int frame);
|
||||
void rectHovered(int objId);
|
||||
@ -122,6 +124,7 @@ private:
|
||||
void showObject(find_object::ObjWidget * obj);
|
||||
void updateObjectSize(find_object::ObjWidget * obj);
|
||||
void updateVocabulary(const QList<int> & ids = QList<int>());
|
||||
void updateObjects(const QList<int> & ids);
|
||||
|
||||
private:
|
||||
Ui_mainWindow * ui_;
|
||||
|
||||
@ -81,7 +81,7 @@ public:
|
||||
const std::vector<cv::KeyPoint> keypoints() const {return keypoints_;}
|
||||
const QMap<int,int> & words() const {return words_;}
|
||||
const QPixmap & pixmap() const {return pixmap_;}
|
||||
QColor defaultColor() const;
|
||||
QColor defaultColor(int id) const;
|
||||
bool isImageShown() const;
|
||||
bool isFeaturesShown() const;
|
||||
bool isSizedFeatures() const;
|
||||
|
||||
@ -267,7 +267,7 @@ class FINDOBJECT_EXP Settings
|
||||
PARAMETER(General, nextObjID, uint, 1, "Next object ID to use.");
|
||||
PARAMETER(General, imageFormats, QString, "*.png *.jpg *.bmp *.tiff *.ppm *.pgm", "Image formats supported.");
|
||||
PARAMETER(General, videoFormats, QString, "*.avi *.m4v *.mp4", "Video formats supported.");
|
||||
PARAMETER(General, mirrorView, bool, true, "Flip the camera image horizontally (like all webcam applications).");
|
||||
PARAMETER(General, mirrorView, bool, false, "Flip the camera image horizontally (like all webcam applications).");
|
||||
PARAMETER(General, invertedSearch, bool, true, "Instead of matching descriptors from the objects to those in a vocabulary created with descriptors extracted from the scene, we create a vocabulary from all the objects' descriptors and we match scene's descriptors to this vocabulary. It is the inverted search mode.");
|
||||
PARAMETER(General, controlsShown, bool, false, "Show play/image seek controls (useful with video file and directory of images modes).");
|
||||
PARAMETER(General, threads, int, 1, "Number of threads used for objects matching and homography computation. 0 means as many threads as objects. On InvertedSearch mode, multi-threading has only effect on homography computation.");
|
||||
|
||||
@ -143,6 +143,29 @@ bool FindObject::saveSession(const QString & path)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FindObject::saveVocabulary(const QString & filePath) const
|
||||
{
|
||||
return vocabulary_->save(filePath);
|
||||
}
|
||||
|
||||
bool FindObject::loadVocabulary(const QString & filePath)
|
||||
{
|
||||
if(!Settings::getGeneral_vocabularyFixed() || !Settings::getGeneral_invertedSearch())
|
||||
{
|
||||
UWARN("Doesn't make sense to load a vocabulary if \"General/vocabularyFixed\" and \"General/invertedSearch\" are not enabled! It will "
|
||||
"be cleared at the time the objects are updated.");
|
||||
}
|
||||
if(vocabulary_->load(filePath))
|
||||
{
|
||||
if(objects_.size())
|
||||
{
|
||||
updateVocabulary();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int FindObject::loadObjects(const QString & dirPath, bool recursive)
|
||||
{
|
||||
QString formats = Settings::getGeneral_imageFormats().remove('*').remove('.');
|
||||
@ -192,7 +215,6 @@ int FindObject::loadObjects(const QString & dirPath, bool recursive)
|
||||
|
||||
const ObjSignature * FindObject::addObject(const QString & filePath)
|
||||
{
|
||||
UINFO("Load file %s", filePath.toStdString().c_str());
|
||||
if(!filePath.isNull())
|
||||
{
|
||||
cv::Mat img = cv::imread(filePath.toStdString().c_str(), cv::IMREAD_GRAYSCALE);
|
||||
@ -218,8 +240,26 @@ const ObjSignature * FindObject::addObject(const QString & filePath)
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
return this->addObject(img, id, filePath);
|
||||
else
|
||||
{
|
||||
UERROR("File name doesn't contain \".\" (\"%s\")", filePath.toStdString().c_str());
|
||||
}
|
||||
|
||||
const ObjSignature * s = this->addObject(img, id, filePath);
|
||||
if(s)
|
||||
{
|
||||
UINFO("Added object %d (%s)", s->id(), filePath.toStdString().c_str());
|
||||
return s;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Could not read image \"%s\"", filePath.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("File path is null!?");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ public:
|
||||
|
||||
void setColor(const QColor & color);
|
||||
void setWordID(int id) {wordID_ = id;}
|
||||
int wordID() const {return wordID_;}
|
||||
int id() const {return id_;}
|
||||
|
||||
protected:
|
||||
|
||||
@ -183,7 +183,7 @@ MainWindow::MainWindow(FindObject * findObject, Camera * camera, QWidget * paren
|
||||
|
||||
//buttons
|
||||
connect(ui_->pushButton_restoreDefaults, SIGNAL(clicked()), ui_->toolBox, SLOT(resetCurrentPage()));
|
||||
connect(ui_->pushButton_updateObjects, SIGNAL(clicked()), this, SLOT(updateObjects(const QList<int> &)));
|
||||
connect(ui_->pushButton_updateObjects, SIGNAL(clicked()), this, SLOT(updateObjects()));
|
||||
connect(ui_->horizontalSlider_objectsSize, SIGNAL(valueChanged(int)), this, SLOT(updateObjectsSize()));
|
||||
|
||||
ui_->actionStop_camera->setEnabled(false);
|
||||
@ -211,6 +211,8 @@ MainWindow::MainWindow(FindObject * findObject, Camera * camera, QWidget * paren
|
||||
connect(ui_->actionLoad_settings, SIGNAL(triggered()), this, SLOT(loadSettings()));
|
||||
connect(ui_->actionSave_session, SIGNAL(triggered()), this, SLOT(saveSession()));
|
||||
connect(ui_->actionLoad_session, SIGNAL(triggered()), this, SLOT(loadSession()));
|
||||
connect(ui_->actionSave_vocabulary, SIGNAL(triggered()), this, SLOT(saveVocabulary()));
|
||||
connect(ui_->actionLoad_vocabulary, SIGNAL(triggered()), this, SLOT(loadVocabulary()));
|
||||
connect(ui_->actionShow_objects_features, SIGNAL(triggered()), this, SLOT(showObjectsFeatures()));
|
||||
connect(ui_->actionHide_objects_features, SIGNAL(triggered()), this, SLOT(hideObjectsFeatures()));
|
||||
|
||||
@ -251,6 +253,13 @@ MainWindow::MainWindow(FindObject * findObject, Camera * camera, QWidget * paren
|
||||
objWidgets_.insert(obj->id(), obj);
|
||||
this->showObject(obj);
|
||||
}
|
||||
ui_->actionSave_objects->setEnabled(true);
|
||||
ui_->actionSave_session->setEnabled(true);
|
||||
}
|
||||
if(findObject_->vocabulary()->size())
|
||||
{
|
||||
ui_->label_vocabularySize->setNum(findObject_->vocabulary()->size());
|
||||
ui_->actionSave_session->setEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
@ -585,6 +594,66 @@ bool MainWindow::saveObjects()
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainWindow::loadVocabulary()
|
||||
{
|
||||
if(!Settings::getGeneral_vocabularyFixed() ||
|
||||
!Settings::getGeneral_invertedSearch())
|
||||
{
|
||||
QMessageBox::StandardButton b = QMessageBox::question(this, tr("Load vocabulary..."),
|
||||
tr("Parameters \"General/vocabularyFixed\" and \"General/invertedSearch\" should be enabled to load a vocabulary. "
|
||||
"Do you want to enable them now?"),
|
||||
QMessageBox::Cancel | QMessageBox::Yes);
|
||||
if(b == QMessageBox::Yes)
|
||||
{
|
||||
Settings::setGeneral_vocabularyFixed(true);
|
||||
Settings::setGeneral_invertedSearch(true);
|
||||
}
|
||||
}
|
||||
if(Settings::getGeneral_vocabularyFixed() &&
|
||||
Settings::getGeneral_invertedSearch())
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Load vocabulary..."), Settings::workingDirectory(), "Data (*.yaml *.xml)");
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
if(findObject_->loadVocabulary(path))
|
||||
{
|
||||
ui_->label_vocabularySize->setNum(findObject_->vocabulary()->size());
|
||||
ui_->actionSave_session->setEnabled(findObject_->vocabulary()->size() || findObject_->objects().size());
|
||||
QMessageBox::information(this, tr("Loading..."), tr("Vocabulary loaded from \"%1\" (%2 words).").arg(path).arg(findObject_->vocabulary()->size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Loading..."), tr("Failed to load vocabulary \"%1\"!").arg(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::saveVocabulary()
|
||||
{
|
||||
if(findObject_->vocabulary()->size() == 0)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Saving vocabulary..."), tr("Vocabulary is empty!"));
|
||||
return;
|
||||
}
|
||||
QString path = QFileDialog::getSaveFileName(this, tr("Save vocabulary..."), Settings::workingDirectory(), "Data (*.yaml *.xml)");
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
if(QFileInfo(path).suffix().compare("yaml") != 0 && QFileInfo(path).suffix().compare("xml") != 0)
|
||||
{
|
||||
path.append(".yaml");
|
||||
}
|
||||
if(findObject_->saveVocabulary(path))
|
||||
{
|
||||
QMessageBox::information(this, tr("Saving..."), tr("Vocabulary saved to \"%1\" (%2 words).").arg(path).arg(findObject_->vocabulary()->size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Saving..."), tr("Failed to save vocabulary \"%1\"!").arg(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::removeObject(find_object::ObjWidget * object)
|
||||
{
|
||||
if(object)
|
||||
@ -977,6 +1046,11 @@ void MainWindow::showObject(ObjWidget * obj)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateObjects()
|
||||
{
|
||||
updateObjects(QList<int>());
|
||||
}
|
||||
|
||||
void MainWindow::updateObjects(const QList<int> & ids)
|
||||
{
|
||||
if(objWidgets_.size())
|
||||
@ -1045,6 +1119,7 @@ void MainWindow::updateVocabulary(const QList<int> & ids)
|
||||
}
|
||||
lastObjectsUpdateParameters_ = Settings::getParameters();
|
||||
this->statusBar()->clearMessage();
|
||||
ui_->dockWidget_objects->update();
|
||||
}
|
||||
|
||||
void MainWindow::startProcessing()
|
||||
|
||||
@ -71,7 +71,7 @@ ObjWidget::ObjWidget(int id, const std::vector<cv::KeyPoint> & keypoints, const
|
||||
graphicsView_(0),
|
||||
graphicsViewInitialized_(false),
|
||||
alpha_(100),
|
||||
color_(QColor((Qt::GlobalColor)((id % 11 + 7)==Qt::yellow?Qt::gray:(id % 11 + 7))))
|
||||
color_(QColor((Qt::GlobalColor)((id % 10 + 7)==Qt::yellow?Qt::darkYellow:(id % 10 + 7))))
|
||||
{
|
||||
setupUi();
|
||||
this->updateImage(image);
|
||||
@ -136,7 +136,7 @@ void ObjWidget::setupUi()
|
||||
|
||||
void ObjWidget::setId(int id)
|
||||
{
|
||||
color_ = QColor((Qt::GlobalColor)((id % 11 + 7)==Qt::yellow?Qt::gray:(id % 11 + 7)));
|
||||
color_ = QColor((Qt::GlobalColor)((id % 10 + 7)==Qt::yellow?Qt::darkYellow:(id % 10 + 7)));
|
||||
id_=id;
|
||||
if(id_)
|
||||
{
|
||||
@ -274,7 +274,7 @@ void ObjWidget::updateImage(const QImage & image)
|
||||
void ObjWidget::updateData(const std::vector<cv::KeyPoint> & keypoints, const QMultiMap<int, int> & words)
|
||||
{
|
||||
keypoints_ = keypoints;
|
||||
kptColors_ = QVector<QColor>((int)keypoints.size(), defaultColor());
|
||||
kptColors_ = QVector<QColor>((int)keypoints.size(), defaultColor(0));
|
||||
keypointItems_.clear();
|
||||
rectItems_.clear();
|
||||
this->updateWords(words);
|
||||
@ -297,9 +297,14 @@ void ObjWidget::updateWords(const QMultiMap<int,int> & words)
|
||||
{
|
||||
words_.insert(iter.value(), iter.key());
|
||||
}
|
||||
for(int i=0; i<keypointItems_.size(); ++i)
|
||||
for(int i=0; i<kptColors_.size(); ++i)
|
||||
{
|
||||
keypointItems_[i]->setWordID(words_.value(i,-1));
|
||||
kptColors_[i] = defaultColor(words_.size()?words_.value(i,-1):0);
|
||||
if(keypointItems_.size() == kptColors_.size())
|
||||
{
|
||||
keypointItems_[i]->setWordID(words_.value(i,-1));
|
||||
keypointItems_[i]->setColor(defaultColor(words_.size()?keypointItems_[i]->wordID():0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,10 +312,14 @@ void ObjWidget::resetKptsColor()
|
||||
{
|
||||
for(int i=0; i<kptColors_.size(); ++i)
|
||||
{
|
||||
kptColors_[i] = defaultColor();
|
||||
if(graphicsViewMode_->isChecked())
|
||||
if(keypointItems_.size() == kptColors_.size())
|
||||
{
|
||||
keypointItems_[i]->setColor(this->defaultColor());
|
||||
kptColors_[i] = defaultColor(keypointItems_[i]->wordID());
|
||||
keypointItems_[i]->setColor(this->defaultColor(keypointItems_[i]->wordID()));
|
||||
}
|
||||
else
|
||||
{
|
||||
kptColors_[i] = defaultColor(words_.value(i,-1));
|
||||
}
|
||||
}
|
||||
qDeleteAll(rectItems_.begin(), rectItems_.end());
|
||||
@ -738,6 +747,8 @@ void ObjWidget::drawKeypoints(QPainter * painter)
|
||||
item->setVisible(this->isFeaturesShown());
|
||||
item->setZValue(2);
|
||||
graphicsView_->scene()->addItem(item);
|
||||
item->setColor(defaultColor(item->wordID()));
|
||||
kptColors_[i] = defaultColor(item->wordID());
|
||||
keypointItems_.append(item);
|
||||
}
|
||||
|
||||
@ -752,9 +763,9 @@ void ObjWidget::drawKeypoints(QPainter * painter)
|
||||
}
|
||||
}
|
||||
|
||||
QColor ObjWidget::defaultColor() const
|
||||
QColor ObjWidget::defaultColor(int id) const
|
||||
{
|
||||
QColor color(Qt::yellow);
|
||||
QColor color(id >= 0 ? Qt::yellow : Qt::white);
|
||||
color.setAlpha(alpha_);
|
||||
return color;
|
||||
}
|
||||
|
||||
@ -60,6 +60,8 @@ void Vocabulary::clear()
|
||||
|
||||
if(Settings::getGeneral_vocabularyFixed() && Settings::getGeneral_invertedSearch())
|
||||
{
|
||||
this->update(); // if vocabulary structure has changed
|
||||
|
||||
// If the dictionary is fixed, don't clear indexed descriptors
|
||||
return;
|
||||
}
|
||||
@ -67,41 +69,81 @@ void Vocabulary::clear()
|
||||
indexedDescriptors_ = cv::Mat();
|
||||
}
|
||||
|
||||
void Vocabulary::save(QDataStream & streamPtr) const
|
||||
void Vocabulary::save(QDataStream & streamSessionPtr) const
|
||||
{
|
||||
if(!indexedDescriptors_.empty() && !wordToObjects_.empty())
|
||||
{
|
||||
UASSERT(notIndexedDescriptors_.empty() && notIndexedWordIds_.empty());
|
||||
// save index
|
||||
streamSessionPtr << wordToObjects_;
|
||||
|
||||
// save index
|
||||
streamPtr << wordToObjects_;
|
||||
|
||||
// save words
|
||||
qint64 dataSize = indexedDescriptors_.elemSize()*indexedDescriptors_.cols*indexedDescriptors_.rows;
|
||||
streamPtr << indexedDescriptors_.rows <<
|
||||
indexedDescriptors_.cols <<
|
||||
indexedDescriptors_.type() <<
|
||||
dataSize;
|
||||
streamPtr << QByteArray((char*)indexedDescriptors_.data, dataSize);
|
||||
}
|
||||
// save words
|
||||
qint64 dataSize = indexedDescriptors_.elemSize()*indexedDescriptors_.cols*indexedDescriptors_.rows;
|
||||
streamSessionPtr << indexedDescriptors_.rows <<
|
||||
indexedDescriptors_.cols <<
|
||||
indexedDescriptors_.type() <<
|
||||
dataSize;
|
||||
streamSessionPtr << QByteArray((char*)indexedDescriptors_.data, dataSize);
|
||||
}
|
||||
|
||||
void Vocabulary::load(QDataStream & streamPtr)
|
||||
void Vocabulary::load(QDataStream & streamSessionPtr)
|
||||
{
|
||||
// load index
|
||||
streamPtr >> wordToObjects_;
|
||||
streamSessionPtr >> wordToObjects_;
|
||||
|
||||
// load words
|
||||
int rows,cols,type;
|
||||
qint64 dataSize;
|
||||
streamPtr >> rows >> cols >> type >> dataSize;
|
||||
streamSessionPtr >> rows >> cols >> type >> dataSize;
|
||||
QByteArray data;
|
||||
streamPtr >> data;
|
||||
streamSessionPtr >> data;
|
||||
indexedDescriptors_ = cv::Mat(rows, cols, type, data.data()).clone();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
bool Vocabulary::save(const QString & filename) const
|
||||
{
|
||||
// save descriptors
|
||||
cv::FileStorage fs(filename.toStdString(), cv::FileStorage::WRITE);
|
||||
if(fs.isOpened())
|
||||
{
|
||||
fs << "Descriptors" << indexedDescriptors_;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Failed to open vocabulary file \"%s\"", filename.toStdString().c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Vocabulary::load(const QString & filename)
|
||||
{
|
||||
// save descriptors
|
||||
cv::FileStorage fs(filename.toStdString(), cv::FileStorage::READ);
|
||||
if(fs.isOpened())
|
||||
{
|
||||
cv::Mat tmp;
|
||||
fs["Descriptors"] >> tmp;
|
||||
|
||||
if(!tmp.empty())
|
||||
{
|
||||
// clear index
|
||||
wordToObjects_.clear();
|
||||
indexedDescriptors_ = tmp;
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Failed to read \"Descriptors\" matrix field (doesn't exist or is empty) from vocabulary file \"%s\"", filename.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Failed to open vocabulary file \"%s\"", filename.toStdString().c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QMultiMap<int, int> Vocabulary::addWords(const cv::Mat & descriptors, int objectId)
|
||||
{
|
||||
QMultiMap<int, int> words;
|
||||
@ -119,7 +161,21 @@ QMultiMap<int, int> Vocabulary::addWords(const cv::Mat & descriptors, int object
|
||||
bool globalSearch = false;
|
||||
if(!indexedDescriptors_.empty() && indexedDescriptors_.rows >= (int)k)
|
||||
{
|
||||
UASSERT(indexedDescriptors_.type() == descriptors.type() && indexedDescriptors_.cols == descriptors.cols);
|
||||
if(indexedDescriptors_.type() != descriptors.type() || indexedDescriptors_.cols != descriptors.cols)
|
||||
{
|
||||
if(Settings::getGeneral_vocabularyFixed())
|
||||
{
|
||||
UERROR("Descriptors (type=%d size=%d) to search in vocabulary are not the same type/size as those in the vocabulary (type=%d size=%d)! Empty words returned.",
|
||||
descriptors.type(), descriptors.cols, indexedDescriptors_.type(), indexedDescriptors_.cols);
|
||||
return words;
|
||||
}
|
||||
else
|
||||
{
|
||||
UFATAL("Descriptors (type=%d size=%d) to search in vocabulary are not the same type/size as those in the vocabulary (type=%d size=%d)!",
|
||||
descriptors.type(), descriptors.cols, indexedDescriptors_.type(), indexedDescriptors_.cols);
|
||||
}
|
||||
}
|
||||
|
||||
this->search(descriptors, results, dists, k);
|
||||
|
||||
if( dists.type() == CV_32S )
|
||||
|
||||
@ -49,8 +49,10 @@ public:
|
||||
const QMultiMap<int, int> & wordToObjects() const {return wordToObjects_;}
|
||||
const cv::Mat & indexedDescriptors() const {return indexedDescriptors_;}
|
||||
|
||||
void save(QDataStream & streamPtr) const;
|
||||
void load(QDataStream & streamPtr);
|
||||
void save(QDataStream & streamSessionPtr) const;
|
||||
void load(QDataStream & streamSessionPtr);
|
||||
bool save(const QString & filename) const;
|
||||
bool load(const QString & filename);
|
||||
|
||||
private:
|
||||
cv::flann::Index flannIndex_;
|
||||
|
||||
@ -225,6 +225,9 @@
|
||||
<addaction name="actionLoad_objects"/>
|
||||
<addaction name="actionSave_objects"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLoad_vocabulary"/>
|
||||
<addaction name="actionSave_vocabulary"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLoad_settings"/>
|
||||
<addaction name="actionSave_settings"/>
|
||||
<addaction name="separator"/>
|
||||
@ -894,6 +897,16 @@
|
||||
<string>Show objects features</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoad_vocabulary">
|
||||
<property name="text">
|
||||
<string>Load vocabulary...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_vocabulary">
|
||||
<property name="text">
|
||||
<string>Save vocabulary...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user