5 #include "modules/root.h"
6 #include "modules/squarePixels.h"
7 #include "modules/stdEncoder.h"
8 #include "modules/quadTree.h"
9 #include "modules/stdDomains.h"
10 #include "modules/saupePredictor.h"
16 #include <QTableWidget>
20 int pos
; ///< modified by STREAM_POS macro - stores the current position (to ease debugging)
25 QWidget
* MRoot::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
26 // create a new modeless dialog window
27 QDialog
*dlg
= new QDialog
;
29 // add a laid-out single widget created by IShapeTransformer
30 ( new QVBoxLayout(dlg
) )->addWidget( moduleShape()->debugModule(pixmap
,click
) );
36 typedef const IColorTransformer::PlaneSettings CPlSet
;
40 PlaneFinder(CPlSet
*plSet2find
): plSet(plSet2find
) {}
41 bool operator()(const IColorTransformer::Plane
&plane
)
42 { return plane
.settings
==plSet
; }
45 QWidget
* MSquarePixels::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
46 ASSERT( !planeList
.empty() );
47 // create a tab widget
48 QTabWidget
*tabs
= new QTabWidget
;
49 bool isInside
= pixmap
.rect().contains(click
);
50 // fill one tab for every job by three sub-tabs with the three modules
51 for (int i
=0; i
<(int)jobs
.size(); ++i
) {
52 PlaneBlock
&job
= jobs
[i
];
53 if ( job
.ranges
->getRangeList().size() == 1 )
55 // find the plane which is the job from
56 PlaneList::const_iterator plane
=
57 find_if( planeList
.begin(), planeList
.end(), PlaneFinder(job
.settings
) );
58 ASSERT( plane
!= planeList
.end() );
59 // find out the position of the job in the plane
60 QPoint jobClick
= click
;
62 int xShift
=-1, yShift
;
63 plane
->pixels
.getPosition(job
.pixels
.start
,xShift
,yShift
);
65 jobClick
-= QPoint(xShift
,yShift
);
66 if ( jobClick
.x()<0 || jobClick
.y()<0
67 || jobClick
.x()>=job
.width
|| jobClick
.y()>=job
.height
)
70 // make children do the work
71 QTabWidget
*tabs2
= new QTabWidget
;
72 tabs2
->addTab( job
.encoder
->debugModule(pixmap
,jobClick
), "Encoder" );
73 tabs2
->addTab( job
.ranges
->debugModule(pixmap
,jobClick
), "Ranges" );
74 tabs2
->addTab( job
.domains
->debugModule(pixmap
,jobClick
), "Domains" );
76 tabs
->addTab( tabs2
, QString("Job %1").arg(i
+1) );
83 struct RangeInfoAccumulator
{
84 const ISquareDomains::PoolList
*pools
;
86 vector
<int> poolCounts
, levelCounts
;
88 RangeInfoAccumulator(const ISquareDomains::PoolList
&poolList
,int maxLevel
)
89 : pools( &poolList
), poolCounts( pools
->size(), 0 ), levelCounts( maxLevel
+1, 0 ) {
90 for (int i
=0; i
<9; ++i
)
94 void operator()(const ISquareRanges::RangeNode
*range
) {
95 const MStdEncoder::RangeInfo
&info
= *MStdEncoder::RangeInfo::get(range
);
96 // increment the counts of ranges on this rotation and level
97 ++rotCounts
[info
.rotation
+1];
98 ++levelCounts
.at(range
->level
);
99 // find and increment the pool of the range's domain (if exists)
100 if ( info
.rotation
>=0 ) {
101 int index
= info
.decAccel
.pool
- &*pools
->begin() ;
102 ASSERT( index
>=0 && index
<(int)pools
->size() );
106 }; // RangeAccumulator struct
108 const ISquareRanges::RangeNode
* findRangeOnPoint
109 ( const ISquareRanges::RangeList
&ranges
, const QPoint
&click
) {
110 int x
= click
.x(), y
= click
.y();
111 ISquareRanges::RangeList::const_iterator it
;
112 for (it
=ranges
.begin(); it
!=ranges
.end(); ++it
) {
113 const Block
&b
= **it
;
114 if ( b
.x0
<=x
&& b
.y0
<=y
&& b
.xend
>x
&& b
.yend
>y
)
117 ASSERT(false); return 0;
122 static void addFramedImage(QLayout
*layout
,const QImage
&image
) {
123 QLabel
*label
= new QLabel
;
124 label
->setPixmap( QPixmap::fromImage(image
) );
125 label
->setFrameStyle( QFrame::Plain
| QFrame::Box
); // to have a thin frame
126 label
->setSizePolicy( QSizePolicy() ); // to have the frame exatly around the image
127 layout
->addWidget(label
);
129 template<class Assigner
>
130 QImage
imageFromMatrix(CSMatrix matrix
,Block block
,int rotation
,Assigner assigner
) {
131 QImage
image(block
.width(),block
.height(),QImage::Format_RGB32
);
133 using namespace MatrixWalkers
;
134 // changing rotation because of transposed CheckedImage
135 rotation
= Rotation::compose(1,rotation
);
137 walkOperateCheckRotate( CheckedImage
<QImage
,QRgb
>(image
), assigner
138 , matrix
, block
, rotation
);
142 struct GrayImageAssigner
{
143 void operator()(QRgb
&rgb
,const SReal
&pixel
) {
144 int gray
= Float2int
<8,Real
>::convertCheck(pixel
);
145 rgb
= qRgb(gray
,gray
,255); // not gray colour (intentionally)
147 void innerEnd() const {}
149 struct GrayImageMulAddAssigner
: public GrayImageAssigner
{
152 GrayImageMulAddAssigner(Real toMul
,Real toAdd
)
153 : mul(toMul
), add(toAdd
) {}
154 void operator()(QRgb
&rgb
,const SReal
&pixel
)
155 { GrayImageAssigner::operator()( rgb
, pixel
*mul
+add
); }
158 QWidget
* MStdEncoder::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
159 const ISquareRanges::RangeList
&ranges
= planeBlock
->ranges
->getRangeList();
161 QWidget
*widget
= new QWidget
;
162 QBoxLayout
*layout
= new QVBoxLayout(widget
);
164 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
165 const RangeNode
&range
= *findRangeOnPoint( ranges
, click
);
166 const RangeInfo
&info
= *RangeInfo::get(&range
);
168 QString msg
= QString("Quantized average: %1\nQuantized deviation: %2\n\n")
169 .arg((double)info
.qrAvg
) .arg((double)sqrt(info
.qrDev2
));
171 msg
+= QString("Encoding SE: %1\n") .arg(info
.bestSE
);
174 int poolIndex
= info
.decAccel
.pool
- &*planeBlock
->domains
->getPools().begin();
175 const Block
&domBlock
= info
.decAccel
.domBlock
;
176 msg
+= QString("Domain pool: %1\nDomain block top-left corner coordinates:\n"
177 "\t %2 %3\n") .arg(poolIndex
) .arg(domBlock
.x0
) .arg(domBlock
.y0
);
179 msg
+= QString("Rotation: %1\nInversion: %2")
180 .arg((int)info
.rotation
) .arg(info
.inverted
);
182 msg
+= "Only using solid color";
184 layout
->addWidget( new QLabel(msg
) );
187 layout
->addWidget( new QLabel("Domain block:") );
188 addFramedImage( layout
189 , imageFromMatrix( info
.decAccel
.pool
->pixels
, info
.decAccel
.domBlock
190 , 0, GrayImageAssigner() )
193 layout
->addWidget( new QLabel("Domain block, transformed (encode-mode-only):") );
194 addFramedImage( layout
195 , imageFromMatrix( info
.decAccel
.pool
->pixels
, info
.decAccel
.domBlock
196 , info
.rotation
, GrayImageMulAddAssigner(info
.exact
.linCoeff
,info
.exact
.constCoeff
) )
200 layout
->addWidget( new QLabel("Range block:") );
201 addFramedImage( layout
202 , imageFromMatrix( planeBlock
->pixels
, range
, 0, GrayImageAssigner() )
205 } else { // provide general info
206 int maxLevel
= 1 +log2ceil( max(planeBlock
->width
,planeBlock
->height
) );
207 RangeInfoAccumulator
info( planeBlock
->domains
->getPools(), maxLevel
);
208 info
= for_each(ranges
,info
);
210 {// create a label with various counts info
211 QString msg
= "Range count: %1\nRotation counts: %2\nDomain pool counts: %3";
212 // fill in the total range count
213 msg
= msg
.arg( ranges
.size() );
214 // fill in the rotation counts
215 QString rots
= QString::number(info
.rotCounts
[0]);
216 for (int i
=1; i
<9; ++i
)
217 (rots
+= ", ")+= QString::number(info
.rotCounts
[i
]);
219 // fill in the domain counts
220 QString doms
= QString::number(info
.rotCounts
[0]);
221 vector
<int>::const_iterator it
;
222 for (it
= info
.poolCounts
.begin(); it
!=info
.poolCounts
.end(); ++it
)
223 (doms
+= ", ")+= QString::number(*it
);
225 // create the label and add it to the layout
226 layout
->addWidget( new QLabel(msg
) );
229 QTableWidget
*table
= new QTableWidget( maxLevel
-2, 3 );
230 table
->setHorizontalHeaderLabels
231 ( QStringList() << "Level" << "Ranges" << "Domain count" );
232 for (int level
=2; level
<maxLevel
; ++level
) {
233 // the number of the level
234 table
->setItem( level
-2, 0, new QTableWidgetItem(QString::number(level
)) );
235 // the count of the ranges on the level
236 table
->setItem( level
-2, 1, new QTableWidgetItem(
237 QString::number( info
.levelCounts
[level
] )
239 // the maximum allowed SE for the level
240 //float maxSE= planeBlock->moduleQ2SE->rangeSE( planeBlock->quality, powers[2*level] );
241 //table->setItem( level-2, 1.5, new QTableWidgetItem(QString::number(maxSE)) );
242 // the domain count for the level
243 int domCount
= levelPoolInfos
[level
].empty() ? -1
244 : levelPoolInfos
[level
].back().indexBegin
;
245 table
->setItem( level
-2, 2, new QTableWidgetItem(
246 QString("2 ^ %1").arg( log2(domCount
) )
249 // resize the label and add it to the layout
250 table
->resizeColumnsToContents();
251 table
->resizeRowsToContents();
252 layout
->addWidget(table
);
254 if ( modulePredictor() )
255 layout
->addWidget( modulePredictor()->debugModule(pixmap
,click
) );
259 } // MStdEncoder::debugModule method
262 QWidget
* MQuadTree::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
264 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
265 const ISquareRanges::RangeNode
&range
= *findRangeOnPoint( fringe
, click
);
268 planeBlock
->summers_makeValid(); // \todo only approximation
269 planeBlock
->getSums(range
).unpack(rSum
,r2Sum
);
270 float estSE
= estimateSE(rSum
,r2Sum
,range
.size(),range
.level
);
271 float realSE
= range
.encoderData
->bestSE
;
273 realSE
= numeric_limits
<float>::infinity();
275 QString msg
= QString("Level: %1\nRegular: %2\n"
276 "Top-left corner: %3 %4\nWidth: %5\nHeight: %6\n"
277 "Estimated SE: %7 (%8% of the encoded value)")
278 .arg(range
.level
) .arg(range
.isRegular())
279 .arg(range
.x0
) .arg(range
.y0
)
280 .arg(range
.width()) .arg(range
.height())
281 .arg(estSE
) .arg(100*estSE
/realSE
);
282 return new QLabel(msg
);
284 } else { // provide general info
286 // add info about heuristic dividing (if it's allowed)
287 if ( settingsInt(HeuristicAllowed
) ) {
288 msg
+= "Heuristic dividing info:\n"
289 "\tBad tries (forced to divide): %1\n"
290 "\tBad divides (successful merges): %2\n"
291 "\tUnsuccessful merges: %3\n";
292 msg
= msg
.arg(badTries
).arg(badDivides
).arg(triedMerges
);
294 return new QLabel(msg
);
297 } // MQuadTree::debugModule method
302 void debugPool(const ISquareDomains::Pool &pool) {
303 // create and fill the image
304 QImage image( pool.width, pool.height, QImage::Format_RGB32 );
306 for (int y=0; y<pool.height; ++y) {
307 QRgb *line= (QRgb*)image.scanLine(y);
308 for (int x=0; x<pool.width; ++x) {
309 int c= checkBoundsFunc( 0, (int)(pool.pixels[x][y]*256), 255 );
310 line[x]= qRgb(c,c,c);
314 image.save("pool.png");
319 QWidget
* MStdDomains::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
321 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
324 } else { // provide general info
331 QWidget
* MSaupePredictor::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
332 if ( pixmap
.rect().contains(click
) )
334 return new QLabel( QString("Predicted %1/%2 (%3%)")
335 .arg(predicted
) .arg(maxpred
) .arg(double(100)*predicted
/(double)maxpred
) );