Added option to recursively parse subdirectories when loading objects (File->"Load objects...")

This commit is contained in:
matlabbe 2015-06-03 21:46:35 -04:00
parent 34f0262bfd
commit 76b6ff4b7e
7 changed files with 111 additions and 43 deletions

View File

@ -70,7 +70,7 @@ public:
// Those maps have the same size
QMultiMap<int, QTransform> objDetected_;
QMultiMap<int, QSize> objDetectedSizes_; // Object ID <width, height> match the number of detected objects
QMultiMap<int, QString > objDetectedFilenames_; // Object ID <filename> match the number of detected objects
QMultiMap<int, QString > objDetectedFilePaths_; // Object ID <filename> match the number of detected objects
QMultiMap<int, int> objDetectedInliersCount_; // ObjectID <count> match the number of detected objects
QMultiMap<int, int> objDetectedOutliersCount_; // ObjectID <count> match the number of detected objects
QMultiMap<int, QMultiMap<int, int> > objDetectedInliers_; // ObjectID Map< ObjectDescriptorIndex, SceneDescriptorIndex >, match the number of detected objects
@ -98,7 +98,7 @@ inline QDataStream & operator<<(QDataStream &out, const DetectionInfo & info)
QMultiMap<int, int>::const_iterator iterInliers = info.objDetectedInliersCount_.constBegin();
QMultiMap<int, int>::const_iterator iterOutliers = info.objDetectedOutliersCount_.constBegin();
QMultiMap<int, QSize>::const_iterator iterSizes = info.objDetectedSizes_.constBegin();
QMultiMap<int, QString>::const_iterator iterFilenames = info.objDetectedFilenames_.constBegin();
QMultiMap<int, QString>::const_iterator iterFilenames = info.objDetectedFilePaths_.constBegin();
for(QMultiMap<int, QTransform>::const_iterator iter=info.objDetected_.constBegin();
iter!=info.objDetected_.constEnd();
++iter)
@ -148,7 +148,7 @@ inline QDataStream & operator>>(QDataStream &in, DetectionInfo & info)
in >> id >> size >> homography >> filename >> inliers >> outliers;
info.objDetected_.insert(id, homography);
info.objDetectedSizes_.insert(id, size);
info.objDetectedFilenames_.insert(id, filename);
info.objDetectedFilePaths_.insert(id, filename);
info.objDetectedInliersCount_.insert(id, inliers);
info.objDetectedOutliersCount_.insert(id, outliers);
}

View File

@ -69,9 +69,9 @@ public:
bool saveSession(const QString & path);
bool isSessionModified() const {return sessionModified_;}
int loadObjects(const QString & dirPath); // call updateObjects()
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 & filename = QString());
const ObjSignature * addObject(const cv::Mat & image, int id=0, const QString & filePath = QString());
bool addObject(ObjSignature * obj); // take ownership when true is returned
void removeObject(int id);
void removeAllObjects();
@ -86,7 +86,7 @@ public:
const Vocabulary * vocabulary() const {return vocabulary_;}
public Q_SLOTS:
void addObjectAndUpdate(const cv::Mat & image, int id=0, const QString & filename = QString());
void addObjectAndUpdate(const cv::Mat & image, int id=0, const QString & filePath = QString());
void removeObjectAndUpdate(int id);
void detect(const cv::Mat & image); // emit objectsFound()

View File

@ -115,7 +115,7 @@ Q_SIGNALS:
private:
bool loadSettings(const QString & path);
bool saveSettings(const QString & path) const;
int loadObjects(const QString & dirPath);
int loadObjects(const QString & dirPath, bool recursive = false);
int saveObjects(const QString & dirPath);
void setupTCPServer();
int addObjectFromFile(const QString & filePath);

View File

