00001 /*!@file GUI/QtImageFrame.qt.C */ 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: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/GUI/QtImageFrame.qt.C $ 00035 // $Id: QtImageFrame.qt.C 14290 2010-12-01 21:44:03Z itti $ 00036 // 00037 00038 #include "GUI/QtImageFrame.qt.H" 00039 00040 #include "Image/ColorOps.H" 00041 #include "Image/FilterOps.H" 00042 #include "Image/Image.H" 00043 #include "Image/MathOps.H" 00044 #include "Image/Normalize.H" 00045 #include "Image/Pixels.H" 00046 #include "Image/Range.H" 00047 #include "Image/ShapeOps.H" 00048 #include "QtUtil/ImageConvert4.H" 00049 #include "Raster/GenericFrame.H" 00050 #include "Raster/Raster.H" 00051 #include "Transport/FrameInfo.H" 00052 #include "Util/MathFunctions.H" 00053 #include "Util/sformat.H" 00054 #include "rutz/demangle.h" 00055 #include "rutz/trace.h" 00056 00057 #include <QtGui/QFrame> 00058 #include <QtGui/QShowEvent> 00059 #include <QtGui/QPixmap> 00060 #include <QtGui/QErrorMessage> 00061 #include <QtGui/QFileDialog> 00062 #include <QtGui/QLabel> 00063 #include <QtGui/QPushButton> 00064 #include <QtGui/QSpinBox> 00065 #include <QtGui/QVBoxLayout> 00066 #include <QtGui/QHBoxLayout> 00067 00068 #include <typeinfo> 00069 00070 namespace 00071 { 00072 const int MAXZOOM = 6; 00073 const int MINZOOM = -6; 00074 00075 // ###################################################################### 00076 // escape any characters from the given string so that it will 00077 // render cleanly as Qt::RichText 00078 static std::string richTextEncode(const std::string& s) 00079 { 00080 std::string result; 00081 00082 for (std::string::size_type i = 0; i < s.size(); ++i) 00083 { 00084 switch (s[i]) 00085 { 00086 case '<': result += "<"; break; 00087 default: result += s[i]; break; 00088 } 00089 } 00090 00091 return result; 00092 } 00093 00094 // ###################################################################### 00095 static std::string buildTitle(const GenericFrame& img, const std::string& title, 00096 const int frameNumber, const FrameInfo& auxinfo) 00097 { 00098 std::string result; 00099 00100 if (auxinfo.description.length() > 0) 00101 result += sformat("<b>%s</b>", auxinfo.description.c_str()); 00102 00103 result += "<br>"; 00104 00105 result += sformat("<b>%s</b> [frame #%06d]<br><i>%dx%d %s</i>", 00106 title.c_str(), frameNumber, img.getDims().w(), img.getDims().h(), 00107 richTextEncode(img.nativeTypeName()).c_str()); 00108 00109 result += "<br>"; 00110 00111 if (auxinfo.srcpos.m_file_name != 0) 00112 result += sformat("from %s:%d", auxinfo.srcpos.m_file_name, auxinfo.srcpos.m_line_no); 00113 00114 result += "<br>"; 00115 00116 if (img.nativeType() == GenericFrame::GRAY_F32) 00117 { 00118 Range<float> r = rangeOf(img.asFloat()); 00119 result += sformat("range=[%g .. %g]", r.min(), r.max()); 00120 } 00121 else if (img.nativeType() == GenericFrame::RGB_F32) 00122 { 00123 float mi, ma; 00124 getMinMaxC(img.asRgbF32(), mi, ma); 00125 result += sformat("range=[%g .. %g]", mi, ma); 00126 } 00127 00128 return result; 00129 } 00130 } 00131 00132 // ###################################################################### 00133 struct QtImageFrame::Impl 00134 { 00135 Impl() 00136 : 00137 title(0), 00138 zoom(0), 00139 frame(0), 00140 genFrame(), 00141 titlestring(), 00142 preferredDims(), 00143 preferredMaxDims(), 00144 doInitialDims(true), 00145 isUpdated(false) 00146 {} 00147 00148 QLabel* title; 00149 QSpinBox* zoom; 00150 QLabel* frame; 00151 00152 GenericFrame genFrame; 00153 std::string shortname; 00154 std::string titlestring; 00155 Dims preferredDims; 00156 Dims preferredMaxDims; 00157 bool doInitialDims; 00158 00159 bool isUpdated; 00160 00161 Dims rawDims() const 00162 { 00163 return this->genFrame.getDims(); 00164 } 00165 00166 Dims scaledDims() const 00167 { 00168 const Dims raw = this->rawDims(); 00169 00170 if (raw.isEmpty()) return raw; 00171 else if (this->zoom->value() >= 0) return Dims(raw.w() << this->zoom->value(), raw.h() << this->zoom->value()); 00172 00173 // else... 00174 return Dims(raw.w() >> -(this->zoom->value()), raw.h() >> -(this->zoom->value())); 00175 } 00176 00177 void setInitialDims() 00178 { 00179 if (this->doInitialDims) 00180 { 00181 if (this->preferredDims.isNonEmpty()) 00182 { 00183 Dims dims = this->scaledDims(); 00184 00185 while (dims.w() < this->preferredDims.w() && 00186 dims.h() < this->preferredDims.h() && 00187 this->zoom->value() < this->zoom->maximum()) 00188 { 00189 this->zoom->blockSignals(true); 00190 this->zoom->stepUp(); 00191 this->zoom->blockSignals(false); 00192 dims = this->scaledDims(); 00193 } 00194 } 00195 00196 if (this->preferredMaxDims.isNonEmpty()) 00197 { 00198 Dims dims = this->scaledDims(); 00199 00200 while (dims.w() > this->preferredMaxDims.w() || 00201 dims.h() > this->preferredMaxDims.h()) 00202 { 00203 this->zoom->blockSignals(true); 00204 this->zoom->stepDown(); 00205 this->zoom->blockSignals(false); 00206 dims = this->scaledDims(); 00207 } 00208 } 00209 00210 this->doInitialDims = false; 00211 } 00212 } 00213 00214 void updateSize() 00215 { 00216 this->setInitialDims(); 00217 00218 const Dims dims = this->scaledDims(); 00219 00220 if (dims.isNonEmpty()) this->frame->setFixedSize(dims.w(), dims.h()); 00221 } 00222 00223 template <class T> 00224 Image<T> scaleImage(const Image<T>& img) 00225 { 00226 if (this->zoom->value() >= 0) 00227 return zoomXY(img, (1 << this->zoom->value()), (1 << this->zoom->value())); 00228 else 00229 { 00230 Image<T> result = img; 00231 for (int i = 0; i < -this->zoom->value(); ++i) result = decXY(lowPass3(result)); 00232 return result; 00233 } 00234 } 00235 00236 void update() 00237 { 00238 if (this->isUpdated) return; 00239 00240 GVX_TRACE(__PRETTY_FUNCTION__); 00241 00242 this->setInitialDims(); 00243 00244 QPixmap pixmap; 00245 00246 switch (this->genFrame.nativeType()) 00247 { 00248 case GenericFrame::NONE: 00249 break; 00250 00251 case GenericFrame::RGB_U8: 00252 case GenericFrame::RGBD: 00253 case GenericFrame::RGB_F32: 00254 case GenericFrame::VIDEO: 00255 pixmap = convertToQPixmap4(scaleImage(this->genFrame.asRgbU8())); 00256 break; 00257 00258 case GenericFrame::GRAY_U8: 00259 case GenericFrame::GRAY_F32: 00260 pixmap = convertToQPixmap4(scaleImage(this->genFrame.asGrayU8())); 00261 break; 00262 00263 case GenericFrame::RGB_U16: 00264 break; 00265 case GenericFrame::GRAY_U16: 00266 break; 00267 } 00268 00269 this->title->setText(titlestring.c_str()); 00270 this->title->setTextFormat(Qt::RichText); 00271 this->title->setAlignment(Qt::Alignment(Qt::AlignLeft|Qt::AlignVCenter|Qt::TextExpandTabs|Qt::TextSingleLine)); 00272 00273 this->frame->setPixmap(pixmap); 00274 00275 this->updateSize(); 00276 00277 this->isUpdated = true; 00278 } 00279 }; 00280 00281 // ###################################################################### 00282 QtImageFrame::QtImageFrame(QWidget* parent, const Dims& preferredDims, const Dims& preferredMaxDims) : 00283 QWidget(parent), rep(new Impl) 00284 { 00285 rep->preferredDims = preferredDims; 00286 rep->preferredMaxDims = preferredMaxDims; 00287 00288 QVBoxLayout *main = new QVBoxLayout(this); 00289 main->setSpacing(4); 00290 main->setMargin(2); 00291 00292 QVBoxLayout* header = new QVBoxLayout; 00293 main->addLayout(header); 00294 00295 rep->title = new QLabel(this); 00296 header->addWidget(rep->title); 00297 00298 QHBoxLayout* spingroup = new QHBoxLayout; 00299 spingroup->setSpacing(4); 00300 00301 QLabel* spinlabel = new QLabel("zoom:", this); 00302 spingroup->addWidget(spinlabel); 00303 00304 rep->zoom = new QSpinBox(this); 00305 spingroup->addWidget(rep->zoom); 00306 rep->zoom->setMinimum(MINZOOM); 00307 rep->zoom->setMaximum(MAXZOOM); 00308 rep->zoom->setSingleStep(1); 00309 rep->zoom->setButtonSymbols(QSpinBox::PlusMinus); 00310 rep->zoom->setValue(0); 00311 rep->zoom->setPrefix("pow(2, "); 00312 rep->zoom->setSuffix(")"); 00313 00314 spingroup->addStretch(1); 00315 00316 QPushButton* savebutton = new QPushButton(this); 00317 savebutton->setText("Save this image"); 00318 spingroup->addWidget(savebutton); 00319 00320 spingroup->addStretch(1); 00321 00322 this->connect(savebutton, SIGNAL(clicked()), this, SLOT(saveImage())); 00323 00324 header->addLayout(spingroup); 00325 00326 QFrame* hline = new QFrame(this); 00327 hline->setFrameShape(QFrame::HLine); 00328 hline->setFrameShadow(QFrame::Raised); 00329 hline->setLineWidth(2); 00330 main->addWidget(hline); 00331 00332 main->addStretch(1); 00333 00334 QHBoxLayout* himage = new QHBoxLayout; 00335 himage->addStretch(1); 00336 rep->frame = new QLabel(this); 00337 himage->addWidget(rep->frame); 00338 himage->addStretch(1); 00339 00340 main->addLayout(himage); 00341 00342 main->addStretch(1); 00343 00344 this->connect(rep->zoom, SIGNAL(valueChanged(int)), this, SLOT(setZoom(int))); 00345 00346 this->setLayout(main); 00347 } 00348 00349 QtImageFrame::~QtImageFrame() 00350 { 00351 delete rep; 00352 } 00353 00354 void QtImageFrame::setFrame(const GenericFrame& frame, const std::string& title, 00355 const int frameNumber, const FrameInfo& auxinfo) 00356 { 00357 rep->genFrame = frame; 00358 rep->genFrame.setFloatFlags(frame.floatFlags() | FLOAT_NORM_0_255); 00359 00360 rep->shortname = sformat("%s%06d", title.c_str(), frameNumber); 00361 rep->titlestring = buildTitle(frame, title, frameNumber, auxinfo); 00362 00363 rep->isUpdated = false; 00364 00365 if (this->isVisible()) rep->update(); 00366 else rep->updateSize(); 00367 } 00368 00369 void QtImageFrame::setZoom(int z) 00370 { 00371 rep->isUpdated = false; 00372 00373 if (this->isVisible()) rep->update(); 00374 } 00375 00376 void QtImageFrame::saveImage() 00377 { 00378 QString s = QFileDialog::getSaveFileName(this, QString("Select filename to save to"), 00379 QString(sformat("./%s.png", rep->shortname.c_str()).c_str())); 00380 00381 if (!s.isEmpty()) 00382 { 00383 try 00384 { 00385 Raster::WriteFrame(rep->genFrame, s.toStdString()); 00386 } 00387 catch (std::exception& e) 00388 { 00389 QErrorMessage* dlg = new QErrorMessage(this); 00390 dlg->showMessage(e.what()); 00391 } 00392 } 00393 } 00394 00395 void QtImageFrame::showEvent(QShowEvent* event) 00396 { 00397 rep->update(); 00398 } 00399 00400 // ###################################################################### 00401 /* So things look consistent in everyone's emacs... */ 00402 /* Local Variables: */ 00403 /* mode: c++ */ 00404 /* indent-tabs-mode: nil */ 00405 /* End: */