LinearAlgebra.cpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // This file is part of the Integrating Vision Toolkit (IVT).
3 //
4 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
5 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
6 //
7 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright
17 // notice, this list of conditions and the following disclaimer in the
18 // documentation and/or other materials provided with the distribution.
19 //
20 // 3. Neither the name of the KIT nor the names of its contributors may be
21 // used to endorse or promote products derived from this software
22 // without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
25 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
28 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 // ****************************************************************************
35 // ****************************************************************************
36 // Filename: LinearAlgebra.cpp
37 // Author: Pedram Azad
38 // Date: 23.01.2008
39 // ****************************************************************************
40 
41 
42 // ****************************************************************************
43 // Includes
44 // ****************************************************************************
45 
46 #include <new> // for explicitly using correct new/delete operators on VC DSPs
47 
48 #include "LinearAlgebra.h"
49 #include "Image/ImageProcessor.h"
50 #include "Helpers/Quicksort.h"
51 #include "Helpers/helpers.h"
52 #include "Math/FloatMatrix.h"
53 #include "Math/FloatVector.h"
54 #include "Math/DoubleMatrix.h"
55 #include "Math/DoubleVector.h"
56 
57 #include <stdio.h>
58 #include <math.h>
59 #include <float.h>
60 #include <string.h>
61 
62 
63 
64 // ****************************************************************************
65 // Functions
66 // ****************************************************************************
67 
68 void LinearAlgebra::SelfProduct(const CFloatMatrix *pMatrix, CFloatMatrix *pResultMatrix, bool AAT)
69 {
70  if (
71  (AAT && (pResultMatrix->columns != pMatrix->rows || pResultMatrix->rows != pMatrix->rows)) ||
72  (!AAT && (pResultMatrix->columns != pMatrix->columns || pResultMatrix->rows != pMatrix->columns))
73  )
74  {
75  printf("error: matrix dimensions do not match for LinearAlgebra::SelfProduct\n");
76  return;
77  }
78 
79  if (!AAT)
80  {
81  CFloatMatrix *pTransposedMatrix = new CFloatMatrix(pMatrix->rows, pMatrix->columns);
82  Transpose(pMatrix, pTransposedMatrix);
83  pMatrix = pTransposedMatrix;
84  }
85 
86  const int columns = pMatrix->columns;
87  const int rows = pMatrix->rows;
88 
89  const float *data = pMatrix->data;
90  float *result = pResultMatrix->data;
91 
92  if (data != result)
93  {
94  for (int i = 0, input_offset1 = 0; i < rows; i++, input_offset1 += columns)
95  {
96  for (int j = i, input_offset2 = input_offset1; j < rows; j++, input_offset2 += columns)
97  {
98  const float *data1 = data + input_offset1;
99  const float *data2 = data + input_offset2;
100  float sum = 0;
101 
102  for (int k = 0; k < columns; k++)
103  sum += data1[k] * data2[k];
104 
105  result[i * rows + j] = result[j * rows + i] = sum;
106  }
107  }
108  }
109  else
110  {
111  CFloatMatrix temp(pResultMatrix);
112  float *temp_data = temp.data;
113 
114  for (int i = 0, input_offset1 = 0; i < rows; i++, input_offset1 += columns)
115  {
116  for (int j = i, input_offset2 = input_offset1; j < rows; j++, input_offset2 += columns)
117  {
118  const float *data1 = data + input_offset1;
119  const float *data2 = data + input_offset2;
120  float sum = 0;
121 
122  for (int k = 0; k < columns; k++)
123  sum += data1[k] * data2[k];
124 
125  temp_data[i * rows + j] = temp_data[j * rows + i] = sum;
126  }
127  }
128 
129  memcpy(pResultMatrix->data, temp_data, pResultMatrix->rows * pResultMatrix->columns * sizeof(float));
130  }
131 
132  if (!AAT)
133  delete pMatrix;
134 }
135 
136 void LinearAlgebra::MulMatMat(const CFloatMatrix *A, const CFloatMatrix *B, CFloatMatrix *pResultMatrix, bool bTransposeB)
137 {
138  if (!bTransposeB && (A->columns != B->rows || pResultMatrix->columns != B->columns || pResultMatrix->rows != A->rows))
139  {
140  printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebra::Multiply\n");
141  return;
142  }
143 
144  if (bTransposeB && (A->columns != B->columns || pResultMatrix->columns != B->rows || pResultMatrix->rows != A->rows))
145  {
146  printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebra::Multiply\n");
147  return;
148  }
149 
150  const float *data1 = A->data;
151  const float *data2 = B->data;
152  float *result = pResultMatrix->data;
153 
154  const int nSize = pResultMatrix->columns * pResultMatrix->rows;
155 
156  if (bTransposeB)
157  {
158  const int rowsA = A->rows;
159  const int rowsB = B->rows;
160  const int columns = A->columns;
161 
162  if (data1 != result && data2 != result)
163  {
164  for (int i = 0, input_offset1 = 0, output_offset = 0; i < rowsA; i++, input_offset1 += columns)
165  {
166  for (int j = 0, input_offset2 = 0; j < rowsB; j++, input_offset2 += columns, output_offset++)
167  {
168  const float *data1_ = data1 + input_offset1;
169  const float *data2_ = data2 + input_offset2;
170  float sum = 0;
171 
172  for (int k = 0; k < columns; k++)
173  sum += data1_[k] * data2_[k];
174 
175  result[output_offset] = sum;
176  }
177  }
178  }
179  else
180  {
181  CFloatMatrix temp(pResultMatrix);
182  float *temp_data = temp.data;
183 
184  int l;
185 
186  for (l = 0; l < nSize; l++)
187  temp_data[l] = 0;
188 
189  for (int i = 0, input_offset1 = 0, output_offset = 0; i < rowsA; i++, input_offset1 += columns)
190  {
191  for (int j = 0, input_offset2 = input_offset1; j < rowsB; j++, input_offset2 += columns, output_offset++)
192  {
193  const float *data1_ = data1 + input_offset1;
194  const float *data2_ = data2 + input_offset2;
195  float sum = 0;
196 
197  for (int k = 0; k < columns; k++)
198  sum += data1_[k] * data2_[k];
199 
200  temp_data[output_offset] = sum;
201  }
202  }
203 
204  for (l = 0; l < nSize; l++)
205  result[l] = temp_data[l];
206  }
207  }
208  else
209  {
210  const int i_max = A->rows;
211  const int j_max = B->columns;
212  const int k_max = A->columns;
213 
214  // not optimized yet
215  if (data1 != result && data2 != result)
216  {
217  for (int l = 0; l < nSize; l++)
218  result[l] = 0;
219 
220  for (int i = 0, input1_offset = 0; i < i_max; i++)
221  {
222  const int result_offset_start = i * j_max;
223 
224  for (int k = 0, input2_offset = 0; k < k_max; k++, input1_offset++)
225  for (int j = 0, result_offset = result_offset_start; j < j_max; j++, result_offset++, input2_offset++)
226  result[result_offset] += data1[input1_offset] * data2[input2_offset];
227  }
228  }
229  else
230  {
231  CFloatMatrix temp(pResultMatrix);
232  float *temp_data = temp.data;
233 
234  int l;
235 
236  for (l = 0; l < nSize; l++)
237  temp_data[l] = 0;
238 
239  for (int i = 0, input1_offset = 0; i < i_max; i++)
240  {
241  const int result_offset_start = i * j_max;
242 
243  for (int k = 0, input2_offset = 0; k < k_max; k++, input1_offset++)
244  for (int j = 0, result_offset = result_offset_start; j < j_max; j++, result_offset++, input2_offset++)
245  temp_data[result_offset] += data1[input1_offset] * data2[input2_offset];
246  }
247 
248  for (l = 0; l < nSize; l++)
249  result[l] = temp_data[l];
250  }
251  }
252 }
253 
254 void LinearAlgebra::Transpose(const CFloatMatrix *pMatrix, CFloatMatrix *pResultMatrix)
255 {
256  if (pMatrix->columns != pResultMatrix->rows || pMatrix->rows != pResultMatrix->columns)
257  {
258  printf("error: input and output matrix do not match LinearAlgebra::Transpose\n");
259  return;
260  }
261 
262  const int rows = pMatrix->rows;
263  const int columns = pMatrix->columns;
264  const float *input = pMatrix->data;
265  float *output = pResultMatrix->data;
266 
267  if (input != output)
268  {
269  for (int i = 0, input_offset = 0; i < rows; i++)
270  for (int j = 0, output_offset = i; j < columns; j++, input_offset++, output_offset += rows)
271  output[output_offset] = input[input_offset];
272  }
273  else
274  {
275  // not optimized yet
276  CFloatMatrix temp(pResultMatrix);
277  float *temp_data = temp.data;
278 
279  int i, input_offset;
280 
281  for (i = 0, input_offset = 0; i < rows; i++)
282  for (int j = 0, output_offset = i; j < columns; j++, input_offset++, output_offset += rows)
283  temp_data[output_offset] = input[input_offset];
284 
285  const int nSize = rows * columns;
286 
287  for (i = 0; i < nSize; i++)
288  output[i] = temp_data[i];
289  }
290 }
291 
292 void LinearAlgebra::MulMatVec(const CFloatMatrix *pMatrix, const CFloatVector *pVector, CFloatVector *pResultVector)
293 {
294  if (pMatrix->columns != pVector->dimension || pMatrix->rows != pResultVector->dimension)
295  {
296  printf("error: input matrix and vector and output vector do not match for CFloatMatrix::Multiply\n");
297  return;
298  }
299 
300  const int rows = pMatrix->rows;
301  const int columns = pMatrix->columns;
302  const float *data_m = pMatrix->data;
303  const float *data_v = pVector->data;
304  float *data_r = pResultVector->data;
305 
306  if (data_r != data_v)
307  {
308  for (int i = 0, offset = 0; i < rows; i++)
309  {
310  float sum = 0.0f;
311 
312  for (int j = 0; j < columns; j++, offset++)
313  sum += data_m[offset] * data_v[j];
314 
315  data_r[i] = sum;
316  }
317  }
318  else
319  {
320  float *temp = new float[rows];
321  int i, offset;
322 
323  for (i = 0, offset = 0; i < rows; i++)
324  {
325  float sum = 0.0f;
326 
327  for (int j = 0; j < columns; j++, offset++)
328  sum += data_m[offset] * data_v[j];
329 
330  temp[i] = sum;
331  }
332 
333  for (i = 0; i < rows; i++)
334  data_r[i] = temp[i];
335 
336  delete [] temp;
337  }
338 }
339 
340 void LinearAlgebra::MulMatVec(const CFloatMatrix *pMatrix, const CFloatVector *pVector1, const CFloatVector *pVector2, CFloatVector *pResultVector)
341 {
342  MulMatVec(pMatrix, pVector1, pResultVector);
343  AddToVec(pResultVector, pVector2);
344 }
345 
346 void LinearAlgebra::AddMatMat(const CFloatMatrix *pMatrix1, const CFloatMatrix *pMatrix2, CFloatMatrix *pResultMatrix)
347 {
348  if (pMatrix1->rows != pMatrix2->rows || pMatrix1->columns != pMatrix2->columns ||
349  pMatrix1->rows != pResultMatrix->rows || pMatrix1->columns != pResultMatrix->columns)
350  {
351  printf("error: matrix dimensions do not match in LinearAlgebra::AddMatMat\n");
352  return;
353  }
354 
355  const int nSize = pMatrix1->rows * pMatrix1->columns;
356  const float *data1 = pMatrix1->data;
357  const float *data2 = pMatrix2->data;
358  float *result = pResultMatrix->data;
359 
360  for (int i = 0; i < nSize; i++)
361  result[i] = data1[i] + data2[i];
362 }
363 
364 void LinearAlgebra::SubtractMatMat(const CFloatMatrix *pMatrix1, const CFloatMatrix *pMatrix2, CFloatMatrix *pResultMatrix)
365 {
366  if (pMatrix1->rows != pMatrix2->rows || pMatrix1->columns != pMatrix2->columns ||
367  pMatrix1->rows != pResultMatrix->rows || pMatrix1->columns != pResultMatrix->columns)
368  {
369  printf("error: matrix dimensions do not match in LinearAlgebra::SubtractMatMat\n");
370  return;
371  }
372 
373  const int nSize = pMatrix1->rows * pMatrix1->columns;
374  const float *data1 = pMatrix1->data;
375  const float *data2 = pMatrix2->data;
376  float *result = pResultMatrix->data;
377 
378  for (int i = 0; i < nSize; i++)
379  result[i] = data1[i] - data2[i];
380 }
381 
382 void LinearAlgebra::AddVecVec(const CFloatVector *pVector1, const CFloatVector *pVector2, CFloatVector *pResultVector)
383 {
384  if (pVector1->dimension != pVector2->dimension || pVector1->dimension != pResultVector->dimension)
385  {
386  printf("error: vector dimensions do not match in LinearAlgebra::AddVecVec\n");
387  return;
388  }
389 
390  const int nDimension = pVector1->dimension;
391  const float *data1 = pVector1->data;
392  const float *data2 = pVector2->data;
393  float *result = pResultVector->data;
394 
395  for (int i = 0; i < nDimension; i++)
396  result[i] = data1[i] + data2[i];
397 }
398 
399 void LinearAlgebra::SubtractVecVec(const CFloatVector *pVector1, const CFloatVector *pVector2, CFloatVector *pResultVector)
400 {
401  if (pVector1->dimension != pVector2->dimension || pVector1->dimension != pResultVector->dimension)
402  {
403  printf("error: vector dimensions do not match in LinearAlgebra::SubtractVecVec\n");
404  return;
405  }
406 
407  const int nDimension = pVector1->dimension;
408  const float *data1 = pVector1->data;
409  const float *data2 = pVector2->data;
410  float *result = pResultVector->data;
411 
412  for (int i = 0; i < nDimension; i++)
413  result[i] = data1[i] - data2[i];
414 }
415 
416 void LinearAlgebra::AddToMat(CFloatMatrix *pMatrix, const CFloatMatrix *pMatrixToAdd)
417 {
418  if (pMatrix->rows != pMatrixToAdd->rows || pMatrix->columns != pMatrixToAdd->columns)
419  {
420  printf("error: matrix dimensions do not match in LinearAlgebra::AddToMat\n");
421  return;
422  }
423 
424  const int nSize = pMatrix->rows * pMatrix->columns;
425  float *data = pMatrix->data;
426  const float *data_to_add = pMatrixToAdd->data;
427 
428  for (int i = 0; i < nSize; i++)
429  data[i] += data_to_add[i];
430 }
431 
432 void LinearAlgebra::SubtractFromMat(CFloatMatrix *pMatrix, const CFloatMatrix *pMatrixToAdd)
433 {
434  if (pMatrix->rows != pMatrixToAdd->rows || pMatrix->columns != pMatrixToAdd->columns)
435  {
436  printf("error: matrix dimensions do not match in LinearAlgebra::SubtractFromMat\n");
437  return;
438  }
439 
440  const int nSize = pMatrix->rows * pMatrix->columns;
441  float *data = pMatrix->data;
442  const float *data_to_subtract = pMatrixToAdd->data;
443 
444  for (int i = 0; i < nSize; i++)
445  data[i] -= data_to_subtract[i];
446 }
447 
448 void LinearAlgebra::AddToVec(CFloatVector *pVector, const CFloatVector *pVectorToAdd)
449 {
450  if (pVector->dimension != pVectorToAdd->dimension)
451  {
452  printf("error: vector dimensions do not match in LinearAlgebra::AddToVec\n");
453  return;
454  }
455 
456  const int nDimension = pVector->dimension;
457  float *data = pVector->data;
458  const float *data_to_add = pVectorToAdd->data;
459 
460  for (int i = 0; i < nDimension; i++)
461  data[i] += data_to_add[i];
462 }
463 
464 void LinearAlgebra::SubtractFromVec(CFloatVector *pVector, const CFloatVector *pVectorToSubtract)
465 {
466  if (pVector->dimension != pVectorToSubtract->dimension)
467  {
468  printf("error: vector dimensions do not match in LinearAlgebra::SubtractFromVec\n");
469  return;
470  }
471 
472  const int nDimension = pVector->dimension;
473  float *data = pVector->data;
474  const float *data_to_subtract = pVectorToSubtract->data;
475 
476  for (int i = 0; i < nDimension; i++)
477  data[i] -= data_to_subtract[i];
478 }
479 
480 
482 {
483  if (pMatrix->columns != pResultMatrix->columns || pMatrix->rows != pResultMatrix->rows)
484  return;
485 
486  const int columns = pMatrix->columns;
487  const int rows = pMatrix->rows;
488  const int max = rows * columns;
489  const float *data = pMatrix->data;
490  float *output = pResultMatrix->data;
491 
492  for (int i = 0; i < columns; i++)
493  {
494  float mean = 0;
495  int j;
496 
497  for (j = 0; j < max; j += columns)
498  mean += data[j];
499 
500  mean /= rows;
501 
502  for (j = 0; j < max; j += columns)
503  output[j] = data[j] - mean;
504 
505  data++;
506  output++;
507  }
508 }
509 
511 {
512  if (pMatrix->columns != pResultMatrix->columns || pMatrix->rows != pResultMatrix->rows)
513  return;
514 
515  const int columns = pMatrix->columns;
516  const int rows = pMatrix->rows;
517  const float *data = pMatrix->data;
518  float *output = pResultMatrix->data;
519 
520  for (int i = 0; i < rows; i++)
521  {
522  float mean = 0;
523  int j;
524 
525  for (j = 0; j < columns; j++)
526  mean += data[j];
527 
528  mean /= columns;
529 
530  for (j = 0; j < columns; j++)
531  output[j] = data[j] - mean;
532 
533  data += columns;
534  output += columns;
535  }
536 }
537 
539 {
540  if (A->columns != x->dimension)
541  {
542  printf("error: A, x do not match LinearAlgebra::SolveLinearLeastSquaresHomogeneousSVD\n");
543  return;
544  }
545 
546  if (A->rows < A->columns)
547  {
548  printf("error: equation system is underdetermined in LinearAlgebra::SolveLinearLeastSquaresHomogeneousSVD\n");
549  return;
550  }
551 
552  const int m = A->rows;
553  const int n = A->columns;
554 
555  CFloatMatrix W(n, m), V(n, n);
556 
557  SVD(A, &W, 0, &V, false, false, false);
558 
559  for (int i = 0, offset = n - 1; i < n; i++, offset += n)
560  x->data[i] = V.data[offset];
561 }
562 
564 {
565  if (A->columns != x->dimension || A->rows != b->dimension)
566  {
567  printf("error: A, b, x do not match LinearAlgebra::SolveLinearLeastSquaresSVD\n");
568  return;
569  }
570 
571  if (A->rows < A->columns)
572  {
573  printf("error: equation system is underdetermined in LinearAlgebra::SolveLinearLeastSquaresSVD\n");
574  return;
575  }
576 
577  CFloatMatrix A_(A->rows, A->columns);
579  LinearAlgebra::MulMatVec(&A_, b, x);
580 }
581 
583 {
584  if (A->columns != x->dimension || A->rows != b->dimension)
585  {
586  printf("error: A, b, x do not match LinearAlgebra::SolveLinearLeastSquaresSimple\n");
587  return false;
588  }
589 
590  if (A->rows < A->columns)
591  {
592  printf("error: equation system is underdetermined in LinearAlgebra::SolveLinearLeastSquaresSimple\n");
593  return false;
594  }
595 
596  CFloatMatrix A_(A->rows, A->columns);
597 
598  if (!CalculatePseudoInverseSimple(A, &A_))
599  return false;
600 
601  LinearAlgebra::MulMatVec(&A_, b, x);
602 
603  return true;
604 }
605 
606 void LinearAlgebra::CalculatePseudoInverseSVD(const CFloatMatrix *pInputMatrix, CFloatMatrix *pResultMatrix)
607 {
608  if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
609  {
610  printf("error: input and output matrix do not match LinearAlgebra::CalculatePseudoInverseSVD\n");
611  return;
612  }
613 
614  // algorithm:
615  // 1: compute U * W * V^T = A
616  // 2: compute W' = W^T with all non-zero values inverted
617  // 3: compute V * W' * U^T (=pseudoinverse of A)
618 
619  const CFloatMatrix *A = pInputMatrix;
620  const int m = pInputMatrix->rows;
621  const int n = pInputMatrix->columns;
622 
623  CFloatMatrix W(n, m), WT(m, n), UT(m, m), V(n, n);
624 
625  // calculate SVD
626  SVD(A, &W, &UT, &V, false, true, false);
627 
628  // transpose middle diagonal matrix
629  Transpose(&W, &WT);
630 
631  const int min = MY_MIN(m, n);
632 
633  int i;
634  float fThreshold = 0.0f;
635 
636  for (i = 0; i < min; i++)
637  fThreshold += WT(i, i);
638 
639  fThreshold *= 2 * FLT_EPSILON;
640 
641  // invert non-zero values (along diagonal)
642  for (i = 0; i < min; i++)
643  if (WT(i, i) < fThreshold)
644  WT(i, i) = 0.0f;
645  else
646  WT(i, i) = 1.0f / WT(i, i);
647 
648  // calculate pseudoinverse
649  CFloatMatrix temp(m, n);
650  MulMatMat(&V, &WT, &temp);
651  MulMatMat(&temp, &UT, pResultMatrix);
652 }
653 
655 {
656  if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
657  {
658  printf("error: input and output matrix do not match LinearAlgebra::CalculatePseudoInverseSimple\n");
659  return false;
660  }
661 
662  // algorithm:
663  // compute (A * A^T)^-1 * A^T
664 
665  const CFloatMatrix *A = pInputMatrix;
666  const int m = pInputMatrix->rows;
667  const int n = pInputMatrix->columns;
668 
669  CFloatMatrix AT(m, n), ATA(n, n), ATA_inverted(n, n);
670 
671  Transpose(A, &AT);
672  SelfProduct(A, &ATA);
673 
674  if (!Invert(&ATA, &ATA_inverted))
675  return false;
676 
677  MulMatMat(&ATA_inverted, &AT, pResultMatrix);
678 
679  return true;
680 }
681 
682 void LinearAlgebra::PCA(const CFloatMatrix *pData, CFloatMatrix *pTransformationMatrix, CFloatMatrix *pTransformedData, int nTargetDimension)
683 {
684  if (nTargetDimension > pData->columns)
685  {
686  printf("error: target dimension is greater than number of columns in training data matrix in LinearAlgebra::PCA\n");
687  return;
688  }
689 
690  const int samples = pData->rows;
691  const int dimension = pData->columns;
692 
693  if (pTransformationMatrix->columns != dimension || pTransformationMatrix->rows != nTargetDimension ||
694  pTransformedData->columns != samples || pTransformedData->rows != nTargetDimension)
695  {
696  printf("error: input to LinearAlgebra::PCA does not match\n");
697  return;
698  }
699 
700  CFloatMatrix adjustedData(pData);
701  CFloatMatrix covarianceMatrix(dimension, dimension);
702  CFloatMatrix eigenValues(dimension, dimension);
703  CFloatMatrix eigenVectors(dimension, dimension);
704 
705  //printf("info: subtracting mean from columns...\n");
706  SubtractMeanFromColumns(pData, &adjustedData);
707 
708  //printf("info: calculating covariance matrix...\n");
709  SelfProduct(&adjustedData, &covarianceMatrix);
710 
711  //printf("info: calculating SVD on %ix%i matrix...\n", dimension, dimension);
712  SVD(&covarianceMatrix, &eigenValues, &eigenVectors, 0, true, true);
713 
714  //printf("info: SVD calculated\n");
715 
716  for (int i = 0, offset = 0; i < nTargetDimension; i++)
717  {
718  for (int j = 0; j < dimension; j++)
719  {
720  pTransformationMatrix->data[offset] = eigenVectors.data[i * dimension + j];
721  offset++;
722  }
723  }
724 
725  MulMatMat(pTransformationMatrix, pData, pTransformedData, true);
726 }
727 
728 void LinearAlgebra::PCA(const CFloatMatrix *pData, CFloatMatrix *pTransformationMatrix, CFloatMatrix *pEigenValues)
729 {
730  const int dimension = pData->columns;
731 
732  if (pTransformationMatrix->columns != dimension || pTransformationMatrix->rows != dimension || pEigenValues->columns != 1 || pEigenValues->rows != dimension)
733  {
734  printf("error: input to LinearAlgebra::PCA does not match\n");
735  return;
736  }
737 
738  CFloatMatrix adjustedData(pData);
739  CFloatMatrix covarianceMatrix(dimension, dimension);
740  CFloatMatrix eigenValues(dimension, dimension);
741  CFloatMatrix eigenVectors(dimension, dimension);
742 
743  //printf("info: subtracting mean from columns...\n");
744  SubtractMeanFromColumns(pData, &adjustedData);
745 
746  //printf("info: calculating covariance matrix...\n");
747  SelfProduct(&adjustedData, &covarianceMatrix);
748 
749  //printf("info: calculating SVD on %ix%i matrix...\n", dimension, dimension);
750  SVD(&covarianceMatrix, &eigenValues, pTransformationMatrix, 0, true, true);
751 
752  //printf("info: SVD calculated\n");
753 
754  for (int i = 0; i < dimension; i++)
755  pEigenValues->data[i] = eigenValues.data[i * dimension + i];
756 }
757 
758 bool LinearAlgebra::Invert(const CFloatMatrix *pInputMatrix, CFloatMatrix *pResultMatrix)
759 {
760  if (pInputMatrix->data == pResultMatrix->data)
761  {
762  printf("error: pInputMatrix and pResultMatrix may not point to the same data in LinearAlgebra::Invert\n");
763  return false;
764  }
765 
766  if (pInputMatrix->rows != pInputMatrix->columns)
767  {
768  printf("error: input matrix must be square matrix for LinearAlgebra::Invert\n");
769  return false;
770  }
771 
772  if (pInputMatrix->columns != pResultMatrix->columns || pInputMatrix->rows != pResultMatrix->rows)
773  {
774  printf("error: input and output matrix do not match LinearAlgebra::Invert\n");
775  return false;
776  }
777 
778  const int n = pInputMatrix->columns;
779  int i;
780 
781  CFloatMatrix copiedMatrix(pInputMatrix);
782  CFloatMatrix tempMatrix(pInputMatrix);
783  ImageProcessor::CopyMatrix(pInputMatrix, &copiedMatrix);
784 
785  ImageProcessor::Zero(&tempMatrix);
786  for (i = 0; i < n; i++)
787  tempMatrix[i][i] = 1;
788 
789  int *pPivotRows = new int[n];
790  for (i = 0; i < n; i++)
791  pPivotRows[i] = 0;
792 
793  // invert by gauss elimination
794  for (i = 0; i < n; i++)
795  {
796  int j, nPivotColumn = 0;
797 
798  float *helper1 = copiedMatrix[i];
799  float *helper2 = tempMatrix[i];
800 
801  // determine pivot element
802  float max = 0;
803  for (j = 0; j < n; j++)
804  if (fabsf(helper1[j]) > max)
805  {
806  max = fabsf(helper1[j]);
807  nPivotColumn = j;
808  }
809 
810  pPivotRows[nPivotColumn] = i;
811 
812  const float fPivotElement = copiedMatrix[i][nPivotColumn];
813 
814  if (fabsf(fPivotElement) < 0.00001f)
815  {
816  //printf("error: input matrix is not regular for LinearAlgebra::Invert\n");
817  delete [] pPivotRows;
818  return false;
819  }
820 
821  const float fFactor = 1.0f / fPivotElement;
822 
823  for (j = 0; j < n; j++)
824  {
825  helper1[j] *= fFactor;
826  helper2[j] *= fFactor;
827  }
828 
829  for (j = 0; j < n; j++)
830  {
831  if (i != j)
832  {
833  const float v = copiedMatrix[j][nPivotColumn];
834  int k;
835 
836  helper1 = copiedMatrix[j];
837  helper2 = copiedMatrix[i];
838  for (k = 0; k < n; k++)
839  helper1[k] -= v * helper2[k];
840  helper1[nPivotColumn] = 0; // explicitly set to zero
841 
842  helper1 = tempMatrix[j];
843  helper2 = tempMatrix[i];
844  for (k = 0; k < n; k++)
845  helper1[k] -= v * helper2[k];
846  }
847  }
848  }
849 
850  // copy result rows in pivot order
851  for (i = 0; i < n; i++)
852  {
853  float *helper1 = (*pResultMatrix)[i];
854  const float *helper2 = tempMatrix[pPivotRows[i]];
855 
856  for (int j = 0; j < n; j++)
857  helper1[j] = helper2[j];
858  }
859 
860  delete [] pPivotRows;
861 
862  return true;
863 }
864 
866 {
867  memset(pMatrix->data, 0, pMatrix->columns * pMatrix->rows * sizeof(float));
868 }
869 
871 {
872  memset(pVector->data, 0, pVector->dimension * sizeof(float));
873 }
874 
875 
876 
877 
878 
879 // copy & paste implementation for CDoubleMatrix and CDoubleVector
880 // not nice, but i don't like templates.
881 
882 void LinearAlgebra::SelfProduct(const CDoubleMatrix *pMatrix, CDoubleMatrix *pResultMatrix, bool AAT)
883 {
884  if (
885  (AAT && (pResultMatrix->columns != pMatrix->rows || pResultMatrix->rows != pMatrix->rows)) ||
886  (!AAT && (pResultMatrix->columns != pMatrix->columns || pResultMatrix->rows != pMatrix->columns))
887  )
888  {
889  printf("error: matrix dimensions do not match for LinearAlgebra::SelfProduct\n");
890  return;
891  }
892 
893  if (!AAT)
894  {
895  CDoubleMatrix *pTransposedMatrix = new CDoubleMatrix(pMatrix->rows, pMatrix->columns);
896  Transpose(pMatrix, pTransposedMatrix);
897  pMatrix = pTransposedMatrix;
898  }
899 
900  const int columns = pMatrix->columns;
901  const int rows = pMatrix->rows;
902 
903  const double *data = pMatrix->data;
904  double *result = pResultMatrix->data;
905 
906  if (data != result)
907  {
908  for (int i = 0, input_offset1 = 0; i < rows; i++, input_offset1 += columns)
909  {
910  for (int j = i, input_offset2 = input_offset1; j < rows; j++, input_offset2 += columns)
911  {
912  const double *data1 = data + input_offset1;
913  const double *data2 = data + input_offset2;
914  double sum = 0;
915 
916  for (int k = 0; k < columns; k++)
917  sum += data1[k] * data2[k];
918 
919  result[i * rows + j] = result[j * rows + i] = sum;
920  }
921  }
922  }
923  else
924  {
925  CDoubleMatrix temp(pResultMatrix);
926  double *temp_data = temp.data;
927 
928  for (int i = 0, input_offset1 = 0; i < rows; i++, input_offset1 += columns)
929  {
930  for (int j = i, input_offset2 = input_offset1; j < rows; j++, input_offset2 += columns)
931  {
932  const double *data1 = data + input_offset1;
933  const double *data2 = data + input_offset2;
934  double sum = 0;
935 
936  for (int k = 0; k < columns; k++)
937  sum += data1[k] * data2[k];
938 
939  temp_data[i * rows + j] = temp_data[j * rows + i] = sum;
940  }
941  }
942 
943  memcpy(pResultMatrix->data, temp_data, pResultMatrix->rows * pResultMatrix->columns * sizeof(double));
944  }
945 
946  if (!AAT)
947  delete pMatrix;
948 }
949 
950 void LinearAlgebra::MulMatMat(const CDoubleMatrix *A, const CDoubleMatrix *B, CDoubleMatrix *pResultMatrix, bool bTransposeB)
951 {
952  if (!bTransposeB && (A->columns != B->rows || pResultMatrix->columns != B->columns || pResultMatrix->rows != A->rows))
953  {
954  printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebra::Multiply\n");
955  return;
956  }
957 
958  if (bTransposeB && (A->columns != B->columns || pResultMatrix->columns != B->rows || pResultMatrix->rows != A->rows))
959  {
960  printf("error: matrices A, B, and pResultMatrix do not satisfy requirements for LinearAlgebra::Multiply\n");
961  return;
962  }
963 
964  const double *data1 = A->data;
965  const double *data2 = B->data;
966  double *result = pResultMatrix->data;
967 
968  const int nSize = pResultMatrix->columns * pResultMatrix->rows;
969 
970  if (bTransposeB)
971  {
972  const int rowsA = A->rows;
973  const int rowsB = B->rows;
974  const int columns = A->columns;
975 
976  if (data1 != result && data2 != result)
977  {
978  for (int i = 0, input_offset1 = 0, output_offset = 0; i < rowsA; i++, input_offset1 += columns)
979  {
980  for (int j = 0, input_offset2 = input_offset1; j < rowsB; j++, input_offset2 += columns, output_offset++)
981  {
982  const double *data1_ = data1 + input_offset1;
983  const double *data2_ = data2 + input_offset2;
984  double sum = 0;
985 
986  for (int k = 0; k < columns; k++)
987  sum += data1_[k] * data2_[k];
988 
989  result[output_offset] = sum;
990  }
991  }
992  }
993  else
994  {
995  CDoubleMatrix temp(pResultMatrix);
996  double *temp_data = temp.data;
997 
998  int l;
999 
1000  for (l = 0; l < nSize; l++)
1001  temp_data[l] = 0;
1002 
1003  for (int i = 0, input_offset1 = 0, output_offset = 0; i < rowsA; i++, input_offset1 += columns)
1004  {
1005  for (int j = 0, input_offset2 = input_offset1; j < rowsB; j++, input_offset2 += columns, output_offset++)
1006  {
1007  const double *data1_ = data1 + input_offset1;
1008  const double *data2_ = data2 + input_offset2;
1009  double sum = 0;
1010 
1011  for (int k = 0; k < columns; k++)
1012  sum += data1_[k] * data2_[k];
1013 
1014  temp_data[output_offset] = sum;
1015  }
1016  }
1017 
1018  for (l = 0; l < nSize; l++)
1019  result[l] = temp_data[l];
1020  }
1021  }
1022  else
1023  {
1024  const int i_max = A->rows;
1025  const int j_max = B->columns;
1026  const int k_max = A->columns;
1027 
1028  // not optimized yet
1029  if (data1 != result && data2 != result)
1030  {
1031  for (int l = 0; l < nSize; l++)
1032  result[l] = 0;
1033 
1034  for (int i = 0, input1_offset = 0; i < i_max; i++)
1035  {
1036  const int result_offset_start = i * j_max;
1037 
1038  for (int k = 0, input2_offset = 0; k < k_max; k++, input1_offset++)
1039  for (int j = 0, result_offset = result_offset_start; j < j_max; j++, result_offset++, input2_offset++)
1040  result[result_offset] += data1[input1_offset] * data2[input2_offset];
1041  }
1042  }
1043  else
1044  {
1045  CDoubleMatrix temp(pResultMatrix);
1046  double *temp_data = temp.data;
1047 
1048  int l;
1049 
1050  for (l = 0; l < nSize; l++)
1051  temp_data[l] = 0;
1052 
1053  for (int i = 0, input1_offset = 0; i < i_max; i++)
1054  {
1055  const int result_offset_start = i * j_max;
1056 
1057  for (int k = 0, input2_offset = 0; k < k_max; k++, input1_offset++)
1058  for (int j = 0, result_offset = result_offset_start; j < j_max; j++, result_offset++, input2_offset++)
1059  temp_data[result_offset] += data1[input1_offset] * data2[input2_offset];
1060  }
1061 
1062  for (l = 0; l < nSize; l++)
1063  result[l] = temp_data[l];
1064  }
1065  }
1066 }
1067 
1068 void LinearAlgebra::Transpose(const CDoubleMatrix *pMatrix, CDoubleMatrix *pResultMatrix)
1069 {
1070  if (pMatrix->columns != pResultMatrix->rows || pMatrix->rows != pResultMatrix->columns)
1071  {
1072  printf("error: input and output matrix do not match LinearAlgebra::Transpose\n");
1073  return;
1074  }
1075 
1076  const int rows = pMatrix->rows;
1077  const int columns = pMatrix->columns;
1078  const double *input = pMatrix->data;
1079  double *output = pResultMatrix->data;
1080 
1081  if (input != output)
1082  {
1083  for (int i = 0, input_offset = 0; i < rows; i++)
1084  for (int j = 0, output_offset = i; j < columns; j++, input_offset++, output_offset += rows)
1085  output[output_offset] = input[input_offset];
1086  }
1087  else
1088  {
1089  // not optimized yet
1090  CDoubleMatrix temp(pResultMatrix);
1091  double *temp_data = temp.data;
1092 
1093  int i, input_offset;
1094 
1095  for (i = 0, input_offset = 0; i < rows; i++)
1096  for (int j = 0, output_offset = i; j < columns; j++, input_offset++, output_offset += rows)
1097  temp_data[output_offset] = input[input_offset];
1098 
1099  const int nSize = rows * columns;
1100 
1101  for (i = 0; i < nSize; i++)
1102  output[i] = temp_data[i];
1103  }
1104 }
1105 
1106 void LinearAlgebra::MulMatVec(const CDoubleMatrix *pMatrix, const CDoubleVector *pVector, CDoubleVector *pResultVector)
1107 {
1108  if (pMatrix->columns != pVector->dimension || pMatrix->rows != pResultVector->dimension)
1109  {
1110  printf("error: input matrix and vector and output vector do not match for CDoubleMatrix::Multiply\n");
1111  return;
1112  }
1113 
1114  const int rows = pMatrix->rows;
1115  const int columns = pMatrix->columns;
1116  const double *data_m = pMatrix->data;
1117  const double *data_v = pVector->data;
1118  double *data_r = pResultVector->data;
1119 
1120  if (data_r != data_v)
1121  {
1122  for (int i = 0, offset = 0; i < rows; i++)
1123  {
1124  double sum = 0.0f;
1125 
1126  for (int j = 0; j < columns; j++, offset++)
1127  sum += data_m[offset] * data_v[j];
1128 
1129  data_r[i] = sum;
1130  }
1131  }
1132  else
1133  {
1134  double *temp = new double[rows];
1135  int i, offset;
1136 
1137  for (i = 0, offset = 0; i < rows; i++)
1138  {
1139  double sum = 0.0f;
1140 
1141  for (int j = 0; j < columns; j++, offset++)
1142  sum += data_m[offset] * data_v[j];
1143 
1144  temp[i] = sum;
1145  }
1146 
1147  for (i = 0; i < rows; i++)
1148  data_r[i] = temp[i];
1149 
1150  delete [] temp;
1151  }
1152 }
1153 
1154 void LinearAlgebra::MulMatVec(const CDoubleMatrix *pMatrix, const CDoubleVector *pVector1, const CDoubleVector *pVector2, CDoubleVector *pResultVector)
1155 {
1156  MulMatVec(pMatrix, pVector1, pResultVector);
1157  AddToVec(pResultVector, pVector2);
1158 }
1159 
1160 void LinearAlgebra::AddMatMat(const CDoubleMatrix *pMatrix1, const CDoubleMatrix *pMatrix2, CDoubleMatrix *pResultMatrix)
1161 {
1162  if (pMatrix1->rows != pMatrix2->rows || pMatrix1->columns != pMatrix2->columns ||
1163  pMatrix1->rows != pResultMatrix->rows || pMatrix1->columns != pResultMatrix->columns)
1164  {
1165  printf("error: matrix dimensions do not match in LinearAlgebra::AddMatMat\n");
1166  return;
1167  }
1168 
1169  const int nSize = pMatrix1->rows * pMatrix1->columns;
1170  const double *data1 = pMatrix1->data;
1171  const double *data2 = pMatrix2->data;
1172  double *result = pResultMatrix->data;
1173 
1174  for (int i = 0; i < nSize; i++)
1175  result[i] = data1[i] + data2[i];
1176 }
1177 
1178 void LinearAlgebra::SubtractMatMat(const CDoubleMatrix *pMatrix1, const CDoubleMatrix *pMatrix2, CDoubleMatrix *pResultMatrix)
1179 {
1180  if (pMatrix1->rows != pMatrix2->rows || pMatrix1->columns != pMatrix2->columns ||
1181  pMatrix1->rows != pResultMatrix->rows || pMatrix1->columns != pResultMatrix->columns)
1182  {
1183  printf("error: matrix dimensions do not match in LinearAlgebra::SubtractMatMat\n");
1184  return;
1185  }
1186 
1187  const int nSize = pMatrix1->rows * pMatrix1->columns;
1188  const double *data1 = pMatrix1->data;
1189  const double *data2 = pMatrix2->data;
1190  double *result = pResultMatrix->data;
1191 
1192  for (int i = 0; i < nSize; i++)
1193  result[i] = data1[i] - data2[i];
1194 }
1195 
1196 void LinearAlgebra::AddVecVec(const CDoubleVector *pVector1, const CDoubleVector *pVector2, CDoubleVector *pResultVector)
1197 {
1198  if (pVector1->dimension != pVector2->dimension || pVector1->dimension != pResultVector->dimension)
1199  {
1200  printf("error: vector dimensions do not match in LinearAlgebra::AddVecVec\n");
1201  return;
1202  }
1203 
1204  const int nDimension = pVector1->dimension;
1205  const double *data1 = pVector1->data;
1206  const double *data2 = pVector2->data;
1207  double *result = pResultVector->data;
1208 
1209  for (int i = 0; i < nDimension; i++)
1210  result[i] = data1[i] + data2[i];
1211 }
1212 
1213 void LinearAlgebra::SubtractVecVec(const CDoubleVector *pVector1, const CDoubleVector *pVector2, CDoubleVector *pResultVector)
1214 {
1215  if (pVector1->dimension != pVector2->dimension || pVector1->dimension != pResultVector->dimension)
1216  {
1217  printf("error: vector dimensions do not match in LinearAlgebra::SubtractVecVec\n");
1218  return;
1219  }
1220 
1221  const int nDimension = pVector1->dimension;
1222  const double *data1 = pVector1->data;
1223  const double *data2 = pVector2->data;
1224  double *result = pResultVector->data;
1225 
1226  for (int i = 0; i < nDimension; i++)
1227  result[i] = data1[i] - data2[i];
1228 }
1229 
1230 void LinearAlgebra::AddToMat(CDoubleMatrix *pMatrix, const CDoubleMatrix *pMatrixToAdd)
1231 {
1232  if (pMatrix->rows != pMatrixToAdd->rows || pMatrix->columns != pMatrixToAdd->columns)
1233  {
1234  printf("error: matrix dimensions do not match in LinearAlgebra::AddToMat\n");
1235  return;
1236  }
1237 
1238  const int nSize = pMatrix->rows * pMatrix->columns;
1239  double *data = pMatrix->data;
1240  const double *data_to_add = pMatrixToAdd->data;
1241 
1242  for (int i = 0; i < nSize; i++)
1243  data[i] += data_to_add[i];
1244 }
1245 
1247 {
1248  if (pMatrix->rows != pMatrixToAdd->rows || pMatrix->columns != pMatrixToAdd->columns)
1249  {
1250  printf("error: matrix dimensions do not match in LinearAlgebra::SubtractFromMat\n");
1251  return;
1252  }
1253 
1254  const int nSize = pMatrix->rows * pMatrix->columns;
1255  double *data = pMatrix->data;
1256  const double *data_to_subtract = pMatrixToAdd->data;
1257 
1258  for (int i = 0; i < nSize; i++)
1259  data[i] -= data_to_subtract[i];
1260 }
1261 
1262 void LinearAlgebra::AddToVec(CDoubleVector *pVector, const CDoubleVector *pVectorToAdd)
1263 {
1264  if (pVector->dimension != pVectorToAdd->dimension)
1265  {
1266  printf("error: vector dimensions do not match in LinearAlgebra::AddToVec\n");
1267  return;
1268  }
1269 
1270  const int nDimension = pVector->dimension;
1271  double *data = pVector->data;
1272  const double *data_to_add = pVectorToAdd->data;
1273 
1274  for (int i = 0; i < nDimension; i++)
1275  data[i] += data_to_add[i];
1276 }
1277 
1278 void LinearAlgebra::SubtractFromVec(CDoubleVector *pVector, const CDoubleVector *pVectorToSubtract)
1279 {
1280  if (pVector->dimension != pVectorToSubtract->dimension)
1281  {
1282  printf("error: vector dimensions do not match in LinearAlgebra::SubtractFromVec\n");
1283  return;
1284  }
1285 
1286  const int nDimension = pVector->dimension;
1287  double *data = pVector->data;
1288  const double *data_to_subtract = pVectorToSubtract->data;
1289 
1290  for (int i = 0; i < nDimension; i++)
1291  data[i] -= data_to_subtract[i];
1292 }
1293 
1294 
1296 {
1297  if (pMatrix->columns != pResultMatrix->columns || pMatrix->rows != pResultMatrix->rows)
1298  return;
1299 
1300  const int columns = pMatrix->columns;
1301  const int rows = pMatrix->rows;
1302  const int max = rows * columns;
1303  const double *data = pMatrix->data;
1304  double *output = pResultMatrix->data;
1305 
1306  for (int i = 0; i < columns; i++)
1307  {
1308  double mean = 0;
1309  int j;
1310 
1311  for (j = 0; j < max; j += columns)
1312  mean += data[j];
1313 
1314  mean /= rows;
1315 
1316  for (j = 0; j < max; j += columns)
1317  output[j] = data[j] - mean;
1318 
1319  data++;
1320  output++;
1321  }
1322 }
1323 
1325 {
1326  if (pMatrix->columns != pResultMatrix->columns || pMatrix->rows != pResultMatrix->rows)
1327  return;
1328 
1329  const int columns = pMatrix->columns;
1330  const int rows = pMatrix->rows;
1331  const double *data = pMatrix->data;
1332  double *output = pResultMatrix->data;
1333 
1334  for (int i = 0; i < rows; i++)
1335  {
1336  double mean = 0;
1337  int j;
1338 
1339  for (j = 0; j < columns; j++)
1340  mean += data[j];
1341 
1342  mean /= columns;
1343 
1344  for (j = 0; j < columns; j++)
1345  output[j] = data[j] - mean;
1346 
1347  data += columns;
1348  output += columns;
1349  }
1350 }
1351 
1352 bool LinearAlgebra::Invert(const CDoubleMatrix *pInputMatrix, CDoubleMatrix *pResultMatrix)
1353 {
1354  if (pInputMatrix->data == pResultMatrix->data)
1355  {
1356  printf("error: pInputMatrix and pResultMatrix may not point to the same data in LinearAlgebra::Invert\n");
1357  return false;
1358  }
1359 
1360  if (pInputMatrix->rows != pInputMatrix->columns)
1361  {
1362  printf("error: input matrix must be square matrix for LinearAlgebra::Invert\n");
1363  return false;
1364  }
1365 
1366  if (pInputMatrix->columns != pResultMatrix->columns || pInputMatrix->rows != pResultMatrix->rows)
1367  {
1368  printf("error: input and output matrix do not match LinearAlgebra::Invert\n");
1369  return false;
1370  }
1371 
1372  const int n = pInputMatrix->columns;
1373  int i;
1374 
1375  CDoubleMatrix copiedMatrix(pInputMatrix);
1376  CDoubleMatrix tempMatrix(pInputMatrix);
1377  ImageProcessor::CopyMatrix(pInputMatrix, &copiedMatrix);
1378 
1379  ImageProcessor::Zero(&tempMatrix);
1380  for (i = 0; i < n; i++)
1381  tempMatrix[i][i] = 1;
1382 
1383  int *pPivotRows = new int[n];
1384  for (i = 0; i < n; i++)
1385  pPivotRows[i] = 0;
1386 
1387  // invert by gauss elimination
1388  for (i = 0; i < n; i++)
1389  {
1390  int j, nPivotColumn = 0;
1391 
1392  double *helper1 = copiedMatrix[i];
1393  double *helper2 = tempMatrix[i];
1394 
1395  // determine pivot element
1396  double max = 0;
1397  for (j = 0; j < n; j++)
1398  if (fabs(helper1[j]) > max)
1399  {
1400  max = fabs(helper1[j]);
1401  nPivotColumn = j;
1402  }
1403 
1404  pPivotRows[nPivotColumn] = i;
1405 
1406  const double dPivotElement = copiedMatrix[i][nPivotColumn];
1407 
1408  if (fabs(dPivotElement) < 0.00001)
1409  {
1410  //printf("error: input matrix is not regular for LinearAlgebra::Invert\n");
1411  delete [] pPivotRows;
1412  return false;
1413  }
1414 
1415  const double dFactor = 1.0 / dPivotElement;
1416 
1417  for (j = 0; j < n; j++)
1418  {
1419  helper1[j] *= dFactor;
1420  helper2[j] *= dFactor;
1421  }
1422 
1423  for (j = 0; j < n; j++)
1424  {
1425  if (i != j)
1426  {
1427  const double v = copiedMatrix[j][nPivotColumn];
1428  int k;
1429 
1430  helper1 = copiedMatrix[j];
1431  helper2 = copiedMatrix[i];
1432  for (k = 0; k < n; k++)
1433  helper1[k] -= v * helper2[k];
1434  helper1[nPivotColumn] = 0; // explicitly set to zero
1435 
1436  helper1 = tempMatrix[j];
1437  helper2 = tempMatrix[i];
1438  for (k = 0; k < n; k++)
1439  helper1[k] -= v * helper2[k];
1440  }
1441  }
1442  }
1443 
1444  // copy result rows in pivot order
1445  for (i = 0; i < n; i++)
1446  {
1447  double *helper1 = (*pResultMatrix)[i];
1448  const double *helper2 = tempMatrix[pPivotRows[i]];
1449 
1450  for (int j = 0; j < n; j++)
1451  helper1[j] = helper2[j];
1452  }
1453 
1454  delete [] pPivotRows;
1455 
1456  return true;
1457 }
1458 
1460 {
1461  if (A->columns != x->dimension)
1462  {
1463  printf("error: A, x do not match LinearAlgebra::SolveLinearLeastSquaresHomogeneousSVD\n");
1464  return;
1465  }
1466 
1467  if (A->rows < A->columns)
1468  {
1469  printf("error: equation system is underdetermined in LinearAlgebra::SolveLinearLeastSquaresHomogeneousSVD\n");
1470  return;
1471  }
1472 
1473  const int m = A->rows;
1474  const int n = A->columns;
1475 
1476  CDoubleMatrix W(n, m), V(n, n);
1477 
1478  SVD(A, &W, 0, &V, false, false, false);
1479 
1480  for (int i = 0, offset = n - 1; i < n; i++, offset += n)
1481  x->data[i] = V.data[offset];
1482 }
1483 
1485 {
1486  if (A->columns != x->dimension || A->rows != b->dimension)
1487  {
1488  printf("error: A, b, x do not match LinearAlgebra::SolveLinearLeastSquaresSVD\n");
1489  return;
1490  }
1491 
1492  if (A->rows < A->columns)
1493  {
1494  printf("error: equation system is underdetermined in LinearAlgebra::SolveLinearLeastSquaresSVD\n");
1495  return;
1496  }
1497 
1498  CDoubleMatrix A_(A->rows, A->columns);
1499  CalculatePseudoInverseSVD(A, &A_);
1500  MulMatVec(&A_, b, x);
1501 }
1502 
1504 {
1505  if (A->columns != x->dimension || A->rows != b->dimension)
1506  {
1507  printf("error: A, b, x do not match LinearAlgebra::SolveLinearLeastSquaresSimple\n");
1508  return false;
1509  }
1510 
1511  if (A->rows < A->columns)
1512  {
1513  printf("error: equation system is underdetermined in LinearAlgebra::SolveLinearLeastSquaresSimple\n");
1514  return false;
1515  }
1516 
1517  CDoubleMatrix A_(A->rows, A->columns);
1518 
1519  if (!CalculatePseudoInverseSimple(A, &A_))
1520  return false;
1521 
1522  MulMatVec(&A_, b, x);
1523 
1524  return true;
1525 }
1526 
1528 {
1529  if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
1530  {
1531  printf("error: input and output matrix do not match LinearAlgebra::CalculatePseudoInverseSVD\n");
1532  return;
1533  }
1534 
1535  // algorithm:
1536  // 1: compute U * W * V^T = A
1537  // 2: compute W' = W^T with all non-zero values inverted
1538  // 3: compute V * W' * U^T (=pseudoinverse of A)
1539 
1540  const CDoubleMatrix *A = pInputMatrix;
1541  const int m = pInputMatrix->rows;
1542  const int n = pInputMatrix->columns;
1543 
1544  CDoubleMatrix W(n, m), WT(m, n), UT(m, m), V(n, n);
1545 
1546  // calculate SVD
1547  SVD(A, &W, &UT, &V, false, true, false);
1548 
1549  // transpose middle diagonal matrix
1550  Transpose(&W, &WT);
1551 
1552  const int min = MY_MIN(m, n);
1553 
1554  int i;
1555  double dThreshold = 0.0;
1556 
1557  for(i = 0; i < min; i++)
1558  dThreshold += WT(i, i);
1559 
1560  dThreshold *= 2 * DBL_EPSILON;
1561 
1562  // invert non-zero values (along diagonal)
1563  for (i = 0; i < min; i++)
1564  if (WT(i, i) < dThreshold)
1565  WT(i, i) = 0;
1566  else
1567  WT(i, i) = 1.0 / WT(i, i);
1568 
1569  // calculate pseudoinverse
1570  CDoubleMatrix temp(m, n);
1571  MulMatMat(&V, &WT, &temp);
1572  MulMatMat(&temp, &UT, pResultMatrix);
1573 }
1574 
1576 {
1577  if (pInputMatrix->columns != pResultMatrix->rows || pInputMatrix->rows != pResultMatrix->columns)
1578  {
1579  printf("error: input and output matrix do not match LinearAlgebra::CalculatePseudoInverseSimple\n");
1580  return false;
1581  }
1582 
1583  // algorithm:
1584  // compute (A * A^T)^-1 * A^T
1585 
1586  const CDoubleMatrix *A = pInputMatrix;
1587  const int m = pInputMatrix->rows;
1588  const int n = pInputMatrix->columns;
1589 
1590  CDoubleMatrix AT(m, n), ATA(n, n), ATA_inverted(n, n);
1591 
1592  Transpose(A, &AT);
1593  SelfProduct(A, &ATA);
1594 
1595  if (!Invert(&ATA, &ATA_inverted))
1596  return false;
1597 
1598  MulMatMat(&ATA_inverted, &AT, pResultMatrix);
1599 
1600  return true;
1601 }
1602 
1604 {
1605  memset(pVector->data, 0, pVector->dimension * sizeof(double));
1606 }
1607 
1609 {
1610  memset(pMatrix->data, 0, pMatrix->columns * pMatrix->rows * sizeof(double));
1611 }
1612 
1613 
1614 
1615 
1616 bool LinearAlgebra::DetermineAffineTransformation(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD)
1617 {
1618  if (nPoints < 3)
1619  {
1620  printf("error: not enough input point pairs for LinearAlgebra::DetermineAffineTransformation (must be at least 3)\n");
1621  return false;
1622  }
1623 
1624  CFloatMatrix M(6, 2 * nPoints);
1625  CFloatVector b(2 * nPoints);
1626 
1627  float *data = M.data;
1628 
1629  for (int i = 0, offset = 0; i < nPoints; i++, offset += 12)
1630  {
1631  data[offset] = pSourcePoints[i].x;
1632  data[offset + 1] = pSourcePoints[i].y;
1633  data[offset + 2] = 1;
1634  data[offset + 3] = 0;
1635  data[offset + 4] = 0;
1636  data[offset + 5] = 0;
1637 
1638  data[offset + 6] = 0;
1639  data[offset + 7] = 0;
1640  data[offset + 8] = 0;
1641  data[offset + 9] = pSourcePoints[i].x;
1642  data[offset + 10] = pSourcePoints[i].y;
1643  data[offset + 11] = 1;
1644 
1645  const int index = 2 * i;
1646  b.data[index] = pTargetPoints[i].x;
1647  b.data[index + 1] = pTargetPoints[i].y;
1648  }
1649 
1650  CFloatVector x(6);
1651 
1652  for (int i = 0; i < 6; i++)
1653  x.data[i] = 0.0f;
1654 
1655  bool bRet = true;
1656 
1657  if (bUseSVD)
1658  SolveLinearLeastSquaresSVD(&M, &b, &x);
1659  else
1660  bRet = SolveLinearLeastSquaresSimple(&M, &b, &x);
1661 
1662  if (!bRet)
1663  return false;
1664 
1665  Math3d::SetMat(A, x.data[0], x.data[1], x.data[2], x.data[3], x.data[4], x.data[5], 0.0f, 0.0f, 1.0f);
1666 
1667  return true;
1668 }
1669 
1670 bool LinearAlgebra::DetermineHomography(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD)
1671 {
1672  if (nPoints < 4)
1673  {
1674  printf("error: not enough input point pairs for LinearAlgebra::DetermineHomography (must be at least 4)\n");
1675  return false;
1676  }
1677 
1678  // this least squares problem becomes numerically instable when
1679  // using float instead of double!!
1680  CDoubleMatrix M(8, 2 * nPoints);
1681  CDoubleVector b(2 * nPoints);
1682 
1683  double *data = M.data;
1684 
1685  for (int i = 0, offset = 0; i < nPoints; i++, offset += 16)
1686  {
1687  data[offset] = pSourcePoints[i].x;
1688  data[offset + 1] = pSourcePoints[i].y;
1689  data[offset + 2] = 1;
1690  data[offset + 3] = 0;
1691  data[offset + 4] = 0;
1692  data[offset + 5] = 0;
1693  data[offset + 6] = -pSourcePoints[i].x * pTargetPoints[i].x;
1694  data[offset + 7] = -pSourcePoints[i].y * pTargetPoints[i].x;
1695 
1696  data[offset + 8] = 0;
1697  data[offset + 9] = 0;
1698  data[offset + 10] = 0;
1699  data[offset + 11] = pSourcePoints[i].x;
1700  data[offset + 12] = pSourcePoints[i].y;
1701  data[offset + 13] = 1;
1702  data[offset + 14] = -pSourcePoints[i].x * pTargetPoints[i].y;
1703  data[offset + 15] = -pSourcePoints[i].y * pTargetPoints[i].y;
1704 
1705  const int index = 2 * i;
1706  b.data[index] = pTargetPoints[i].x;
1707  b.data[index + 1] = pTargetPoints[i].y;
1708  }
1709 
1710  CDoubleVector x(8);
1711 
1712  for (int i = 0; i < 8; i++)
1713  x.data[i] = 0.0;
1714 
1715  bool bRet = true;
1716 
1717  if (bUseSVD)
1718  SolveLinearLeastSquaresSVD(&M, &b, &x);
1719  else
1720  bRet = SolveLinearLeastSquaresSimple(&M, &b, &x);
1721 
1722  if (!bRet)
1723  return false;
1724 
1725  Math3d::SetMat(A, float(x.data[0]), float(x.data[1]), float(x.data[2]), float(x.data[3]), float(x.data[4]), float(x.data[5]), float(x.data[6]), float(x.data[7]), 1.0f);
1726 
1727  return true;
1728 }
void SubtractFromMat(CFloatMatrix *pMatrix, const CFloatMatrix *pMatrixToSubtract)
double * data
Definition: DoubleMatrix.h:85
bool DetermineHomography(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD=false)
Determines a homography based on a set of 2d-2d point correspondences.
float y
Definition: Math2d.h:84
GLenum GLsizei n
Definition: glext.h:4209
void AddToMat(CFloatMatrix *pMatrix, const CFloatMatrix *pMatrixToAdd)
void SolveLinearLeastSquaresHomogeneousSVD(const CFloatMatrix *A, CFloatVector *x)
bool Invert(const CByteImage *pInputImage, CByteImage *pOutputImage)
Calculates the inverted image of a CByteImage and writes the result to a CByteImage.
bool CalculatePseudoInverseSimple(const CFloatMatrix *pInputMatrix, CFloatMatrix *pResultMatrix)
GLintptr offset
Definition: glext.h:3389
void SolveLinearLeastSquaresSVD(const CFloatMatrix *A, const CFloatVector *b, CFloatVector *x)
Data structure for the representation of a vector of values of the data type double.
Definition: DoubleVector.h:54
void PCA(const CFloatMatrix *pData, CFloatMatrix *pTransformationMatrix, CFloatMatrix *pTransformedData, int nTargetDimension)
void SubtractFromVec(CFloatVector *pVector, const CFloatVector *pVectorToSubtract)
void AddVecVec(const CFloatVector *pVector1, const CFloatVector *pVector2, CFloatVector *pResultVector)
void SVD(const CFloatMatrix *A, CFloatMatrix *W, CFloatMatrix *U=0, CFloatMatrix *V=0, bool bAllowModifyA=false, bool bReturnUTransposed=false, bool bReturnVTransposed=false)
Definition: SVD.cpp:1660
GLenum GLint x
Definition: glext.h:3125
float x
Definition: Math2d.h:84
bool DetermineAffineTransformation(const Vec2d *pSourcePoints, const Vec2d *pTargetPoints, int nPoints, Mat3d &A, bool bUseSVD=false)
Determines an affine transformation based on a set of 2d-2d point correspondences.
GLuint index
Definition: glext.h:3500
bool CopyMatrix(const CFloatMatrix *pInputImage, CFloatMatrix *pOutputImage)
Copies one CFloatMatrix to another.
float * data
Definition: FloatVector.h:78
Data structure for the representation of a matrix of values of the data type float.
Definition: FloatMatrix.h:56
void SubtractMeanFromRows(const CFloatMatrix *pMatrix, CFloatMatrix *pResultMatrix)
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3129
void AddMatMat(const CFloatMatrix *pMatrix1, const CFloatMatrix *pMatrix2, CFloatMatrix *pResultMatrix)
void SubtractMeanFromColumns(const CFloatMatrix *pMatrix, CFloatMatrix *pResultMatrix)
void MulMatVec(const CFloatMatrix *pMatrix, const CFloatVector *pVector, CFloatVector *pResultVector)
float * data
Definition: FloatMatrix.h:91
bool Invert(const CFloatMatrix *pInputMatrix, CFloatMatrix *pResultMatrix)
double * data
Definition: DoubleVector.h:79
void MulMatMat(const CFloatMatrix *A, const CFloatMatrix *B, CFloatMatrix *pResultMatrix, bool bTransposeB=false)
GLubyte GLubyte b
Definition: glext.h:5166
void Zero(CFloatMatrix *pMatrix)
#define MY_MIN(a, b)
Definition: helpers.h:64
void CalculatePseudoInverseSVD(const CFloatMatrix *pInputMatrix, CFloatMatrix *pOutputMatrix)
Data structure for the representation of a vector of values of the data type float.
Definition: FloatVector.h:53
GLenum GLenum GLenum input
Definition: glext.h:5307
bool SolveLinearLeastSquaresSimple(const CFloatMatrix *A, const CFloatVector *b, CFloatVector *x)
const GLdouble * v
Definition: glext.h:3212
Data structure for the representation of a 2D vector.
Definition: Math2d.h:82
void SelfProduct(const CFloatMatrix *pMatrix, CFloatMatrix *pResultMatrix, bool AAT=false)
Data structure for the representation of a matrix of values of the data type double.
Definition: DoubleMatrix.h:54
void Transpose(const CFloatMatrix *pMatrix, CFloatMatrix *pResultMatrix)
void SubtractMatMat(const CFloatMatrix *pMatrix1, const CFloatMatrix *pMatrix2, CFloatMatrix *pResultMatrix)
void AddToVec(CFloatVector *pVector, const CFloatVector *pVectorToAdd)
void SubtractVecVec(const CFloatVector *pVector1, const CFloatVector *pVector2, CFloatVector *pResultVector)
void Zero(CByteImage *pImage, const MyRegion *pROI=0)
Sets all values in a CByteImage to zero.
void SetMat(Mat3d &matrix, float r1, float r2, float r3, float r4, float r5, float r6, float r7, float r8, float r9)
Definition: Math3d.cpp:257
Data structure for the representation of a 3x3 matrix.
Definition: Math3d.h:93


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Mon Dec 2 2019 03:47:28