From ea404d9a3952c0a7c8d596e9d3c8517153677cf1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= Date: Sun, 10 May 2009 20:08:10 +0200 Subject: [PATCH] Added another quality-controller, many small fixes. --- debug.cpp | 2 +- gui.cpp | 6 +-- gui.h | 2 +- interfaces.h | 47 ++++++++++--------- kdTree.h | 2 +- matrixUtil.h | 116 ++++++++++++++++++++++++----------------------- modules.cpp | 3 +- modules.h | 5 +- modules/colorModel.h | 8 ++-- modules/quality2SE.h | 27 ++++++++++- modules/root.h | 5 +- modules/squarePixels.cpp | 2 +- modules/squarePixels.h | 17 ++++--- modules/stdEncoder.cpp | 2 +- 14 files changed, 141 insertions(+), 103 deletions(-) diff --git a/debug.cpp b/debug.cpp index 2df1eb3..559102b 100644 --- a/debug.cpp +++ b/debug.cpp @@ -44,7 +44,7 @@ QWidget* MSquarePixels::debugModule(QPixmap &pixmap,const QPoint &click) { QTabWidget *tabs= new QTabWidget; // fill one tab for every job by three sub-tabs with the three modules for (int i=0; i<(int)jobs.size(); ++i) { - Job &job= jobs[i]; + PlaneBlock &job= jobs[i]; if ( job.ranges->getRangeList().size() == 1 ) continue; // find the plane which is the job from diff --git a/gui.cpp b/gui.cpp index 4f49ea3..88f243a 100644 --- a/gui.cpp +++ b/gui.cpp @@ -537,12 +537,12 @@ void Module::adjustSettings(int which,QTreeWidgetItem *myTree,QGroupBox *setBox) ASSERT(item); widget2settings( item->widget() , which ); // handle module-type settings - const SettingTypeItem *setType= info().setType; - if ( setType[which].type.type == ModuleCombo ) { + const SettingTypeItem &setType= info().setType[which]; + if ( setType.type.type == ModuleCombo ) { ASSERT(myTree); // get the new module id and check whether it has really changed SettingItem &setItem= settings[which]; - int newId= (*setType->type.data.compatIDs)[setItem.val.i]; + int newId= (*setType.type.data.compatIDs)[setItem.val.i]; if ( newId == setItem.m->info().id ) return; // replace the child module diff --git a/gui.h b/gui.h index 34f7b0e..43ad52d 100644 --- a/gui.h +++ b/gui.h @@ -93,7 +93,7 @@ public: private: /** Reloads the image, iterates and shows it (returns true on success) */ bool rezoom(); - /** Gets the path of the last used directory (from #lastPath) */ + /** Gets the path of the last used directory (from ::lastPath) */ QString lastDir() { QDir dir(lastPath); return dir.cdUp() ? dir.path() : QDir::currentPath(); } #ifndef NDEBUG diff --git a/interfaces.h b/interfaces.h index 4caf097..46a3674 100644 --- a/interfaces.h +++ b/interfaces.h @@ -6,9 +6,9 @@ /* Forwards for interfaces */ struct IRoot; +struct IQuality2SE; struct IColorTransformer; struct IShapeTransformer; -struct IQuality2SE; struct ISquareEncoder; struct ISquareRanges; struct ISquareDomains; @@ -26,7 +26,7 @@ namespace MTypes { enum DecodeAct { Clear, Iterate }; ///< Possible decoding actions - struct PlaneBlock; // declared and described at the end of the file + struct PlaneBlock; // declared and described later in the file typedef SummedMatrix SummedPixels; } @@ -90,6 +90,20 @@ struct IRoot: public Interface { +/** Interface for modules deciding how the max.\ SE will depend on block size + * (parametrized by quality) */ +struct IQuality2SE: public Interface { + /** Returns maximum SE for a [0,1] quality and range blocks with pixelCount pixels */ + virtual float rangeSE(float quality,int pixelCount) =0; + /** Fills an array (until levelEnd) with SE's according to [0,1] quality + * : on i-th index for "complete square range blocks" of level i. + * Common implementation - uses ::rangeSE method */ + void regularRangeErrors(float quality,int levelEnd,float *squareErrors); +}; + + + + /** Interface for modules performing color transformations, * following modules always work with single-color (greyscale) images */ struct IColorTransformer: public Interface { @@ -156,8 +170,8 @@ struct IShapeTransformer: public Interface { /** Writes all settings (shared by all jobs) needed for later reconstruction */ virtual void writeSettings(std::ostream &file) =0; - /** Reads settings (shared by all jobs) needed for reconstruction from a stream - * - needs to be done before the job creation */ + /** Reads settings (shared by all jobs) needed for reconstruction from a stream - + * needs to be done before the job creation */ virtual void readSettings(std::istream &file) =0; /** Returns the number of phases (progressive encoding), only depends on settings */ @@ -167,7 +181,7 @@ struct IShapeTransformer: public Interface { virtual void writeJobs(std::ostream &file,int phaseBegin,int phaseEnd) =0; /** Reads all data needed for reconstruction of every job and prepares for encoding, * parameters like ::writeJobs */ - virtual void readJobs (std::istream &file,int phaseBegin,int phaseEnd) =0; + virtual void readJobs(std::istream &file,int phaseBegin,int phaseEnd) =0; /** Shortcut - default parameters "phaseBegin=0,phaseEnd=phaseCount()" */ void writeJobs(std::ostream &file,int phaseBegin=0) @@ -178,20 +192,7 @@ struct IShapeTransformer: public Interface { }; // IShapeTransformer interface - - -/** Interface for modules deciding how the max.\ SE will depend on block size - * (parametrized by quality) */ -struct IQuality2SE: public Interface { - /** Returns maximum SE for a [0,1] quality and range blocks with pixelCount pixels */ - virtual float rangeSE(float quality,int pixelCount) =0; - /** Fills an array (until levelEnd) with SE's according to [0,1] quality - * : on i-th index for "complete square range blocks" of level i. - * Common implementation - uses ::rangeSE method */ - void regularRangeErrors(float quality,int levelEnd,float *squareErrors); -}; - - +/// @} namespace MTypes { @@ -214,6 +215,8 @@ namespace MTypes { } +/** \addtogroup interfaces + * @{ */ /** Interface for modules that control how the image @@ -251,17 +254,17 @@ struct ISquareRanges::RangeNode: public Block { /// Encoders can store their data here, !not deleted! (use BulkAllocator) mutable EncoderData *encoderData; - /// The level of the block, dimensions of the block are usually equal to 2^level + /// The smallest integer such that the block fits into square with side of length 2^level int level; /** Checks whether the block has regular shape (dimensions equal to 2^level) */ - bool isRegular() const + bool isRegular() const { return width()==powers[level] && height()==powers[level]; } protected: /** Constructor - initializes ::encoderData to zero, to be used by derived classes */ RangeNode(const Block &block,int level_) : Block(block), encoderData(0), level(level_) {} -}; // RangeNode struct +}; // ISquareRanges::RangeNode struct diff --git a/kdTree.h b/kdTree.h index 5ef9b16..33fbc15 100644 --- a/kdTree.h +++ b/kdTree.h @@ -42,7 +42,7 @@ namespace FieldMath { namespace NOSPACE { template struct MoveToBounds { - T sqrError; // TODO: double? + T sqrError; MoveToBounds() : sqrError(0) {} diff --git a/matrixUtil.h b/matrixUtil.h index c1527bf..d748bf7 100644 --- a/matrixUtil.h +++ b/matrixUtil.h @@ -4,7 +4,7 @@ #include "debug.h" -/** Structure representing a rectangle */ +/** A simple structure representing a rectangle */ struct Block { short x0, y0, xend, yend; @@ -160,7 +160,7 @@ template struct MatrixSummer { } }; // MatrixSummer class template -/** Helper structuree for computing with value and squared sums at once */ +/** Helper structure for computing with value and squared sums at once */ template struct DoubleNum { Num value, square; @@ -192,6 +192,7 @@ template struct DoubleNum { }; // DoubleNum template struct +/** Structure for a block of pixels - also contains summers and dimensions */ template< class SumT, class PixT, class I=PtrInt > struct SummedMatrix { typedef DoubleNum BSumRes; @@ -204,12 +205,11 @@ struct SummedMatrix { bool sumsValid; ///< Indicates whether the summer values are valid /** Sets the size of #pixels, optionally allocates memory */ - void setSize( I width_, I height_, bool allocPixels=true ) { + void setSize( I width_, I height_ ) { free(); width= width_; height= height_; - if (allocPixels) - pixels.allocate(width,height); + pixels.allocate(width,height); } /** Frees the memory */ void free(bool freePixels=true) { @@ -249,7 +249,38 @@ struct SummedMatrix { * to be used in walkOperate() and walkOperateCheckRotate() */ namespace MatrixWalkers { - /** Base structure for walkers changing 'x' in the outer and 'y' in the inner loop */ + /** Iterates two matrix iterators and performs an action. + * The loop is controled by the first iterator (\p checked) + * and on every corresponding pair (a,b) \p oper(a,b) is invoked. Returns \p oper. */ + template < class Check, class Unchecked, class Operator > + Operator walkOperate( Check checked, Unchecked unchecked, Operator oper ) { + // outer cycle start - to be always run at least once + ASSERT( checked.outerCond() ); + do { + // inner initialization + checked.innerInit(); + unchecked.innerInit(); + // inner cycle start - to be always run at least once + ASSERT( checked.innerCond() ); + do { + // perform the operation and do the inner step for both iterators + oper( checked.get(), unchecked.get() ); + checked.innerStep(); + unchecked.innerStep(); + } while ( checked.innerCond() ); + + // signal the end of inner cycle to the operator and do the outer step for both iterators + oper.innerEnd(); + checked.outerStep(); + unchecked.outerStep(); + + } while ( checked.outerCond() ); + + return oper; + } + + + /** Base structure for walkers */ template struct RotBase { public: typedef MatrixSlice TMatrix; @@ -344,6 +375,25 @@ namespace MatrixWalkers { void outerStep() { --lastStart; } void innerStep() { current.start+= current.colSkip; } }; + + + /** A flavour of walkOperate() choosing the right Rotation_* iterator based on \p rotation */ + template + inline Operator walkOperateCheckRotate( Check checked, Operator oper + , MatrixSlice pixels2, const Block &block2, char rotation) { + typedef PtrInt I; + switch (rotation) { + case 0: return walkOperate( checked, Rotation_0 (pixels2,block2) , oper ); + case 1: return walkOperate( checked, Rotation_0_T(pixels2,block2) , oper ); + case 2: return walkOperate( checked, Rotation_1 (pixels2,block2) , oper ); + case 3: return walkOperate( checked, Rotation_1_T(pixels2,block2) , oper ); + case 4: return walkOperate( checked, Rotation_2 (pixels2,block2) , oper ); + case 5: return walkOperate( checked, Rotation_2_T(pixels2,block2) , oper ); + case 6: return walkOperate( checked, Rotation_3 (pixels2,block2) , oper ); + case 7: return walkOperate( checked, Rotation_3_T(pixels2,block2) , oper ); + default: ASSERT(false); return oper; + } + } /** Performs manipulations with rotation codes 0-7 (dihedral group of order eight) */ @@ -426,54 +476,6 @@ namespace MatrixWalkers { }; // CheckedImage class template - /** Iterates two matrix iterators and performs an action. - * The loop is controled by the first iterator (\p checked) - * and on every corresponding pair (a,b) \p oper(a,b) is invoked. Returns \p oper. */ - template < class Check, class Unchecked, class Operator > - Operator walkOperate( Check checked, Unchecked unchecked, Operator oper ) { - // outer cycle start - to be always run at least once - ASSERT( checked.outerCond() ); - do { - // inner initialization - checked.innerInit(); - unchecked.innerInit(); - // inner cycle start - to be always run at least once - ASSERT( checked.innerCond() ); - do { - // perform the operation and do the inner step for both iterators - oper( checked.get(), unchecked.get() ); - checked.innerStep(); - unchecked.innerStep(); - } while ( checked.innerCond() ); - - // signal the end of inner cycle to the operator and do the outer step for both iterators - oper.innerEnd(); - checked.outerStep(); - unchecked.outerStep(); - - } while ( checked.outerCond() ); - - return oper; - } - - /** A flavour of walkOperate() choosing the right Rotation_* iterator based on \p rotation */ - template - inline Operator walkOperateCheckRotate( Check checked, Operator oper - , MatrixSlice pixels2, const Block &block2, char rotation) { - typedef PtrInt I; - switch (rotation) { - case 0: return walkOperate( checked, Rotation_0 (pixels2,block2) , oper ); - case 1: return walkOperate( checked, Rotation_0_T(pixels2,block2) , oper ); - case 2: return walkOperate( checked, Rotation_1 (pixels2,block2) , oper ); - case 3: return walkOperate( checked, Rotation_1_T(pixels2,block2) , oper ); - case 4: return walkOperate( checked, Rotation_2 (pixels2,block2) , oper ); - case 5: return walkOperate( checked, Rotation_2_T(pixels2,block2) , oper ); - case 6: return walkOperate( checked, Rotation_3 (pixels2,block2) , oper ); - case 7: return walkOperate( checked, Rotation_3_T(pixels2,block2) , oper ); - default: ASSERT(false); return oper; - } - } - /** A convenience base type for operators to use with walkOperate() */ struct OperatorBase { void innerEnd() {} @@ -493,7 +495,7 @@ namespace MatrixWalkers { { ASSERT(!lineSum); return totalSum; } }; - /** An operator performing a= (b+#toAdd)*#toMul */ + /** An operator performing a= (b+::toAdd)*::toMul */ template struct AddMulCopy: public OperatorBase { const T toAdd, toMul; @@ -504,12 +506,14 @@ namespace MatrixWalkers { { res= (f+toAdd)*toMul; } }; - /** An operator performing a= b*#toMul+#toAdd and moving the result into [#min,#max] bounds */ + /** An operator performing a= b*::toMul+::toAdd + * and moving the result into [::min,::max] bounds */ template struct MulAddCopyChecked: public OperatorBase { const T toMul, toAdd, min, max; MulAddCopyChecked(T mul,T add,T minVal,T maxVal) : toMul(mul), toAdd(add), min(minVal), max(maxVal) {} + template void operator()(R1 &res,R2 f) const { res= checkBoundsFunc( min, f*toMul+toAdd, max ); } }; diff --git a/modules.cpp b/modules.cpp index bfadca9..e2ba5c3 100644 --- a/modules.cpp +++ b/modules.cpp @@ -19,7 +19,8 @@ using namespace std; typedef Loki::TL::MakeTypelist< MRoot, MColorModel, MSquarePixels, MQuadTree, MStdDomains -, MQuality2SE_std, MStandardEncoder, MDifferentialVLICodec, MSaupePredictor, NoPredictor > +, MQuality2SE_std, MStandardEncoder, MDifferentialVLICodec, MSaupePredictor, NoPredictor +, MQuality2SE_alt > ::Result Modules; const int powers[31]= { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2*1024 /* 2^11 */ diff --git a/modules.h b/modules.h index 9a9a839..6b6a60b 100644 --- a/modules.h +++ b/modules.h @@ -9,6 +9,7 @@ class ModuleFactory; template class Interface; +/// \defgroup modules Module implementations /** A common base class for all modules */ class Module { friend class ModuleFactory; ///< Permission for the ModuleFactory to manipulate Modules @@ -206,6 +207,7 @@ protected: //// Macros for easier Module-writing #define DECLARE_TypeInfo_helper(CNAME_,NAME_,DESC_,SETTYPE_...) \ +/** \cond */ \ friend class Module; /* Needed for concreteClone */ \ /*friend class ModuleFactory;*/ \ friend struct ModuleFactory::Creator; /* Needed for GCC-3 and ICC */ \ @@ -223,7 +225,8 @@ public: \ setType: setType_ \ }; \ return info_; \ - } + } \ +/** \endcond */ \ /** Declares technical stuff within a Module descendant that contains no settings * - parameters: the name of the class (Token), diff --git a/modules/colorModel.h b/modules/colorModel.h index fc6581d..14ff95e 100644 --- a/modules/colorModel.h +++ b/modules/colorModel.h @@ -6,9 +6,9 @@ #include -/// \file colorModel.h - -/** Simple color transformer, currently supporting RGB and YCbCr color models */ +/// \ingroup modules +/** Simple color transformer for affine models. It currently supports RGB and YCbCr + * color models and allows to se quality multipliers for individual color channels. */ class MColorModel: public IColorTransformer { DECLARE_TypeInfo( MColorModel, "Color models" @@ -98,7 +98,7 @@ inline QRgb getColor( const Real (*coeffs)[4], const Real *planes ) { typedef Float2int<8,Real> Conv; return qRgb( Conv::convertCheck(rgb[0]), Conv::convertCheck(rgb[1]), Conv::convertCheck(rgb[2]) ); } -/** Computes the gray level of a QRgb color in [0..255] interval */ +/** Computes the gray level of a QRgb color in 0-255 interval \relates MColorModel */ inline int getGray(QRgb color) { return Float2int<8,Real>::convert( getColor( color, MColorModel::YCbCrCoeffs[0] ) ); } diff --git a/modules/quality2SE.h b/modules/quality2SE.h index ca67ae3..a3a5c67 100644 --- a/modules/quality2SE.h +++ b/modules/quality2SE.h @@ -3,6 +3,8 @@ #include "../interfaces.h" + +/// \ingroup modules /** Standard quality-to-SE module - uses fixed SE for all block sizes */ class MQuality2SE_std: public IQuality2SE { @@ -14,12 +16,33 @@ public: * @{ */ float rangeSE(float quality,int /*pixelCount*/) { ASSERT( quality>=0 && quality<=1 ); - float maxSE= 4 /// approximate SE for quality=0 - , doubles= 6; ///< how many times the SE doubles + float maxSE= 4 // approximate SE for quality=0 + , doubles= 6; //< how many times the SE doubles return maxSE/exp2(doubles) * ( exp2((1-quality)*doubles) - 1 ); } /// @} }; +/// \ingroup modules +/** Alternate quality-to-SE module - uses fixed MSE for all block sizes */ +class MQuality2SE_alt: public IQuality2SE { + + DECLARE_TypeInfo_noSettings( MQuality2SE_alt, "Constant mean square error" + , "Holds the same mean square error (MSE) for all block sizes" ) + +public: +/** \name IQuality2SE interface + * @{ */ + float rangeSE(float quality,int pixelCount) { + ASSERT( quality>=0 && quality<=1 ); + float maxSE= 4 // approximate SE for quality=0 + , doubles= 6; //< how many times the SE doubles + float sizeQuot= pixelCount/sqr(9.0); + return maxSE/exp2(doubles) * ( exp2((1-quality)*doubles) - 1 ) * sizeQuot; + } +/// @} +}; + + #endif // QUALITY2SE_HEADER_ diff --git a/modules/root.h b/modules/root.h index 89b2433..0a46acd 100644 --- a/modules/root.h +++ b/modules/root.h @@ -5,6 +5,7 @@ #include // ::idealThreadCount +/// \ingroup modules /** The root module implementation. Controls the number of encoding threads, * the color-transforming module (IColorTransformer) * the pixel-shape-transforming module (IShapeTransformer), quality 0-100%, @@ -44,7 +45,7 @@ class MRoot: public IRoot { type: settingInt(0,15,24,IntLog2) } ) -private: +protected: /** Indices for settings */ enum Settings { MaxThreads, ModuleColor, ModuleShape, Quality, ModuleQuality , DomainCountLog2 }; @@ -63,7 +64,7 @@ private: typedef IColorTransformer::PlaneSettings PlaneSettings; typedef IColorTransformer::PlaneList PlaneList; -private: +protected: // Module's data Mode myMode;///< the mode of the tree, returned by ::getMode int width /// zoomed width of the image diff --git a/modules/squarePixels.cpp b/modules/squarePixels.cpp index d9b3a10..9ccb4f1 100644 --- a/modules/squarePixels.cpp +++ b/modules/squarePixels.cpp @@ -11,7 +11,7 @@ int MSquarePixels::createJobs(const PlaneList &planes) { for (PlaneList::const_iterator plane= planes.begin(); plane!=planes.end(); ++plane) { // convert the Plane into a PlaneBlock (containing the whole contents) const IColorTransformer::PlaneSettings *plSet= plane->settings; - Job job; + PlaneBlock job; job.width= plSet->width; job.height= plSet->height; job.pixels= plane->pixels; diff --git a/modules/squarePixels.h b/modules/squarePixels.h index 7f722db..fa75638 100644 --- a/modules/squarePixels.h +++ b/modules/squarePixels.h @@ -4,7 +4,10 @@ #include "../interfaces.h" #include "../fileUtil.h" -/** A simple shape transformer - using square pixels, only splits the planes into rectangles */ +/// \ingroup modules +/** A simple shape transformer using square pixels. It allows to choose modules of types + * ISquareRanges, ISquareDomains and ISquareEncoder for subsequent coding. + * It can split the planes into rectangles - max.\ size is a parameter. */ class MSquarePixels: public IShapeTransformer { DECLARE_debugModule; @@ -30,7 +33,7 @@ class MSquarePixels: public IShapeTransformer { type: settingModule() } ) -private: +protected: /** Indices for settings */ enum Settings { MaxPartSize, ModuleRanges, ModuleDomains, ModuleEncoder }; // Settings-retrieval methods @@ -44,13 +47,13 @@ private: { return debugCast(settings[ModuleEncoder].m); } typedef IColorTransformer::Plane Plane; - typedef MTypes::PlaneBlock Job; + typedef MTypes::PlaneBlock PlaneBlock; - typedef std::vector::iterator JobIterator; + typedef std::vector::iterator JobIterator; -private: +protected: // Module's data - std::vector jobs; ///< Encoding jobs - one part of one color plane makes one job + std::vector jobs; ///< Encoding jobs - one part of one color plane makes one job DEBUG_ONLY( PlaneList planeList; ) //< needed for creating debug info protected: @@ -76,7 +79,7 @@ public: void jobEncode(int jobIndex) { ASSERT( jobIndex>=0 && jobIndexinitialize( IRoot::Encode, job ); job.ranges->encode(job); } diff --git a/modules/stdEncoder.cpp b/modules/stdEncoder.cpp index c814f5e..8b17f54 100644 --- a/modules/stdEncoder.cpp +++ b/modules/stdEncoder.cpp @@ -13,7 +13,7 @@ namespace Quantizer { ASSERT( result>=0 && result<=possib ); return result=0 && i