![]() |
Ansel 0.0
A darktable fork - bloat + design vision
|
Experimental 3x3 polar decomposition helpers used for color transform analysis. More...
Include dependency graph for polar_decomposition.h:
This graph shows which files directly or indirectly include this file:Go to the source code of this file.
Macros | |
| #define | TYPE double |
| #define | ABS(n) fabs(n) |
| #define | SQRT(n) sqrt(n) |
Functions | |
| void | swap_rows (double *m, size_t rows, size_t cols, size_t row0, size_t row1) |
| Swap two rows of a row-major dense matrix in place. | |
| void | swap_cols (double *m, size_t rows, size_t cols, size_t col0, size_t col1) |
| Swap two columns of a row-major dense matrix in place. | |
| void | abs_matrix (double *matrix_abs, size_t num_el) |
| Replace each element of a vector with its absolute value. | |
| void | matrix_multiply (const double *A, const double *B, double *RES, int rows_A, int cols_A, int cols_B) |
| Multiply two dense row-major matrices. | |
| double | max_val_matrix (double *matrice, size_t size) |
| Return the maximum entry of a flat matrix buffer. | |
| static void | normalize_array (double *vector, int size) |
| Normalize a vector to unit Euclidean norm. | |
| void | stampa_matrice (double *m, size_t rows, size_t cols) |
| Print a row-major matrix for manual debugging. | |
| void | compute_null_space (double *nullspace, const double a, const double b, const double c) |
| Compute one non-zero vector in the null space of a symmetric 2x2 matrix. | |
| void | copy (double *dest, double *source, size_t num_el) |
| Copy a flat buffer. | |
| void | orthonormalize_v_with_qr (double *v0, double *v1, const double v00, const double v10, const double v01, const double v11) |
| Build two orthonormal candidate eigenvectors from symbolic QR factors. | |
| void | multiply_il_v (double *RES, const double IL01, const double IL02, const double IL03, const double IL12, const double IL13, const double *v) |
| Multiply a vector by the lower-triangular inverse factor used in the LDL solve. | |
| void | multiply_id_v (double *RES, const double ID00, const double ID11, const double *ID, const double *v) |
| Multiply a vector by the block-diagonal inverse factor used in the LDL solve. | |
| void | multiply_v_il (double *RES, const double *v, const double IL01, const double IL02, const double IL03, const double IL12, const double IL13) |
| Multiply a vector by the transpose-side lower-triangular factor used in the LDL solve. | |
| void | orthonormalize_v_with_qr_single (double *v0, double *v1) |
| Re-orthonormalize two 4D vectors after repeated inverse iteration steps. | |
| void | multiply_minus_v_d (double *RES, double *v, double *D) |
| Apply the negative D factor of the LDL factorization to a vector. | |
| double | vector_scalar (const double *a, const double *b, const size_t num_el) |
| Compute the scalar product of two vectors. | |
| void | polar_decomposition (double A[3][3], double Q[3][3], double H[3][3]) |
| Compute the polar decomposition of a 3x3 matrix. | |
Experimental 3x3 polar decomposition helpers used for color transform analysis.
This implementation follows the 3x3 polar decomposition strategy described in "An algorithm to compute the polar decomposition of a 3 x 3 matrix" by Nicholas J. Higham and Vanni Noferini, 2016.
Let A be a non-singular 3×3 matrice, like the ones used in channel mixer or in cameras input profiles. Such matrices define transforms between RGB and XYZ spaces depending on the vector base transform. The vector base is the 3 RGB primaries, defined from/to XYZ reference (absolute) space. Converting between color spaces is then only a change of coordinates for the pixels color vector, depending on how the primaries rotate and rescale in XYZ.
RGB spaces conversions are therefore linear maps from old RGB to XYZ to new RGB. Geometrically, linear maps can be interpreted as a combination of scalings (homothety), rotations and shear mapping (transvection).
But they also have an interesting property :
For any 3×3 invertible matrice A describing a linear map, the general linear map can be decomposed as a single 3D rotation around a particular 3D vector.
That is, there is a factorization of A = Q * H, where Q is the matrice of rotation around a axis of vector H.
This is interesting for us, on the GUI side. 3×3 matrices (9 params) are not intuitive to users, and the visual result of a single coefficient change is hard to predict. This method allows us to reduce 9 input parameters to :
Usually, this is achieved by using HSL spaces, which suck because they work only for bounded signals in [ 0 ; 1 ]. Also, they are not colorspaces, not connected to either physics or psychology, so they are bad. Anyone saying otherwise is fake news.
The present method generalizes the HSL approach to XYZ, LMS and weird spaces, with none of the drawbacks of the the cheapo lazy-ass maths-disabled HSL bullshit. It's great. You should try it some time. Simply the best.
Reference paper: https://www.researchgate.net/publication/296638898_An_algorithm_to_compute_the_polar_decomposition_of_a_3_3_matrix/link/56e29d8c08ae03f02790a388/download
Reference implementation: https://github.com/higham/polar-decomp-3by3
| #define TYPE double |
Compute one non-zero vector in the null space of a symmetric 2x2 matrix.
The coefficients correspond to the matrix [ a b ; b c ], which is the shape produced by the reduced system in the polar decomposition code.
| [out] | nullspace | Output vector of length 2. |
| [in] | a | Matrix coefficient (0, 0). |
| [in] | b | Matrix coefficient (0, 1) and (1, 0). |
| [in] | c | Matrix coefficient (1, 1). |
Referenced by polar_decomposition().
Copy a flat buffer.
Copy a flat buffer used to initialize test matrices.
| [out] | dest | Destination buffer. |
| [in] | source | Source buffer. |
| [in] | num_el | Number of elements to copy. |
Referenced by _masks_gui_menu_item_forward_event(), _set_help_string(), _update_tree_view_nodes_font(), dt_cairo_sharpen_surface_rgb24(), dt_collection_load_filmroll(), dt_ioppr_extract_multi_instances_list(), dt_ioppr_merge_multi_instance_iop_order_list(), gui_init(), main(), and polar_decomposition().
| void matrix_multiply | ( | const double * | A, |
| const double * | B, | ||
| double * | RES, | ||
| int | rows_A, | ||
| int | cols_A, | ||
| int | cols_B | ||
| ) |
Multiply two dense row-major matrices.
The function assumes the matrix shapes are compatible and does not perform dimension validation. It is used as a small utility inside the decomposition code where the shapes are known statically at the call site.
| [in] | A | Left matrix stored row-major with shape rows_A x cols_A. |
| [in] | B | Right matrix stored row-major with shape cols_A x cols_B. |
| [out] | RES | Product matrix stored row-major with shape rows_A x cols_B. |
| [in] | rows_A | Number of rows in A. |
| [in] | cols_A | Number of columns in A and rows in B. |
| [in] | cols_B | Number of columns in B. |
References A, B, i, k, RES, and TYPE.
Referenced by main(), and polar_decomposition().
| void multiply_id_v | ( | double * | RES, |
| const double | ID00, | ||
| const double | ID11, | ||
| const double * | ID, | ||
| const double * | v | ||
| ) |
Multiply a vector by the block-diagonal inverse factor used in the LDL solve.
| [out] | RES | Output vector of length 4. |
| [in] | ID00 | Reciprocal of the first diagonal coefficient. |
| [in] | ID11 | Reciprocal of the second diagonal coefficient. |
| [in] | ID | Pointer to the trailing 2x2 block stored row-major. |
| [in] | v | Input vector of length 4. |
| void multiply_il_v | ( | double * | RES, |
| const double | IL01, | ||
| const double | IL02, | ||
| const double | IL03, | ||
| const double | IL12, | ||
| const double | IL13, | ||
| const double * | v | ||
| ) |
Multiply a vector by the lower-triangular inverse factor used in the LDL solve.
| [out] | RES | Output vector of length 4. |
| [in] | IL01 | Lower-triangular coefficient. |
| [in] | IL02 | Lower-triangular coefficient. |
| [in] | IL03 | Lower-triangular coefficient. |
| [in] | IL12 | Lower-triangular coefficient. |
| [in] | IL13 | Lower-triangular coefficient. |
| [in] | v | Input vector of length 4. |
| void multiply_v_il | ( | double * | RES, |
| const double * | v, | ||
| const double | IL01, | ||
| const double | IL02, | ||
| const double | IL03, | ||
| const double | IL12, | ||
| const double | IL13 | ||
| ) |
Multiply a vector by the transpose-side lower-triangular factor used in the LDL solve.
| [out] | RES | Output vector of length 4. |
| [in] | v | Input vector of length 4. |
| [in] | IL01 | Lower-triangular coefficient. |
| [in] | IL02 | Lower-triangular coefficient. |
| [in] | IL03 | Lower-triangular coefficient. |
| [in] | IL12 | Lower-triangular coefficient. |
| [in] | IL13 | Lower-triangular coefficient. |
Normalize a vector to unit Euclidean norm.
| [in,out] | vector | Vector to normalize in place. |
| [in] | size | Number of elements in vector. |
References size, SQRT, and TYPE.
Referenced by orthonormalize_v_with_qr(), orthonormalize_v_with_qr_single(), and polar_decomposition().
| void orthonormalize_v_with_qr | ( | double * | v0, |
| double * | v1, | ||
| const double | v00, | ||
| const double | v10, | ||
| const double | v01, | ||
| const double | v11 | ||
| ) |
Build two orthonormal candidate eigenvectors from symbolic QR factors.
| [out] | v0 | First output vector of length 4. |
| [out] | v1 | Second output vector of length 4. |
| [in] | v00 | First symbolic coefficient. |
| [in] | v10 | Second symbolic coefficient. |
| [in] | v01 | Third symbolic coefficient. |
| [in] | v11 | Fourth symbolic coefficient. |
References normalize_array().
Compute the polar decomposition of a 3x3 matrix.
The function factorizes the input matrix as A = Q * H, where Q is orthogonal and H is symmetric positive semidefinite. The implementation first normalizes the input matrix, then builds a reduced eigenproblem whose dominant eigenvector is converted into the quaternion-like parametrization used to reconstruct the orthogonal factor.
| [in,out] | A | Input 3x3 matrix, temporarily normalized in place and restored before returning. |
| [out] | Q | Orthogonal factor. |
| [out] | H | Symmetric factor. |
References A, ABS, B, compute_null_space(), copy(), d, H, i, k, L, m, matrix_multiply(), normalize_array(), p, r, S, SQRT, swap_cols(), swap_rows(), t, TYPE, v, vector_scalar(), and x.
Referenced by main().
Swap two columns of a row-major dense matrix in place.
| [in,out] | m | Matrix data stored row-major. |
| [in] | rows | Number of rows in m. |
| [in] | cols | Number of columns in m. |
| [in] | col0 | Index of the first column to swap. |
| [in] | col1 | Index of the second column to swap. |
Referenced by polar_decomposition().
Swap two rows of a row-major dense matrix in place.
| [in,out] | m | Matrix data stored row-major. |
| [in] | rows | Number of rows in m. |
| [in] | cols | Number of columns in m. |
| [in] | row0 | Index of the first row to swap. |
| [in] | row1 | Index of the second row to swap. |
References i, m, row0, row1, and TYPE.
Referenced by polar_decomposition().
Compute the scalar product of two vectors.
| [in] | a | First vector. |
| [in] | b | Second vector. |
| [in] | num_el | Number of elements in both vectors. |
a and b. References TYPE.
Referenced by polar_decomposition().