@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore/QFileInfo>
#include <QtCore/QStringList>
#include <QtCore/QTime>
#include <QtCore/QDir>
#include <QtGui/QGraphicsRectItem>
#include <stdio.h>
@ -140,25 +141,49 @@ bool FindObject::saveSession(const QString & path)
return false;
}
int FindObject::loadObjects(const QString & dirPath)
int FindObject::loadObjects(const QString & dirPath, bool recursive)
{
int loadedObjects = 0;
QString formats = Settings::getGeneral_imageFormats().remove('*').remove('.');
UDirectory dir(dirPath.toStdString(), formats.toStdString());
QStringList paths;
paths.append(dirPath);
while(paths.size())
{
QString currentDir = paths.front();
UDirectory dir(currentDir.toStdString(), formats.toStdString());
if(dir.isValid())
{
const std::list<std::string> & names = dir.getFileNames(); // sorted in natural order
for(std::list<std::string>::const_iterator iter=names.begin(); iter!=names.end(); ++iter)
{
this->addObject((dirPath.toStdString()+dir.separator()+*iter).c_str());
if(this->addObject((currentDir.toStdString()+dir.separator()+*iter).c_str()))
{
++loadedObjects;
}
if(names.size())
}
}
paths.pop_front();
if(recursive)
{
QDir d(currentDir);
QStringList subDirs = d.entryList(QDir::AllDirs|QDir::NoDotAndDotDot, QDir::Name);
for(int i=subDirs.size()-1; i>=0; --i)
{
paths.prepend(currentDir+QDir::separator()+subDirs[i]);
}
}
}
if(loadedObjects)
{
this->updateObjects();
this->updateVocabulary();
}
loadedObjects = (int)names.size();
}
return loadedObjects;
}
@ -190,16 +215,16 @@ const ObjSignature * FindObject::addObject(const QString & filePath)
id = 0;
}
}
return this->addObject(img, id, file.fileName());
return this->addObject(img, id, filePath);
}
}
return 0;
}
const ObjSignature * FindObject::addObject(const cv::Mat & image, int id, const QString & filename)
const ObjSignature * FindObject::addObject(const cv::Mat & image, int id, const QString & filePath)
{
UASSERT(id >= 0);
ObjSignature * s = new ObjSignature(id, image, filename);
ObjSignature * s = new ObjSignature(id, image, filePath);
if(!this->addObject(s))
{
delete s;
@ -245,9 +270,9 @@ void FindObject::removeAllObjects()
clearVocabulary();
}
void FindObject::addObjectAndUpdate(const cv::Mat & image, int id, const QString & filename)
void FindObject::addObjectAndUpdate(const cv::Mat & image, int id, const QString & filePath)
{
const ObjSignature * s = this->addObject(image, id, filename);
const ObjSignature * s = this->addObject(image, id, filePath);
if(s)
{
QList<int> ids;
@ -1449,7 +1474,7 @@ bool FindObject::detect(const cv::Mat & image, find_object::DetectionInfo & info
info.objDetectedOutliers_.insert(id, threads[j]->getOutliers());
info.objDetectedInliersCount_.insert(id, threads[j]->getInliers().size());
info.objDetectedOutliersCount_.insert(id, threads[j]->getOutliers().size());
info.objDetectedFilenames_.insert(id, objects_.value(id)->filename());
info.objDetectedFilePaths_.insert(id, objects_.value(id)->filePath());
}
else
{

View File

@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtCore/QFileInfo>
#include "json/json.h"
@ -48,7 +49,7 @@ void JsonWriter::write(const DetectionInfo & info, const QString & path)
QMultiMap<int, int>::const_iterator iterInliers = info.objDetectedInliersCount_.constBegin();
QMultiMap<int, int>::const_iterator iterOutliers = info.objDetectedOutliersCount_.constBegin();
QMultiMap<int, QSize>::const_iterator iterSizes = info.objDetectedSizes_.constBegin();
QMultiMap<int, QString>::const_iterator iterFilenames = info.objDetectedFilenames_.constBegin();
QMultiMap<int, QString>::const_iterator iterFilePaths = info.objDetectedFilePaths_.constBegin();
for(QMultiMap<int, QTransform>::const_iterator iter = info.objDetected_.constBegin(); iter!= info.objDetected_.end();)
{
char index = 'a';
@ -73,13 +74,20 @@ void JsonWriter::write(const DetectionInfo & info, const QString & path)
root[name.toStdString()]["homography"] = homography;
root[name.toStdString()]["inliers"] = iterInliers.value();
root[name.toStdString()]["outliers"] = iterOutliers.value();
root[name.toStdString()]["filename"] = iterFilenames.value().toStdString();
root[name.toStdString()]["filepath"] = iterFilePaths.value().toStdString();
QString filename;
if(!iterFilePaths.value().isEmpty())
{
QFileInfo file(iterFilePaths.value());
filename=file.fileName();
}
root[name.toStdString()]["filename"] = filename.toStdString();
++iter;
++iterInliers;
++iterOutliers;
++iterSizes;
++iterFilenames;
++iterFilePaths;
}
}
root["objects"] = detections;

View File

@ -460,27 +460,49 @@ bool MainWindow::saveSettings(const QString & path) const
return false;
}
int MainWindow::loadObjects(const QString & dirPath)
int MainWindow::loadObjects(const QString & dirPath, bool recursive)
{
QList<int> loadedObjects;
QString formats = Settings::getGeneral_imageFormats().remove('*').remove('.');
UDirectory dir(dirPath.toStdString(), formats.toStdString());
QStringList paths;
paths.append(dirPath);
while(paths.size())
{
QString currentDir = paths.front();
UDirectory dir(currentDir.toStdString(), formats.toStdString());
if(dir.isValid())
{
const std::list<std::string> & names = dir.getFileNames(); // sorted in natural order
for(std::list<std::string>::const_iterator iter=names.begin(); iter!=names.end(); ++iter)
{
int id = this->addObjectFromFile((dirPath.toStdString()+dir.separator()+*iter).c_str());
int id = this->addObjectFromFile((currentDir.toStdString()+dir.separator()+*iter).c_str());
if(id >= 0)
{
loadedObjects.push_back(id);
}
}
}
paths.pop_front();
if(recursive)
{
QDir d(currentDir);
QStringList subDirs = d.entryList(QDir::AllDirs|QDir::NoDotAndDotDot, QDir::Name);
for(int i=subDirs.size()-1; i>=0; --i)
{
paths.prepend(currentDir + QDir::separator() + subDirs[i]);
}
}
}
if(loadedObjects.size())
{
this->updateObjects(loadedObjects);
}
}
return loadedObjects.size();
}
@ -511,7 +533,20 @@ void MainWindow::loadObjects()
QString dirPath = QFileDialog::getExistingDirectory(this, tr("Loading objects... Select a directory."), Settings::workingDirectory());
if(!dirPath.isEmpty())
{
int count = loadObjects(dirPath);
QDir d(dirPath);
bool recursive = false;
if(d.entryList(QDir::AllDirs).size())
{
QMessageBox::StandardButton b = QMessageBox::question(
this,
tr("Loading objects..."),
tr("The current directory contains subdirectories. Load objects recursively?"),
QMessageBox::Yes|QMessageBox::No,
QMessageBox::No);
recursive = b == QMessageBox::Yes;
}
int count = loadObjects(dirPath, recursive);
if(count)
{
QMessageBox::information(this, tr("Loading..."), tr("%1 objects loaded from \"%2\".").arg(count).arg(dirPath));

View File

@ -42,10 +42,10 @@ public:
ObjSignature() :
id_(-1)
{}
ObjSignature(int id, const cv::Mat & image, const QString & filename) :
ObjSignature(int id, const cv::Mat & image, const QString & filePath) :
id_(id),
image_(image),
filename_(filename)
filePath_(filePath)
{}
virtual ~ObjSignature() {}
@ -60,7 +60,7 @@ public:
QRect rect() const {return QRect(0,0,image_.cols, image_.rows);}
int id() const {return id_;}
const QString & filename() const {return filename_;}
const QString & filePath() const {return filePath_;}
const cv::Mat & image() const {return image_;}
const std::vector<cv::KeyPoint> & keypoints() const {return keypoints_;}
const cv::Mat & descriptors() const {return descriptors_;}
@ -69,7 +69,7 @@ public:
void save(QDataStream & streamPtr) const
{
streamPtr << id_;
streamPtr << filename_;
streamPtr << filePath_;
streamPtr << (int)keypoints_.size();
for(unsigned int j=0; j<keypoints_.size(); ++j)
{
@ -99,7 +99,7 @@ public:
void load(QDataStream & streamPtr)
{
int nKpts;
streamPtr >> id_ >> filename_ >> nKpts;
streamPtr >> id_ >> filePath_ >> nKpts;
keypoints_.resize(nKpts);
for(int i=0;i<nKpts;++i)
{
@ -132,7 +132,7 @@ public:
private:
int id_;
cv::Mat image_;
QString filename_;
QString filePath_;
std::vector<cv::KeyPoint> keypoints_;
cv::Mat descriptors_;
QMultiMap<int, int> words_; // <word id, keypoint indexes>