Visual Servoing Platform  version 3.6.1 under development (2025-02-18)
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 
44 BEGIN_VISP_NAMESPACE
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  const int val_255 = 255;
161  unsigned int i1_size = I1.getSize();
162  for (unsigned int i = 0; i < i1_size; ++i) {
163  int diff = (I1.bitmap[i] - I2.bitmap[i]) + 128;
164  Idiff.bitmap[i] = static_cast<unsigned char>(std::max<unsigned char>(std::min<unsigned char>(diff, val_255), 0));
165  }
166 #endif
167 }
168 
183 {
184  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
186  "Cannot compute image difference. The two images "
187  "(%ux%u) and (%ux%u) have not the same size",
188  I1.getWidth(), I1.getHeight(), I2.getWidth(), I2.getHeight()));
189  }
190 
191  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
192  Idiff.resize(I1.getHeight(), I1.getWidth());
193  }
194 
195 #if defined(VISP_HAVE_SIMDLIB)
196  SimdImageDifference(reinterpret_cast<unsigned char *>(I1.bitmap), reinterpret_cast<unsigned char *>(I2.bitmap),
197  I1.getSize() * 4, reinterpret_cast<unsigned char *>(Idiff.bitmap));
198 #else
199  const unsigned int val_4 = 4;
200  const int val_255 = 255;
201  unsigned int i1_size = I1.getSize();
202  for (unsigned int i = 0; i < (i1_size * val_4); ++i) {
203  int diffR = (I1.bitmap[i].R - I2.bitmap[i].R) + 128;
204  int diffG = (I1.bitmap[i].G - I2.bitmap[i].G) + 128;
205  int diffB = (I1.bitmap[i].B - I2.bitmap[i].B) + 128;
206  int diffA = (I1.bitmap[i].A - I2.bitmap[i].A) + 128;
207  Idiff.bitmap[i].R = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffR, val_255), 0));
208  Idiff.bitmap[i].G = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffG, val_255), 0));
209  Idiff.bitmap[i].B = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffB, val_255), 0));
210  Idiff.bitmap[i].A = static_cast<unsigned char>(vpMath::maximum(vpMath::minimum(diffA, val_255), 0));
211  }
212 #endif
213 }
214 
226  vpImage<unsigned char> &Idiff)
227 {
228  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
229  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
230  }
231 
232  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
233  Idiff.resize(I1.getHeight(), I1.getWidth());
234  }
235 
236  unsigned int n = I1.getHeight() * I1.getWidth();
237  for (unsigned int b = 0; b < n; ++b) {
238  int diff = I1.bitmap[b] - I2.bitmap[b];
239  Idiff.bitmap[b] = static_cast<unsigned char>(vpMath::abs(diff));
240  }
241 }
242 
251 {
252  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
253  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
254  }
255 
256  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
257  Idiff.resize(I1.getHeight(), I1.getWidth());
258  }
259 
260  unsigned int n = I1.getHeight() * I1.getWidth();
261  for (unsigned int b = 0; b < n; ++b) {
262  Idiff.bitmap[b] = vpMath::abs(I1.bitmap[b] - I2.bitmap[b]);
263  }
264 }
265 
280 {
281  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
282  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
283  }
284 
285  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
286  Idiff.resize(I1.getHeight(), I1.getWidth());
287  }
288 
289  unsigned int n = I1.getHeight() * I1.getWidth();
290  for (unsigned int b = 0; b < n; ++b) {
291  int diffR = I1.bitmap[b].R - I2.bitmap[b].R;
292  int diffG = I1.bitmap[b].G - I2.bitmap[b].G;
293  int diffB = I1.bitmap[b].B - I2.bitmap[b].B;
294  // --comment: int diffA eq I1 dot bitmap[b] dot A minus I2 dot bitmap[b] dot A
295  Idiff.bitmap[b].R = static_cast<unsigned char>(vpMath::abs(diffR));
296  Idiff.bitmap[b].G = static_cast<unsigned char>(vpMath::abs(diffG));
297  Idiff.bitmap[b].B = static_cast<unsigned char>(vpMath::abs(diffB));
298  // --comment: Idiff dot bitmap[b] dot A eq diffA
299  Idiff.bitmap[b].A = 0;
300  }
301 }
302 
317  vpImage<unsigned char> &Ires, bool saturate)
318 {
319  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
320  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
321  }
322 
323  if ((I1.getHeight() != Ires.getHeight()) || (I1.getWidth() != Ires.getWidth())) {
324  Ires.resize(I1.getHeight(), I1.getWidth());
325  }
326 
327 #if defined(VISP_HAVE_SIMDLIB)
328  typedef Simd::View<Simd::Allocator> View;
329  View img1(I1.getWidth(), I1.getHeight(), I1.getWidth(), View::Gray8, I1.bitmap);
330  View img2(I2.getWidth(), I2.getHeight(), I2.getWidth(), View::Gray8, I2.bitmap);
331  View imgAdd(Ires.getWidth(), Ires.getHeight(), Ires.getWidth(), View::Gray8, Ires.bitmap);
332 
333  Simd::OperationBinary8u(img1, img2, imgAdd,
334  saturate ? SimdOperationBinary8uSaturatedAddition : SimdOperationBinary8uAddition);
335 #else
336  unsigned char *ptr_I1 = I1.bitmap;
337  unsigned char *ptr_I2 = I2.bitmap;
338  unsigned char *ptr_Ires = Ires.bitmap;
339  unsigned int ires_size = Ires.getSize();
340  for (unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
341  *ptr_Ires = saturate ? vpMath::saturate<unsigned char>(static_cast<short int>(*ptr_I1) + static_cast<short int>(*ptr_I2)) : ((*ptr_I1) + (*ptr_I2));
342  }
343 #endif
344 }
345 
360  vpImage<unsigned char> &Ires, bool saturate)
361 {
362  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
363  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
364  }
365 
366  if ((I1.getHeight() != Ires.getHeight()) || (I1.getWidth() != Ires.getWidth())) {
367  Ires.resize(I1.getHeight(), I1.getWidth());
368  }
369 
370 #if defined(VISP_HAVE_SIMDLIB)
371  typedef Simd::View<Simd::Allocator> View;
372  View img1(I1.getWidth(), I1.getHeight(), I1.getWidth(), View::Gray8, I1.bitmap);
373  View img2(I2.getWidth(), I2.getHeight(), I2.getWidth(), View::Gray8, I2.bitmap);
374  View imgAdd(Ires.getWidth(), Ires.getHeight(), Ires.getWidth(), View::Gray8, Ires.bitmap);
375 
376  Simd::OperationBinary8u(img1, img2, imgAdd,
377  saturate ? SimdOperationBinary8uSaturatedSubtraction : SimdOperationBinary8uSubtraction);
378 #else
379  unsigned char *ptr_I1 = I1.bitmap;
380  unsigned char *ptr_I2 = I2.bitmap;
381  unsigned char *ptr_Ires = Ires.bitmap;
382  unsigned int ires_size = Ires.getSize();
383  for (unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
384  *ptr_Ires = saturate ?
385  vpMath::saturate<unsigned char>(static_cast<short int>(*ptr_I1) - static_cast<short int>(*ptr_I2)) :
386  ((*ptr_I1) - (*ptr_I2));
387  }
388 #endif
389 }
390 
402 void vpImageTools::initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height,
403  vpArray2D<int> &mapU, vpArray2D<int> &mapV, vpArray2D<float> &mapDu,
404  vpArray2D<float> &mapDv)
405 {
406  mapU.resize(height, width, false, false);
407  mapV.resize(height, width, false, false);
408  mapDu.resize(height, width, false, false);
409  mapDv.resize(height, width, false, false);
410 
412  bool is_KannalaBrandt =
413  (projModel == vpCameraParameters::ProjWithKannalaBrandtDistortion); // Check the projection model used
414 
415  float u0 = static_cast<float>(cam.get_u0());
416  float v0 = static_cast<float>(cam.get_v0());
417  float px = static_cast<float>(cam.get_px());
418  float py = static_cast<float>(cam.get_py());
419  float kud = 0;
420  std::vector<double> dist_coefs;
421 
422  if (!is_KannalaBrandt) {
423  kud = static_cast<float>(cam.get_kud());
424  }
425  else {
426  dist_coefs = cam.getKannalaBrandtDistortionCoefficients();
427  }
428 
429  if ((!is_KannalaBrandt) && (std::fabs(static_cast<double>(kud)) <= std::numeric_limits<double>::epsilon())) {
430  // There is no need to undistort the image (Perpective projection)
431  for (unsigned int i = 0; i < height; ++i) {
432  for (unsigned int j = 0; j < width; ++j) {
433  mapU[i][j] = static_cast<int>(j);
434  mapV[i][j] = static_cast<int>(i);
435  mapDu[i][j] = 0;
436  mapDv[i][j] = 0;
437  }
438  }
439 
440  return;
441  }
442 
443  float invpx, invpy;
444  float kud_px2 = 0., kud_py2 = 0., deltau_px, deltav_py = 0;
445  float fr1 = 0, fr2;
446  float deltav, deltau;
447  float u_float, v_float;
448  int u_round, v_round;
449  double r, scale;
450  double theta, theta_d;
451  double theta2, theta4, theta6, theta8;
452  const unsigned int index_0 = 0;
453  const unsigned int index_1 = 1;
454  const unsigned int index_2 = 2;
455  const unsigned int index_3 = 3;
456 
457  invpx = 1.0f / px;
458  invpy = 1.0f / py;
459 
460  if (!is_KannalaBrandt) {
461  kud_px2 = kud * invpx * invpx;
462  kud_py2 = kud * invpy * invpy;
463  }
464 
465  for (unsigned int v = 0; v < height; ++v) {
466  deltav = v - v0;
467 
468  if (!is_KannalaBrandt) {
469  fr1 = 1.0f + (kud_py2 * deltav * deltav);
470  }
471  else {
472  deltav_py = deltav * invpy;
473  }
474 
475  for (unsigned int u = 0; u < width; ++u) {
476  // computation of u,v : corresponding pixel coordinates in I.
477  deltau = u - u0;
478  if (!is_KannalaBrandt) {
479  fr2 = fr1 + (kud_px2 * deltau * deltau);
480 
481  u_float = (deltau * fr2) + u0;
482  v_float = (deltav * fr2) + v0;
483  }
484 
485  else {
486  deltau_px = deltau * invpx;
487  r = sqrt(vpMath::sqr(deltau_px) + vpMath::sqr(deltav_py));
488  theta = atan(r);
489 
490  theta2 = vpMath::sqr(theta);
491  theta4 = vpMath::sqr(theta2);
492  theta6 = theta2 * theta4;
493  theta8 = vpMath::sqr(theta4);
494 
495  theta_d = theta * (1 + (dist_coefs[index_0] * theta2) + (dist_coefs[index_1] * theta4) + (dist_coefs[index_2] * theta6) +
496  (dist_coefs[index_3] * theta8));
497 
498  // --comment: scale eq (r == 0) 1.0 otherwise theta_d / r
499  scale = (std::fabs(r) < std::numeric_limits<double>::epsilon()) ? 1.0 : (theta_d / r);
500  u_float = static_cast<float>((deltau * scale) + u0);
501  v_float = static_cast<float>((deltav * scale) + v0);
502  }
503 
504  u_round = static_cast<int>(u_float);
505  v_round = static_cast<int>(v_float);
506 
507  mapU[v][u] = u_round;
508  mapV[v][u] = v_round;
509 
510  mapDu[v][u] = u_float - u_round;
511  mapDv[v][u] = v_float - v_round;
512  }
513  }
514 }
515 
528 {
529  if (I.getSize() == 0) {
530  std::cerr << "Error, input image is empty." << std::endl;
531  return;
532  }
533 
534  II.resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
535  IIsq.resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
536 
537  unsigned int ii_height = II.getHeight();
538  unsigned int ii_width = II.getWidth();
539  for (unsigned int i = 1; i < ii_height; ++i) {
540  for (unsigned int j = 1; j < ii_width; ++j) {
541  II[i][j] = (I[i - 1][j - 1] + II[i - 1][j] + II[i][j - 1]) - II[i - 1][j - 1];
542  IIsq[i][j] = (vpMath::sqr(I[i - 1][j - 1]) + IIsq[i - 1][j] + IIsq[i][j - 1]) - IIsq[i - 1][j - 1];
543  }
544  }
545 }
546 
554 double vpImageTools::normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, bool useOptimized)
555 {
556  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
558  "Error: in vpImageTools::normalizedCorrelation(): "
559  "image dimension mismatch between I1=%ux%u and I2=%ux%u",
560  I1.getHeight(), I1.getWidth(), I2.getHeight(), I2.getWidth());
561  }
562 
563  const double a = I1.getMeanValue();
564  const double b = I2.getMeanValue();
565 
566  double ab = 0.0;
567  double a2 = 0.0;
568  double b2 = 0.0;
569 
570 #if defined(VISP_HAVE_SIMDLIB)
571  SimdNormalizedCorrelation(I1.bitmap, a, I2.bitmap, b, I1.getSize(), a2, b2, ab, useOptimized);
572 #else
573  unsigned int i1_size = I1.getSize();
574  for (unsigned int cpt = 0; cpt < i1_size; ++cpt) {
575  ab += (I1.bitmap[cpt] - a) * (I2.bitmap[cpt] - b);
576  a2 += vpMath::sqr(I1.bitmap[cpt] - a);
577  b2 += vpMath::sqr(I2.bitmap[cpt] - b);
578  }
579  (void)useOptimized;
580 #endif
581 
582  return ab / sqrt(a2 * b2);
583 }
584 
592 {
593  unsigned int height = I.getHeight(), width = I.getWidth();
594  V.resize(width); // resize and nullify
595 
596  for (unsigned int i = 0; i < height; ++i) {
597  for (unsigned int j = 0; j < width; ++j) {
598  V[j] += I[i][j];
599  }
600  }
601  for (unsigned int j = 0; j < width; ++j) {
602  V[j] /= height;
603  }
604 }
605 
611 {
612  double s = I.getSum();
613  unsigned int i_height = I.getHeight();
614  unsigned int i_width = I.getWidth();
615  for (unsigned int i = 0; i < i_height; ++i) {
616  for (unsigned int j = 0; j < i_width; ++j) {
617  I(i, j, I(i, j) / s);
618  }
619  }
620 }
621 
622 namespace
623 {
629 double interpolationNearest(const vpImage<unsigned char> &I, const vpImagePoint &point)
630 {
631  int x1 = static_cast<int>(floor(point.get_i()));
632  int x2 = static_cast<int>(ceil(point.get_i()));
633  int y1 = static_cast<int>(floor(point.get_j()));
634  int y2 = static_cast<int>(ceil(point.get_j()));
635  double v1, v2;
636  if (x1 == x2) {
637  v1 = I(x1, y1);
638  v2 = I(x1, y2);
639  }
640  else {
641  v1 = ((x2 - point.get_i()) * I(x1, y1)) + ((point.get_i() - x1) * I(x2, y1));
642  v2 = ((x2 - point.get_i()) * I(x1, y2)) + ((point.get_i() - x1) * I(x2, y2));
643  }
644  if (y1 == y2) {
645  return v1;
646  }
647  return ((y2 - point.get_j()) * v1) + ((point.get_j() - y1) * v2);
648 }
649 }
650 
659  const vpImageInterpolationType &method)
660 {
661  switch (method) {
663  return I(vpMath::round(point.get_i()), vpMath::round(point.get_j()));
664  case INTERPOLATION_LINEAR: {
665  return interpolationNearest(I, point);
666  }
667  case INTERPOLATION_CUBIC: {
669  "vpImageTools::interpolate(): bi-cubic interpolation is not implemented.");
670  }
671  default: {
672  throw vpException(vpException::notImplementedError, "vpImageTools::interpolate(): invalid interpolation type");
673  }
674  }
675 }
676 
684 {
685  unsigned int x_d = vpMath::round(r.getHeight());
686  unsigned int y_d = vpMath::round(r.getWidth());
687  double x1 = r.getTopLeft().get_i();
688  double y1 = r.getTopLeft().get_j();
689  double t = r.getOrientation();
690  double cos_t = cos(t);
691  double sin_t = sin(t);
692  dst.resize(x_d, y_d);
693  for (unsigned int x = 0; x < x_d; ++x) {
694  double x_cos_t = x * cos_t;
695  double x_sin_t = x * sin_t;
696  for (unsigned int y = 0; y < y_d; ++y) {
697  dst(x, y,
698  static_cast<unsigned char>(interpolate(src, vpImagePoint(x1 + x_cos_t + (y * sin_t), (y1 - x_sin_t) + (y * cos_t)),
700  }
701  }
702 }
703 
711 {
712  unsigned int x_d = vpMath::round(r.getHeight());
713  unsigned int y_d = vpMath::round(r.getWidth());
714  double x1 = r.getTopLeft().get_i();
715  double y1 = r.getTopLeft().get_j();
716  double t = r.getOrientation();
717  double cos_t = cos(t);
718  double sin_t = sin(t);
719  dst.resize(x_d, y_d);
720  for (unsigned int x = 0; x < x_d; ++x) {
721  double x_cos_t = x * cos_t;
722  double x_sin_t = x * sin_t;
723  for (unsigned int y = 0; y < y_d; ++y) {
724  dst(x, y,
725  interpolate(src, vpImagePoint(x1 + x_cos_t + (y * sin_t), (y1 - x_sin_t) + (y * cos_t)),
727  }
728  }
729 }
730 
746  vpImage<double> &I_score, unsigned int step_u, unsigned int step_v,
747  bool useOptimized)
748 {
749  if (I.getSize() == 0) {
750  std::cerr << "Error, input image is empty." << std::endl;
751  return;
752  }
753 
754  if (I_tpl.getSize() == 0) {
755  std::cerr << "Error, template image is empty." << std::endl;
756  return;
757  }
758 
759  if ((I_tpl.getHeight() > I.getHeight()) || (I_tpl.getWidth() > I.getWidth())) {
760  std::cerr << "Error, template image is bigger than input image." << std::endl;
761  return;
762  }
763 
764  vpImage<double> I_double, I_tpl_double;
765  vpImageConvert::convert(I, I_double);
766  vpImageConvert::convert(I_tpl, I_tpl_double);
767 
768  unsigned int height_tpl = I_tpl.getHeight(), width_tpl = I_tpl.getWidth();
769  I_score.resize(I.getHeight() - height_tpl, I.getWidth() - width_tpl, 0.0);
770 
771  if (useOptimized) {
772  vpImage<double> II, IIsq;
773  integralImage(I, II, IIsq);
774 
775  vpImage<double> II_tpl, IIsq_tpl;
776  integralImage(I_tpl, II_tpl, IIsq_tpl);
777 
778  // zero-mean template image
779  const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
780  const double mean2 = sum2 / I_tpl.getSize();
781  unsigned int i_tpl_double_size = I_tpl_double.getSize();
782  for (unsigned int cpt = 0; cpt < i_tpl_double_size; ++cpt) {
783  I_tpl_double.bitmap[cpt] -= mean2;
784  }
785 
786 #if defined(_OPENMP) && (_OPENMP >= 200711) // OpenMP 3.1
787 #pragma omp parallel for schedule(dynamic)
788  for (unsigned int i = 0; i < I.getHeight() - height_tpl; i += step_v) {
789  for (unsigned int j = 0; j < I.getWidth() - width_tpl; j += step_u) {
790  I_score[i][j] = normalizedCorrelation(I_double, I_tpl_double, II, IIsq, II_tpl, IIsq_tpl, i, j);
791  }
792  }
793 #else
794  // error C3016: 'i': index variable in OpenMP 'for' statement must have signed integral type
795  int end = static_cast<int>((I.getHeight() - height_tpl) / step_v) + 1;
796  std::vector<unsigned int> vec_step_v(static_cast<size_t>(end));
797  unsigned int i_height = I.getHeight();
798  for (unsigned int cpt = 0, idx = 0; cpt < (i_height - height_tpl); cpt += step_v, ++idx) {
799  vec_step_v[static_cast<size_t>(idx)] = cpt;
800  }
801 #if defined(_OPENMP) // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
802 #pragma omp parallel for schedule(dynamic)
803 #endif
804  for (int cpt = 0; cpt < end; ++cpt) {
805  unsigned int i_width = I.getWidth();
806  for (unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
807  I_score[vec_step_v[cpt]][j] =
808  normalizedCorrelation(I_double, I_tpl_double, II, IIsq, II_tpl, IIsq_tpl, vec_step_v[cpt], j);
809  }
810  }
811 #endif
812  }
813  else {
814  vpImage<double> I_cur;
815 
816  unsigned int i_height = I.getHeight();
817  unsigned int i_width = I.getWidth();
818  for (unsigned int i = 0; i < (i_height - height_tpl); i += step_v) {
819  for (unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
820  vpRect roi(vpImagePoint(i, j), vpImagePoint(((i + height_tpl) - 1), ((j + width_tpl) - 1)));
821  vpImageTools::crop(I_double, roi, I_cur);
822 
823  I_score[i][j] = vpImageTools::normalizedCorrelation(I_cur, I_tpl_double, useOptimized);
824  }
825  }
826  }
827 }
828 
829 // Reference:
830 // http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
831 // t is a value that goes from 0 to 1 to interpolate in a C1 continuous way
832 // across uniformly sampled data points. when t is 0, this will return B.
833 // When t is 1, this will return C. In between values will return an
834 // interpolation between B and C. A and B are used to calculate the slopes at
835 // the edges.
836 float vpImageTools::cubicHermite(const float A, const float B, const float C, const float D, const float t)
837 {
838  float a = (((-A + (3.0f * B)) - (3.0f * C)) + D) / 2.0f;
839  float b = (A + (2.0f * C)) - (((5.0f * B) + D) / 2.0f);
840  float c = (-A + C) / 2.0f;
841  float d = B;
842 
843  return (a * t * t * t) + (b * t * t) + (c * t) + d;
844 }
845 
846 int vpImageTools::coordCast(double x) { return x < 0 ? -1 : static_cast<int>(x); }
847 
848 double vpImageTools::lerp(double A, double B, double t) { return (A * (1.0 - t)) + (B * t); }
849 
850 float vpImageTools::lerp(float A, float B, float t) { return (A * (1.0f - t)) + (B * t); }
851 
852 int64_t vpImageTools::lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1) { return (A * t_1) + (B * t); }
853 
855  const vpImage<double> &II, const vpImage<double> &IIsq,
856  const vpImage<double> &II_tpl, const vpImage<double> &IIsq_tpl,
857  unsigned int i0, unsigned int j0)
858 {
859  double ab = 0.0;
860 
861 #if defined(VISP_HAVE_SIMDLIB)
862  SimdNormalizedCorrelation2(I1.bitmap, I1.getWidth(), I2.bitmap, I2.getWidth(), I2.getHeight(), i0, j0, ab);
863 #else
864  unsigned int i2_height = I2.getHeight();
865  unsigned int i2_width = I2.getWidth();
866  for (unsigned int i = 0; i < i2_height; ++i) {
867  for (unsigned int j = 0; j < i2_width; ++j) {
868  ab += (I1[i0 + i][j0 + j]) * I2[i][j];
869  }
870  }
871 #endif
872 
873  unsigned int height_tpl = I2.getHeight(), width_tpl = I2.getWidth();
874  const double sum1 =
875  (((II[i0 + height_tpl][j0 + width_tpl] + II[i0][j0]) - II[i0][j0 + width_tpl]) - II[i0 + height_tpl][j0]);
876  const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
877 
878  double a2 = ((((IIsq[i0 + I2.getHeight()][j0 + I2.getWidth()] + IIsq[i0][j0]) - IIsq[i0][j0 + I2.getWidth()]) -
879  IIsq[i0 + I2.getHeight()][j0]) -
880  ((1.0 / I2.getSize()) * vpMath::sqr(sum1)));
881 
882  double b2 = ((((IIsq_tpl[I2.getHeight()][I2.getWidth()] + IIsq_tpl[0][0]) - IIsq_tpl[0][I2.getWidth()]) -
883  IIsq_tpl[I2.getHeight()][0]) -
884  ((1.0 / I2.getSize()) * vpMath::sqr(sum2)));
885  return ab / sqrt(a2 * b2);
886 }
887 
899  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<unsigned char> &Iundist)
900 {
901  Iundist.resize(I.getHeight(), I.getWidth());
902  const int I_height = static_cast<int>(I.getHeight());
903 
904 #if defined(_OPENMP) // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
905 #pragma omp parallel for schedule(dynamic)
906 #endif
907  for (int i_ = 0; i_ < I_height; ++i_) {
908  const unsigned int i = static_cast<unsigned int>(i_);
909  unsigned int i_width = I.getWidth();
910  for (unsigned int j = 0; j < i_width; ++j) {
911 
912  int u_round = mapU[i][j];
913  int v_round = mapV[i][j];
914 
915  float du = mapDu[i][j];
916  float dv = mapDv[i][j];
917 
918  if ((0 <= u_round) && (0 <= v_round) && (u_round < (static_cast<int>(I.getWidth()) - 1)) &&
919  (v_round < (I_height - 1))) {
920  // process interpolation
921  float col0 = lerp(I[v_round][u_round], I[v_round][u_round + 1], du);
922  float col1 = lerp(I[v_round + 1][u_round], I[v_round + 1][u_round + 1], du);
923  float value = lerp(col0, col1, dv);
924 
925  Iundist[i][j] = static_cast<unsigned char>(value);
926  }
927  else {
928  Iundist[i][j] = 0;
929  }
930  }
931  }
932 }
933 
944 void vpImageTools::remap(const vpImage<vpRGBa> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
945  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<vpRGBa> &Iundist)
946 {
947  Iundist.resize(I.getHeight(), I.getWidth());
948  const int I_height = static_cast<int>(I.getHeight());
949 #if defined(_OPENMP) // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
950 #pragma omp parallel for schedule(dynamic)
951 #endif
952  for (int i = 0; i < I_height; ++i) {
953 #if defined(VISP_HAVE_SIMDLIB)
954  SimdRemap(reinterpret_cast<unsigned char *>(I.bitmap), 4, I.getWidth(), I.getHeight(), i * I.getWidth(), mapU.data,
955  mapV.data, mapDu.data, mapDv.data, reinterpret_cast<unsigned char *>(Iundist.bitmap));
956 #else
957  const unsigned int i_ = static_cast<unsigned int>(i);
958  unsigned int i_width = I.getWidth();
959  for (unsigned int j = 0; j < i_width; ++j) {
960 
961  int u_round = mapU[i_][j];
962  int v_round = mapV[i_][j];
963 
964  float du = mapDu[i_][j];
965  float dv = mapDv[i_][j];
966 
967  if ((0 <= u_round) && (0 <= v_round) && (u_round < (static_cast<int>(I.getWidth()) - 1))
968  && (v_round < (I_height - 1))) {
969  // process interpolation
970  float col0 = lerp(I[v_round][u_round].R, I[v_round][u_round + 1].R, du);
971  float col1 = lerp(I[v_round + 1][u_round].R, I[v_round + 1][u_round + 1].R, du);
972  float value = lerp(col0, col1, dv);
973 
974  Iundist[i][j].R = static_cast<unsigned char>(value);
975 
976  col0 = lerp(I[v_round][u_round].G, I[v_round][u_round + 1].G, du);
977  col1 = lerp(I[v_round + 1][u_round].G, I[v_round + 1][u_round + 1].G, du);
978  value = lerp(col0, col1, dv);
979 
980  Iundist[i][j].G = static_cast<unsigned char>(value);
981 
982  col0 = lerp(I[v_round][u_round].B, I[v_round][u_round + 1].B, du);
983  col1 = lerp(I[v_round + 1][u_round].B, I[v_round + 1][u_round + 1].B, du);
984  value = lerp(col0, col1, dv);
985 
986  Iundist[i][j].B = static_cast<unsigned char>(value);
987 
988  col0 = lerp(I[v_round][u_round].A, I[v_round][u_round + 1].A, du);
989  col1 = lerp(I[v_round + 1][u_round].A, I[v_round + 1][u_round + 1].A, du);
990  value = lerp(col0, col1, dv);
991 
992  Iundist[i][j].A = static_cast<unsigned char>(value);
993  }
994  else {
995  Iundist[i][j] = 0;
996  }
997  }
998 #endif
999  }
1000 }
1001 
1002 #if defined(VISP_HAVE_SIMDLIB)
1003 void vpImageTools::resizeSimdlib(const vpImage<vpRGBa> &Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
1004  vpImage<vpRGBa> &Idst, int method)
1005 {
1006  Idst.resize(resizeHeight, resizeWidth);
1007 
1008  typedef Simd::View<Simd::Allocator> View;
1009  View src(Isrc.getWidth(), Isrc.getHeight(), Isrc.getWidth() * sizeof(vpRGBa), View::Bgra32, Isrc.bitmap);
1010  View dst(Idst.getWidth(), Idst.getHeight(), Idst.getWidth() * sizeof(vpRGBa), View::Bgra32, Idst.bitmap);
1011 
1012  Simd::Resize(src, dst, method == INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1013 }
1014 
1015 void vpImageTools::resizeSimdlib(const vpImage<unsigned char> &Isrc, unsigned int resizeWidth,
1016  unsigned int resizeHeight, vpImage<unsigned char> &Idst, int method)
1017 {
1018  Idst.resize(resizeHeight, resizeWidth);
1019 
1020  typedef Simd::View<Simd::Allocator> View;
1021  View src(Isrc.getWidth(), Isrc.getHeight(), Isrc.getWidth(), View::Gray8, Isrc.bitmap);
1022  View dst(Idst.getWidth(), Idst.getHeight(), Idst.getWidth(), View::Gray8, Idst.bitmap);
1023 
1024  Simd::Resize(src, dst, method == INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1025 }
1026 #endif
1027 
1028 bool vpImageTools::checkFixedPoint(unsigned int x, unsigned int y, const vpMatrix &T, bool affine)
1029 {
1030  const unsigned int index_0 = 0;
1031  const unsigned int index_1 = 1;
1032  const unsigned int index_2 = 2;
1033  double a0 = T[index_0][index_0];
1034  double a1 = T[index_0][index_1];
1035  double a2 = T[index_0][index_2];
1036  double a3 = T[index_1][index_0];
1037  double a4 = T[index_1][index_1];
1038  double a5 = T[index_1][index_2];
1039  double a6 = affine ? 0.0 : T[index_2][index_0];
1040  double a7 = affine ? 0.0 : T[index_2][index_1];
1041  double a8 = affine ? 1.0 : T[index_2][index_2];
1042 
1043  double w = (a6 * x) + (a7 * y) + a8;
1044  double x2 = ((a0 * x) + (a1 * y) + a2) / w;
1045  double y2 = ((a3 * x) + (a4 * y) + a5) / w;
1046 
1047  const double limit = 1 << 15;
1048  return (vpMath::abs(x2) < limit) && (vpMath::abs(y2) < limit);
1049 }
1050 
1059 {
1060  if ((I.getHeight() != mask.getHeight()) || (I.getWidth() != mask.getWidth())) {
1062  "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
1063  I.getWidth(), I.getHeight(), mask.getWidth(), mask.getHeight()));
1064  }
1065  vpRGBa black(0, 0, 0);
1066  I_mask.resize(I.getHeight(), I.getWidth());
1067  int cpt_in_mask = 0;
1068  int size_ = static_cast<int>(I.getSize());
1069 #if defined(_OPENMP)
1070 #pragma omp parallel for reduction(+:cpt_in_mask)
1071 #endif
1072  for (int i = 0; i < size_; ++i) {
1073  if (mask.bitmap[i] == 0) {
1074  I_mask.bitmap[i] = black;
1075  }
1076  else {
1077  I_mask.bitmap[i] = I.bitmap[i];
1078  ++cpt_in_mask;
1079  }
1080  }
1081  return cpt_in_mask;
1082 }
1083 
1092 {
1093  if ((I.getHeight() != mask.getHeight()) || (I.getWidth() != mask.getWidth())) {
1095  "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
1096  I.getWidth(), I.getHeight(), mask.getWidth(), mask.getHeight()));
1097  }
1098  I_mask.resize(I.getHeight(), I.getWidth());
1099  int cpt_in_mask = 0;
1100  int size_ = static_cast<int>(I.getSize());
1101 #if defined(_OPENMP)
1102 #pragma omp parallel for reduction(+:cpt_in_mask)
1103 #endif
1104  for (int i = 0; i < size_; ++i) {
1105  if (mask.bitmap[i] == 0) {
1106  I_mask.bitmap[i] = 0;
1107  }
1108  else {
1109  I_mask.bitmap[i] = I.bitmap[i];
1110  ++cpt_in_mask;
1111  }
1112  }
1113  return cpt_in_mask;
1114 }
1115 
1132 int vpImageTools::inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
1133  const vpColVector &hsv_range, unsigned char *mask, unsigned int size)
1134 {
1135  const std::size_t val_6 = 6;
1136  if ((hue == nullptr) || (saturation == nullptr) || (value == nullptr)) {
1138  "Error in vpImageTools::inRange(): hsv pointer are empty"));
1139  }
1140  else if (hsv_range.size() != val_6) {
1142  "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.size()));
1143  }
1144  const unsigned int index_0 = 0;
1145  const unsigned int index_1 = 1;
1146  const unsigned int index_2 = 2;
1147  const unsigned int index_3 = 3;
1148  const unsigned int index_4 = 4;
1149  const unsigned int index_5 = 5;
1150  const unsigned char val_uchar_255 = 255;
1151  unsigned char h_low = static_cast<unsigned char>(hsv_range[index_0]);
1152  unsigned char h_high = static_cast<unsigned char>(hsv_range[index_1]);
1153  unsigned char s_low = static_cast<unsigned char>(hsv_range[index_2]);
1154  unsigned char s_high = static_cast<unsigned char>(hsv_range[index_3]);
1155  unsigned char v_low = static_cast<unsigned char>(hsv_range[index_4]);
1156  unsigned char v_high = static_cast<unsigned char>(hsv_range[index_5]);
1157  int size_ = static_cast<int>(size);
1158  int cpt_in_range = 0;
1159 #if defined(_OPENMP)
1160 #pragma omp parallel for reduction(+:cpt_in_range)
1161 #endif
1162  for (int i = 0; i < size_; ++i) {
1163  bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1164  bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1165  bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1166  if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1167  mask[i] = val_uchar_255;
1168  ++cpt_in_range;
1169  }
1170  else {
1171  mask[i] = 0;
1172  }
1173  }
1174  return cpt_in_range;
1175 }
1176 
1194 int vpImageTools::inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
1195  const std::vector<int> &hsv_range, unsigned char *mask, unsigned int size)
1196 {
1197  const std::size_t val_6 = 6;
1198  if ((hue == nullptr) || (saturation == nullptr) || (value == nullptr)) {
1200  "Error in vpImageTools::inRange(): hsv pointer are empty"));
1201  }
1202  else if (hsv_range.size() != val_6) {
1204  "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.size()));
1205  }
1206  const unsigned int index_0 = 0;
1207  const unsigned int index_1 = 1;
1208  const unsigned int index_2 = 2;
1209  const unsigned int index_3 = 3;
1210  const unsigned int index_4 = 4;
1211  const unsigned int index_5 = 5;
1212  unsigned char h_low = static_cast<unsigned char>(hsv_range[index_0]);
1213  unsigned char h_high = static_cast<unsigned char>(hsv_range[index_1]);
1214  unsigned char s_low = static_cast<unsigned char>(hsv_range[index_2]);
1215  unsigned char s_high = static_cast<unsigned char>(hsv_range[index_3]);
1216  unsigned char v_low = static_cast<unsigned char>(hsv_range[index_4]);
1217  unsigned char v_high = static_cast<unsigned char>(hsv_range[index_5]);
1218  int size_ = static_cast<int>(size);
1219  int cpt_in_range = 0;
1220 
1221  const unsigned char val_uc_255 = 255;
1222 #if defined(_OPENMP)
1223 #pragma omp parallel for reduction(+:cpt_in_range)
1224 #endif
1225  for (int i = 0; i < size_; ++i) {
1226  bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1227  bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1228  bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1229  if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1230  mask[i] = val_uc_255;
1231  ++cpt_in_range;
1232  }
1233  else {
1234  mask[i] = 0;
1235  }
1236  }
1237  return cpt_in_range;
1238 }
1239 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:442
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:429
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:544
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:410
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:70
unsigned char B
Blue component.
Definition: vpRGBa.h:187
unsigned char R
Red component.
Definition: vpRGBa.h:185
unsigned char G
Green component.
Definition: vpRGBa.h:186
unsigned char A
Additional component.
Definition: vpRGBa.h:188
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:292