| /*****************************************************************************/ |
| // Copyright 2006-2008 Adobe Systems Incorporated |
| // All Rights Reserved. |
| // |
| // NOTICE: Adobe permits you to use, modify, and distribute this file in |
| // accordance with the terms of the Adobe license agreement accompanying it. |
| /*****************************************************************************/ |
| |
| /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_matrix.cpp#1 $ */ |
| /* $DateTime: 2012/05/30 13:28:51 $ */ |
| /* $Change: 832332 $ */ |
| /* $Author: tknoll $ */ |
| |
| /*****************************************************************************/ |
| |
| #include "dng_matrix.h" |
| |
| #include "dng_exceptions.h" |
| #include "dng_utils.h" |
| |
| /*****************************************************************************/ |
| |
| dng_matrix::dng_matrix () |
| |
| : fRows (0) |
| , fCols (0) |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix::dng_matrix (uint32 rows, |
| uint32 cols) |
| |
| : fRows (0) |
| , fCols (0) |
| |
| { |
| |
| if (rows < 1 || rows > kMaxColorPlanes || |
| cols < 1 || cols > kMaxColorPlanes) |
| { |
| |
| ThrowProgramError (); |
| |
| } |
| |
| fRows = rows; |
| fCols = cols; |
| |
| for (uint32 row = 0; row < fRows; row++) |
| for (uint32 col = 0; col < fCols; col++) |
| { |
| |
| fData [row] [col] = 0.0; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix::dng_matrix (const dng_matrix &m) |
| |
| : fRows (m.fRows) |
| , fCols (m.fCols) |
| |
| { |
| |
| for (uint32 row = 0; row < fRows; row++) |
| for (uint32 col = 0; col < fCols; col++) |
| { |
| |
| fData [row] [col] = m.fData [row] [col]; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_matrix::Clear () |
| { |
| |
| fRows = 0; |
| fCols = 0; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_matrix::SetIdentity (uint32 count) |
| { |
| |
| *this = dng_matrix (count, count); |
| |
| for (uint32 j = 0; j < count; j++) |
| { |
| |
| fData [j] [j] = 1.0; |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| bool dng_matrix::operator== (const dng_matrix &m) const |
| { |
| |
| if (Rows () != m.Rows () || |
| Cols () != m.Cols ()) |
| { |
| |
| return false; |
| |
| } |
| |
| for (uint32 j = 0; j < Rows (); j++) |
| for (uint32 k = 0; k < Cols (); k++) |
| { |
| |
| if (fData [j] [k] != m.fData [j] [k]) |
| { |
| |
| return false; |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| bool dng_matrix::IsDiagonal () const |
| { |
| |
| if (IsEmpty ()) |
| { |
| return false; |
| } |
| |
| if (Rows () != Cols ()) |
| { |
| return false; |
| } |
| |
| for (uint32 j = 0; j < Rows (); j++) |
| for (uint32 k = 0; k < Cols (); k++) |
| { |
| |
| if (j != k) |
| { |
| |
| if (fData [j] [k] != 0.0) |
| { |
| return false; |
| } |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| real64 dng_matrix::MaxEntry () const |
| { |
| |
| if (IsEmpty ()) |
| { |
| |
| return 0.0; |
| |
| } |
| |
| real64 m = fData [0] [0]; |
| |
| for (uint32 j = 0; j < Rows (); j++) |
| for (uint32 k = 0; k < Cols (); k++) |
| { |
| |
| m = Max_real64 (m, fData [j] [k]); |
| |
| } |
| |
| return m; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| real64 dng_matrix::MinEntry () const |
| { |
| |
| if (IsEmpty ()) |
| { |
| |
| return 0.0; |
| |
| } |
| |
| real64 m = fData [0] [0]; |
| |
| for (uint32 j = 0; j < Rows (); j++) |
| for (uint32 k = 0; k < Cols (); k++) |
| { |
| |
| m = Min_real64 (m, fData [j] [k]); |
| |
| } |
| |
| return m; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_matrix::Scale (real64 factor) |
| { |
| |
| for (uint32 j = 0; j < Rows (); j++) |
| for (uint32 k = 0; k < Cols (); k++) |
| { |
| |
| fData [j] [k] *= factor; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_matrix::Round (real64 factor) |
| { |
| |
| real64 invFactor = 1.0 / factor; |
| |
| for (uint32 j = 0; j < Rows (); j++) |
| for (uint32 k = 0; k < Cols (); k++) |
| { |
| |
| fData [j] [k] = Round_int32 (fData [j] [k] * factor) * invFactor; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_matrix::SafeRound (real64 factor) |
| { |
| |
| real64 invFactor = 1.0 / factor; |
| |
| for (uint32 j = 0; j < Rows (); j++) |
| { |
| |
| // Round each row to the specified accuracy, but make sure the |
| // a rounding does not affect the total of the elements in a row |
| // more than necessary. |
| |
| real64 error = 0.0; |
| |
| for (uint32 k = 0; k < Cols (); k++) |
| { |
| |
| fData [j] [k] += error; |
| |
| real64 rounded = Round_int32 (fData [j] [k] * factor) * invFactor; |
| |
| error = fData [j] [k] - rounded; |
| |
| fData [j] [k] = rounded; |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix_3by3::dng_matrix_3by3 () |
| |
| : dng_matrix (3, 3) |
| |
| { |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix_3by3::dng_matrix_3by3 (const dng_matrix &m) |
| |
| : dng_matrix (m) |
| |
| { |
| |
| if (Rows () != 3 || |
| Cols () != 3) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a01, real64 a02, |
| real64 a10, real64 a11, real64 a12, |
| real64 a20, real64 a21, real64 a22) |
| |
| |
| : dng_matrix (3, 3) |
| |
| { |
| |
| fData [0] [0] = a00; |
| fData [0] [1] = a01; |
| fData [0] [2] = a02; |
| |
| fData [1] [0] = a10; |
| fData [1] [1] = a11; |
| fData [1] [2] = a12; |
| |
| fData [2] [0] = a20; |
| fData [2] [1] = a21; |
| fData [2] [2] = a22; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a11, real64 a22) |
| |
| : dng_matrix (3, 3) |
| |
| { |
| |
| fData [0] [0] = a00; |
| fData [1] [1] = a11; |
| fData [2] [2] = a22; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix_4by3::dng_matrix_4by3 () |
| |
| : dng_matrix (4, 3) |
| |
| { |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix_4by3::dng_matrix_4by3 (const dng_matrix &m) |
| |
| : dng_matrix (m) |
| |
| { |
| |
| if (Rows () != 4 || |
| Cols () != 3) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix_4by3::dng_matrix_4by3 (real64 a00, real64 a01, real64 a02, |
| real64 a10, real64 a11, real64 a12, |
| real64 a20, real64 a21, real64 a22, |
| real64 a30, real64 a31, real64 a32) |
| |
| |
| : dng_matrix (4, 3) |
| |
| { |
| |
| fData [0] [0] = a00; |
| fData [0] [1] = a01; |
| fData [0] [2] = a02; |
| |
| fData [1] [0] = a10; |
| fData [1] [1] = a11; |
| fData [1] [2] = a12; |
| |
| fData [2] [0] = a20; |
| fData [2] [1] = a21; |
| fData [2] [2] = a22; |
| |
| fData [3] [0] = a30; |
| fData [3] [1] = a31; |
| fData [3] [2] = a32; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_vector::dng_vector () |
| |
| : fCount (0) |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_vector::dng_vector (uint32 count) |
| |
| : fCount (0) |
| |
| { |
| |
| if (count < 1 || count > kMaxColorPlanes) |
| { |
| |
| ThrowProgramError (); |
| |
| } |
| |
| fCount = count; |
| |
| for (uint32 index = 0; index < fCount; index++) |
| { |
| |
| fData [index] = 0.0; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_vector::dng_vector (const dng_vector &v) |
| |
| : fCount (v.fCount) |
| |
| { |
| |
| for (uint32 index = 0; index < fCount; index++) |
| { |
| |
| fData [index] = v.fData [index]; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_vector::Clear () |
| { |
| |
| fCount = 0; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_vector::SetIdentity (uint32 count) |
| { |
| |
| *this = dng_vector (count); |
| |
| for (uint32 j = 0; j < count; j++) |
| { |
| |
| fData [j] = 1.0; |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| bool dng_vector::operator== (const dng_vector &v) const |
| { |
| |
| if (Count () != v.Count ()) |
| { |
| |
| return false; |
| |
| } |
| |
| for (uint32 j = 0; j < Count (); j++) |
| { |
| |
| if (fData [j] != v.fData [j]) |
| { |
| |
| return false; |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| real64 dng_vector::MaxEntry () const |
| { |
| |
| if (IsEmpty ()) |
| { |
| |
| return 0.0; |
| |
| } |
| |
| real64 m = fData [0]; |
| |
| for (uint32 j = 0; j < Count (); j++) |
| { |
| |
| m = Max_real64 (m, fData [j]); |
| |
| } |
| |
| return m; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| real64 dng_vector::MinEntry () const |
| { |
| |
| if (IsEmpty ()) |
| { |
| |
| return 0.0; |
| |
| } |
| |
| real64 m = fData [0]; |
| |
| for (uint32 j = 0; j < Count (); j++) |
| { |
| |
| m = Min_real64 (m, fData [j]); |
| |
| } |
| |
| return m; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_vector::Scale (real64 factor) |
| { |
| |
| for (uint32 j = 0; j < Count (); j++) |
| { |
| |
| fData [j] *= factor; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_vector::Round (real64 factor) |
| { |
| |
| real64 invFactor = 1.0 / factor; |
| |
| for (uint32 j = 0; j < Count (); j++) |
| { |
| |
| fData [j] = Round_int32 (fData [j] * factor) * invFactor; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix dng_vector::AsDiagonal () const |
| { |
| |
| dng_matrix M (Count (), Count ()); |
| |
| for (uint32 j = 0; j < Count (); j++) |
| { |
| |
| M [j] [j] = fData [j]; |
| |
| } |
| |
| return M; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_matrix dng_vector::AsColumn () const |
| { |
| |
| dng_matrix M (Count (), 1); |
| |
| for (uint32 j = 0; j < Count (); j++) |
| { |
| |
| M [j] [0] = fData [j]; |
| |
| } |
| |
| return M; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector_3::dng_vector_3 () |
| |
| : dng_vector (3) |
| |
| { |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector_3::dng_vector_3 (const dng_vector &v) |
| |
| : dng_vector (v) |
| |
| { |
| |
| if (Count () != 3) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector_3::dng_vector_3 (real64 a0, |
| real64 a1, |
| real64 a2) |
| |
| : dng_vector (3) |
| |
| { |
| |
| fData [0] = a0; |
| fData [1] = a1; |
| fData [2] = a2; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector_4::dng_vector_4 () |
| |
| : dng_vector (4) |
| |
| { |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector_4::dng_vector_4 (const dng_vector &v) |
| |
| : dng_vector (v) |
| |
| { |
| |
| if (Count () != 4) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector_4::dng_vector_4 (real64 a0, |
| real64 a1, |
| real64 a2, |
| real64 a3) |
| |
| : dng_vector (4) |
| |
| { |
| |
| fData [0] = a0; |
| fData [1] = a1; |
| fData [2] = a2; |
| fData [3] = a3; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_matrix operator* (const dng_matrix &A, |
| const dng_matrix &B) |
| { |
| |
| if (A.Cols () != B.Rows ()) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| dng_matrix C (A.Rows (), B.Cols ()); |
| |
| for (uint32 j = 0; j < C.Rows (); j++) |
| for (uint32 k = 0; k < C.Cols (); k++) |
| { |
| |
| C [j] [k] = 0.0; |
| |
| for (uint32 m = 0; m < A.Cols (); m++) |
| { |
| |
| real64 aa = A [j] [m]; |
| |
| real64 bb = B [m] [k]; |
| |
| C [j] [k] += aa * bb; |
| |
| } |
| |
| } |
| |
| return C; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector operator* (const dng_matrix &A, |
| const dng_vector &B) |
| { |
| |
| if (A.Cols () != B.Count ()) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| dng_vector C (A.Rows ()); |
| |
| for (uint32 j = 0; j < C.Count (); j++) |
| { |
| |
| C [j] = 0.0; |
| |
| for (uint32 m = 0; m < A.Cols (); m++) |
| { |
| |
| real64 aa = A [j] [m]; |
| |
| real64 bb = B [m]; |
| |
| C [j] += aa * bb; |
| |
| } |
| |
| } |
| |
| return C; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_matrix operator* (real64 scale, |
| const dng_matrix &A) |
| { |
| |
| dng_matrix B (A); |
| |
| B.Scale (scale); |
| |
| return B; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_vector operator* (real64 scale, |
| const dng_vector &A) |
| { |
| |
| dng_vector B (A); |
| |
| B.Scale (scale); |
| |
| return B; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_matrix operator+ (const dng_matrix &A, |
| const dng_matrix &B) |
| { |
| |
| if (A.Cols () != B.Cols () || |
| A.Rows () != B.Rows ()) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| dng_matrix C (A); |
| |
| for (uint32 j = 0; j < C.Rows (); j++) |
| for (uint32 k = 0; k < C.Cols (); k++) |
| { |
| |
| C [j] [k] += B [j] [k]; |
| |
| } |
| |
| return C; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| const real64 kNearZero = 1.0E-10; |
| |
| /******************************************************************************/ |
| |
| // Work around bug #1294195, which may be a hardware problem on a specific machine. |
| // This pragma turns on "improved" floating-point consistency. |
| #ifdef _MSC_VER |
| #pragma optimize ("p", on) |
| #endif |
| |
| static dng_matrix Invert3by3 (const dng_matrix &A) |
| { |
| |
| real64 a00 = A [0] [0]; |
| real64 a01 = A [0] [1]; |
| real64 a02 = A [0] [2]; |
| real64 a10 = A [1] [0]; |
| real64 a11 = A [1] [1]; |
| real64 a12 = A [1] [2]; |
| real64 a20 = A [2] [0]; |
| real64 a21 = A [2] [1]; |
| real64 a22 = A [2] [2]; |
| |
| real64 temp [3] [3]; |
| |
| temp [0] [0] = a11 * a22 - a21 * a12; |
| temp [0] [1] = a21 * a02 - a01 * a22; |
| temp [0] [2] = a01 * a12 - a11 * a02; |
| temp [1] [0] = a20 * a12 - a10 * a22; |
| temp [1] [1] = a00 * a22 - a20 * a02; |
| temp [1] [2] = a10 * a02 - a00 * a12; |
| temp [2] [0] = a10 * a21 - a20 * a11; |
| temp [2] [1] = a20 * a01 - a00 * a21; |
| temp [2] [2] = a00 * a11 - a10 * a01; |
| |
| real64 det = (a00 * temp [0] [0] + |
| a01 * temp [1] [0] + |
| a02 * temp [2] [0]); |
| |
| if (Abs_real64 (det) < kNearZero) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| dng_matrix B (3, 3); |
| |
| for (uint32 j = 0; j < 3; j++) |
| for (uint32 k = 0; k < 3; k++) |
| { |
| |
| B [j] [k] = temp [j] [k] / det; |
| |
| } |
| |
| return B; |
| |
| } |
| |
| // Reset floating-point optimization. See comment above. |
| #ifdef _MSC_VER |
| #pragma optimize ("p", off) |
| #endif |
| |
| /******************************************************************************/ |
| |
| static dng_matrix InvertNbyN (const dng_matrix &A) |
| { |
| |
| uint32 i; |
| uint32 j; |
| uint32 k; |
| |
| uint32 n = A.Rows (); |
| |
| real64 temp [kMaxColorPlanes] [kMaxColorPlanes * 2]; |
| |
| for (i = 0; i < n; i++) |
| for (j = 0; j < n; j++) |
| { |
| |
| temp [i] [j ] = A [i] [j]; |
| |
| temp [i] [j + n] = (i == j ? 1.0 : 0.0); |
| |
| } |
| |
| for (i = 0; i < n; i++) |
| { |
| |
| real64 alpha = temp [i] [i]; |
| |
| if (Abs_real64 (alpha) < kNearZero) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| for (j = 0; j < n * 2; j++) |
| { |
| |
| temp [i] [j] /= alpha; |
| |
| } |
| |
| for (k = 0; k < n; k++) |
| { |
| |
| if (i != k) |
| { |
| |
| real64 beta = temp [k] [i]; |
| |
| for (j = 0; j < n * 2; j++) |
| { |
| |
| temp [k] [j] -= beta * temp [i] [j]; |
| |
| } |
| |
| } |
| |
| } |
| |
| } |
| |
| dng_matrix B (n, n); |
| |
| for (i = 0; i < n; i++) |
| for (j = 0; j < n; j++) |
| { |
| |
| B [i] [j] = temp [i] [j + n]; |
| |
| } |
| |
| return B; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_matrix Transpose (const dng_matrix &A) |
| { |
| |
| dng_matrix B (A.Cols (), A.Rows ()); |
| |
| for (uint32 j = 0; j < B.Rows (); j++) |
| for (uint32 k = 0; k < B.Cols (); k++) |
| { |
| |
| B [j] [k] = A [k] [j]; |
| |
| } |
| |
| return B; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_matrix Invert (const dng_matrix &A) |
| { |
| |
| if (A.Rows () < 2 || A.Cols () < 2) |
| { |
| |
| ThrowMatrixMath (); |
| |
| } |
| |
| if (A.Rows () == A.Cols ()) |
| { |
| |
| if (A.Rows () == 3) |
| { |
| |
| return Invert3by3 (A); |
| |
| } |
| |
| return InvertNbyN (A); |
| |
| } |
| |
| else |
| { |
| |
| // Compute the pseudo inverse. |
| |
| dng_matrix B = Transpose (A); |
| |
| return Invert (B * A) * B; |
| |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| dng_matrix Invert (const dng_matrix &A, |
| const dng_matrix &hint) |
| { |
| |
| if (A.Rows () == A .Cols () || |
| A.Rows () != hint.Cols () || |
| A.Cols () != hint.Rows ()) |
| { |
| |
| return Invert (A); |
| |
| } |
| |
| else |
| { |
| |
| // Use the specified hint matrix. |
| |
| return Invert (hint * A) * hint; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |