00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "SIFT/VisualObjectDBQt.qt.H"
00039
00040 #include <QtCore/QTimer>
00041 #include <QtGui/QLabel>
00042 #include <QtGui/QVBoxLayout>
00043 #include <QtGui/QHBoxLayout>
00044 #include <QtGui/QListWidget>
00045 #include <QtGui/QSplitter>
00046 #include <QtGui/QFrame>
00047 #include <QtGui/QAction>
00048 #include <QtGui/QMenu>
00049 #include <QtGui/QMenuBar>
00050 #include <QtGui/QFileDialog>
00051 #include <QtGui/QStatusBar>
00052 #include <QtGui/QMessageBox>
00053
00054 #include "QtUtil/ImageConvert4.H"
00055 #include "Raster/Raster.H"
00056 #include "Util/FileUtil.H"
00057 #include "Util/log.H"
00058 #include "Util/sformat.H"
00059 #include "Util/StringUtil.H"
00060
00061 #include <dirent.h>
00062
00063
00064 VisualObjectDBQt::VisualObjectDBQt(QWidget* parent) :
00065 QMainWindow(parent), itsVDBchanged(false)
00066 {
00067 QAction *loadaction = new QAction("&Load VisualObjectDB", this);
00068 QAction *saveaction = new QAction("&Save VisualObjectDB", this);
00069 QAction *quitaction = new QAction("&Quit", this);
00070
00071 QMenu *file = menuBar()->addMenu("&File");
00072 file->addAction(loadaction); connect(loadaction, SIGNAL(triggered()), this, SLOT(load()));
00073 file->addAction(saveaction); connect(saveaction, SIGNAL(triggered()), this, SLOT(save()));
00074 file->addAction(quitaction); connect(quitaction, SIGNAL(triggered()), this, SLOT(close()));
00075
00076 QAction *importaction = new QAction("I&mport Image", this);
00077 QAction *rimportaction = new QAction("&Recursive Import Images", this);
00078
00079 QMenu *import = menuBar()->addMenu("&Import");
00080 import->addAction(importaction); connect(importaction, SIGNAL(triggered()), this, SLOT(import()));
00081 import->addAction(rimportaction); connect(rimportaction, SIGNAL(triggered()), this, SLOT(rimport()));
00082
00083 QAction *matchaction = new QAction("&Match against Image", this);
00084
00085 QMenu *process = menuBar()->addMenu("&Processing");
00086 process->addAction(matchaction); connect(matchaction, SIGNAL(triggered()), this, SLOT(match()));
00087
00088 QVBoxLayout *main = new QVBoxLayout();
00089 main->setSpacing(4);
00090 main->setMargin(2);
00091
00092 QSplitter* splitter = new QSplitter(Qt::Horizontal, this);
00093 splitter->setChildrenCollapsible(false);
00094
00095 itsListWidget = new QListWidget(this);
00096 itsListWidget->setMinimumWidth(180);
00097 itsListWidget->setSortingEnabled(true);
00098
00099 splitter->addWidget(itsListWidget);
00100 connect(itsListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(listChanged(int)));
00101
00102 itsFrameWidget = new QLabel(this);
00103 splitter->addWidget(itsFrameWidget);
00104
00105 splitter->setStretchFactor(0, 1);
00106 splitter->setStretchFactor(1, 7);
00107
00108 splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00109 main->addWidget(splitter);
00110
00111 QWidget *centralWidget = new QWidget;
00112 setCentralWidget(centralWidget);
00113 centralWidget->setLayout(main);
00114
00115 statusBar();
00116 statusBar()->showMessage("Status: Idle. Use the File menu to load a VisualObjectDB.");
00117 }
00118
00119
00120 VisualObjectDBQt::~VisualObjectDBQt()
00121 { }
00122
00123
00124 bool VisualObjectDBQt::load()
00125 {
00126 asksave();
00127
00128 QString fileName = QFileDialog::getOpenFileName(this, tr("Select VisualObjectDB File to Load"),
00129 QString(""), tr("VisualObjectDB Files (*.vdb)"));
00130 statusBar()->showMessage(sformat("Loading: %s ...", fileName.toLatin1().data()).c_str()); repaint();
00131 LINFO("Loading: %s", fileName.toLatin1().data());
00132
00133 if (itsVDB.loadFrom(fileName.toStdString(), false)) {
00134 itsFileName = fileName.toStdString();
00135 LINFO("Loaded VisualObjectDB with %u objects.", itsVDB.numObjects());
00136 } else {
00137 itsFileName = "";
00138 LINFO("Error loading VisualObjectDB");
00139 QMessageBox::warning(this, tr("VisualObjectDBQt"), tr("Error loading VisualObjectDB"),
00140 QMessageBox::Ok | QMessageBox::Default);
00141 return false;
00142 }
00143
00144
00145 refreshList();
00146
00147 return true;
00148 }
00149
00150
00151 void VisualObjectDBQt::refreshList()
00152 {
00153 itsListWidget->clear();
00154 for (uint i = 0; i < itsVDB.numObjects(); ++i) itsListWidget->addItem(itsVDB.getObject(i)->getName().c_str());
00155 if (itsVDB.numObjects() > 0) itsListWidget->setCurrentRow(0);
00156 }
00157
00158
00159 bool VisualObjectDBQt::save()
00160 {
00161 if (itsFileName.empty()) {
00162 QString fileName = QFileDialog::getSaveFileName(this, tr("Select VisualObjectDB File to Save"),
00163 QString(""), tr("VisualObjectDB Files (*.vdb)"));
00164 itsFileName = fileName.toStdString();
00165 if (itsFileName.empty()) return false;
00166 }
00167
00168 if (itsVDB.saveTo(itsFileName)) {
00169 LINFO("Saved VisualObjectDB with %u objects.", itsVDB.numObjects());
00170 itsVDBchanged = false;
00171 return true;
00172 }
00173
00174 QMessageBox::warning(this, tr("VisualObjectDBQt"), tr("Error saving VisualObjectDB"),
00175 QMessageBox::Ok | QMessageBox::Default);
00176 return false;
00177 }
00178
00179
00180 bool VisualObjectDBQt::import()
00181 {
00182 QString fileName = QFileDialog::getOpenFileName(this, tr("Select Image File to Load"),
00183 QString(""), tr("Image Files (*.png *.pnm *.ppm *.jpg)"));
00184 itsVDBchanged = importcore(fileName.toLatin1().data());
00185
00186 refreshList();
00187
00188 return itsVDBchanged;
00189 }
00190
00191
00192 bool VisualObjectDBQt::importcore(const char *fil)
00193 {
00194 statusBar()->showMessage(sformat("Importing image: %s", fil).c_str()); repaint();
00195
00196 QFileInfo fi(fil);
00197 std::string path = fi.canonicalPath().toStdString();
00198 std::string name = fi.completeBaseName().toStdString();
00199 std::vector<std::string> tokens; split(path, "/", std::back_inserter(tokens));
00200 if (tokens.size() >= 2) name = tokens[tokens.size()-2] + ':' + tokens[tokens.size()-1] + ':' + name;
00201
00202 Image< PixRGB<byte> > img = Raster::ReadRGB(fil);
00203
00204 rutz::shared_ptr<VisualObject> obj(new VisualObject(name, fil, img));
00205 if (itsVDB.addObject(obj)) {
00206 LINFO("Added VisualObject '%s'", name.c_str());
00207 return true;
00208 }
00209
00210 QMessageBox::warning(this, tr("VisualObjectDBQt"), tr("Error adding VisualObject"),
00211 QMessageBox::Ok | QMessageBox::Default);
00212 return false;
00213 }
00214
00215
00216 bool VisualObjectDBQt::rimport()
00217 {
00218 QString fileName = QFileDialog::getExistingDirectory(this, tr("Select Directory to Load"));
00219 statusBar()->showMessage(sformat("Recursively importing images from: %s", fileName.toLatin1().data()).c_str());
00220 repaint();
00221
00222 itsVDBchanged = rimportcore(fileName.toLatin1().data());
00223
00224 refreshList();
00225 return itsVDBchanged;
00226 }
00227
00228
00229 bool VisualObjectDBQt::rimportcore(const char *dir)
00230 {
00231 LINFO("Considering: %s", dir);
00232
00233 bool ret = true;
00234 DIR *dp = opendir(dir); dirent *dirp;
00235 while( (dirp = readdir(dp)) ) {
00236 if (dirp->d_name[0] != '.') {
00237 std::string fil = sformat("%s/%s", dir, dirp->d_name);
00238 if (isDirectory(dirp)) ret &= rimportcore(fil.c_str()); else ret &= importcore(fil.c_str());
00239 }
00240 }
00241 closedir(dp);
00242
00243 return ret;
00244 }
00245
00246
00247 void VisualObjectDBQt::listChanged(const int idx)
00248 {
00249 if (itsListWidget->count() && idx >= 0)
00250 {
00251 const QListWidgetItem *item = itsListWidget->item(idx);
00252 std::string oname = item->text().toStdString();
00253
00254 rutz::shared_ptr<VisualObject> obj = itsVDB.getObject(oname);
00255 if (obj.is_invalid()) LFATAL("Selected a non-existent object!");
00256
00257 const Image<PixRGB<byte> > &img = obj->getKeypointImage(1.0F);
00258
00259
00260 QPixmap pixmap = convertToQPixmap4(img);
00261 itsFrameWidget->setPixmap(pixmap);
00262
00263 statusBar()->showMessage(sformat("%u keypoints, %u features -- %s", obj->numKeypoints(), obj->numFeatures(),
00264 obj->getImageFname().c_str()).c_str());
00265 }
00266 }
00267
00268
00269 bool VisualObjectDBQt::match()
00270 {
00271 QString fileName = QFileDialog::getOpenFileName(this, tr("Select Image File to Load"),
00272 QString(""), tr("Image Files (*.png *.pnm *.ppm *.jpg)"));
00273
00274 statusBar()->showMessage(sformat("Matching image: %s", fileName.toLatin1().data()).c_str()); repaint();
00275
00276 Image< PixRGB<byte> > img = Raster::ReadRGB(fileName.toLatin1().data());
00277 rutz::shared_ptr<VisualObject> obj(new VisualObject("Test Object", fileName.toLatin1().data(), img));
00278
00279 std::vector< rutz::shared_ptr<VisualObjectMatch> > matches;
00280 if (itsVDB.getObjectMatchesParallel(obj, matches, 50 , 0.05F, 0.95F, 0.5F, 5U, 9U, false)) {
00281 std::string msg = "Object matches found:\n\n";
00282
00283 size_t bestidx = 0; float bestscore = -1.0F;
00284 for (size_t i = 0; i < matches.size(); ++i) {
00285 rutz::shared_ptr<VisualObject> ref = matches[i]->getVoTest();
00286 LINFO("Matched %s, score = %f", ref->getName().c_str(), matches[i]->getScore());
00287 msg += sformat("%s: score = %f\n", ref->getName().c_str(), matches[i]->getScore());
00288
00289 if (matches[i]->getScore() > bestscore) { bestscore = matches[i]->getScore(); bestidx = i; }
00290 }
00291
00292 msg += sformat("\nShowing image for match %"ZU, bestidx);
00293 QMessageBox mbox(this);
00294 mbox.setInformativeText(msg.c_str());
00295 mbox.addButton(QMessageBox::Ok);
00296 QPixmap pixmap = convertToQPixmap4(matches[bestidx]->getMatchImage(0.5F));
00297 mbox.setIconPixmap(pixmap);
00298 mbox.exec();
00299 return true;
00300 } else {
00301 LINFO("No good object match found.");
00302 QMessageBox::information(this, tr("VisualObjectDBQt"), tr("No good object match found!"),
00303 QMessageBox::Ok | QMessageBox::Default);
00304 return false;
00305 }
00306 }
00307
00308
00309 void VisualObjectDBQt::asksave()
00310 {
00311 if (itsVDBchanged) {
00312 int r = QMessageBox::warning(this, tr("VisualObjectDBQt"),
00313 tr("The VisualObjectDB has been modified.\n"
00314 "Do you want to save your changes?"),
00315 QMessageBox::Yes | QMessageBox::Default,
00316 QMessageBox::No | QMessageBox::Escape);
00317 if (r == QMessageBox::Yes) itsVDBchanged = save();
00318 else if (r == QMessageBox::No) itsVDBchanged = false;
00319 }
00320 }
00321
00322
00323 void VisualObjectDBQt::closeEvent(QCloseEvent *event)
00324 {
00325 asksave();
00326 close();
00327 }
00328
00329
00330
00331
00332
00333
00334