00001 /*!@file Apps/BorderWatch/BorderWatchQt.qt.C Simple GUI for BorderWatch */ 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 "Apps/BorderWatch/BorderWatchQt.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/QProgressBar> 00048 #include <QtGui/QLineEdit> 00049 #include <QtGui/QCheckBox> 00050 00051 #include "Apps/BorderWatch/BorderWatchData.H" 00052 #include "Image/DrawOps.H" 00053 #include "Image/ShapeOps.H" 00054 #include "QtUtil/ImageConvert4.H" 00055 #include "Raster/GenericFrame.H" 00056 #include "Util/log.H" 00057 #include "Util/sformat.H" 00058 00059 #include <cstdio> 00060 00061 // ###################################################################### 00062 BorderWatchQt::BorderWatchQt(std::vector<GenericFrame>& frames, std::vector<BorderWatchData>& data, QWidget* parent) : 00063 QWidget(parent), itsThreshold(4.0e-10F), itsFrames(frames), itsLogData(data), itsListIndex(0), 00064 itsMovieFrame(0), itsZoomed(false) 00065 { 00066 QVBoxLayout *main = new QVBoxLayout(this); 00067 main->setSpacing(4); 00068 main->setMargin(2); 00069 00070 QSplitter* splitter = new QSplitter(Qt::Horizontal, this); 00071 splitter->setChildrenCollapsible(false); 00072 00073 itsListWidget = new QListWidget(this); 00074 itsListWidget->setMinimumWidth(180); 00075 00076 splitter->addWidget(itsListWidget); 00077 connect(itsListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(listChanged(int))); 00078 00079 QFrame *frame = new QFrame(this); 00080 frame->setFrameShape(QFrame::StyledPanel); 00081 00082 QVBoxLayout *panel = new QVBoxLayout; 00083 00084 QHBoxLayout *ed = new QHBoxLayout; 00085 ed->addStretch(1); 00086 00087 QLabel *lbl = new QLabel("Threshold:", this); 00088 ed->addWidget(lbl); 00089 00090 itsThreshEdit = new QLineEdit(sformat("%g", itsThreshold).c_str(), this); 00091 ed->addWidget(itsThreshEdit); 00092 connect(itsThreshEdit, SIGNAL(editingFinished()), this, SLOT(threshChanged())); 00093 00094 ed->addStretch(1); 00095 00096 QLabel *lbl2 = new QLabel(" Zoom X2:", this); 00097 ed->addWidget(lbl2); 00098 00099 QCheckBox *chk = new QCheckBox(this); 00100 chk->setCheckState(Qt::Checked); itsZoomed = true; 00101 connect(chk, SIGNAL(stateChanged(int)), this, SLOT(zoomChanged(int))); 00102 ed->addWidget(chk); 00103 00104 ed->addStretch(1); 00105 00106 panel->addLayout(ed); 00107 00108 QFrame* hline = new QFrame(this); 00109 hline->setFrameShape(QFrame::HLine); 00110 hline->setFrameShadow(QFrame::Raised); 00111 hline->setLineWidth(2); 00112 panel->addWidget(hline); 00113 00114 panel->addStretch(1); 00115 00116 QHBoxLayout* himage = new QHBoxLayout; 00117 himage->addStretch(1); 00118 itsFrameWidget = new QLabel(this); 00119 himage->addWidget(itsFrameWidget); 00120 himage->addStretch(1); 00121 00122 panel->addLayout(himage); 00123 00124 panel->addStretch(1); 00125 00126 itsProgressBar = new QProgressBar(this); 00127 panel->addWidget(itsProgressBar); 00128 00129 panel->addStretch(1); 00130 00131 frame->setLayout(panel); 00132 splitter->addWidget(frame); 00133 00134 splitter->setStretchFactor(0, 1); 00135 splitter->setStretchFactor(1, 7); // preferentially stretch the image pane over the text list pane 00136 00137 splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 00138 main->addWidget(splitter); 00139 00140 itsStatusLabel = new QLabel("Status: Idle.", this); 00141 itsStatusLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); 00142 main->addWidget(itsStatusLabel); 00143 00144 this->setLayout(main); 00145 00146 // populate the list with a bunch of events: 00147 parseEvents(); 00148 00149 // get our timer going: 00150 itsTimer = new QTimer(this); 00151 itsTimer->setInterval(33); // in milliseconds 00152 connect(itsTimer, SIGNAL(timeout()), this, SLOT(timerTick())); 00153 itsTimer->start(); 00154 } 00155 00156 // ###################################################################### 00157 BorderWatchQt::~BorderWatchQt() 00158 { 00159 itsTimer->stop(); 00160 } 00161 00162 // ###################################################################### 00163 void BorderWatchQt::listChanged(const int idx) 00164 { 00165 itsListIndex = idx; 00166 if (itsEvents.size()) { 00167 const uint estart = itsEvents[idx].start, eend = itsEvents[idx].end; 00168 00169 itsListWidget->setCurrentRow(itsListIndex); 00170 itsMovieFrame = estart; 00171 itsProgressBar->setRange(estart, eend - 1); 00172 itsProgressBar->setValue(estart); 00173 00174 // compute max score achieved over this event: 00175 float mscore = 0.0F; 00176 for (uint i = estart; i < eend; ++i) mscore = std::max(mscore, itsLogData[i].score); 00177 00178 itsStatusLabel->setText(sformat("Event %d || Frames: %06u - %06u || Max Score: %g", idx, 00179 estart, eend-1, mscore).c_str()); 00180 } 00181 } 00182 00183 // ###################################################################### 00184 void BorderWatchQt::parseEvents() 00185 { 00186 itsEvents.clear(); itsListWidget->clear(); bool inevent = false; const uint margin = 33; uint i = 0; 00187 char buf[100]; uint count = 0; 00188 std::vector<BorderWatchData>::const_iterator itr = itsLogData.begin(), stop = itsLogData.end(); 00189 BWevent e; 00190 while (itr != stop) { 00191 // are we above threshold? 00192 if (itr->score >= itsThreshold) { 00193 count = 0; // then continue any ongoing event 00194 // start a new event? 00195 if (inevent == false) 00196 { inevent = true; e.start = i; if (e.start <= margin) e.start = 0; else e.start -= margin; } 00197 } 00198 00199 // write out a completed event? 00200 if (inevent && count > margin) { 00201 inevent = false; count = 0; e.end = i; 00202 itsEvents.push_back(e); 00203 snprintf(buf, 100, "%04"ZU": %06u-%06u", itsEvents.size(), e.start, e.end); 00204 itsListWidget->addItem(buf); 00205 } 00206 ++itr; ++i; ++count; 00207 } 00208 00209 // maybe one last event is still open: 00210 if (inevent) { 00211 e.end = itsLogData.size()-1; 00212 itsEvents.push_back(e); 00213 snprintf(buf, 100, "%04"ZU": %06u-%06u", itsEvents.size(), e.start, e.end); 00214 itsListWidget->addItem(buf); 00215 } 00216 00217 // reset our position in our list: 00218 listChanged(0); 00219 00220 snprintf(buf, 100, "Extracted %"ZU" events above threshold = %e", itsEvents.size(), itsThreshold); 00221 itsStatusLabel->setText(buf); 00222 } 00223 00224 // ###################################################################### 00225 void BorderWatchQt::timerTick() 00226 { 00227 if (itsEvents.size()) { 00228 // get the current movie frame and log data: 00229 GenericFrame genframe = itsFrames[itsMovieFrame]; 00230 Image<PixRGB<byte> > im = genframe.asRgbU8(); 00231 if (itsZoomed) im = quickInterpolate(im, 2); 00232 BorderWatchData& d = itsLogData[itsMovieFrame]; 00233 00234 // add some drawings: 00235 Point2D<int> p = d.salpoint; if (itsZoomed) { p.i *= 2; p.j *= 2; } 00236 if (d.score > itsThreshold) drawCircle(im, p, itsZoomed ? 30 : 15, PixRGB<byte>(255,255,0), 2); 00237 else drawCircle(im, p, itsZoomed ? 10 : 5, PixRGB<byte>(0,128,0), 1); 00238 writeText(im, Point2D<int>(10,0), sformat("%s - S=%g %06d", d.itime.c_str(), d.score, d.iframe).c_str(), 00239 PixRGB<byte>(255, 64, 0), PixRGB<byte>(0), SimpleFont::FIXED(6), true); 00240 00241 // display the image in our widget: 00242 QPixmap pixmap = convertToQPixmap4(im); 00243 itsFrameWidget->setPixmap(pixmap); 00244 00245 // update progress bar: 00246 itsProgressBar->setValue(itsMovieFrame); 00247 00248 // roll on to the next frame: 00249 ++itsMovieFrame; if (itsMovieFrame >= itsEvents[itsListIndex].end) itsMovieFrame = itsEvents[itsListIndex].start; 00250 } 00251 } 00252 00253 // ###################################################################### 00254 void BorderWatchQt::threshChanged() 00255 { 00256 QString txt = itsThreshEdit->text(); bool ok; 00257 float t = txt.toFloat(&ok); 00258 00259 if (ok) { itsThreshold = t; parseEvents(); } 00260 else itsStatusLabel->setText("Invalid threshold value"); 00261 } 00262 00263 // ###################################################################### 00264 void BorderWatchQt::zoomChanged(int state) 00265 { 00266 if (state == Qt::Checked) itsZoomed = true; else itsZoomed = false; 00267 } 00268 00269 // ###################################################################### 00270 /* So things look consistent in everyone's emacs... */ 00271 /* Local Variables: */ 00272 /* mode: c++ */ 00273 /* indent-tabs-mode: nil */ 00274 /* End: */