Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
vpImageTools.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  * Image tools.
32  *
33 *****************************************************************************/
34 
35 #include <visp3/core/vpCPUFeatures.h>
36 #include <visp3/core/vpImageConvert.h>
37 #include <visp3/core/vpImageTools.h>
38 #include <visp3/core/vpImageException.h>
39 
40 #if defined(VISP_HAVE_SIMDLIB)
41 #include <Simd/SimdLib.hpp>
42 #endif
43 
104 void vpImageTools::changeLUT(vpImage<unsigned char> &I, unsigned char A, unsigned char A_star, unsigned char B,
105  unsigned char B_star)
106 {
107  // Test if input values are valid
108  if (B <= A) {
110  }
111  unsigned char v;
112 
113  double factor = static_cast<double>((B_star - A_star) / static_cast<double>((B - A)));
114 
115  unsigned int i_height = I.getHeight();
116  unsigned int i_width = I.getWidth();
117  for (unsigned int i = 0; i < i_height; ++i) {
118  for (unsigned int j = 0; j < i_width; ++j) {
119  v = I[i][j];
120 
121  if (v <= A) {
122  I[i][j] = A_star;
123  }
124  else if (v >= B) {
125  I[i][j] = B_star;
126  }
127  else {
128  I[i][j] = static_cast<unsigned char>(A_star + (factor * (v - A)));
129  }
130  }
131  }
132 }
133 
147  vpImage<unsigned char> &Idiff)
148 {
149  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
150  throw(vpException(vpException::dimensionError, "The two images have not the same size"));
151  }
152 
153  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
154  Idiff.resize(I1.getHeight(), I1.getWidth());
155  }
156 
157 #if defined(VISP_HAVE_SIMDLIB)
158  SimdImageDifference(I1.bitmap, I2.bitmap, I1.getSize(), Idiff.bitmap);
159 #else
160  for (unsigned int i = 0; i < I1.getSize(); ++i) {
161  int diff = (I1.bitmap[i] - I2.bitmap[i]) + 128;
162  Idiff.bitmap[i] = static_cast<unsigned char>(std::max<unsigned char>(std::min<unsigned char>(diff, 255), 0));
163  }
164 #endif
165 }
166 
181 {
182  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
184  "Cannot compute image difference. The two images "
185  "(%ux%u) and (%ux%u) have not the same size",
186  I1.getWidth(), I1.getHeight(), I2.getWidth(), I2.getHeight()));
187  }
188 
189  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
190  Idiff.resize(I1.getHeight(), I1.getWidth());
191  }
192 
193 #if defined(VISP_HAVE_SIMDLIB)
194  SimdImageDifference(reinterpret_cast<unsigned char *>(I1.bitmap), reinterpret_cast<unsigned char *>(I2.bitmap),
195  I1.getSize() * 4, reinterpret_cast<unsigned char *>(Idiff.bitmap));
196 #else
197  unsigned int i1_size = I1.getSize();
198  for (unsigned int i = 0; i < (i1_size * 4); ++i) {
199  int diffR = (I1.bitmap[i].R - I2.bitmap[i].R) + 128;
200  int diffG = (I1.bitmap[i].G - I2.bitmap[i].G) + 128;
201  int diffB = (I1.bitmap[i].B - I2.bitmap[i].B) + 128;
202  int diffA = (I1.bitmap[i].A - I2.bitmap[i].A) + 128;
203  Idiff.bitmap[i].R = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffR, 255), 0));
204  Idiff.bitmap[i].G = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffG, 255), 0));
205  Idiff.bitmap[i].B = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffB, 255), 0));
206  Idiff.bitmap[i].A = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffA, 255), 0));
207  }
208 #endif
209 }
210 
222  vpImage<unsigned char> &Idiff)
223 {
224  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
225  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
226  }
227 
228  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
229  Idiff.resize(I1.getHeight(), I1.getWidth());
230  }
231 
232  unsigned int n = I1.getHeight() * I1.getWidth();
233  for (unsigned int b = 0; b < n; ++b) {
234  int diff = I1.bitmap[b] - I2.bitmap[b];
235  Idiff.bitmap[b] = static_cast<unsigned char>(vpMath::abs(diff));
236  }
237 }
238 
247 {
248  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
249  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
250  }
251 
252  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
253  Idiff.resize(I1.getHeight(), I1.getWidth());
254  }
255 
256  unsigned int n = I1.getHeight() * I1.getWidth();
257  for (unsigned int b = 0; b < n; ++b) {
258  Idiff.bitmap[b] = vpMath::abs(I1.bitmap[b] - I2.bitmap[b]);
259  }
260 }
261 
276 {
277  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
278  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
279  }
280 
281  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
282  Idiff.resize(I1.getHeight(), I1.getWidth());
283  }
284 
285  unsigned int n = I1.getHeight() * I1.getWidth();
286  for (unsigned int b = 0; b < n; ++b) {
287  int diffR = I1.bitmap[b].R - I2.bitmap[b].R;
288  int diffG = I1.bitmap[b].G - I2.bitmap[b].G;
289  int diffB = I1.bitmap[b].B - I2.bitmap[b].B;
290  // --comment: int diffA eq I1 dot bitmap[b] dot A minus I2 dot bitmap[b] dot A
291  Idiff.bitmap[b].R = static_cast<unsigned char>(vpMath::abs(diffR));
292  Idiff.bitmap[b].G = static_cast<unsigned char>(vpMath::abs(diffG));
293  Idiff.bitmap[b].B = static_cast<unsigned char>(vpMath::abs(diffB));
294  // --comment: Idiff dot bitmap[b] dot A eq diffA
295  Idiff.bitmap[b].A = 0;
296  }
297 }
298 
313  vpImage<unsigned char> &Ires, bool saturate)
314 {
315  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
316  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
317  }
318 
319  if ((I1.getHeight() != Ires.getHeight()) || (I1.getWidth() != Ires.getWidth())) {
320  Ires.resize(I1.getHeight(), I1.getWidth());
321  }
322 
323 #if defined(VISP_HAVE_SIMDLIB)
324  typedef Simd::View<Simd::Allocator> View;
325  View img1(I1.getWidth(), I1.getHeight(), I1.getWidth(), View::Gray8, I1.bitmap);
326  View img2(I2.getWidth(), I2.getHeight(), I2.getWidth(), View::Gray8, I2.bitmap);
327  View imgAdd(Ires.getWidth(), Ires.getHeight(), Ires.getWidth(), View::Gray8, Ires.bitmap);
328 
329  Simd::OperationBinary8u(img1, img2, imgAdd,
330  saturate ? SimdOperationBinary8uSaturatedAddition : SimdOperationBinary8uAddition);
331 #else
332  unsigned char *ptr_I1 = I1.bitmap;
333  unsigned char *ptr_I2 = I2.bitmap;
334  unsigned char *ptr_Ires = Ires.bitmap;
335  unsigned int ires_size = Ires.getSize();
336  for (unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
337  *ptr_Ires = saturate ? vpMath::saturate<unsigned char>(static_cast<short int>(*ptr_I1) + static_cast<short int>(*ptr_I2)) : ((*ptr_I1) + (*ptr_I2));
338  }
339 #endif
340 }
341 
356  vpImage<unsigned char> &Ires, bool saturate)
357 {
358  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
359  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
360  }
361 
362  if ((I1.getHeight() != Ires.getHeight()) || (I1.getWidth() != Ires.getWidth())) {
363  Ires.resize(I1.getHeight(), I1.getWidth());
364  }
365 
366 #if defined(VISP_HAVE_SIMDLIB)
367  typedef Simd::View<Simd::Allocator> View;
368  View img1(I1.getWidth(), I1.getHeight(), I1.getWidth(), View::Gray8, I1.bitmap);
369  View img2(I2.getWidth(), I2.getHeight(), I2.getWidth(), View::Gray8, I2.bitmap);
370  View imgAdd(Ires.getWidth(), Ires.getHeight(), Ires.getWidth(), View::Gray8, Ires.bitmap);
371 
372  Simd::OperationBinary8u(img1, img2, imgAdd,
373  saturate ? SimdOperationBinary8uSaturatedSubtraction : SimdOperationBinary8uSubtraction);
374 #else
375  unsigned char *ptr_I1 = I1.bitmap;
376  unsigned char *ptr_I2 = I2.bitmap;
377  unsigned char *ptr_Ires = Ires.bitmap;
378  unsigned int ires_size = Ires.getSize();
379  for (unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
380  *ptr_Ires = saturate ?
381  vpMath::saturate<unsigned char>(static_cast<short int>(*ptr_I1) - static_cast<short int>(*ptr_I2)) :
382  ((*ptr_I1) - (*ptr_I2));
383  }
384 #endif
385 }
386 
398 void vpImageTools::initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height,
399  vpArray2D<int> &mapU, vpArray2D<int> &mapV, vpArray2D<float> &mapDu,
400  vpArray2D<float> &mapDv)
401 {
402  mapU.resize(height, width, false, false);
403  mapV.resize(height, width, false, false);
404  mapDu.resize(height, width, false, false);
405  mapDv.resize(height, width, false, false);
406 
408  bool is_KannalaBrandt =
409  (projModel == vpCameraParameters::ProjWithKannalaBrandtDistortion); // Check the projection model used
410 
411  float u0 = static_cast<float>(cam.get_u0());
412  float v0 = static_cast<float>(cam.get_v0());
413  float px = static_cast<float>(cam.get_px());
414  float py = static_cast<float>(cam.get_py());
415  float kud = 0;
416  std::vector<double> dist_coefs;
417 
418  if (!is_KannalaBrandt) {
419  kud = static_cast<float>(cam.get_kud());
420  }
421  else {
422  dist_coefs = cam.getKannalaBrandtDistortionCoefficients();
423  }
424 
425  if ((!is_KannalaBrandt) && (std::fabs(static_cast<double>(kud)) <= std::numeric_limits<double>::epsilon())) {
426  // There is no need to undistort the image (Perpective projection)
427  for (unsigned int i = 0; i < height; ++i) {
428  for (unsigned int j = 0; j < width; ++j) {
429  mapU[i][j] = static_cast<int>(j);
430  mapV[i][j] = static_cast<int>(i);
431  mapDu[i][j] = 0;
432  mapDv[i][j] = 0;
433  }
434  }
435 
436  return;
437  }
438 
439  float invpx, invpy;
440  float kud_px2 = 0., kud_py2 = 0., deltau_px, deltav_py = 0;
441  float fr1 = 0, fr2;
442  float deltav, deltau;
443  float u_float, v_float;
444  int u_round, v_round;
445  double r, scale;
446  double theta, theta_d;
447  double theta2, theta4, theta6, theta8;
448  const unsigned int index_0 = 0;
449  const unsigned int index_1 = 1;
450  const unsigned int index_2 = 2;
451  const unsigned int index_3 = 3;
452 
453  invpx = 1.0f / px;
454  invpy = 1.0f / py;
455 
456  if (!is_KannalaBrandt) {
457  kud_px2 = kud * invpx * invpx;
458  kud_py2 = kud * invpy * invpy;
459  }
460 
461  for (unsigned int v = 0; v < height; ++v) {
462  deltav = v - v0;
463 
464  if (!is_KannalaBrandt) {
465  fr1 = 1.0f + (kud_py2 * deltav * deltav);
466  }
467  else {
468  deltav_py = deltav * invpy;
469  }
470 
471  for (unsigned int u = 0; u < width; ++u) {
472  // computation of u,v : corresponding pixel coordinates in I.
473  deltau = u - u0;
474  if (!is_KannalaBrandt) {
475  fr2 = fr1 + (kud_px2 * deltau * deltau);
476 
477  u_float = (deltau * fr2) + u0;
478  v_float = (deltav * fr2) + v0;
479  }
480 
481  else {
482  deltau_px = deltau * invpx;
483  r = sqrt(vpMath::sqr(deltau_px) + vpMath::sqr(deltav_py));
484  theta = atan(r);
485 
486  theta2 = vpMath::sqr(theta);
487  theta4 = vpMath::sqr(theta2);
488  theta6 = theta2 * theta4;
489  theta8 = vpMath::sqr(theta4);
490 
491  theta_d = theta * (1 + (dist_coefs[index_0] * theta2) + (dist_coefs[index_1] * theta4) + (dist_coefs[index_2] * theta6) +
492  (dist_coefs[index_3] * theta8));
493 
494  // --comment: scale eq (r == 0) 1.0 otherwise theta_d / r
495  scale = (std::fabs(r) < std::numeric_limits<double>::epsilon()) ? 1.0 : (theta_d / r);
496  u_float = static_cast<float>((deltau * scale) + u0);
497  v_float = static_cast<float>((deltav * scale) + v0);
498  }
499 
500  u_round = static_cast<int>(u_float);
501  v_round = static_cast<int>(v_float);
502 
503  mapU[v][u] = u_round;
504  mapV[v][u] = v_round;
505 
506  mapDu[v][u] = u_float - u_round;
507  mapDv[v][u] = v_float - v_round;
508  }
509  }
510 }
511 
524 {
525  if (I.getSize() == 0) {
526  std::cerr << "Error, input image is empty." << std::endl;
527  return;
528  }
529 
530  II.resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
531  IIsq.resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
532 
533  unsigned int ii_height = II.getHeight();
534  unsigned int ii_width = II.getWidth();
535  for (unsigned int i = 1; i < ii_height; ++i) {
536  for (unsigned int j = 1; j < ii_width; ++j) {
537  II[i][j] = (I[i - 1][j - 1] + II[i - 1][j] + II[i][j - 1]) - II[i - 1][j - 1];
538  IIsq[i][j] = (vpMath::sqr(I[i - 1][j - 1]) + IIsq[i - 1][j] + IIsq[i][j - 1]) - IIsq[i - 1][j - 1];
539  }
540  }
541 }
542 
550 double vpImageTools::normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, bool useOptimized)
551 {
552  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
554  "Error: in vpImageTools::normalizedCorrelation(): "
555  "image dimension mismatch between I1=%ux%u and I2=%ux%u",
556  I1.getHeight(), I1.getWidth(), I2.getHeight(), I2.getWidth());
557  }
558 
559  const double a = I1.getMeanValue();
560  const double b = I2.getMeanValue();
561 
562  double ab = 0.0;
563  double a2 = 0.0;
564  double b2 = 0.0;
565 
566 #if defined(VISP_HAVE_SIMDLIB)
567  SimdNormalizedCorrelation(I1.bitmap, a, I2.bitmap, b, I1.getSize(), a2, b2, ab, useOptimized);
568 #else
569  unsigned int i1_size = I1.getSize();
570  for (unsigned int cpt = 0; cpt < i1_size; ++cpt) {
571  ab += (I1.bitmap[cpt] - a) * (I2.bitmap[cpt] - b);
572  a2 += vpMath::sqr(I1.bitmap[cpt] - a);
573  b2 += vpMath::sqr(I2.bitmap[cpt] - b);
574  }
575  (void)useOptimized;
576 #endif
577 
578  return ab / sqrt(a2 * b2);
579 }
580 
588 {
589  unsigned int height = I.getHeight(), width = I.getWidth();
590  V.resize(width); // resize and nullify
591 
592  for (unsigned int i = 0; i < height; ++i) {
593  for (unsigned int j = 0; j < width; ++j) {
594  V[j] += I[i][j];
595  }
596  }
597  for (unsigned int j = 0; j < width; ++j) {
598  V[j] /= height;
599  }
600 }
601 
607 {
608  double s = I.getSum();
609  unsigned int i_height = I.getHeight();
610  unsigned int i_width = I.getWidth();
611  for (unsigned int i = 0; i < i_height; ++i) {
612  for (unsigned int j = 0; j < i_width; ++j) {
613  I(i, j, I(i, j) / s);
614  }
615  }
616 }
617 
618 namespace
619 {
625 double interpolationNearest(const vpImage<unsigned char> &I, const vpImagePoint &point)
626 {
627  int x1 = static_cast<int>(floor(point.get_i()));
628  int x2 = static_cast<int>(ceil(point.get_i()));
629  int y1 = static_cast<int>(floor(point.get_j()));
630  int y2 = static_cast<int>(ceil(point.get_j()));
631  double v1, v2;
632  if (x1 == x2) {
633  v1 = I(x1, y1);
634  v2 = I(x1, y2);
635  }
636  else {
637  v1 = ((x2 - point.get_i()) * I(x1, y1)) + ((point.get_i() - x1) * I(x2, y1));
638  v2 = ((x2 - point.get_i()) * I(x1, y2)) + ((point.get_i() - x1) * I(x2, y2));
639  }
640  if (y1 == y2) {
641  return v1;
642  }
643  return ((y2 - point.get_j()) * v1) + ((point.get_j() - y1) * v2);
644 }
645 }
646 
655  const vpImageInterpolationType &method)
656 {
657  switch (method) {
659  return I(vpMath::round(point.get_i()), vpMath::round(point.get_j()));
660  case INTERPOLATION_LINEAR: {
661  return interpolationNearest(I, point);
662  }
663  case INTERPOLATION_CUBIC: {
665  "vpImageTools::interpolate(): bi-cubic interpolation is not implemented.");
666  }
667  default: {
668  throw vpException(vpException::notImplementedError, "vpImageTools::interpolate(): invalid interpolation type");
669  }
670  }
671 }
672 
680 {
681  unsigned int x_d = vpMath::round(r.getHeight());
682  unsigned int y_d = vpMath::round(r.getWidth());
683  double x1 = r.getTopLeft().get_i();
684  double y1 = r.getTopLeft().get_j();
685  double t = r.getOrientation();
686  double cos_t = cos(t);
687  double sin_t = sin(t);
688  dst.resize(x_d, y_d);
689  for (unsigned int x = 0; x < x_d; ++x) {
690  double x_cos_t = x * cos_t;
691  double x_sin_t = x * sin_t;
692  for (unsigned int y = 0; y < y_d; ++y) {
693  dst(x, y,
694  static_cast<unsigned char>(interpolate(src, vpImagePoint(x1 + x_cos_t + (y * sin_t), (y1 - x_sin_t) + (y * cos_t)),
696  }
697  }
698 }
699 
707 {
708  unsigned int x_d = vpMath::round(r.getHeight());
709  unsigned int y_d = vpMath::round(r.getWidth());
710  double x1 = r.getTopLeft().get_i();
711  double y1 = r.getTopLeft().get_j();
712  double t = r.getOrientation();
713  double cos_t = cos(t);
714  double sin_t = sin(t);
715  dst.resize(x_d, y_d);
716  for (unsigned int x = 0; x < x_d; ++x) {
717  double x_cos_t = x * cos_t;
718  double x_sin_t = x * sin_t;
719  for (unsigned int y = 0; y < y_d; ++y) {
720  dst(x, y,
721  interpolate(src, vpImagePoint(x1 + x_cos_t + (y * sin_t), (y1 - x_sin_t) + (y * cos_t)),
723  }
724  }
725 }
726 
742  vpImage<double> &I_score, unsigned int step_u, unsigned int step_v,
743  bool useOptimized)
744 {
745  if (I.getSize() == 0) {
746  std::cerr << "Error, input image is empty." << std::endl;
747  return;
748  }
749 
750  if (I_tpl.getSize() == 0) {
751  std::cerr << "Error, template image is empty." << std::endl;
752  return;
753  }
754 
755  if ((I_tpl.getHeight() > I.getHeight()) || (I_tpl.getWidth() > I.getWidth())) {
756  std::cerr << "Error, template image is bigger than input image." << std::endl;
757  return;
758  }
759 
760  vpImage<double> I_double, I_tpl_double;
761  vpImageConvert::convert(I, I_double);
762  vpImageConvert::convert(I_tpl, I_tpl_double);
763 
764  unsigned int height_tpl = I_tpl.getHeight(), width_tpl = I_tpl.getWidth();
765  I_score.resize(I.getHeight() - height_tpl, I.getWidth() - width_tpl, 0.0);
766 
767  if (useOptimized) {
768  vpImage<double> II, IIsq;
769  integralImage(I, II, IIsq);
770 
771  vpImage<double> II_tpl, IIsq_tpl;
772  integralImage(I_tpl, II_tpl, IIsq_tpl);
773 
774  // zero-mean template image
775  const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
776  const double mean2 = sum2 / I_tpl.getSize();
777  unsigned int i_tpl_double_size = I_tpl_double.getSize();
778  for (unsigned int cpt = 0; cpt < i_tpl_double_size; ++cpt) {
779  I_tpl_double.bitmap[cpt] -= mean2;
780  }
781 
782 #if defined(_OPENMP) && (_OPENMP >= 200711) // OpenMP 3.1
783 #pragma omp parallel for schedule(dynamic)
784  for (unsigned int i = 0; i < I.getHeight() - height_tpl; i += step_v) {
785  for (unsigned int j = 0; j < I.getWidth() - width_tpl; j += step_u) {
786  I_score[i][j] = normalizedCorrelation(I_double, I_tpl_double, II, IIsq, II_tpl, IIsq_tpl, i, j);
787  }
788  }
789 #else
790  // error C3016: 'i': index variable in OpenMP 'for' statement must have signed integral type
791  int end = static_cast<int>((I.getHeight() - height_tpl) / step_v) + 1;
792  std::vector<unsigned int> vec_step_v(static_cast<size_t>(end));
793  unsigned int i_height = I.getHeight();
794  for (unsigned int cpt = 0, idx = 0; cpt < (i_height - height_tpl); cpt += step_v, ++idx) {
795  vec_step_v[static_cast<size_t>(idx)] = cpt;
796  }
797 #if defined(_OPENMP) // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
798 #pragma omp parallel for schedule(dynamic)
799 #endif
800  for (int cpt = 0; cpt < end; ++cpt) {
801  unsigned int i_width = I.getWidth();
802  for (unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
803  I_score[vec_step_v[cpt]][j] =
804  normalizedCorrelation(I_double, I_tpl_double, II, IIsq, II_tpl, IIsq_tpl, vec_step_v[cpt], j);
805  }
806  }
807 #endif
808  }
809  else {
810  vpImage<double> I_cur;
811 
812  unsigned int i_height = I.getHeight();
813  unsigned int i_width = I.getWidth();
814  for (unsigned int i = 0; i < (i_height - height_tpl); i += step_v) {
815  for (unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
816  vpRect roi(vpImagePoint(i, j), vpImagePoint(((i + height_tpl) - 1), ((j + width_tpl) - 1)));
817  vpImageTools::crop(I_double, roi, I_cur);
818 
819  I_score[i][j] = vpImageTools::normalizedCorrelation(I_cur, I_tpl_double, useOptimized);
820  }
821  }
822  }
823 }
824 
825 // Reference:
826 // http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
827 // t is a value that goes from 0 to 1 to interpolate in a C1 continuous way
828 // across uniformly sampled data points. when t is 0, this will return B.
829 // When t is 1, this will return C. In between values will return an
830 // interpolation between B and C. A and B are used to calculate the slopes at
831 // the edges.
832 float vpImageTools::cubicHermite(const float A, const float B, const float C, const float D, const float t)
833 {
834  float a = (((-A + (3.0f * B)) - (3.0f * C)) + D) / 2.0f;
835  float b = (A + (2.0f * C)) - (((5.0f * B) + D) / 2.0f);
836  float c = (-A + C) / 2.0f;
837  float d = B;
838 
839  return (a * t * t * t) + (b * t * t) + (c * t) + d;
840 }
841 
842 int vpImageTools::coordCast(double x) { return x < 0 ? -1 : static_cast<int>(x); }
843 
844 double vpImageTools::lerp(double A, double B, double t) { return (A * (1.0 - t)) + (B * t); }
845 
846 float vpImageTools::lerp(float A, float B, float t) { return (A * (1.0f - t)) + (B * t); }
847 
848 int64_t vpImageTools::lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1) { return (A * t_1) + (B * t); }
849 
851  const vpImage<double> &II, const vpImage<double> &IIsq,
852  const vpImage<double> &II_tpl, const vpImage<double> &IIsq_tpl,
853  unsigned int i0, unsigned int j0)
854 {
855  double ab = 0.0;
856 
857 #if defined(VISP_HAVE_SIMDLIB)
858  SimdNormalizedCorrelation2(I1.bitmap, I1.getWidth(), I2.bitmap, I2.getWidth(), I2.getHeight(), i0, j0, ab);
859 #else
860  unsigned int i2_height = I2.getHeight();
861  unsigned int i2_width = I2.getWidth();
862  for (unsigned int i = 0; i < i2_height; ++i) {
863  for (unsigned int j = 0; j < i2_width; ++j) {
864  ab += (I1[i0 + i][j0 + j]) * I2[i][j];
865  }
866  }
867 #endif
868 
869  unsigned int height_tpl = I2.getHeight(), width_tpl = I2.getWidth();
870  const double sum1 =
871  (((II[i0 + height_tpl][j0 + width_tpl] + II[i0][j0]) - II[i0][j0 + width_tpl]) - II[i0 + height_tpl][j0]);
872  const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
873 
874  double a2 = ((((IIsq[i0 + I2.getHeight()][j0 + I2.getWidth()] + IIsq[i0][j0]) - IIsq[i0][j0 + I2.getWidth()]) -
875  IIsq[i0 + I2.getHeight()][j0]) -
876  ((1.0 / I2.getSize()) * vpMath::sqr(sum1)));
877 
878  double b2 = ((((IIsq_tpl[I2.getHeight()][I2.getWidth()] + IIsq_tpl[0][0]) - IIsq_tpl[0][I2.getWidth()]) -
879  IIsq_tpl[I2.getHeight()][0]) -
880  ((1.0 / I2.getSize()) * vpMath::sqr(sum2)));
881  return ab / sqrt(a2 * b2);
882 }
883 
895  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<unsigned char> &Iundist)
896 {
897  Iundist.resize(I.getHeight(), I.getWidth());
898  const int I_height = static_cast<int>(I.getHeight());
899 
900 #if defined(_OPENMP) // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
901 #pragma omp parallel for schedule(dynamic)
902 #endif
903  for (int i_ = 0; i_ < I_height; ++i_) {
904  const unsigned int i = static_cast<unsigned int>(i_);
905  unsigned int i_width = I.getWidth();
906  for (unsigned int j = 0; j < i_width; ++j) {
907 
908  int u_round = mapU[i][j];
909  int v_round = mapV[i][j];
910 
911  float du = mapDu[i][j];
912  float dv = mapDv[i][j];
913 
914  if ((0 <= u_round) && (0 <= v_round) && (u_round < (static_cast<int>(I.getWidth()) - 1)) &&
915  (v_round < (I_height - 1))) {
916  // process interpolation
917  float col0 = lerp(I[v_round][u_round], I[v_round][u_round + 1], du);
918  float col1 = lerp(I[v_round + 1][u_round], I[v_round + 1][u_round + 1], du);
919  float value = lerp(col0, col1, dv);
920 
921  Iundist[i][j] = static_cast<unsigned char>(value);
922  }
923  else {
924  Iundist[i][j] = 0;
925  }
926  }
927  }
928 }
929 
940 void vpImageTools::remap(const vpImage<vpRGBa> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
941  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<vpRGBa> &Iundist)
942 {
943  Iundist.resize(I.getHeight(), I.getWidth());
944  const int I_height = static_cast<int>(I.getHeight());
945 #if defined(_OPENMP) // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
946 #pragma omp parallel for schedule(dynamic)
947 #endif
948  for (int i = 0; i < I_height; ++i) {
949 #if defined(VISP_HAVE_SIMDLIB)
950  SimdRemap(reinterpret_cast<unsigned char *>(I.bitmap), 4, I.getWidth(), I.getHeight(), i * I.getWidth(), mapU.data,
951  mapV.data, mapDu.data, mapDv.data, reinterpret_cast<unsigned char *>(Iundist.bitmap));
952 #else
953  const unsigned int i_ = static_cast<unsigned int>(i);
954  unsigned int i_width = I.getWidth();
955  for (unsigned int j = 0; j < i_width; ++j) {
956 
957  int u_round = mapU[i_][j];
958  int v_round = mapV[i_][j];
959 
960  float du = mapDu[i_][j];
961  float dv = mapDv[i_][j];
962 
963  if ((0 <= u_round) && (0 <= v_round) && (u_round < (static_cast<int>(I.getWidth()) - 1))
964  && (v_round < (I_height - 1))) {
965  // process interpolation
966  float col0 = lerp(I[v_round][u_round].R, I[v_round][u_round + 1].R, du);
967  float col1 = lerp(I[v_round + 1][u_round].R, I[v_round + 1][u_round + 1].R, du);
968  float value = lerp(col0, col1, dv);
969 
970  Iundist[i][j].R = static_cast<unsigned char>(value);
971 
972  col0 = lerp(I[v_round][u_round].G, I[v_round][u_round + 1].G, du);
973  col1 = lerp(I[v_round + 1][u_round].G, I[v_round + 1][u_round + 1].G, du);
974  value = lerp(col0, col1, dv);
975 
976  Iundist[i][j].G = static_cast<unsigned char>(value);
977 
978  col0 = lerp(I[v_round][u_round].B, I[v_round][u_round + 1].B, du);
979  col1 = lerp(I[v_round + 1][u_round].B, I[v_round + 1][u_round + 1].B, du);
980  value = lerp(col0, col1, dv);
981 
982  Iundist[i][j].B = static_cast<unsigned char>(value);
983 
984  col0 = lerp(I[v_round][u_round].A, I[v_round][u_round + 1].A, du);
985  col1 = lerp(I[v_round + 1][u_round].A, I[v_round + 1][u_round + 1].A, du);
986  value = lerp(col0, col1, dv);
987 
988  Iundist[i][j].A = static_cast<unsigned char>(value);
989  }
990  else {
991  Iundist[i][j] = 0;
992  }
993  }
994 #endif
995  }
996 }
997 
998 #if defined(VISP_HAVE_SIMDLIB)
999 void vpImageTools::resizeSimdlib(const vpImage<vpRGBa> &Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
1000  vpImage<vpRGBa> &Idst, int method)
1001 {
1002  Idst.resize(resizeHeight, resizeWidth);
1003 
1004  typedef Simd::View<Simd::Allocator> View;
1005  View src(Isrc.getWidth(), Isrc.getHeight(), Isrc.getWidth() * sizeof(vpRGBa), View::Bgra32, Isrc.bitmap);
1006  View dst(Idst.getWidth(), Idst.getHeight(), Idst.getWidth() * sizeof(vpRGBa), View::Bgra32, Idst.bitmap);
1007 
1008  Simd::Resize(src, dst, method == INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1009 }
1010 
1011 void vpImageTools::resizeSimdlib(const vpImage<unsigned char> &Isrc, unsigned int resizeWidth,
1012  unsigned int resizeHeight, vpImage<unsigned char> &Idst, int method)
1013 {
1014  Idst.resize(resizeHeight, resizeWidth);
1015 
1016  typedef Simd::View<Simd::Allocator> View;
1017  View src(Isrc.getWidth(), Isrc.getHeight(), Isrc.getWidth(), View::Gray8, Isrc.bitmap);
1018  View dst(Idst.getWidth(), Idst.getHeight(), Idst.getWidth(), View::Gray8, Idst.bitmap);
1019 
1020  Simd::Resize(src, dst, method == INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1021 }
1022 #endif
1023 
1024 bool vpImageTools::checkFixedPoint(unsigned int x, unsigned int y, const vpMatrix &T, bool affine)
1025 {
1026  const unsigned int index_0 = 0;
1027  const unsigned int index_1 = 1;
1028  const unsigned int index_2 = 2;
1029  double a0 = T[index_0][index_0];
1030  double a1 = T[index_0][index_1];
1031  double a2 = T[index_0][index_2];
1032  double a3 = T[index_1][index_0];
1033  double a4 = T[index_1][index_1];
1034  double a5 = T[index_1][index_2];
1035  double a6 = affine ? 0.0 : T[index_2][index_0];
1036  double a7 = affine ? 0.0 : T[index_2][index_1];
1037  double a8 = affine ? 1.0 : T[index_2][index_2];
1038 
1039  double w = (a6 * x) + (a7 * y) + a8;
1040  double x2 = ((a0 * x) + (a1 * y) + a2) / w;
1041  double y2 = ((a3 * x) + (a4 * y) + a5) / w;
1042 
1043  const double limit = 1 << 15;
1044  return (vpMath::abs(x2) < limit) && (vpMath::abs(y2) < limit);
1045 }
1046 
1055 {
1056  if ((I.getHeight() != mask.getHeight()) || (I.getWidth() != mask.getWidth())) {
1058  "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
1059  I.getWidth(), I.getHeight(), mask.getWidth(), mask.getHeight()));
1060  }
1061  vpRGBa black(0, 0, 0);
1062  I_mask.resize(I.getHeight(), I.getWidth());
1063  int cpt_in_mask = 0;
1064  int size_ = static_cast<int>(I.getSize());
1065 #if defined(_OPENMP)
1066 #pragma omp parallel for reduction(+:cpt_in_mask)
1067 #endif
1068  for (int i = 0; i < size_; ++i) {
1069  if (mask.bitmap[i] == 0) {
1070  I_mask.bitmap[i] = black;
1071  }
1072  else {
1073  I_mask.bitmap[i] = I.bitmap[i];
1074  ++cpt_in_mask;
1075  }
1076  }
1077  return cpt_in_mask;
1078 }
1079 
1088 {
1089  if ((I.getHeight() != mask.getHeight()) || (I.getWidth() != mask.getWidth())) {
1091  "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
1092  I.getWidth(), I.getHeight(), mask.getWidth(), mask.getHeight()));
1093  }
1094  I_mask.resize(I.getHeight(), I.getWidth());
1095  int cpt_in_mask = 0;
1096  int size_ = static_cast<int>(I.getSize());
1097 #if defined(_OPENMP)
1098 #pragma omp parallel for reduction(+:cpt_in_mask)
1099 #endif
1100  for (int i = 0; i < size_; ++i) {
1101  if (mask.bitmap[i] == 0) {
1102  I_mask.bitmap[i] = 0;
1103  }
1104  else {
1105  I_mask.bitmap[i] = I.bitmap[i];
1106  ++cpt_in_mask;
1107  }
1108  }
1109  return cpt_in_mask;
1110 }
1111 
1128 int vpImageTools::inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
1129  const vpColVector &hsv_range, unsigned char *mask, unsigned int size)
1130 {
1131  if ((hue == nullptr) || (saturation == nullptr) || (value == nullptr)) {
1133  "Error in vpImageTools::inRange(): hsv pointer are empty"));
1134  }
1135  else if (hsv_range.size() != 6) {
1137  "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.size()));
1138  }
1139  const unsigned int index_0 = 0;
1140  const unsigned int index_1 = 1;
1141  const unsigned int index_2 = 2;
1142  const unsigned int index_3 = 3;
1143  const unsigned int index_4 = 4;
1144  const unsigned int index_5 = 5;
1145  unsigned char h_low = static_cast<unsigned char>(hsv_range[index_0]);
1146  unsigned char h_high = static_cast<unsigned char>(hsv_range[index_1]);
1147  unsigned char s_low = static_cast<unsigned char>(hsv_range[index_2]);
1148  unsigned char s_high = static_cast<unsigned char>(hsv_range[index_3]);
1149  unsigned char v_low = static_cast<unsigned char>(hsv_range[index_4]);
1150  unsigned char v_high = static_cast<unsigned char>(hsv_range[index_5]);
1151  int size_ = static_cast<int>(size);
1152  int cpt_in_range = 0;
1153 #if defined(_OPENMP)
1154 #pragma omp parallel for reduction(+:cpt_in_range)
1155 #endif
1156  for (int i = 0; i < size_; ++i) {
1157  bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1158  bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1159  bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1160  if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1161  mask[i] = 255;
1162  ++cpt_in_range;
1163  }
1164  else {
1165  mask[i] = 0;
1166  }
1167  }
1168  return cpt_in_range;
1169 }
1170 
1188 int vpImageTools::inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
1189  const std::vector<int> &hsv_range, unsigned char *mask, unsigned int size)
1190 {
1191  if ((hue == nullptr) || (saturation == nullptr) || (value == nullptr)) {
1193  "Error in vpImageTools::inRange(): hsv pointer are empty"));
1194  }
1195  else if (hsv_range.size() != 6) {
1197  "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.size()));
1198  }
1199  const unsigned int index_0 = 0;
1200  const unsigned int index_1 = 1;
1201  const unsigned int index_2 = 2;
1202  const unsigned int index_3 = 3;
1203  const unsigned int index_4 = 4;
1204  const unsigned int index_5 = 5;
1205  unsigned char h_low = static_cast<unsigned char>(hsv_range[index_0]);
1206  unsigned char h_high = static_cast<unsigned char>(hsv_range[index_1]);
1207  unsigned char s_low = static_cast<unsigned char>(hsv_range[index_2]);
1208  unsigned char s_high = static_cast<unsigned char>(hsv_range[index_3]);
1209  unsigned char v_low = static_cast<unsigned char>(hsv_range[index_4]);
1210  unsigned char v_high = static_cast<unsigned char>(hsv_range[index_5]);
1211  int size_ = static_cast<int>(size);
1212  int cpt_in_range = 0;
1213 #if defined(_OPENMP)
1214 #pragma omp parallel for reduction(+:cpt_in_range)
1215 #endif
1216  for (int i = 0; i < size_; ++i) {
1217  bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1218  bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1219  bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1220  if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1221  mask[i] = 255;
1222  ++cpt_in_range;
1223  }
1224  else {
1225  mask[i] = 0;
1226  }
1227  }
1228  return cpt_in_range;
1229 }
1230 END_VISP_NAMESPACE
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition: vpArray2D.h:145
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:148
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:349
Generic class defining intrinsic camera parameters.
std::vector< double > getKannalaBrandtDistortionCoefficients() const
@ ProjWithKannalaBrandtDistortion
Projection with Kannala-Brandt distortion model.
vpCameraParametersProjType get_projModel() const
double get_kud() const
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
@ notImplementedError
Not implemented.
Definition: vpException.h:69
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Error that can be emitted by the vpImage class and its derivatives.
@ notInitializedError
Image not initialized.
@ incorrectInitializationError
Wrong image initialization.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_j() const
Definition: vpImagePoint.h:125
double get_i() const
Definition: vpImagePoint.h:114
static void imageDifference(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Idiff)
static void templateMatching(const vpImage< unsigned char > &I, const vpImage< unsigned char > &I_tpl, vpImage< double > &I_score, unsigned int step_u, unsigned int step_v, bool useOptimized=true)
static void initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height, vpArray2D< int > &mapU, vpArray2D< int > &mapV, vpArray2D< float > &mapDu, vpArray2D< float > &mapDv)
static void crop(const vpImage< Type > &I, double roi_top, double roi_left, unsigned int roi_height, unsigned int roi_width, vpImage< Type > &crop, unsigned int v_scale=1, unsigned int h_scale=1)
Definition: vpImageTools.h:315
static double interpolate(const vpImage< unsigned char > &I, const vpImagePoint &point, const vpImageInterpolationType &method=INTERPOLATION_NEAREST)
static void integralImage(const vpImage< unsigned char > &I, vpImage< double > &II, vpImage< double > &IIsq)
static void extract(const vpImage< unsigned char > &src, vpImage< unsigned char > &dst, const vpRectOriented &r)
static void imageSubtract(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, bool saturate=false)
static void imageAdd(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, bool saturate=false)
static int inMask(const vpImage< unsigned char > &I, const vpImage< unsigned char > &mask, vpImage< unsigned char > &I_mask)
static void columnMean(const vpImage< double > &I, vpRowVector &result)
static void normalize(vpImage< double > &I)
static void remap(const vpImage< unsigned char > &I, const vpArray2D< int > &mapU, const vpArray2D< int > &mapV, const vpArray2D< float > &mapDu, const vpArray2D< float > &mapDv, vpImage< unsigned char > &Iundist)
@ INTERPOLATION_LINEAR
Definition: vpImageTools.h:81
@ INTERPOLATION_NEAREST
Definition: vpImageTools.h:80
static void changeLUT(vpImage< unsigned char > &I, unsigned char A, unsigned char newA, unsigned char B, unsigned char newB)
static double normalizedCorrelation(const vpImage< double > &I1, const vpImage< double > &I2, bool useOptimized=true)
static int inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value, const vpColVector &hsv_range, unsigned char *mask, unsigned int size)
static void imageDifferenceAbsolute(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Idiff)
double getSum(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Compute the sum of image intensities.
unsigned int getWidth() const
Definition: vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:538
unsigned int getSize() const
Definition: vpImage.h:221
Type * bitmap
points toward the bitmap
Definition: vpImage.h:135
unsigned int getHeight() const
Definition: vpImage.h:181
double getMeanValue(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Return the mean value of the bitmap.
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:254
static double sqr(double x)
Definition: vpMath.h:203
static Type abs(const Type &x)
Definition: vpMath.h:269
static int round(double x)
Definition: vpMath.h:409
static Type minimum(const Type &a, const Type &b)
Definition: vpMath.h:262
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
Definition: vpRGBa.h:65
unsigned char B
Blue component.
Definition: vpRGBa.h:169
unsigned char R
Red component.
Definition: vpRGBa.h:167
unsigned char G
Green component.
Definition: vpRGBa.h:168
unsigned char A
Additionnal component.
Definition: vpRGBa.h:170
Defines an oriented rectangle in the plane.
double getHeight() const
Get the rectangle height.
double getOrientation() const
Get the rectangle orientation (rad).
double getWidth() const
Get the rectangle width.
vpImagePoint getTopLeft() const
Get the top-left corner.
Defines a rectangle in the plane.
Definition: vpRect.h:79
Implementation of row vector and the associated operations.
Definition: vpRowVector.h:124
void resize(unsigned int i, bool flagNullify=true)
Definition: vpRowVector.h:287