Reimplemented things working with summed pixels, other fixes.
[fic.git] / matrixUtil.h
blobc1527bf24a59e9116ca02d65282d100409393f65
1 #ifndef MATRIXUTIL_HEADER_
2 #define MATRIXUTIL_HEADER_
4 #include "debug.h"
7 /** Structure representing a rectangle */
8 struct Block {
9 short x0, y0, xend, yend;
11 int width() const { return xend-x0; }
12 int height() const { return yend-y0; }
13 int size() const { return width()*height(); }
15 bool contains(short x,short y) const
16 { return x0<=x && x<xend && y0<=y && y<yend; }
18 Block() {}
19 Block(short x0_,short y0_,short xend_,short yend_)
20 : x0(x0_), y0(y0_), xend(xend_), yend(yend_) {}
23 //// Matrix templates
25 /** A simple generic template for matrices of fixed size, uses shallow copying
26 * and manual memory management */
27 template<class T,class I=PtrInt> struct MatrixSlice {
28 typedef MatrixSlice<const T,I> Const; ///< the class is convertible to Const type
30 T *start; ///< pointer to the top-left pixel
31 I colSkip; ///< how many pixels to skip to get in the next column
33 /** Initializes an empty slice */
34 MatrixSlice(): start(0) {}
36 /** Creates a shallow copy (deleting one destroys all copies) */
37 MatrixSlice(const MatrixSlice &m): start(m.start), colSkip(m.colSkip) {}
39 /** Converts to a matrix of constant objects (shallow copy) */
40 operator Const() const {
41 Const result;
42 result.start= start;
43 result.colSkip= colSkip;
44 return result;
47 /** Indexing operator - returns pointer to a column */
48 T* operator[](I column) {
49 ASSERT( isValid() );
50 return start+column*colSkip;
52 /** Const version of indexing operator - doesn't allow to change the elements */
53 const T* operator[](I column) const {
54 return constCast(*this)[column];
57 /** Reallocates the matrix for a new size. If \p memory parameter is given,
58 * it is used for storage (the user is responsible that the matrix fits in it, etc.) */
59 void allocate( I width, I height, T *memory=0 ) {
60 ASSERT( width>0 && height>0 );
61 free();
62 start= memory ? memory : new T[width*height];
63 colSkip= height;
65 /** Releases the memory */
66 void free() {
67 delete[] start;
68 start= 0;
70 /** Returns whether the matrix is allocated (and thus usable for indexing) */
71 bool isValid() const {
72 return start;
75 /** Fills a submatrix of a valid matrix with a value */
76 void fillSubMatrix(const Block &block,T value) {
77 ASSERT( isValid() );
78 // compute begin and end column starts
79 T *begin= start+block.y0+colSkip*block.x0
80 , *end= start+block.y0+colSkip*block.xend;
81 // fill the columns
82 for (T *it= begin; it!=end; it+= colSkip)
83 std::fill( it, it+block.height(), value );
85 /** Shifts the indexing of this matrix - dangerous.
86 * After calling this, only addressing or more shifts can be done (not checked).
87 * Also shifts out of the allocated matrix aren't detected */
88 MatrixSlice& shiftMatrix(I x0,I y0) {
89 ASSERT( isValid() );
90 start+= x0*colSkip+y0;
91 return *this;
93 /** Computes relative position of a pointer in the matrix (always 0 <= \p y < #colSkip) */
94 void getPosition(const T *elem,int &x,int &y) const {
95 ASSERT( isValid() );
96 PtrInt diff= elem-start;
97 if (diff>=0) {
98 x= diff/colSkip;
99 y= diff%colSkip;
100 } else {
101 x= -((-diff-1)/colSkip) -1;
102 y= colSkip - (-diff-1)%colSkip -1;
105 }; // MatrixSlice class template
108 /** MatrixSummer objects store partial sums of a matrix, allowing quick computation
109 * of sum of any rectangle in the matrix. It's parametrized by "type of the result",
110 * "type of the input" and "indexing type" (defaults to Int) */
111 template<class T,class I=PtrInt> struct MatrixSummer {
112 typedef T Result;
114 MatrixSlice<T,I> sums; ///< Internal matrix containing precomputed partial sums
116 #ifndef NDEBUG
117 /** Creates an empty summer */
118 MatrixSummer() {}
119 /** Only empty objects are allowed to be copied (assertion) */
120 MatrixSummer( const MatrixSummer &other )
121 { ASSERT( !other.isValid() ); }
122 /** Only empty objects are allowed to be assigned (assertion) */
123 MatrixSummer& operator=( const MatrixSummer &other )
124 { ASSERT( !other.isValid() && !isValid() ); return *this; }
125 #endif
127 /** Returns whether the object is filled with data */
128 bool isValid() const { return sums.isValid(); }
129 /** Clears the object */
130 void free() { sums.free(); };
132 /** Computes the sum of a rectangle (in constant time) */
133 Result getSum(I x0,I y0,I xend,I yend) const {
134 ASSERT( sums.isValid() );
135 return sums[xend][yend] -sums[x0][yend] -sums[xend][y0] +sums[x0][y0];
137 /** A shortcut to get the sum of a block */
138 Result getSum(const Block &b) const
139 { return getSum( b.x0, b.y0, b.xend, b.yend ); }
141 /** Prepares object to make sums for a matrix. If the summer has already been
142 * used before, the method assumes it was for a matrix of the same size */
143 template<class Input> void fill(Input inp,I width,I height) {
144 if ( !sums.isValid() )
145 sums.allocate(width+1,height+1);
147 // fill the edges with zeroes
148 for (I i=0; i<=width; ++i)
149 sums[i][0]= 0;
150 for (I j=1; j<=height; ++j)
151 sums[0][j]= 0;
152 // acummulate in the y-growing direction
153 for (I i=1; i<=width; ++i)
154 for (I j=1; j<=height; ++j)
155 sums[i][j]= sums[i][j-1] + Result(inp[i-1][j-1]);
156 // acummulate in the x-growing direction
157 for (I i=2; i<=width; ++i)
158 for (I j=1; j<=height; ++j)
159 sums[i][j]+= sums[i-1][j];
161 }; // MatrixSummer class template
163 /** Helper structuree for computing with value and squared sums at once */
164 template<class Num> struct DoubleNum {
165 Num value, square;
167 DoubleNum()
168 { DEBUG_ONLY( value= square= std::numeric_limits<Num>::quiet_NaN(); ) }
170 DoubleNum(Num val)
171 : value(val), square(sqr(val)) {}
173 DoubleNum(const DoubleNum &other)
174 : value(other.value), square(other.square) {}
176 void unpack(Num &val,Num &sq) const { val= value; sq= square; }
178 DoubleNum& operator+=(const DoubleNum &other) {
179 value+= other.value;
180 square+= other.square;
181 return *this;
183 DoubleNum& operator-=(const DoubleNum &other) {
184 value-= other.value;
185 square-= other.square;
186 return *this;
188 friend DoubleNum operator+(const DoubleNum &a,const DoubleNum &b)
189 { return DoubleNum(a)+= b; }
190 friend DoubleNum operator-(const DoubleNum &a,const DoubleNum &b)
191 { return DoubleNum(a)-= b; }
192 }; // DoubleNum template struct
195 template< class SumT, class PixT, class I=PtrInt >
196 struct SummedMatrix {
197 typedef DoubleNum<SumT> BSumRes;
198 typedef MatrixSummer<BSumRes> BSummer;
200 I width /// The width of #pixels
201 , height; ///< The height of #pixels
202 MatrixSlice<PixT> pixels; ///< The matrix of pixels
203 BSummer summer; ///< Summer for values and squares of #pixels
204 bool sumsValid; ///< Indicates whether the summer values are valid
206 /** Sets the size of #pixels, optionally allocates memory */
207 void setSize( I width_, I height_, bool allocPixels=true ) {
208 free();
209 width= width_;
210 height= height_;
211 if (allocPixels)
212 pixels.allocate(width,height);
214 /** Frees the memory */
215 void free(bool freePixels=true) {
216 if (freePixels)
217 pixels.free();
218 else
219 pixels.start= 0;
220 summer.free();
221 sumsValid= false;
224 /** Just validates both summers (if needed) */
225 void summers_makeValid() const {
226 ASSERT(pixels.isValid());
227 if (!sumsValid) {
228 constCast(summer).fill(pixels,width,height);
229 constCast(sumsValid)= true;
232 /** Justs invalidates both summers (to be called after changes in the pixel-matrix) */
233 void summers_invalidate()
234 { sumsValid= false; }
235 /** A shortcut for getting sums of a block */
236 BSumRes getSums(const Block &block) const
237 { return getSums( block.x0, block.y0, block.xend, block.yend ); }
238 /** Gets both sums of a nonempty rectangle in #pixels, the summer isn't validated */
239 BSumRes getSums( I x0, I y0, I xend, I yend ) const {
240 ASSERT( sumsValid && x0>=0 && y0>=0 && xend>x0 && yend>y0
241 && xend<=width && yend<=height );
242 return summer.getSum(x0,y0,xend,yend);
244 }; // SummedPixels template struct
248 /** Contains various iterators for matrices (see Matrix)
249 * to be used in walkOperate() and walkOperateCheckRotate() */
250 namespace MatrixWalkers {
252 /** Base structure for walkers changing 'x' in the outer and 'y' in the inner loop */
253 template<class T,class I> struct RotBase {
254 public:
255 typedef MatrixSlice<T,I> TMatrix;
256 protected:
257 TMatrix current; ///< matrix starting on the current element
258 T *lastStart; ///< the place of the last enter of the inner loop
260 public:
261 RotBase( TMatrix matrix, int x0, int y0 )
262 : current( matrix.shiftMatrix(x0,y0) ), lastStart(current.start) {
263 DEBUG_ONLY( current.start= 0; )
264 ASSERT( matrix.isValid() );
267 void innerInit() { current.start= lastStart; }
268 T& get() { return *current.start; }
269 }; // RotBase class template
271 #define ROTBASE_INHERIT \
272 typedef typename RotBase<T,I>::TMatrix TMatrix; \
273 using RotBase<T,I>::current; \
274 using RotBase<T,I>::lastStart;
276 /** No rotation: x->, y-> */
277 template<class T,class I> struct Rotation_0: public RotBase<T,I> { ROTBASE_INHERIT
278 Rotation_0( TMatrix matrix, const Block &block )
279 : RotBase<T,I>( matrix, block.x0, block.y0 ) {}
281 void outerStep() { lastStart+= current.colSkip; }
282 void innerStep() { ++current.start; }
285 /** Rotated 90deg\. cw\., transposed: x<-, y-> */
286 template<class T,class I> struct Rotation_1_T: public RotBase<T,I> { ROTBASE_INHERIT
287 Rotation_1_T( TMatrix matrix, const Block &block )
288 : RotBase<T,I>( matrix, block.xend-1, block.y0 ) {}
290 void outerStep() { lastStart-= current.colSkip; }
291 void innerStep() { ++current.start; }
294 /** Rotated 180deg\. cw\.: x<-, y<- */
295 template<class T,class I> struct Rotation_2: public RotBase<T,I> { ROTBASE_INHERIT
296 Rotation_2( TMatrix matrix, const Block &block )
297 : RotBase<T,I>( matrix, block.xend-1, block.yend-1 ) {}
299 void outerStep() { lastStart-= current.colSkip; }
300 void innerStep() { --current.start; }
303 /** Rotated 270deg\. cw\., transposed: x->, y<- */
304 template<class T,class I> struct Rotation_3_T: public RotBase<T,I> { ROTBASE_INHERIT
305 Rotation_3_T( TMatrix matrix, const Block &block )
306 : RotBase<T,I>( matrix, block.x0, block.yend-1 ) {}
308 void outerStep() { lastStart+= current.colSkip; }
309 void innerStep() { --current.start; }
312 /** No rotation, transposed: y->, x-> */
313 template<class T,class I> struct Rotation_0_T: public RotBase<T,I> { ROTBASE_INHERIT
314 Rotation_0_T( TMatrix matrix, const Block &block )
315 : RotBase<T,I>( matrix, block.x0, block.y0 ) {}
317 void outerStep() { ++lastStart; }
318 void innerStep() { current.start+= current.colSkip; }
321 /** Rotated 90deg\. cw\.: y->, x<- */
322 template<class T,class I> struct Rotation_1: public RotBase<T,I> { ROTBASE_INHERIT
323 Rotation_1( TMatrix matrix, const Block &block )
324 : RotBase<T,I>( matrix, block.xend-1, block.y0 ) {}
326 void outerStep() { ++lastStart; }
327 void innerStep() { current.start-= current.colSkip; }
330 /** Rotated 180deg\. cw\., transposed: y<-, x<- */
331 template<class T,class I> struct Rotation_2_T: public RotBase<T,I> { ROTBASE_INHERIT
332 Rotation_2_T( TMatrix matrix, const Block &block )
333 : RotBase<T,I>( matrix, block.xend-1, block.yend-1 ) {}
335 void outerStep() { --lastStart; }
336 void innerStep() { current.start-= current.colSkip; }
339 /** Rotated 270deg\. cw\.: y<-, x-> */
340 template<class T,class I> struct Rotation_3: public RotBase<T,I> { ROTBASE_INHERIT
341 Rotation_3( TMatrix matrix, const Block &block )
342 : RotBase<T,I>( matrix, block.x0, block.yend-1 ) {}
344 void outerStep() { --lastStart; }
345 void innerStep() { current.start+= current.colSkip; }
349 /** Performs manipulations with rotation codes 0-7 (dihedral group of order eight) */
350 struct Rotation {
351 /** Asserts the parameter is within 0-7 */
352 static void check(int DEBUG_ONLY(r)) {
353 ASSERT( 0<=r && r<8 );
355 /** Returns inverted rotation (the one that takes this one back to identity) */
356 static int invert(int r) {
357 check(r);
358 return (4-r/2)%4 *2 +r%2;
360 /** Computes rotation equal to projecting at first with \p r1 and the result with \p r2 */
361 static int compose(int r1,int r2) {
362 check(r1); check(r2);
363 if (r2%2)
364 r1= invert(r1);
365 return (r1/2 + r2/2) %4 *2+ ( (r1%2)^(r2%2) );
367 }; // Rotation struct
369 /** Checked_ iterator for a rectangle in a matrix, no rotation */
370 template<class T,class I=PtrInt> struct Checked: public Rotation_0<T,I> {
371 typedef MatrixSlice<T,I> TMatrix;
372 typedef Rotation_0<T,I> Base;
373 using Base::current;
374 using Base::lastStart;
376 T *colEnd /// the end of the current column
377 , *colsEndStart; ///< the start of the end column
379 /** Initializes a new iterator for a \p block of \p pixels */
380 Checked( TMatrix pixels, const Block &block )
381 : Base( pixels, block ), colEnd( pixels.start+pixels.colSkip*block.x0+block.yend )
382 , colsEndStart( pixels.start+pixels.colSkip*block.xend+block.y0 ) {
383 ASSERT( block.xend>block.x0 && block.yend>block.y0 );
386 bool outerCond() {
387 ASSERT(lastStart<=colsEndStart);
388 return lastStart!=colsEndStart;
390 void outerStep() {
391 colEnd+= current.colSkip;
392 Base::outerStep();
394 bool innerCond() {
395 ASSERT(current.start<=colEnd);
396 return current.start!=colEnd;
398 }; // Checked class template
400 /** Checked_ iterator for a whole QImage; no rotation, but always transposed */
401 template<class T,class U> struct CheckedImage {
402 typedef T QImage;
403 typedef U QRgb;
404 protected:
405 QImage &img; ///< reference to the image
406 int lineIndex /// index of the current line
407 , width /// the width of the image
408 , height; ///< the height of the image
409 QRgb *line /// pointer to the current pixel
410 , *lineEnd; ///< pointer to the end of the line
412 public:
413 /** Initializes a new iterator for an instance of QImage (Qt class) */
414 CheckedImage(QImage &image)
415 : img(image), lineIndex(0), width(image.width()), height(image.height())
416 { DEBUG_ONLY(line=lineEnd=0;) }
418 bool outerCond() { return lineIndex<height; }
419 void outerStep() { ++lineIndex; }
421 void innerInit() { line= (QRgb*)img.scanLine(lineIndex); lineEnd= line+width; }
422 bool innerCond() { return line!=lineEnd; }
423 void innerStep() { ++line; }
425 QRgb& get() { return *line; }
426 }; // CheckedImage class template
429 /** Iterates two matrix iterators and performs an action.
430 * The loop is controled by the first iterator (\p checked)
431 * and on every corresponding pair (a,b) \p oper(a,b) is invoked. Returns \p oper. */
432 template < class Check, class Unchecked, class Operator >
433 Operator walkOperate( Check checked, Unchecked unchecked, Operator oper ) {
434 // outer cycle start - to be always run at least once
435 ASSERT( checked.outerCond() );
436 do {
437 // inner initialization
438 checked.innerInit();
439 unchecked.innerInit();
440 // inner cycle start - to be always run at least once
441 ASSERT( checked.innerCond() );
442 do {
443 // perform the operation and do the inner step for both iterators
444 oper( checked.get(), unchecked.get() );
445 checked.innerStep();
446 unchecked.innerStep();
447 } while ( checked.innerCond() );
449 // signal the end of inner cycle to the operator and do the outer step for both iterators
450 oper.innerEnd();
451 checked.outerStep();
452 unchecked.outerStep();
454 } while ( checked.outerCond() );
456 return oper;
459 /** A flavour of walkOperate() choosing the right Rotation_* iterator based on \p rotation */
460 template<class Check,class U,class Operator>
461 inline Operator walkOperateCheckRotate( Check checked, Operator oper
462 , MatrixSlice<U> pixels2, const Block &block2, char rotation) {
463 typedef PtrInt I;
464 switch (rotation) {
465 case 0: return walkOperate( checked, Rotation_0 <U,I>(pixels2,block2) , oper );
466 case 1: return walkOperate( checked, Rotation_0_T<U,I>(pixels2,block2) , oper );
467 case 2: return walkOperate( checked, Rotation_1 <U,I>(pixels2,block2) , oper );
468 case 3: return walkOperate( checked, Rotation_1_T<U,I>(pixels2,block2) , oper );
469 case 4: return walkOperate( checked, Rotation_2 <U,I>(pixels2,block2) , oper );
470 case 5: return walkOperate( checked, Rotation_2_T<U,I>(pixels2,block2) , oper );
471 case 6: return walkOperate( checked, Rotation_3 <U,I>(pixels2,block2) , oper );
472 case 7: return walkOperate( checked, Rotation_3_T<U,I>(pixels2,block2) , oper );
473 default: ASSERT(false); return oper;
477 /** A convenience base type for operators to use with walkOperate() */
478 struct OperatorBase {
479 void innerEnd() {}
482 /** An operator computing the sum of products */
483 template<class TOut,class TIn> struct RDSummer: public OperatorBase {
484 TOut totalSum, lineSum;
486 RDSummer()
487 : totalSum(0), lineSum(0) {}
488 void operator()(const TIn &num1,const TIn& num2)
489 { lineSum+= TOut(num1) * TOut(num2); }
490 void innerEnd()
491 { totalSum+= lineSum; lineSum= 0; }
492 TOut result() ///< returns the result
493 { ASSERT(!lineSum); return totalSum; }
496 /** An operator performing a= (b+#toAdd)*#toMul */
497 template<class T> struct AddMulCopy: public OperatorBase {
498 const T toAdd, toMul;
500 AddMulCopy(T add,T mul)
501 : toAdd(add), toMul(mul) {}
503 template<class R1,class R2> void operator()(R1 &res,R2 f) const
504 { res= (f+toAdd)*toMul; }
507 /** An operator performing a= b*#toMul+#toAdd and moving the result into [#min,#max] bounds */
508 template<class T> struct MulAddCopyChecked: public OperatorBase {
509 const T toMul, toAdd, min, max;
511 MulAddCopyChecked(T mul,T add,T minVal,T maxVal)
512 : toMul(mul), toAdd(add), min(minVal), max(maxVal) {}
513 template<class R1,class R2> void operator()(R1 &res,R2 f) const
514 { res= checkBoundsFunc( min, f*toMul+toAdd, max ); }
518 #endif // MATRIXUTIL_HEADER_