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