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 #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
00075
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
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,
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
00418
00419
00420
00421
00422
00423 #endif // GUI_QTIMAGEFRAME_Q_DEFINED