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 // fill one tab for every job by three sub-tabs with the three modules
46 for (int i
=0; i
<(int)jobs
.size(); ++i
) {
48 if ( job
.ranges
->getRangeList().size() == 1 )
50 // find the plane which is the job from
51 PlaneList::const_iterator plane
=
52 find_if( planeList
.begin(), planeList
.end(), PlaneFinder(job
.settings
) );
53 ASSERT( plane
!= planeList
.end() );
54 // find out the position of the job in the plane
55 int xShift
=-1, yShift
;
56 plane
->pixels
.getPosition(job
.pixels
.start
,xShift
,yShift
);
58 QPoint jobClick
= click
-QPoint(xShift
,yShift
);
59 if ( jobClick
.x()<0 || jobClick
.y()<0
60 || jobClick
.x()>=job
.width
|| jobClick
.y()>=job
.height
)
62 // make children do the work
63 QTabWidget
*tabs2
= new QTabWidget
;
64 tabs2
->addTab( job
.encoder
->debugModule(pixmap
,jobClick
) , "Encoder" );
65 tabs2
->addTab( job
.ranges
->debugModule(pixmap
,jobClick
), "Ranges" );
66 tabs2
->addTab( job
.domains
->debugModule(pixmap
,jobClick
), "Domains" );
68 tabs
->addTab( tabs2
, QString("Job %1").arg(i
+1) );
75 struct RangeInfoAccumulator
{
76 const ISquareDomains::PoolList
*pools
;
78 vector
<int> poolCounts
, levelCounts
;
80 RangeInfoAccumulator(const ISquareDomains::PoolList
&poolList
)
81 : pools( &poolList
), poolCounts( pools
->size(), 0 ), levelCounts( 10, 0 ) {
82 for (int i
=0; i
<9; ++i
)
86 void operator()(const ISquareRanges::RangeNode
*range
) {
87 const MStandardEncoder::RangeInfo
&info
88 = static_cast<MStandardEncoder::RangeInfo
&>( *range
->encoderData
);
89 // increment the counts of ranges on this rotation and level
90 ++rotCounts
[info
.rotation
+1];
91 ++levelCounts
.at(range
->level
);
92 // find and increment the pool of the range's domain (if exists)
93 if ( info
.rotation
>=0 ) {
94 int index
= info
.decAccel
.pool
- &*pools
->begin() ;
95 ASSERT( index
>=0 && index
<(int)pools
->size() );
99 }; // RangeAccumulator struct
101 const ISquareRanges::RangeNode
* findRangeOnPoint
102 ( const ISquareRanges::RangeList
&ranges
, const QPoint
&click
) {
103 int x
= click
.x(), y
= click
.y();
104 ISquareRanges::RangeList::const_iterator it
;
105 for (it
=ranges
.begin(); it
!=ranges
.end(); ++it
) {
106 const Block
&b
= **it
;
107 if ( b
.x0
<=x
&& b
.y0
<=y
&& b
.xend
>x
&& b
.yend
>y
)
110 ASSERT(false); return 0;
115 static void addFramedImage(QLayout
*layout
,const QImage
&image
) {
116 QLabel
*label
= new QLabel
;
117 label
->setPixmap( QPixmap::fromImage(image
) );
118 label
->setFrameStyle( QFrame::Plain
| QFrame::Box
); // to have a thin frame
119 label
->setSizePolicy( QSizePolicy() ); // to have the frame exatly around the image
120 layout
->addWidget(label
);
122 template<class Assigner
>
123 QImage
imageFromMatrix(CSMatrix matrix
,Block block
,int rotation
,Assigner assigner
) {
124 QImage
image(block
.width(),block
.height(),QImage::Format_RGB32
);
126 using namespace MatrixWalkers
;
127 // changing rotation because of transposed CheckedImage
128 rotation
= Rotation::compose(1,rotation
);
130 walkOperateCheckRotate( CheckedImage
<QImage
,QRgb
>(image
), assigner
131 , matrix
, block
, rotation
);
135 struct GrayImageAssigner
{
136 void operator()(QRgb
&rgb
,const SReal
&pixel
) {
137 int gray
= Float2int
<8,Real
>::convertCheck(pixel
);
138 rgb
= qRgb(gray
,gray
,255); // not gray colour (intentionally)
140 void innerEnd() const {}
142 struct GrayImageMulAddAssigner
: public GrayImageAssigner
{
145 GrayImageMulAddAssigner(Real toMul
,Real toAdd
)
146 : mul(toMul
), add(toAdd
) {}
147 void operator()(QRgb
&rgb
,const SReal
&pixel
)
148 { GrayImageAssigner::operator()( rgb
, pixel
*mul
+add
); }
151 QWidget
* MStandardEncoder::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
152 const ISquareRanges::RangeList
&ranges
= planeBlock
->ranges
->getRangeList();
154 QWidget
*widget
= new QWidget
;
155 QBoxLayout
*layout
= new QVBoxLayout(widget
);
157 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
158 const RangeNode
&range
= *findRangeOnPoint( ranges
, click
);
159 const RangeInfo
&info
= static_cast<RangeInfo
&>(*range
.encoderData
);
161 QString msg
= QString("Quantized average: %1\nQuantized deviation: %2\n\n")
162 .arg(info
.qrAvg
) .arg(sqrt(info
.qrDev2
));
164 msg
+= QString("Encoding SE: %1\n") .arg(info
.bestSE
);
167 int poolIndex
= info
.decAccel
.pool
- &*planeBlock
->domains
->getPools().begin();
168 const Block
&domBlock
= info
.decAccel
.domBlock
;
169 msg
+= QString("Domain pool: %1\nDomain block top-left corner coordinates:\n"
170 "\t %2 %3\n") .arg(poolIndex
) .arg(domBlock
.x0
) .arg(domBlock
.y0
);
172 msg
+= QString("Rotation: %1\nInversion: %2")
173 .arg((int)info
.rotation
) .arg(info
.inverted
);
175 msg
+= "Only using solid color";
177 layout
->addWidget( new QLabel(msg
) );
180 layout
->addWidget( new QLabel("Domain block:") );
181 addFramedImage( layout
182 , imageFromMatrix( info
.decAccel
.pool
->pixels
, info
.decAccel
.domBlock
183 , 0, GrayImageAssigner() )
186 layout
->addWidget( new QLabel("Domain block, transformed (encode-mode-only):") );
187 addFramedImage( layout
188 , imageFromMatrix( info
.decAccel
.pool
->pixels
, info
.decAccel
.domBlock
189 , info
.rotation
, GrayImageMulAddAssigner(info
.exact
.linCoeff
,info
.exact
.constCoeff
) )
193 layout
->addWidget( new QLabel("Range block:") );
194 addFramedImage( layout
195 , imageFromMatrix( planeBlock
->pixels
, range
, 0, GrayImageAssigner() )
198 } else { // provide general info
199 RangeInfoAccumulator
info( planeBlock
->domains
->getPools() );
200 info
= for_each( ranges
.begin(), ranges
.end(), info
);
202 {// create a label with various counts info
203 QString msg
= "Range count: %1\nRotation counts: %2\nDomain pool counts: %3";
204 // fill in the total range count
205 msg
= msg
.arg( ranges
.size() );
206 // fill in the rotation counts
207 QString rots
= QString::number(info
.rotCounts
[0]);
208 for (int i
=1; i
<9; ++i
)
209 (rots
+= ", ")+= QString::number(info
.rotCounts
[i
]);
211 // fill in the domain counts
212 QString doms
= QString::number(info
.rotCounts
[0]);
213 vector
<int>::const_iterator it
;
214 for (it
= info
.poolCounts
.begin(); it
!=info
.poolCounts
.end(); ++it
)
215 (doms
+= ", ")+= QString::number(*it
);
217 // create the label and add it to the layout
218 layout
->addWidget( new QLabel(msg
) );
221 int maxLevel
= 1 +log2ceil( max(planeBlock
->width
,planeBlock
->height
) );
223 QTableWidget
*table
= new QTableWidget( maxLevel
-2, 3 );
224 table
->setHorizontalHeaderLabels
225 ( QStringList() << "Level" << "Ranges" << "Domain count" );
226 for (int level
=2; level
<maxLevel
; ++level
) {
227 // the number of the level
228 table
->setItem( level
-2, 0, new QTableWidgetItem(QString::number(level
)) );
229 // the count of the ranges on the level
230 table
->setItem( level
-2, 1, new QTableWidgetItem(
231 QString::number( info
.levelCounts
[level
] )
233 // the maximum allowed SE for the level
234 //float maxSE= planeBlock->moduleQ2SE->rangeSE( planeBlock->quality, powers[2*level] );
235 //table->setItem( level-2, 1.5, new QTableWidgetItem(QString::number(maxSE)) );
236 // the domain count for the level
237 int domCount
= levelPoolInfos
[level
].empty() ? -1
238 : levelPoolInfos
[level
].back().indexBegin
;
239 table
->setItem( level
-2, 2, new QTableWidgetItem(
240 QString("2 ^ %1").arg( log2(domCount
) )
243 // resize the label and add it to the layout
244 table
->resizeColumnsToContents();
245 table
->resizeRowsToContents();
246 layout
->addWidget(table
);
248 if ( modulePredictor() )
249 layout
->addWidget( modulePredictor()->debugModule(pixmap
,click
) );
253 } // MStandardEncoder::debugModule method
256 QWidget
* MQuadTree::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
258 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
259 const ISquareRanges::RangeNode
&range
= *findRangeOnPoint( fringe
, click
);
261 QString msg
= QString("Level: %1\nRegular: %2\n"
262 "Top-left corner: %3 %4\nWidth: %5\nHeight: %6")
263 .arg(range
.level
) .arg(range
.isRegular())
264 .arg(range
.x0
) .arg(range
.y0
)
265 .arg(range
.width()) .arg(range
.height());
266 return new QLabel(msg
);
268 } else { // provide general info
270 // add info about heuristic dividing (if it's allowed)
271 if ( settingsInt(HeuristicAllowed
) ) {
272 msg
+= "Heuristic dividing info:\n"
273 "\tBad tries (forced to divide): %1\n"
274 "\tBad divides (successful merges): %2\n"
275 "\tUnsuccessful merges: %3\n";
276 msg
= msg
.arg(badTries
).arg(badDivides
).arg(triedMerges
);
278 return new QLabel(msg
);
281 } // MQuadTree::debugModule method
284 QWidget
* MStdDomains::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
286 if ( pixmap
.rect().contains(click
) ) { // info about range clicked on
289 } else { // provide general info
296 QWidget
* MSaupePredictor::debugModule(QPixmap
&pixmap
,const QPoint
&click
) {
297 if ( pixmap
.rect().contains(click
) )
299 return new QLabel( QString("Predicted %1/%2 (%3%)")
300 .arg(predicted
) .arg(maxpred
) .arg(double(100)*predicted
/(double)maxpred
) );