Visual Servoing Platform  version 3.6.1 under development (2024-12-03)
vpMatrix_operations.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Stack matrix.
32  */
33 
34 #include <visp3/core/vpConfig.h>
35 #include <visp3/core/vpMatrix.h>
36 
37 #if defined(VISP_HAVE_SIMDLIB)
38 #include <Simd/SimdLib.h>
39 #endif
40 
41 BEGIN_VISP_NAMESPACE
42 
46 vpMatrix vpMatrix::t() const { return transpose(); }
47 
54 {
55  vpMatrix At;
56  transpose(At);
57  return At;
58 }
59 
66 {
67  At.resize(colNum, rowNum, false, false);
68 
69  const unsigned int val_16 = 16;
70  if ((rowNum <= val_16) || (colNum <= val_16)) {
71  for (unsigned int i = 0; i < rowNum; ++i) {
72  for (unsigned int j = 0; j < colNum; ++j) {
73  At[j][i] = (*this)[i][j];
74  }
75  }
76  }
77  else {
78 #if defined(VISP_HAVE_SIMDLIB)
79  SimdMatTranspose(data, rowNum, colNum, At.data);
80 #else
81  // https://stackoverflow.com/a/21548079
82  const int tileSize = 32;
83  for (unsigned int i = 0; i < rowNum; i += tileSize) {
84  for (unsigned int j = 0; j < colNum; ++j) {
85  for (unsigned int b = 0; ((b < static_cast<unsigned int>(tileSize)) && ((i + b) < rowNum)); ++b) {
86  At[j][i + b] = (*this)[i + b][j];
87  }
88  }
89  }
90 #endif
91  }
92 }
93 
103 {
104  if (A.colNum != v.getRows()) {
105  throw(vpException(vpException::dimensionError, "Cannot multiply a (%dx%d) matrix by a (%d) column vector",
106  A.getRows(), A.getCols(), v.getRows()));
107  }
108 
109  if (A.rowNum != w.rowNum) {
110  w.resize(A.rowNum, false);
111  }
112 
113  // If available use Lapack only for large matrices
114  bool useLapack = ((A.rowNum > vpMatrix::m_lapack_min_size) || (A.colNum > vpMatrix::m_lapack_min_size));
115 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
116  useLapack = false;
117 #endif
118 
119  if (useLapack) {
120 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
121  double alpha = 1.0;
122  double beta = 0.0;
123  char trans = 't';
124  int incr = 1;
125 
126  vpMatrix::blas_dgemv(trans, A.colNum, A.rowNum, alpha, A.data, A.colNum, v.data, incr, beta, w.data, incr);
127 #endif
128  }
129  else {
130  w = 0.0;
131  for (unsigned int j = 0; j < A.colNum; ++j) {
132  double vj = v[j]; // optimization em 5/12/2006
133  for (unsigned int i = 0; i < A.rowNum; ++i) {
134  w[i] += A.rowPtrs[i][j] * vj;
135  }
136  }
137  }
138 }
139 
140 //---------------------------------
141 // Matrix operations.
142 //---------------------------------
143 
153 void vpMatrix::mult2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
154 {
155  if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum)) {
156  C.resize(A.rowNum, B.colNum, false, false);
157  }
158 
159  if (A.colNum != B.rowNum) {
160  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (%dx%d) matrix", A.getRows(),
161  A.getCols(), B.getRows(), B.getCols()));
162  }
163 
164  // If available use Lapack only for large matrices
165  bool useLapack = ((A.rowNum > vpMatrix::m_lapack_min_size) || (A.colNum > vpMatrix::m_lapack_min_size) ||
166  (B.colNum > vpMatrix::m_lapack_min_size));
167 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
168  useLapack = false;
169 #endif
170 
171  if (useLapack) {
172 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
173  const double alpha = 1.0;
174  const double beta = 0.0;
175  const char trans = 'n';
176  vpMatrix::blas_dgemm(trans, trans, B.colNum, A.rowNum, A.colNum, alpha, B.data, B.colNum, A.data, A.colNum, beta,
177  C.data, B.colNum);
178 #endif
179  }
180  else {
181  // 5/12/06 some "very" simple optimization to avoid indexation
182  const unsigned int BcolNum = B.colNum;
183  const unsigned int BrowNum = B.rowNum;
184  double **BrowPtrs = B.rowPtrs;
185  for (unsigned int i = 0; i < A.rowNum; ++i) {
186  const double *rowptri = A.rowPtrs[i];
187  double *ci = C[i];
188  for (unsigned int j = 0; j < BcolNum; ++j) {
189  double s = 0;
190  for (unsigned int k = 0; k < BrowNum; ++k) {
191  s += rowptri[k] * BrowPtrs[k][j];
192  }
193  ci[j] = s;
194  }
195  }
196  }
197 }
198 
212 {
213  const unsigned int val_3 = 3;
214  if ((A.colNum != val_3) || (A.rowNum != val_3) || (B.colNum != val_3) || (B.rowNum != val_3)) {
216  "Cannot multiply (%dx%d) matrix by (%dx%d) matrix as a "
217  "rotation matrix",
218  A.getRows(), A.getCols(), B.getRows(), B.getCols()));
219  }
220  // 5/12/06 some "very" simple optimization to avoid indexation
221  const unsigned int BcolNum = B.colNum;
222  const unsigned int BrowNum = B.rowNum;
223  double **BrowPtrs = B.rowPtrs;
224  for (unsigned int i = 0; i < A.rowNum; ++i) {
225  const double *rowptri = A.rowPtrs[i];
226  double *ci = C[i];
227  for (unsigned int j = 0; j < BcolNum; ++j) {
228  double s = 0;
229  for (unsigned int k = 0; k < BrowNum; ++k) {
230  s += rowptri[k] * BrowPtrs[k][j];
231  }
232  ci[j] = s;
233  }
234  }
235 }
236 
250 {
251  const unsigned int val_4 = 4;
252  if ((A.colNum != val_4) || (A.rowNum != val_4) || (B.colNum != val_4) || (B.rowNum != val_4)) {
254  "Cannot multiply (%dx%d) matrix by (%dx%d) matrix as a "
255  "rotation matrix",
256  A.getRows(), A.getCols(), B.getRows(), B.getCols()));
257  }
258  // Considering perfMatrixMultiplication.cpp benchmark,
259  // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
260  // Lapack usage needs to be validated again.
261  // If available use Lapack only for large matrices.
262  // Using SSE2 doesn't speed up.
263  bool useLapack = ((A.rowNum > vpMatrix::m_lapack_min_size) || (A.colNum > vpMatrix::m_lapack_min_size) ||
264  (B.colNum > vpMatrix::m_lapack_min_size));
265 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
266  useLapack = false;
267 #endif
268 
269  if (useLapack) {
270 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
271  const double alpha = 1.0;
272  const double beta = 0.0;
273  const char trans = 'n';
274  vpMatrix::blas_dgemm(trans, trans, B.colNum, A.rowNum, A.colNum, alpha, B.data, B.colNum, A.data, A.colNum, beta,
275  C.data, B.colNum);
276 #endif
277  }
278  else {
279  // 5/12/06 some "very" simple optimization to avoid indexation
280  const unsigned int BcolNum = B.colNum;
281  const unsigned int BrowNum = B.rowNum;
282  double **BrowPtrs = B.rowPtrs;
283  for (unsigned int i = 0; i < A.rowNum; ++i) {
284  const double *rowptri = A.rowPtrs[i];
285  double *ci = C[i];
286  for (unsigned int j = 0; j < BcolNum; ++j) {
287  double s = 0;
288  for (unsigned int k = 0; k < BrowNum; ++k) {
289  s += rowptri[k] * BrowPtrs[k][j];
290  }
291  ci[j] = s;
292  }
293  }
294  }
295 }
296 
310 {
312 }
313 
324 void vpMatrix::add2WeightedMatrices(const vpMatrix &A, const double &wA, const vpMatrix &B, const double &wB,
325  vpMatrix &C)
326 {
327  if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum)) {
328  C.resize(A.rowNum, B.colNum, false, false);
329  }
330 
331  if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
332  throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
333  A.getCols(), B.getRows(), B.getCols()));
334  }
335 
336  double **ArowPtrs = A.rowPtrs;
337  double **BrowPtrs = B.rowPtrs;
338  double **CrowPtrs = C.rowPtrs;
339 
340  for (unsigned int i = 0; i < A.rowNum; ++i) {
341  for (unsigned int j = 0; j < A.colNum; ++j) {
342  CrowPtrs[i][j] = (wB * BrowPtrs[i][j]) + (wA * ArowPtrs[i][j]);
343  }
344  }
345 }
346 
356 void vpMatrix::add2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
357 {
358  if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum)) {
359  C.resize(A.rowNum, B.colNum, false, false);
360  }
361 
362  if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
363  throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
364  A.getCols(), B.getRows(), B.getCols()));
365  }
366 
367  double **ArowPtrs = A.rowPtrs;
368  double **BrowPtrs = B.rowPtrs;
369  double **CrowPtrs = C.rowPtrs;
370 
371  for (unsigned int i = 0; i < A.rowNum; ++i) {
372  for (unsigned int j = 0; j < A.colNum; ++j) {
373  CrowPtrs[i][j] = BrowPtrs[i][j] + ArowPtrs[i][j];
374  }
375  }
376 }
377 
391 {
392  if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum)) {
393  C.resize(A.rowNum);
394  }
395 
396  if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
397  throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
398  A.getCols(), B.getRows(), B.getCols()));
399  }
400 
401  double **ArowPtrs = A.rowPtrs;
402  double **BrowPtrs = B.rowPtrs;
403  double **CrowPtrs = C.rowPtrs;
404 
405  for (unsigned int i = 0; i < A.rowNum; ++i) {
406  for (unsigned int j = 0; j < A.colNum; ++j) {
407  CrowPtrs[i][j] = BrowPtrs[i][j] + ArowPtrs[i][j];
408  }
409  }
410 }
411 
428 {
429  if ((A.rowNum != C.rowNum) || (A.colNum != C.colNum)) {
430  C.resize(A.rowNum);
431  }
432 
433  if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
434  throw(vpException(vpException::dimensionError, "Cannot subtract (%dx%d) matrix to (%dx%d) matrix", A.getRows(),
435  A.getCols(), B.getRows(), B.getCols()));
436  }
437 
438  double **ArowPtrs = A.rowPtrs;
439  double **BrowPtrs = B.rowPtrs;
440  double **CrowPtrs = C.rowPtrs;
441 
442  for (unsigned int i = 0; i < A.rowNum; ++i) {
443  for (unsigned int j = 0; j < A.colNum; ++j) {
444  CrowPtrs[i][j] = ArowPtrs[i][j] - BrowPtrs[i][j];
445  }
446  }
447 }
448 
461 void vpMatrix::sub2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
462 {
463  if ((A.rowNum != C.rowNum) || (A.colNum != C.colNum)) {
464  C.resize(A.rowNum, A.colNum, false, false);
465  }
466 
467  if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
468  throw(vpException(vpException::dimensionError, "Cannot subtract (%dx%d) matrix to (%dx%d) matrix", A.getRows(),
469  A.getCols(), B.getRows(), B.getCols()));
470  }
471 
472  double **ArowPtrs = A.rowPtrs;
473  double **BrowPtrs = B.rowPtrs;
474  double **CrowPtrs = C.rowPtrs;
475 
476  for (unsigned int i = 0; i < A.rowNum; ++i) {
477  for (unsigned int j = 0; j < A.colNum; ++j) {
478  CrowPtrs[i][j] = ArowPtrs[i][j] - BrowPtrs[i][j];
479  }
480  }
481 }
482 
493 {
494  if ((A.rowNum != C.rowNum) || (A.colNum != C.colNum)) {
495  C.resize(A.rowNum, A.colNum, false, false);
496  }
497 
498  double **ArowPtrs = A.rowPtrs;
499  double **CrowPtrs = C.rowPtrs;
500 
501  for (unsigned int i = 0; i < A.rowNum; ++i) {
502  for (unsigned int j = 0; j < A.colNum; ++j) {
503  CrowPtrs[i][j] = -ArowPtrs[i][j];
504  }
505  }
506 }
507 
514 {
515  vpMatrix B;
516 
517  AAt(B);
518 
519  return B;
520 }
521 
533 void vpMatrix::AAt(vpMatrix &B) const
534 {
535  if ((B.rowNum != rowNum) || (B.colNum != rowNum)) {
536  B.resize(rowNum, rowNum, false, false);
537  }
538 
539  // If available use Lapack only for large matrices
540  bool useLapack = ((rowNum > vpMatrix::m_lapack_min_size) || (colNum > vpMatrix::m_lapack_min_size));
541 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
542  useLapack = false;
543 #endif
544 
545  if (useLapack) {
546 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
547  const double alpha = 1.0;
548  const double beta = 0.0;
549  const char transa = 't';
550  const char transb = 'n';
551 
552  vpMatrix::blas_dgemm(transa, transb, rowNum, rowNum, colNum, alpha, data, colNum, data, colNum, beta, B.data,
553  rowNum);
554 #endif
555  }
556  else {
557  // compute A*A^T
558  for (unsigned int i = 0; i < rowNum; ++i) {
559  for (unsigned int j = i; j < rowNum; ++j) {
560  double *pi = rowPtrs[i]; // row i
561  double *pj = rowPtrs[j]; // row j
562 
563  // sum (row i .* row j)
564  double ssum = 0;
565  for (unsigned int k = 0; k < colNum; ++k) {
566  ssum += (*pi) * (*pj);
567  ++pi;
568  ++pj;
569  }
570 
571  B[i][j] = ssum; // upper triangle
572  if (i != j) {
573  B[j][i] = ssum; // lower triangle
574  }
575  }
576  }
577  }
578 }
579 
591 void vpMatrix::AtA(vpMatrix &B) const
592 {
593  if ((B.rowNum != colNum) || (B.colNum != colNum)) {
594  B.resize(colNum, colNum, false, false);
595  }
596 
597  // If available use Lapack only for large matrices
598  bool useLapack = ((rowNum > vpMatrix::m_lapack_min_size) || (colNum > vpMatrix::m_lapack_min_size));
599 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
600  useLapack = false;
601 #endif
602 
603  if (useLapack) {
604 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
605  const double alpha = 1.0;
606  const double beta = 0.0;
607  const char transa = 'n';
608  const char transb = 't';
609 
610  vpMatrix::blas_dgemm(transa, transb, colNum, colNum, rowNum, alpha, data, colNum, data, colNum, beta, B.data,
611  colNum);
612 #endif
613  }
614  else {
615  for (unsigned int i = 0; i < colNum; ++i) {
616  double *Bi = B[i];
617  for (unsigned int j = 0; j < i; ++j) {
618  double *ptr = data;
619  double s = 0;
620  for (unsigned int k = 0; k < rowNum; ++k) {
621  s += (*(ptr + i)) * (*(ptr + j));
622  ptr += colNum;
623  }
624  *Bi++ = s;
625  B[j][i] = s;
626  }
627  double *ptr = data;
628  double s = 0;
629  for (unsigned int k = 0; k < rowNum; ++k) {
630  s += (*(ptr + i)) * (*(ptr + i));
631  ptr += colNum;
632  }
633  *Bi = s;
634  }
635  }
636 }
637 
644 {
645  vpMatrix B;
646 
647  AtA(B);
648 
649  return B;
650 }
651 
692 {
693  unsigned int rows = A.getRows();
694  this->resize(rows, rows);
695 
696  (*this) = 0;
697  for (unsigned int i = 0; i < rows; ++i) {
698  (*this)[i][i] = A[i];
699  }
700 }
701 
736 void vpMatrix::diag(const double &val)
737 {
738  (*this) = 0;
739  unsigned int min_ = (rowNum < colNum) ? rowNum : colNum;
740  for (unsigned int i = 0; i < min_; ++i) {
741  (*this)[i][i] = val;
742  }
743 }
744 
756 {
757  unsigned int rows = A.getRows();
758  DA.resize(rows, rows, true);
759 
760  for (unsigned int i = 0; i < rows; ++i) {
761  DA[i][i] = A[i];
762  }
763 }
764 
769 void vpMatrix::eye(unsigned int n) { eye(n, n); }
770 
775 void vpMatrix::eye(unsigned int m, unsigned int n)
776 {
777  resize(m, n);
778 
779  eye();
780 }
781 
787 {
788  for (unsigned int i = 0; i < rowNum; ++i) {
789  for (unsigned int j = 0; j < colNum; ++j) {
790  if (i == j) {
791  (*this)[i][j] = 1.0;
792  }
793  else {
794  (*this)[i][j] = 0;
795  }
796  }
797  }
798 }
799 
807 {
808  if ((m.getRows() != rowNum) || (m.getCols() != colNum)) {
809  throw(vpException(vpException::dimensionError, "In Hadamard product: bad dimension of input matrix"));
810  }
811 
812  vpMatrix out;
813  out.resize(rowNum, colNum, false, false);
814 
815 #if defined(VISP_HAVE_SIMDLIB)
816  SimdVectorHadamard(data, m.data, dsize, out.data);
817 #else
818  for (unsigned int i = 0; i < dsize; ++i) {
819  out.data[i] = data[i] * m.data[i];
820  }
821 #endif
822 
823  return out;
824 }
825 
832 void vpMatrix::kron(const vpMatrix &m1, const vpMatrix &m2, vpMatrix &out)
833 {
834  unsigned int r1 = m1.getRows();
835  unsigned int c1 = m1.getCols();
836  unsigned int r2 = m2.getRows();
837  unsigned int c2 = m2.getCols();
838 
839  out.resize(r1 * r2, c1 * c2, false, false);
840 
841  for (unsigned int r = 0; r < r1; ++r) {
842  for (unsigned int c = 0; c < c1; ++c) {
843  double alpha = m1[r][c];
844  double *m2ptr = m2[0];
845  unsigned int roffset = r * r2;
846  unsigned int coffset = c * c2;
847  for (unsigned int rr = 0; rr < r2; ++rr) {
848  for (unsigned int cc = 0; cc < c2; ++cc) {
849  out[roffset + rr][coffset + cc] = alpha * (*m2ptr);
850  ++m2ptr;
851  }
852  }
853  }
854  }
855 }
856 
863 void vpMatrix::kron(const vpMatrix &m, vpMatrix &out) const { kron(*this, m, out); }
864 
872 {
873  unsigned int r1 = m1.getRows();
874  unsigned int c1 = m1.getCols();
875  unsigned int r2 = m2.getRows();
876  unsigned int c2 = m2.getCols();
877 
878  vpMatrix out;
879  out.resize(r1 * r2, c1 * c2, false, false);
880 
881  for (unsigned int r = 0; r < r1; ++r) {
882  for (unsigned int c = 0; c < c1; ++c) {
883  double alpha = m1[r][c];
884  double *m2ptr = m2[0];
885  unsigned int roffset = r * r2;
886  unsigned int coffset = c * c2;
887  for (unsigned int rr = 0; rr < r2; ++rr) {
888  for (unsigned int cc = 0; cc < c2; ++cc) {
889  out[roffset + rr][coffset + cc] = alpha * (*m2ptr);
890  ++m2ptr;
891  }
892  }
893  }
894  }
895  return out;
896 }
897 
903 vpMatrix vpMatrix::kron(const vpMatrix &m) const { return kron(*this, m); }
904 
905 vpMatrix vpMatrix::conv2(const vpMatrix &M, const vpMatrix &kernel, const std::string &mode)
906 {
907  vpMatrix res;
908  conv2(M, kernel, res, mode);
909  return res;
910 }
911 
912 void vpMatrix::conv2(const vpMatrix &M, const vpMatrix &kernel, vpMatrix &res, const std::string &mode)
913 {
914  if (((M.getRows() * M.getCols()) == 0) || ((kernel.getRows() * kernel.getCols()) == 0)) {
915  return;
916  }
917 
918  if (mode == "valid") {
919  if ((kernel.getRows() > M.getRows()) || (kernel.getCols() > M.getCols())) {
920  return;
921  }
922  }
923 
924  vpMatrix M_padded, res_same;
925 
926  if ((mode == "full") || (mode == "same")) {
927  const unsigned int pad_x = kernel.getCols() - 1;
928  const unsigned int pad_y = kernel.getRows() - 1;
929  const unsigned int pad = 2;
930  M_padded.resize(M.getRows() + (pad * pad_y), M.getCols() + (pad * pad_x), true, false);
931  M_padded.insert(M, pad_y, pad_x);
932 
933  if (mode == "same") {
934  res.resize(M.getRows(), M.getCols(), false, false);
935  res_same.resize(M.getRows() + pad_y, M.getCols() + pad_x, true, false);
936  }
937  else {
938  res.resize(M.getRows() + pad_y, M.getCols() + pad_x, true, false);
939  }
940  }
941  else if (mode == "valid") {
942  M_padded = M;
943  res.resize((M.getRows() - kernel.getRows()) + 1, (M.getCols() - kernel.getCols()) + 1);
944  }
945  else {
946  return;
947  }
948 
949  if (mode == "same") {
950  unsigned int res_same_rows = res_same.getRows();
951  unsigned int res_same_cols = res_same.getCols();
952  unsigned int kernel_rows = kernel.getRows();
953  unsigned int kernel_cols = kernel.getCols();
954  for (unsigned int i = 0; i < res_same_rows; ++i) {
955  for (unsigned int j = 0; j < res_same_cols; ++j) {
956  for (unsigned int k = 0; k < kernel_rows; ++k) {
957  for (unsigned int l = 0; l < kernel_cols; ++l) {
958  res_same[i][j] += M_padded[i + k][j + l] * kernel[kernel.getRows() - k - 1][kernel.getCols() - l - 1];
959  }
960  }
961  }
962  }
963 
964  const unsigned int start_i = kernel.getRows() / 2;
965  const unsigned int start_j = kernel.getCols() / 2;
966  unsigned int m_rows = M.getRows();
967  for (unsigned int i = 0; i < m_rows; ++i) {
968  memcpy(res.data + (i * M.getCols()), res_same.data + ((i + start_i) * res_same.getCols()) + start_j,
969  sizeof(double) * M.getCols());
970  }
971  }
972  else {
973  unsigned int res_rows = res.getRows();
974  unsigned int res_cols = res.getCols();
975  unsigned int kernel_rows = kernel.getRows();
976  unsigned int kernel_cols = kernel.getCols();
977  for (unsigned int i = 0; i < res_rows; ++i) {
978  for (unsigned int j = 0; j < res_cols; ++j) {
979  for (unsigned int k = 0; k < kernel_rows; ++k) {
980  for (unsigned int l = 0; l < kernel_cols; ++l) {
981  res[i][j] += M_padded[i + k][j + l] * kernel[kernel.getRows() - k - 1][kernel.getCols() - l - 1];
982  }
983  }
984  }
985  }
986  }
987 }
988 END_VISP_NAMESPACE
unsigned int getCols() const
Definition: vpArray2D.h:337
double * data
Address of the first element of the data array.
Definition: vpArray2D.h:148
Type ** rowPtrs
Address of the first element of each rows.
Definition: vpArray2D.h:1105
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:1101
unsigned int dsize
Current array size (rowNum * colNum)
Definition: vpArray2D.h:1107
unsigned int getRows() const
Definition: vpArray2D.h:347
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:1103
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
void resize(unsigned int i, bool flagNullify=true)
Definition: vpColVector.h:1143
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
Implementation of an homogeneous matrix and operations on such kind of matrices.
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
vpMatrix hadamard(const vpMatrix &m) const
unsigned int kernel(vpMatrix &kerAt, double svThreshold=1e-6) const
Definition: vpMatrix.cpp:1412
static void sub2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
void diag(const double &val=1.0)
static void add2WeightedMatrices(const vpMatrix &A, const double &wA, const vpMatrix &B, const double &wB, vpMatrix &C)
vpMatrix AtA() const
static void createDiagonalMatrix(const vpColVector &A, vpMatrix &DA)
static void multMatrixVector(const vpMatrix &A, const vpColVector &v, vpColVector &w)
static void add2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
void insert(const vpMatrix &A, unsigned int r, unsigned int c)
Definition: vpMatrix.cpp:1133
void kron(const vpMatrix &m1, vpMatrix &out) const
vpMatrix AAt() const
static vpMatrix conv2(const vpMatrix &M, const vpMatrix &kernel, const std::string &mode)
vpMatrix transpose() const
static void mult2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
static void negateMatrix(const vpMatrix &A, vpMatrix &C)
vpMatrix t() const
Implementation of a rotation matrix and operations on such kind of matrices.