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 #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
00077
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
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
00402
00403
00404
00405