1 #include "interfaces.h"
4 #include "modules/root.h"
5 #include "modules/squarePixels.h"
6 #include "modules/stdEncoder.h"
7 #include "modules/quadTree.h"
8 #include "modules/stdDomains.h"
9 #include "modules/saupePredictor.h"
15 #include <QTableWidget>
21 QWidget
* MRoot::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
22 // create a new modeless dialog window
23 QDialog
*dlg
= new QDialog
;
25 // add a laid-out single widget created by IShapeTransformer
26 ( new QVBoxLayout(dlg
) )->addWidget( moduleShape()->debugModule(pixmap
,click
) );
32 typedef const IColorTransformer::PlaneSettings CPlSet
;
36 PlaneFinder(CPlSet
*plSet2find
): plSet(plSet2find
) {}
37 bool operator()(const IColorTransformer::Plane
&plane
)
38 { return plane
.settings
==plSet
; }
41 QWidget
* MSquarePixels::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
42 ASSERT( !planeList
.empty() );
43 // create a tab widget
44 QTabWidget
*tabs
= new QTabWidget
;
45 bool isInside
= pixmap
.rect().contains(click
);
46 // fill one tab for every job by three sub-tabs with the three modules
47 for (int i
=0; i
<(int)jobs
.size(); ++i
) {
48 PlaneBlock
&job
= jobs
[i
];
49 if ( job
.ranges
->getRangeList().size() == 1 )
51 // find the plane which is the job from
52 PlaneList::const_iterator plane
=
53 find_if( planeList
.begin(), planeList
.end(), PlaneFinder(job
.settings
) );
54 ASSERT( plane
!= planeList
.end() );
55 // find out the position of the job in the plane
56 QPoint jobClick
= click
;
58 int xShift
=-1, yShift
;
59 plane
->pixels
.getPosition(job
.pixels
.start
,xShift
,yShift
);
61 jobClick
-= QPoint(xShift
,yShift
);
62 if ( jobClick
.x()<0 || jobClick
.y()<0
63 || jobClick
.x()>=job
.width
|| jobClick
.y()>=job
.height
)
66 // make children do the work
67 QTabWidget
*tabs2
= new QTabWidget
;
68 tabs2
->addTab( job
.encoder
->debugModule(pixmap
,jobClick
), "Encoder" );
69 tabs2
->addTab( job
.ranges
->debugModule(pixmap
,jobClick
), "Ranges" );
70 tabs2
->addTab( job
.domains
->debugModule(pixmap
,jobClick
), "Domains" );
72 tabs
->addTab( tabs2
, QString("Job %1").arg(i
+1) );
79 struct RangeInfoAccumulator
{
80 const ISquareDomains::PoolList
*pools
;
82 vector
<int> poolCounts
, levelCounts
;
84 RangeInfoAccumulator(const ISquareDomains::PoolList
&poolList
,int maxLevel
)
85 : pools( &poolList
), poolCounts( pools
->size(), 0 ), levelCounts( maxLevel
+1, 0 ) {
86 for (int i
=0; i
<9; ++i
)
90 void operator()(const ISquareRanges::RangeNode
*range
) {
91 const MStandardEncoder::RangeInfo
&info
92 = static_cast<MStandardEncoder::RangeInfo
&>( *range
->encoderData
);
93 // increment the counts of ranges on this rotation and level
94 ++rotCounts
[info
.rotation
+1];
95 ++levelCounts
.at(range
->level
);
96 // find and increment the pool of the range's domain (if exists)
97 if ( info
.rotation
>=0 ) {
98 int index
= info
.decAccel
.pool
- &*pools
->begin() ;
99 ASSERT( index
>=0 && index
<(int)pools
->size() );
103 }; // RangeAccumulator struct
105 const ISquareRanges::RangeNode
* findRangeOnPoint
106 ( const ISquareRanges::RangeList
&ranges
, const QPoint
&click
) {
107 int x
= click
.x(), y
= click
.y();
108 ISquareRanges::RangeList::const_iterator it
;
109 for (it
=ranges
.begin(); it
!=ranges
.end(); ++it
) {
110 const Block
&b
= **it
;
111 if ( b
.x0
<=x
&& b
.y0
<=y
&& b
.xend
>x
&& b
.yend
>y
)
114 ASSERT(false); return 0;
119 static void addFramedImage(QLayout
*layout
,const QImage
&image
) {
120 QLabel
*label
= new QLabel
;
121 label
->setPixmap( QPixmap::fromImage(image
) );
122 label
->setFrameStyle( QFrame::Plain
| QFrame::Box
); // to have a thin frame
123 label
->setSizePolicy( QSizePolicy() ); // to have the frame exatly around the image
124 layout
->addWidget(label
);
126 template<class Assigner
>
127 QImage
imageFromMatrix(CSMatrix matrix
,Block block
,int rotation
,Assigner assigner
) {
128 QImage
image(block
.width(),block
.height(),QImage::Format_RGB32
);
130 using namespace MatrixWalkers
;
131 // changing rotation because of transposed CheckedImage
132 rotation
= Rotation::compose(1,rotation
);
134 walkOperateCheckRotate( CheckedImage
<QImage
,QRgb
>(image
), assigner
135 , matrix
, block
, rotation
);
139 struct GrayImageAssigner
{
140 void operator()(QRgb
&rgb
,const SReal
&pixel
) {
141 int gray
= Float2int
<8,Real
>::convertCheck(pixel
);
142 rgb
= qRgb(gray
,gray
,255); // not gray colour (intentionally)
144 void innerEnd() const {}
146 struct GrayImageMulAddAssigner
: public GrayImageAssigner
{
149 GrayImageMulAddAssigner(Real toMul
,Real toAdd
)
150 : mul(toMul
), add(toAdd
) {}
151 void operator()(QRgb
&rgb
,const SReal
&pixel
)
152 { GrayImageAssigner::operator()( rgb
, pixel
*mul
+add
); }
155 QWidget
* MStandardEncoder::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
156 const ISquareRanges::RangeList
&ranges
= planeBlock
->ranges
->getRangeList();
158 QWidget
*widget
= new QWidget
;
159 QBoxLayout
*layout
= new QVBoxLayout(widget
);
161 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
162 const RangeNode
&range
= *findRangeOnPoint( ranges
, click
);
163 const RangeInfo
&info
= static_cast<RangeInfo
&>(*range
.encoderData
);
165 QString msg
= QString("Quantized average: %1\nQuantized deviation: %2\n\n")
166 .arg((double)info
.qrAvg
) .arg((double)sqrt(info
.qrDev2
));
168 msg
+= QString("Encoding SE: %1\n") .arg(info
.bestSE
);
171 int poolIndex
= info
.decAccel
.pool
- &*planeBlock
->domains
->getPools().begin();
172 const Block
&domBlock
= info
.decAccel
.domBlock
;
173 msg
+= QString("Domain pool: %1\nDomain block top-left corner coordinates:\n"
174 "\t %2 %3\n") .arg(poolIndex
) .arg(domBlock
.x0
) .arg(domBlock
.y0
);
176 msg
+= QString("Rotation: %1\nInversion: %2")
177 .arg((int)info
.rotation
) .arg(info
.inverted
);
179 msg
+= "Only using solid color";
181 layout
->addWidget( new QLabel(msg
) );
184 layout
->addWidget( new QLabel("Domain block:") );
185 addFramedImage( layout
186 , imageFromMatrix( info
.decAccel
.pool
->pixels
, info
.decAccel
.domBlock
187 , 0, GrayImageAssigner() )
190 layout
->addWidget( new QLabel("Domain block, transformed (encode-mode-only):") );
191 addFramedImage( layout
192 , imageFromMatrix( info
.decAccel
.pool
->pixels
, info
.decAccel
.domBlock
193 , info
.rotation
, GrayImageMulAddAssigner(info
.exact
.linCoeff
,info
.exact
.constCoeff
) )
197 layout
->addWidget( new QLabel("Range block:") );
198 addFramedImage( layout
199 , imageFromMatrix( planeBlock
->pixels
, range
, 0, GrayImageAssigner() )
202 } else { // provide general info
203 int maxLevel
= 1 +log2ceil( max(planeBlock
->width
,planeBlock
->height
) );
204 RangeInfoAccumulator
info( planeBlock
->domains
->getPools(), maxLevel
);
205 info
= for_each( ranges
.begin(), ranges
.end(), info
);
207 {// create a label with various counts info
208 QString msg
= "Range count: %1\nRotation counts: %2\nDomain pool counts: %3";
209 // fill in the total range count
210 msg
= msg
.arg( ranges
.size() );
211 // fill in the rotation counts
212 QString rots
= QString::number(info
.rotCounts
[0]);
213 for (int i
=1; i
<9; ++i
)
214 (rots
+= ", ")+= QString::number(info
.rotCounts
[i
]);
216 // fill in the domain counts
217 QString doms
= QString::number(info
.rotCounts
[0]);
218 vector
<int>::const_iterator it
;
219 for (it
= info
.poolCounts
.begin(); it
!=info
.poolCounts
.end(); ++it
)
220 (doms
+= ", ")+= QString::number(*it
);
222 // create the label and add it to the layout
223 layout
->addWidget( new QLabel(msg
) );
226 QTableWidget
*table
= new QTableWidget( maxLevel
-2, 3 );
227 table
->setHorizontalHeaderLabels
228 ( QStringList() << "Level" << "Ranges" << "Domain count" );
229 for (int level
=2; level
<maxLevel
; ++level
) {
230 // the number of the level
231 table
->setItem( level
-2, 0, new QTableWidgetItem(QString::number(level
)) );
232 // the count of the ranges on the level
233 table
->setItem( level
-2, 1, new QTableWidgetItem(
234 QString::number( info
.levelCounts
[level
] )
236 // the maximum allowed SE for the level
237 //float maxSE= planeBlock->moduleQ2SE->rangeSE( planeBlock->quality, powers[2*level] );
238 //table->setItem( level-2, 1.5, new QTableWidgetItem(QString::number(maxSE)) );
239 // the domain count for the level
240 int domCount
= levelPoolInfos
[level
].empty() ? -1
241 : levelPoolInfos
[level
].back().indexBegin
;
242 table
->setItem( level
-2, 2, new QTableWidgetItem(
243 QString("2 ^ %1").arg( log2(domCount
) )
246 // resize the label and add it to the layout
247 table
->resizeColumnsToContents();
248 table
->resizeRowsToContents();
249 layout
->addWidget(table
);
251 if ( modulePredictor() )
252 layout
->addWidget( modulePredictor()->debugModule(pixmap
,click
) );
256 } // MStandardEncoder::debugModule method
259 QWidget
* MQuadTree::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
261 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
262 const ISquareRanges::RangeNode
&range
= *findRangeOnPoint( fringe
, click
);
265 planeBlock
->summers_makeValid(); /// \todo only approximation
266 planeBlock
->getSums(range
).unpack(rSum
,r2Sum
);
267 float estSE
= estimateSE(rSum
,r2Sum
,range
.size(),range
.level
);
269 QString msg
= QString("Level: %1\nRegular: %2\n"
270 "Top-left corner: %3 %4\nWidth: %5\nHeight: %6\n"
271 "Estimated SE: %7 - %8% of the encoded value")
272 .arg(range
.level
) .arg(range
.isRegular())
273 .arg(range
.x0
) .arg(range
.y0
)
274 .arg(range
.width()) .arg(range
.height())
275 .arg(estSE
) .arg(100*estSE
/range
.encoderData
->bestSE
);
276 return new QLabel(msg
);
278 } else { // provide general info
280 // add info about heuristic dividing (if it's allowed)
281 if ( settingsInt(HeuristicAllowed
) ) {
282 msg
+= "Heuristic dividing info:\n"
283 "\tBad tries (forced to divide): %1\n"
284 "\tBad divides (successful merges): %2\n"
285 "\tUnsuccessful merges: %3\n";
286 msg
= msg
.arg(badTries
).arg(badDivides
).arg(triedMerges
);
288 return new QLabel(msg
);
291 } // MQuadTree::debugModule method
296 void debugPool(const ISquareDomains::Pool &pool) {
297 // create and fill the image
298 QImage image( pool.width, pool.height, QImage::Format_RGB32 );
300 for (int y=0; y<pool.height; ++y) {
301 QRgb *line= (QRgb*)image.scanLine(y);
302 for (int x=0; x<pool.width; ++x) {
303 int c= checkBoundsFunc( 0, (int)(pool.pixels[x][y]*256), 255 );
304 line[x]= qRgb(c,c,c);
308 image.save("pool.png");
313 QWidget
* MStdDomains::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
315 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
318 } else { // provide general info
325 QWidget
* MSaupePredictor::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
326 if ( pixmap
.rect().contains(click
) )
328 return new QLabel( QString("Predicted %1/%2 (%3%)")
329 .arg(predicted
) .arg(maxpred
) .arg(double(100)*predicted
/(double)maxpred
) );