1 #ifndef MATRIXUTIL_HEADER_
2 #define MATRIXUTIL_HEADER_
4 /** A simple structure representing a rectangle */
6 short x0
, y0
, xend
, yend
;
8 int width() const { return xend
-x0
; }
9 int height() const { return yend
-y0
; }
10 int size() const { return width()*height(); }
12 bool contains(short x
,short y
) const
13 { return x0
<=x
&& x
<xend
&& y0
<=y
&& y
<yend
; }
16 Block(short x0_
,short y0_
,short xend_
,short yend_
)
17 : x0(x0_
), y0(y0_
), xend(xend_
), yend(yend_
) {}
22 /** A simple generic template for matrices of fixed size, uses shallow copying
23 * and manual memory management */
24 template<class T
,class I
=PtrInt
> struct MatrixSlice
{
25 typedef MatrixSlice
<const T
,I
> Const
; ///< the class is convertible to Const type
27 T
*start
; ///< pointer to the top-left pixel
28 I colSkip
; ///< how many pixels to skip to get in the next column
30 /** Initializes an empty slice */
31 MatrixSlice(): start(0) {}
33 /** Creates an instance with pre-filled member fields */
34 static MatrixSlice
makeRaw(T
*start
,I colSkip
) {
37 result
.colSkip
= colSkip
;
41 /** Converts to a matrix of constant objects (shallow copy) */
42 operator Const() const {
45 result
.colSkip
= colSkip
;
49 /** Indexing operator - returns pointer to a column */
50 T
* operator[](I column
) {
52 return start
+column
*colSkip
;
54 /** Const version of indexing operator - doesn't allow to change the elements */
55 const T
* operator[](I column
) const {
56 return constCast(*this)[column
];
59 /** Reallocates the matrix for a new size. If \p memory parameter is given,
60 * it is used for storage (the user is responsible that the matrix fits in it, etc.) */
61 void allocate( I width
, I height
, T
*memory
=0 ) {
62 ASSERT( width
>0 && height
>0 );
64 start
= memory
? memory
: new T
[width
*height
];
67 /** Releases the memory */
72 /** Returns whether the matrix is allocated (and thus usable for indexing) */
73 bool isValid() const {
77 /** Fills a submatrix of a valid matrix with a value */
78 void fillSubMatrix(const Block
&block
,T value
) {
80 // compute begin and end column starts
81 T
*begin
= start
+block
.y0
+colSkip
*block
.x0
82 , *end
= start
+block
.y0
+colSkip
*block
.xend
;
84 for (T
*it
= begin
; it
!=end
; it
+= colSkip
)
85 std::fill( it
, it
+block
.height(), value
);
87 /** Shifts the indexing of this matrix - dangerous.
88 * After calling this, only addressing or more shifts can be done (not checked).
89 * Also shifts out of the allocated matrix aren't detected */
90 MatrixSlice
& shiftMatrix(I x0
,I y0
) {
92 start
+= x0
*colSkip
+y0
;
95 /** Computes relative position of a pointer in the matrix (always 0 <= \p y < #colSkip) */
96 void getPosition(const T
*elem
,int &x
,int &y
) const {
98 PtrInt diff
= elem
-start
;
103 x
= -((-diff
-1)/colSkip
) -1;
104 y
= colSkip
- (-diff
-1)%colSkip
-1;
107 }; // MatrixSlice class template
110 /** MatrixSummer objects store partial sums of a matrix, allowing quick computation
111 * of sum of any rectangle in the matrix. It's parametrized by "type of the result",
112 * "type of the input" and "indexing type" (defaults to Int). Uses shallow copying. */
113 template<class T
,class I
=PtrInt
> struct MatrixSummer
{
116 MatrixSlice
<T
,I
> sums
; ///< Internal matrix containing precomputed partial sums
118 /** Returns whether the object is filled with data */
119 bool isValid() const { return sums
.isValid(); }
120 /** Clears the object */
121 void free() { sums
.free(); };
123 /** Computes the sum of a rectangle (in constant time) */
124 Result
getSum(I x0
,I y0
,I xend
,I yend
) const {
125 ASSERT( sums
.isValid() );
126 return sums
[xend
][yend
] -(sums
[x0
][yend
]+sums
[xend
][y0
]) +sums
[x0
][y0
];
128 /** A shortcut to get the sum of a block */
129 Result
getSum(const Block
&b
) const
130 { return getSum( b
.x0
, b
.y0
, b
.xend
, b
.yend
); }
132 /** Prepares object to make sums for a matrix. If the summer has already been
133 * used before, the method assumes it was for a matrix of the same size */
134 template<class Input
> void fill(Input inp
,I width
,I height
) {
135 if ( !sums
.isValid() )
136 sums
.allocate(width
+1,height
+1);
138 // fill the edges with zeroes
139 for (I i
=0; i
<=width
; ++i
)
141 for (I j
=1; j
<=height
; ++j
)
143 // acummulate in the y-growing direction
144 for (I i
=1; i
<=width
; ++i
)
145 for (I j
=1; j
<=height
; ++j
)
146 sums
[i
][j
]= sums
[i
][j
-1] + Result(inp
[i
-1][j
-1]);
147 // acummulate in the x-growing direction
148 for (I i
=2; i
<=width
; ++i
)
149 for (I j
=1; j
<=height
; ++j
)
150 sums
[i
][j
]+= sums
[i
-1][j
];
152 }; // MatrixSummer class template
154 /** Helper structure for computing with value and squared sums at once */
155 template<class Num
> struct DoubleNum
{
159 { DEBUG_ONLY( value
= square
= std::numeric_limits
<Num
>::quiet_NaN(); ) }
162 : value(val
), square(sqr(val
)) {}
164 DoubleNum(const DoubleNum
&other
)
165 : value(other
.value
), square(other
.square
) {}
167 void unpack(Num
&val
,Num
&sq
) const { val
= value
; sq
= square
; }
169 DoubleNum
& operator+=(const DoubleNum
&other
) {
171 square
+= other
.square
;
174 DoubleNum
& operator-=(const DoubleNum
&other
) {
176 square
-= other
.square
;
179 friend DoubleNum
operator+(const DoubleNum
&a
,const DoubleNum
&b
)
180 { return DoubleNum(a
)+= b
; }
181 friend DoubleNum
operator-(const DoubleNum
&a
,const DoubleNum
&b
)
182 { return DoubleNum(a
)-= b
; }
183 }; // DoubleNum template struct
186 /** Structure for a block of pixels - also contains summers and dimensions */
187 template< class SumT
, class PixT
, class I
=PtrInt
>
188 struct SummedMatrix
{
189 typedef DoubleNum
<SumT
> BSumRes
;
190 typedef MatrixSummer
<BSumRes
,I
> BSummer
;
192 I width
/// The width of ::pixels
193 , height
; ///< The height of ::pixels
194 MatrixSlice
<PixT
> pixels
; ///< The matrix of pixels
195 BSummer summer
; ///< Summer for values and squares of ::pixels
196 bool sumsValid
; ///< Indicates whether the summer values are valid
198 /** Sets the size of ::pixels, optionally allocates memory */
199 void setSize( I width_
, I height_
) {
203 pixels
.allocate(width
,height
);
205 /** Frees the memory */
206 void free(bool freePixels
=true) {
215 /** Just validates both summers (if needed) */
216 void summers_makeValid() const {
217 ASSERT(pixels
.isValid());
219 constCast(summer
).fill(pixels
,width
,height
);
220 constCast(sumsValid
)= true;
223 /** Justs invalidates both summers (to be called after changes in the pixel-matrix) */
224 void summers_invalidate()
225 { sumsValid
= false; }
226 /** A shortcut for getting sums of a block */
227 BSumRes
getSums(const Block
&block
) const
228 { return getSums( block
.x0
, block
.y0
, block
.xend
, block
.yend
); }
229 /** Gets both sums of a nonempty rectangle in ::pixels, the summer isn't validated */
230 BSumRes
getSums( I x0
, I y0
, I xend
, I yend
) const {
231 ASSERT( sumsValid
&& x0
>=0 && y0
>=0 && xend
>x0
&& yend
>y0
232 && xend
<=width
&& yend
<=height
);
233 return summer
.getSum(x0
,y0
,xend
,yend
);
235 /** Gets only the sum of values (not the sum of squares) */
236 SumT
getValueSum( I x0
, I y0
, I xend
, I yend
) const {
237 /// \todo quicker version
238 return getSums(x0
,y0
,xend
,yend
).value
;
240 }; // SummedPixels template struct
244 /** Contains various iterators for matrices (see Matrix)
245 * to be used in walkOperate() and walkOperateCheckRotate() */
246 namespace MatrixWalkers
{
248 /** Iterates two matrix iterators and performs an action.
249 * The loop is controled by the first iterator (\p checked)
250 * and on every corresponding pair (a,b) \p oper(a,b) is invoked. Returns \p oper. */
251 template < class Checked
, class Unchecked
, class Operator
>
252 Operator
walkOperate( Checked checked
, Unchecked unchecked
, Operator oper
) {
253 // outer cycle start - to be always run at least once
254 ASSERT( checked
.outerCond() );
256 // inner initialization
258 unchecked
.innerInit();
259 // inner cycle start - to be always run at least once
260 ASSERT( checked
.innerCond() );
262 // perform the operation and do the inner step for both iterators
263 oper( checked
.get(), unchecked
.get() );
265 unchecked
.innerStep();
266 } while ( checked
.innerCond() );
268 // signal the end of inner cycle to the operator and do the outer step for both iterators
271 unchecked
.outerStep();
273 } while ( checked
.outerCond() );
279 /** Base structure for walkers */
280 template<class T
,class I
> struct RotBase
{
282 typedef MatrixSlice
<T
,I
> TMatrix
;
284 TMatrix current
; ///< matrix starting on the current element
285 T
*lastStart
; ///< the place of the last enter of the inner loop
288 RotBase( TMatrix matrix
, int x0
, int y0
)
289 : current( matrix
.shiftMatrix(x0
,y0
) ), lastStart(current
.start
) {
290 DEBUG_ONLY( current
.start
= 0; )
291 ASSERT( matrix
.isValid() );
294 void innerInit() { current
.start
= lastStart
; }
295 T
& get() { return *current
.start
; }
296 }; // RotBase class template
298 #define ROTBASE_INHERIT \
299 typedef typename RotBase<T,I>::TMatrix TMatrix; \
300 using RotBase<T,I>::current; \
301 using RotBase<T,I>::lastStart;
303 /** No rotation: x->, y-> */
304 template<class T
,class I
=PtrInt
> struct Rotation_0
: public RotBase
<T
,I
> { ROTBASE_INHERIT
305 Rotation_0( TMatrix matrix
, const Block
&block
)
306 : RotBase
<T
,I
>( matrix
, block
.x0
, block
.y0
) {}
308 explicit Rotation_0( TMatrix matrix
, I x0
=0, I y0
=0 )
309 : RotBase
<T
,I
>( matrix
, x0
, y0
) {}
311 void outerStep() { lastStart
+= current
.colSkip
; }
312 void innerStep() { ++current
.start
; }
315 /** Rotated 90deg\. cw\., transposed: x<-, y-> */
316 template<class T
,class I
> struct Rotation_1_T
: public RotBase
<T
,I
> { ROTBASE_INHERIT
317 Rotation_1_T( TMatrix matrix
, const Block
&block
)
318 : RotBase
<T
,I
>( matrix
, block
.xend
-1, block
.y0
) {}
320 void outerStep() { lastStart
-= current
.colSkip
; }
321 void innerStep() { ++current
.start
; }
324 /** Rotated 180deg\. cw\.: x<-, y<- */
325 template<class T
,class I
> struct Rotation_2
: public RotBase
<T
,I
> { ROTBASE_INHERIT
326 Rotation_2( TMatrix matrix
, const Block
&block
)
327 : RotBase
<T
,I
>( matrix
, block
.xend
-1, block
.yend
-1 ) {}
329 void outerStep() { lastStart
-= current
.colSkip
; }
330 void innerStep() { --current
.start
; }
333 /** Rotated 270deg\. cw\., transposed: x->, y<- */
334 template<class T
,class I
> struct Rotation_3_T
: public RotBase
<T
,I
> { ROTBASE_INHERIT
335 Rotation_3_T( TMatrix matrix
, const Block
&block
)
336 : RotBase
<T
,I
>( matrix
, block
.x0
, block
.yend
-1 ) {}
338 void outerStep() { lastStart
+= current
.colSkip
; }
339 void innerStep() { --current
.start
; }
342 /** No rotation, transposed: y->, x-> */
343 template<class T
,class I
> struct Rotation_0_T
: public RotBase
<T
,I
> { ROTBASE_INHERIT
344 Rotation_0_T( TMatrix matrix
, const Block
&block
)
345 : RotBase
<T
,I
>( matrix
, block
.x0
, block
.y0
) {}
347 explicit Rotation_0_T( TMatrix matrix
, I x0
=0, I y0
=0 )
348 : RotBase
<T
,I
>( matrix
, x0
, y0
) {}
350 void outerStep() { ++lastStart
; }
351 void innerStep() { current
.start
+= current
.colSkip
; }
354 /** Rotated 90deg\. cw\.: y->, x<- */
355 template<class T
,class I
> struct Rotation_1
: public RotBase
<T
,I
> { ROTBASE_INHERIT
356 Rotation_1( TMatrix matrix
, const Block
&block
)
357 : RotBase
<T
,I
>( matrix
, block
.xend
-1, block
.y0
) {}
359 void outerStep() { ++lastStart
; }
360 void innerStep() { current
.start
-= current
.colSkip
; }
363 /** Rotated 180deg\. cw\., transposed: y<-, x<- */
364 template<class T
,class I
> struct Rotation_2_T
: public RotBase
<T
,I
> { ROTBASE_INHERIT
365 Rotation_2_T( TMatrix matrix
, const Block
&block
)
366 : RotBase
<T
,I
>( matrix
, block
.xend
-1, block
.yend
-1 ) {}
368 void outerStep() { --lastStart
; }
369 void innerStep() { current
.start
-= current
.colSkip
; }
372 /** Rotated 270deg\. cw\.: y<-, x-> */
373 template<class T
,class I
> struct Rotation_3
: public RotBase
<T
,I
> { ROTBASE_INHERIT
374 Rotation_3( TMatrix matrix
, const Block
&block
)
375 : RotBase
<T
,I
>( matrix
, block
.x0
, block
.yend
-1 ) {}
377 void outerStep() { --lastStart
; }
378 void innerStep() { current
.start
+= current
.colSkip
; }
382 /** A flavour of walkOperate() choosing the right Rotation_* iterator
383 * based on \p rotation and constructing it from \p pixels2 and \p block2 */
384 template<class Check
,class U
,class Operator
>
385 inline Operator
walkOperateCheckRotate( Check checked
, Operator oper
386 , MatrixSlice
<U
> pixels2
, const Block
&block2
, char rotation
) {
389 case 0: return walkOperate( checked
, Rotation_0
<U
,I
>(pixels2
,block2
) , oper
);
390 case 1: return walkOperate( checked
, Rotation_0_T
<U
,I
>(pixels2
,block2
) , oper
);
391 case 2: return walkOperate( checked
, Rotation_1
<U
,I
>(pixels2
,block2
) , oper
);
392 case 3: return walkOperate( checked
, Rotation_1_T
<U
,I
>(pixels2
,block2
) , oper
);
393 case 4: return walkOperate( checked
, Rotation_2
<U
,I
>(pixels2
,block2
) , oper
);
394 case 5: return walkOperate( checked
, Rotation_2_T
<U
,I
>(pixels2
,block2
) , oper
);
395 case 6: return walkOperate( checked
, Rotation_3
<U
,I
>(pixels2
,block2
) , oper
);
396 case 7: return walkOperate( checked
, Rotation_3_T
<U
,I
>(pixels2
,block2
) , oper
);
397 default: ASSERT(false); return oper
;
402 /** Performs manipulations with rotation codes 0-7 (dihedral group of order eight) */
404 /** Asserts the parameter is within 0-7 */
405 static void check(int DEBUG_ONLY(r
)) {
406 ASSERT( 0<=r
&& r
<8 );
408 /** Returns inverted rotation (the one that takes this one back to identity) */
409 static int invert(int r
) {
411 return (4-r
/2)%4 *2 +r
%2;
413 /** Computes rotation equal to projecting at first with \p r1 and the result with \p r2 */
414 static int compose(int r1
,int r2
) {
415 check(r1
); check(r2
);
418 return (r1
/2 + r2
/2) %4 *2+ ( (r1
%2)^(r2
%2) );
420 }; // Rotation struct
422 /** Checked_ iterator for a rectangle in a matrix, no rotation */
423 template<class T
,class I
=PtrInt
> struct Checked
: public Rotation_0
<T
,I
> {
424 typedef MatrixSlice
<T
,I
> TMatrix
;
425 typedef Rotation_0
<T
,I
> Base
;
427 using Base::lastStart
;
429 T
*colEnd
/// the end of the current column
430 , *colsEndStart
; ///< the start of the end column
432 /** Initializes a new iterator for a \p block of \p pixels */
433 Checked( TMatrix pixels
, const Block
&block
)
434 : Base( pixels
, block
), colEnd( pixels
.start
+pixels
.colSkip
*block
.x0
+block
.yend
)
435 , colsEndStart( pixels
.start
+pixels
.colSkip
*block
.xend
+block
.y0
) {
436 ASSERT( block
.xend
>block
.x0
&& block
.yend
>block
.y0
);
440 ASSERT(lastStart
<=colsEndStart
);
441 return lastStart
!=colsEndStart
;
444 colEnd
+= current
.colSkip
;
448 ASSERT(current
.start
<=colEnd
);
449 return current
.start
!=colEnd
;
451 }; // Checked class template
453 /** Checked_ iterator for a whole QImage; no rotation, but always transposed */
454 template<class T
,class U
> struct CheckedImage
{
458 QImage
&img
; ///< reference to the image
459 int lineIndex
/// index of the current line
460 , width
/// the width of the image
461 , height
; ///< the height of the image
462 QRgb
*line
/// pointer to the current pixel
463 , *lineEnd
; ///< pointer to the end of the line
466 /** Initializes a new iterator for an instance of QImage (Qt class) */
467 CheckedImage(QImage
&image
)
468 : img(image
), lineIndex(0), width(image
.width()), height(image
.height())
469 { DEBUG_ONLY(line
=lineEnd
=0;) }
471 bool outerCond() { return lineIndex
<height
; }
472 void outerStep() { ++lineIndex
; }
474 void innerInit() { line
= (QRgb
*)img
.scanLine(lineIndex
); lineEnd
= line
+width
; }
475 bool innerCond() { return line
!=lineEnd
; }
476 void innerStep() { ++line
; }
478 QRgb
& get() { return *line
; }
479 }; // CheckedImage class template
482 /** A convenience base type for operators to use with walkOperate() */
483 struct OperatorBase
{
487 /** An operator computing the sum of products */
488 template<class TOut
,class TIn
> struct RDSummer
: public OperatorBase
{
489 TOut totalSum
, lineSum
;
492 : totalSum(0), lineSum(0) {}
493 void operator()(const TIn
&num1
,const TIn
& num2
)
494 { lineSum
+= TOut(num1
) * TOut(num2
); }
496 { totalSum
+= lineSum
; lineSum
= 0; }
497 TOut
result() ///< returns the result
498 { ASSERT(!lineSum
); return totalSum
; }
501 /** An operator performing a= (b+::toAdd)*::toMul */
502 template<class T
> struct AddMulCopy
: public OperatorBase
{
503 const T toAdd
, toMul
;
505 AddMulCopy(T add
,T mul
)
506 : toAdd(add
), toMul(mul
) {}
508 template<class R1
,class R2
> void operator()(R1
&res
,R2 f
) const
509 { res
= (f
+toAdd
)*toMul
; }
512 /** An operator performing a= b*::toMul+::toAdd
513 * and moving the result into [::min,::max] bounds */
514 template<class T
> struct MulAddCopyChecked
: public OperatorBase
{
515 const T toMul
, toAdd
, min
, max
;
517 MulAddCopyChecked(T mul
,T add
,T minVal
,T maxVal
)
518 : toMul(mul
), toAdd(add
), min(minVal
), max(maxVal
) {}
520 template<class R1
,class R2
> void operator()(R1
&res
,R2 f
) const
521 { res
= checkBoundsFunc( min
, f
*toMul
+toAdd
, max
); }
523 } // MatrixWalkers namespace
525 #endif // MATRIXUTIL_HEADER_