00001 #include "headers.h"
00002
00003 #ifndef NDEBUG
00004
00005 #include "modules/root.h"
00006 #include "modules/squarePixels.h"
00007 #include "modules/stdEncoder.h"
00008 #include "modules/quadTree.h"
00009 #include "modules/stdDomains.h"
00010 #include "modules/saupePredictor.h"
00011
00012 #include <QBoxLayout>
00013 #include <QDialog>
00014 #include <QLabel>
00015 #include <QTabWidget>
00016 #include <QTableWidget>
00017
00018 using namespace std;
00019
00020 int pos;
00021
00022
00023
00024
00025 QWidget* MRoot::debugModule(QPixmap &pixmap,const QPoint &click) {
00026
00027 QDialog *dlg= new QDialog;
00028 dlg->setModal(false);
00029
00030 ( new QVBoxLayout(dlg) )->addWidget( moduleShape()->debugModule(pixmap,click) );
00031 return dlg;
00032 }
00033
00034 namespace NOSPACE {
00035 struct PlaneFinder {
00036 typedef const IColorTransformer::PlaneSettings CPlSet;
00037
00038 CPlSet* const plSet;
00039
00040 PlaneFinder(CPlSet *plSet2find): plSet(plSet2find) {}
00041 bool operator()(const IColorTransformer::Plane &plane)
00042 { return plane.settings==plSet; }
00043 };
00044 }
00045 QWidget* MSquarePixels::debugModule(QPixmap &pixmap,const QPoint &click) {
00046 ASSERT( !planeList.empty() );
00047
00048 QTabWidget *tabs= new QTabWidget;
00049 bool isInside= pixmap.rect().contains(click);
00050
00051 for (int i=0; i<(int)jobs.size(); ++i) {
00052 PlaneBlock &job= jobs[i];
00053 if ( job.ranges->getRangeList().size() == 1 )
00054 continue;
00055
00056 PlaneList::const_iterator plane=
00057 find_if( planeList.begin(), planeList.end(), PlaneFinder(job.settings) );
00058 ASSERT( plane != planeList.end() );
00059
00060 QPoint jobClick= click;
00061 if (isInside) {
00062 int xShift=-1, yShift;
00063 plane->pixels.getPosition(job.pixels.start,xShift,yShift);
00064 ASSERT(xShift>=0);
00065 jobClick-= QPoint(xShift,yShift);
00066 if ( jobClick.x()<0 || jobClick.y()<0
00067 || jobClick.x()>=job.width || jobClick.y()>=job.height )
00068 continue;
00069 }
00070
00071 QTabWidget *tabs2= new QTabWidget;
00072 tabs2->addTab( job.encoder->debugModule(pixmap,jobClick), "Encoder" );
00073 tabs2->addTab( job.ranges->debugModule(pixmap,jobClick), "Ranges" );
00074 tabs2->addTab( job.domains->debugModule(pixmap,jobClick), "Domains" );
00075
00076 tabs->addTab( tabs2, QString("Job %1").arg(i+1) );
00077 }
00078 return tabs;
00079 }
00080
00081
00082 namespace NOSPACE {
00083 struct RangeInfoAccumulator {
00084 const ISquareDomains::PoolList *pools;
00085 int rotCounts[9];
00086 vector<int> poolCounts, levelCounts;
00087
00088 RangeInfoAccumulator(const ISquareDomains::PoolList &poolList,int maxLevel)
00089 : pools( &poolList ), poolCounts( pools->size(), 0 ), levelCounts( maxLevel+1, 0 ) {
00090 for (int i=0; i<9; ++i)
00091 rotCounts[i]= 0;
00092 }
00093
00094 void operator()(const ISquareRanges::RangeNode *range) {
00095 const MStdEncoder::RangeInfo &info= *MStdEncoder::RangeInfo::get(range);
00096
00097 ++rotCounts[info.rotation+1];
00098 ++levelCounts.at(range->level);
00099
00100 if ( info.rotation>=0 ) {
00101 int index= info.decAccel.pool - &*pools->begin() ;
00102 ASSERT( index>=0 && index<(int)pools->size() );
00103 ++poolCounts[index];
00104 }
00105 }
00106 };
00107
00108 const ISquareRanges::RangeNode* findRangeOnPoint
00109 ( const ISquareRanges::RangeList &ranges, const QPoint &click ) {
00110 int x= click.x(), y= click.y();
00111 ISquareRanges::RangeList::const_iterator it;
00112 for (it=ranges.begin(); it!=ranges.end(); ++it) {
00113 const Block &b= **it;
00114 if ( b.x0<=x && b.y0<=y && b.xend>x && b.yend>y )
00115 return *it;
00116 }
00117 ASSERT(false); return 0;
00118 }
00119 }
00120
00121 namespace NOSPACE {
00122 static void addFramedImage(QLayout *layout,const QImage &image) {
00123 QLabel *label= new QLabel;
00124 label->setPixmap( QPixmap::fromImage(image) );
00125 label->setFrameStyle( QFrame::Plain | QFrame::Box );
00126 label->setSizePolicy( QSizePolicy() );
00127 layout->addWidget(label);
00128 }
00129 template<class Assigner>
00130 QImage imageFromMatrix(CSMatrix matrix,Block block,int rotation,Assigner assigner) {
00131 QImage image(block.width(),block.height(),QImage::Format_RGB32);
00132
00133 using namespace MatrixWalkers;
00134
00135 rotation= Rotation::compose(1,rotation);
00136
00137 walkOperateCheckRotate( CheckedImage<QImage,QRgb>(image), assigner
00138 , matrix, block, rotation );
00139
00140 return image;
00141 }
00142 struct GrayImageAssigner {
00143 void operator()(QRgb &rgb,const SReal &pixel) {
00144 int gray= Float2int<8,Real>::convertCheck(pixel);
00145 rgb= qRgb(gray,gray,255);
00146 }
00147 void innerEnd() const {}
00148 };
00149 struct GrayImageMulAddAssigner: public GrayImageAssigner {
00150 Real mul, add;
00151
00152 GrayImageMulAddAssigner(Real toMul,Real toAdd)
00153 : mul(toMul), add(toAdd) {}
00154 void operator()(QRgb &rgb,const SReal &pixel)
00155 { GrayImageAssigner::operator()( rgb, pixel*mul+add ); }
00156 };
00157 }
00158 QWidget* MStdEncoder::debugModule(QPixmap &pixmap,const QPoint &click) {
00159 const ISquareRanges::RangeList &ranges= planeBlock->ranges->getRangeList();
00160
00161 QWidget *widget= new QWidget;
00162 QBoxLayout *layout= new QVBoxLayout(widget);
00163
00164 if ( pixmap.rect().contains(click) ) {
00165 const RangeNode &range= *findRangeOnPoint( ranges, click );
00166 const RangeInfo &info= *RangeInfo::get(&range);
00167
00168 QString msg= QString("Quantized average: %1\nQuantized deviation: %2\n\n")
00169 .arg((double)info.qrAvg) .arg((double)sqrt(info.qrDev2));
00170
00171 msg+= QString("Encoding SE: %1\n") .arg(info.bestSE);
00172
00173 if (info.qrDev2) {
00174 int poolIndex= info.decAccel.pool - &*planeBlock->domains->getPools().begin();
00175 const Block &domBlock= info.decAccel.domBlock;
00176 msg+= QString("Domain pool: %1\nDomain block top-left corner coordinates:\n"
00177 "\t %2 %3\n") .arg(poolIndex) .arg(domBlock.x0) .arg(domBlock.y0);
00178
00179 msg+= QString("Rotation: %1\nInversion: %2")
00180 .arg((int)info.rotation) .arg(info.inverted);
00181 } else
00182 msg+= "Only using solid color";
00183
00184 layout->addWidget( new QLabel(msg) );
00185
00186 if (info.qrDev2) {
00187 layout->addWidget( new QLabel("Domain block:") );
00188 addFramedImage( layout
00189 , imageFromMatrix( info.decAccel.pool->pixels, info.decAccel.domBlock
00190 , 0, GrayImageAssigner() )
00191 );
00192
00193 layout->addWidget( new QLabel("Domain block, transformed (encode-mode-only):") );
00194 addFramedImage( layout
00195 , imageFromMatrix( info.decAccel.pool->pixels, info.decAccel.domBlock
00196 , info.rotation, GrayImageMulAddAssigner(info.exact.linCoeff,info.exact.constCoeff) )
00197 );
00198 }
00199
00200 layout->addWidget( new QLabel("Range block:") );
00201 addFramedImage( layout
00202 , imageFromMatrix( planeBlock->pixels, range, 0, GrayImageAssigner() )
00203 );
00204
00205 } else {
00206 int maxLevel= 1 +log2ceil( max(planeBlock->width,planeBlock->height) );
00207 RangeInfoAccumulator info( planeBlock->domains->getPools(), maxLevel );
00208 info= for_each(ranges,info);
00209
00210 {
00211 QString msg= "Range count: %1\nRotation counts: %2\nDomain pool counts: %3";
00212
00213 msg= msg.arg( ranges.size() );
00214
00215 QString rots= QString::number(info.rotCounts[0]);
00216 for (int i=1; i<9; ++i)
00217 (rots+= ", ")+= QString::number(info.rotCounts[i]);
00218 msg= msg.arg(rots);
00219
00220 QString doms= QString::number(info.rotCounts[0]);
00221 vector<int>::const_iterator it;
00222 for (it= info.poolCounts.begin(); it!=info.poolCounts.end(); ++it)
00223 (doms+= ", ")+= QString::number(*it);
00224 msg= msg.arg(doms);
00225
00226 layout->addWidget( new QLabel(msg) );
00227 }
00228
00229 QTableWidget *table= new QTableWidget( maxLevel-2, 3 );
00230 table->setHorizontalHeaderLabels
00231 ( QStringList() << "Level" << "Ranges" << "Domain count" );
00232 for (int level=2; level<maxLevel; ++level) {
00233
00234 table->setItem( level-2, 0, new QTableWidgetItem(QString::number(level)) );
00235
00236 table->setItem( level-2, 1, new QTableWidgetItem(
00237 QString::number( info.levelCounts[level] )
00238 ) );
00239
00240
00241
00242
00243 int domCount= levelPoolInfos[level].empty() ? -1
00244 : levelPoolInfos[level].back().indexBegin;
00245 table->setItem( level-2, 2, new QTableWidgetItem(
00246 QString("2 ^ %1").arg( log2(domCount) )
00247 ) );
00248 }
00249
00250 table->resizeColumnsToContents();
00251 table->resizeRowsToContents();
00252 layout->addWidget(table);
00253
00254 if ( modulePredictor() )
00255 layout->addWidget( modulePredictor()->debugModule(pixmap,click) );
00256 }
00257
00258 return widget;
00259 }
00260
00261
00262 QWidget* MQuadTree::debugModule(QPixmap &pixmap,const QPoint &click) {
00263
00264 if ( pixmap.rect().contains(click) ) {
00265 const ISquareRanges::RangeNode &range= *findRangeOnPoint( fringe, click );
00266
00267 Real rSum, r2Sum;
00268 planeBlock->summers_makeValid();
00269 planeBlock->getSums(range).unpack(rSum,r2Sum);
00270 float estSE= estimateSE(rSum,r2Sum,range.size(),range.level);
00271 float realSE= range.encoderData->bestSE;
00272 if (realSE==-1)
00273 realSE= numeric_limits<float>::infinity();
00274
00275 QString msg= QString("Level: %1\nRegular: %2\n"
00276 "Top-left corner: %3 %4\nWidth: %5\nHeight: %6\n"
00277 "Estimated SE: %7 (%8% of the encoded value)")
00278 .arg(range.level) .arg(range.isRegular())
00279 .arg(range.x0) .arg(range.y0)
00280 .arg(range.width()) .arg(range.height())
00281 .arg(estSE) .arg(100*estSE/realSE);
00282 return new QLabel(msg);
00283
00284 } else {
00285 QString msg;
00286
00287 if ( settingsInt(HeuristicAllowed) ) {
00288 msg+= "Heuristic dividing info:\n"
00289 "\tBad tries (forced to divide): %1\n"
00290 "\tBad divides (successful merges): %2\n"
00291 "\tUnsuccessful merges: %3\n";
00292 msg= msg.arg(badTries).arg(badDivides).arg(triedMerges);
00293 }
00294 return new QLabel(msg);
00295 }
00296
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319 QWidget* MStdDomains::debugModule(QPixmap &pixmap,const QPoint &click) {
00320
00321 if ( pixmap.rect().contains(click) ) {
00322
00323
00324 } else {
00325
00326
00327 }
00328 return 0;
00329 }
00330
00331 QWidget* MSaupePredictor::debugModule(QPixmap &pixmap,const QPoint &click) {
00332 if ( pixmap.rect().contains(click) )
00333 return 0;
00334 return new QLabel( QString("Predicted %1/%2 (%3%)")
00335 .arg(predicted) .arg(maxpred) .arg(double(100)*predicted/(double)maxpred) );
00336 }
00337
00338 #endif