VisualObjectDBQt.qt.C

Go to the documentation of this file.
00001 /*!@file SIFT/VisualObjectDBQt.qt.C Qt GUI around VisualObjectDB */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Apps/BorderWatch/BorderWatchQt.qt.C $
00035 // $Id: BorderWatchQt.qt.C 13059 2010-03-26 08:14:32Z itti $
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); // sort list entries
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);  // preferentially stretch the image pane over the text list pane
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(); // initialize the 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   // refresh our list:
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); //getImage();
00258 
00259       // display the image in our widget:
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 /* numthreads */, 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(); // do an event->accept() or event->ignore()
00326   close();
00327 }
00328 
00329 // ######################################################################
00330 /* So things look consistent in everyone's emacs... */
00331 /* Local Variables: */
00332 /* mode: c++ */
00333 /* indent-tabs-mode: nil */
00334 /* End: */
Generated on Sun May 8 08:06:50 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3