Added Load/Save vocabulary actions in File menu (in console mode, see "--vocabulary" option) (issue #2)

This commit is contained in:
matlabbe 2015-07-07 16:49:38 -04:00
parent a4a9b8ca5f
commit dd14e5e1ca
12 changed files with 341 additions and 58 deletions

View File

@ -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...");
}
}
}

View File

@ -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());

View File

@ -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_;

View File

@ -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;

View File

@ -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.");

View File

@ -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;
}

View File

@ -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:

View File

@ -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()

View File

@ -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;
}

View File

@ -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 )

View File

@ -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_;

View File

@ -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>