Visual Servoing Platform  version 3.5.1 under development (2023-09-22)
vpImageTools.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Image tools.
33  *
34 *****************************************************************************/
35 
36 #include <visp3/core/vpCPUFeatures.h>
37 #include <visp3/core/vpImageConvert.h>
38 #include <visp3/core/vpImageTools.h>
39 
40 #include <Simd/SimdLib.hpp>
41 
97 void vpImageTools::changeLUT(vpImage<unsigned char> &I, unsigned char A, unsigned char A_star, unsigned char B,
98  unsigned char B_star)
99 {
100  // Test if input values are valid
101  if (B <= A) {
102  vpERROR_TRACE("Bad gray levels");
104  }
105  unsigned char v;
106 
107  double factor = (double)(B_star - A_star) / (double)(B - A);
108 
109  for (unsigned int i = 0; i < I.getHeight(); i++)
110  for (unsigned int j = 0; j < I.getWidth(); j++) {
111  v = I[i][j];
112 
113  if (v <= A)
114  I[i][j] = A_star;
115  else if (v >= B)
116  I[i][j] = B_star;
117  else
118  I[i][j] = (unsigned char)(A_star + factor * (v - A));
119  }
120 }
121 
135  vpImage<unsigned char> &Idiff)
136 {
137  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
138  throw(vpException(vpException::dimensionError, "The two images have not the same size"));
139  }
140 
141  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
142  Idiff.resize(I1.getHeight(), I1.getWidth());
143  }
144 
145  SimdImageDifference(I1.bitmap, I2.bitmap, I1.getSize(), Idiff.bitmap);
146 }
147 
162 {
163  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
165  "Cannot compute image difference. The two images "
166  "(%ux%u) and (%ux%u) have not the same size",
167  I1.getWidth(), I1.getHeight(), I2.getWidth(), I2.getHeight()));
168  }
169 
170  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
171  Idiff.resize(I1.getHeight(), I1.getWidth());
172  }
173 
174  SimdImageDifference(reinterpret_cast<unsigned char *>(I1.bitmap), reinterpret_cast<unsigned char *>(I2.bitmap),
175  I1.getSize() * 4, reinterpret_cast<unsigned char *>(Idiff.bitmap));
176 }
177 
189  vpImage<unsigned char> &Idiff)
190 {
191  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
192  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
193  }
194 
195  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
196  Idiff.resize(I1.getHeight(), I1.getWidth());
197  }
198 
199  unsigned int n = I1.getHeight() * I1.getWidth();
200  for (unsigned int b = 0; b < n; b++) {
201  int diff = I1.bitmap[b] - I2.bitmap[b];
202  Idiff.bitmap[b] = static_cast<unsigned char>(vpMath::abs(diff));
203  }
204 }
205 
214 {
215  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
216  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
217  }
218 
219  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
220  Idiff.resize(I1.getHeight(), I1.getWidth());
221  }
222 
223  unsigned int n = I1.getHeight() * I1.getWidth();
224  for (unsigned int b = 0; b < n; b++) {
225  Idiff.bitmap[b] = vpMath::abs(I1.bitmap[b] - I2.bitmap[b]);
226  }
227 }
228 
243 {
244  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
245  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
246  }
247 
248  if ((I1.getHeight() != Idiff.getHeight()) || (I1.getWidth() != Idiff.getWidth())) {
249  Idiff.resize(I1.getHeight(), I1.getWidth());
250  }
251 
252  unsigned int n = I1.getHeight() * I1.getWidth();
253  for (unsigned int b = 0; b < n; b++) {
254  int diffR = I1.bitmap[b].R - I2.bitmap[b].R;
255  int diffG = I1.bitmap[b].G - I2.bitmap[b].G;
256  int diffB = I1.bitmap[b].B - I2.bitmap[b].B;
257  // int diffA = I1.bitmap[b].A - I2.bitmap[b].A;
258  Idiff.bitmap[b].R = static_cast<unsigned char>(vpMath::abs(diffR));
259  Idiff.bitmap[b].G = static_cast<unsigned char>(vpMath::abs(diffG));
260  Idiff.bitmap[b].B = static_cast<unsigned char>(vpMath::abs(diffB));
261  // Idiff.bitmap[b].A = diffA;
262  Idiff.bitmap[b].A = 0;
263  }
264 }
265 
280  vpImage<unsigned char> &Ires, bool saturate)
281 {
282  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
283  throw(vpException(vpException::dimensionError, "The two images do not have the same size"));
284  }
285 
286  if ((I1.getHeight() != Ires.getHeight()) || (I1.getWidth() != Ires.getWidth())) {
287  Ires.resize(I1.getHeight(), I1.getWidth());
288  }
289 
290  typedef Simd::View<Simd::Allocator> View;
291  View img1(I1.getWidth(), I1.getHeight(), I1.getWidth(), View::Gray8, I1.bitmap);
292  View img2(I2.getWidth(), I2.getHeight(), I2.getWidth(), View::Gray8, I2.bitmap);
293  View imgAdd(Ires.getWidth(), Ires.getHeight(), Ires.getWidth(), View::Gray8, Ires.bitmap);
294 
295  Simd::OperationBinary8u(img1, img2, imgAdd,
296  saturate ? SimdOperationBinary8uSaturatedAddition : SimdOperationBinary8uAddition);
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  typedef Simd::View<Simd::Allocator> View;
324  View img1(I1.getWidth(), I1.getHeight(), I1.getWidth(), View::Gray8, I1.bitmap);
325  View img2(I2.getWidth(), I2.getHeight(), I2.getWidth(), View::Gray8, I2.bitmap);
326  View imgAdd(Ires.getWidth(), Ires.getHeight(), Ires.getWidth(), View::Gray8, Ires.bitmap);
327 
328  Simd::OperationBinary8u(img1, img2, imgAdd,
329  saturate ? SimdOperationBinary8uSaturatedSubtraction : SimdOperationBinary8uSubtraction);
330 }
331 
343 void vpImageTools::initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height,
344  vpArray2D<int> &mapU, vpArray2D<int> &mapV, vpArray2D<float> &mapDu,
345  vpArray2D<float> &mapDv)
346 {
347  mapU.resize(height, width, false, false);
348  mapV.resize(height, width, false, false);
349  mapDu.resize(height, width, false, false);
350  mapDv.resize(height, width, false, false);
351 
353  bool is_KannalaBrandt =
354  (projModel == vpCameraParameters::ProjWithKannalaBrandtDistortion); // Check the projection model used
355 
356  float u0 = static_cast<float>(cam.get_u0());
357  float v0 = static_cast<float>(cam.get_v0());
358  float px = static_cast<float>(cam.get_px());
359  float py = static_cast<float>(cam.get_py());
360  float kud = 0;
361  std::vector<double> dist_coefs;
362 
363  if (!is_KannalaBrandt)
364  kud = static_cast<float>(cam.get_kud());
365 
366  else
367  dist_coefs = cam.getKannalaBrandtDistortionCoefficients();
368 
369  if (!is_KannalaBrandt && std::fabs(static_cast<double>(kud)) <= std::numeric_limits<double>::epsilon()) {
370  // There is no need to undistort the image (Perpective projection)
371  for (unsigned int i = 0; i < height; i++) {
372  for (unsigned int j = 0; j < width; j++) {
373  mapU[i][j] = static_cast<int>(j);
374  mapV[i][j] = static_cast<int>(i);
375  mapDu[i][j] = 0;
376  mapDv[i][j] = 0;
377  }
378  }
379 
380  return;
381  }
382 
383  float invpx, invpy;
384  float kud_px2 = 0., kud_py2 = 0., deltau_px, deltav_py = 0;
385  float fr1 = 0, fr2;
386  float deltav, deltau;
387  float u_float, v_float;
388  int u_round, v_round;
389  double r, scale;
390  double theta, theta_d;
391  double theta2, theta4, theta6, theta8;
392 
393  invpx = 1.0f / px;
394  invpy = 1.0f / py;
395 
396  if (!is_KannalaBrandt) {
397  kud_px2 = kud * invpx * invpx;
398  kud_py2 = kud * invpy * invpy;
399  }
400 
401  for (unsigned int v = 0; v < height; v++) {
402  deltav = v - v0;
403 
404  if (!is_KannalaBrandt)
405  fr1 = 1.0f + kud_py2 * deltav * deltav;
406  else
407  deltav_py = deltav * invpy;
408 
409  for (unsigned int u = 0; u < width; u++) {
410  // computation of u,v : corresponding pixel coordinates in I.
411  deltau = u - u0;
412  if (!is_KannalaBrandt) {
413  fr2 = fr1 + kud_px2 * deltau * deltau;
414 
415  u_float = deltau * fr2 + u0;
416  v_float = deltav * fr2 + v0;
417  }
418 
419  else {
420  deltau_px = deltau * invpx;
421  r = sqrt(vpMath::sqr(deltau_px) + vpMath::sqr(deltav_py));
422  theta = atan(r);
423 
424  theta2 = vpMath::sqr(theta);
425  theta4 = vpMath::sqr(theta2);
426  theta6 = theta2 * theta4;
427  theta8 = vpMath::sqr(theta4);
428 
429  theta_d = theta * (1 + dist_coefs[0] * theta2 + dist_coefs[1] * theta4 + dist_coefs[2] * theta6 +
430  dist_coefs[3] * theta8);
431 
432  // scale = (r == 0) ? 1.0 : theta_d / r;
433  scale = (std::fabs(r) < std::numeric_limits<double>::epsilon()) ? 1.0 : theta_d / r;
434  u_float = static_cast<float>(deltau * scale + u0);
435  v_float = static_cast<float>(deltav * scale + v0);
436  }
437 
438  u_round = static_cast<int>(u_float);
439  v_round = static_cast<int>(v_float);
440 
441  mapU[v][u] = u_round;
442  mapV[v][u] = v_round;
443 
444  mapDu[v][u] = u_float - u_round;
445  mapDv[v][u] = v_float - v_round;
446  }
447  }
448 }
449 
462 {
463  if (I.getSize() == 0) {
464  std::cerr << "Error, input image is empty." << std::endl;
465  return;
466  }
467 
468  II.resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
469  IIsq.resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
470 
471  for (unsigned int i = 1; i < II.getHeight(); i++) {
472  for (unsigned int j = 1; j < II.getWidth(); j++) {
473  II[i][j] = I[i - 1][j - 1] + II[i - 1][j] + II[i][j - 1] - II[i - 1][j - 1];
474  IIsq[i][j] = vpMath::sqr(I[i - 1][j - 1]) + IIsq[i - 1][j] + IIsq[i][j - 1] - IIsq[i - 1][j - 1];
475  }
476  }
477 }
478 
486 double vpImageTools::normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, bool useOptimized)
487 {
488  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
490  "Error: in vpImageTools::normalizedCorrelation(): "
491  "image dimension mismatch between I1=%ux%u and I2=%ux%u",
492  I1.getHeight(), I1.getWidth(), I2.getHeight(), I2.getWidth());
493  }
494 
495  const double a = I1.getMeanValue();
496  const double b = I2.getMeanValue();
497 
498  double ab = 0.0;
499  double a2 = 0.0;
500  double b2 = 0.0;
501 
502  SimdNormalizedCorrelation(I1.bitmap, a, I2.bitmap, b, I1.getSize(), a2, b2, ab, useOptimized);
503 
504  return ab / sqrt(a2 * b2);
505 }
506 
514 {
515  unsigned int height = I.getHeight(), width = I.getWidth();
516  V.resize(width); // resize and nullify
517 
518  for (unsigned int i = 0; i < height; ++i)
519  for (unsigned int j = 0; j < width; ++j)
520  V[j] += I[i][j];
521  for (unsigned int j = 0; j < width; ++j)
522  V[j] /= height;
523 }
524 
530 {
531  double s = I.getSum();
532  for (unsigned int i = 0; i < I.getHeight(); ++i)
533  for (unsigned int j = 0; j < I.getWidth(); ++j)
534  I(i, j, I(i, j) / s);
535 }
536 
545  const vpImageInterpolationType &method)
546 {
547  switch (method) {
549  return I(vpMath::round(point.get_i()), vpMath::round(point.get_j()));
550  case INTERPOLATION_LINEAR: {
551  int x1 = (int)floor(point.get_i());
552  int x2 = (int)ceil(point.get_i());
553  int y1 = (int)floor(point.get_j());
554  int y2 = (int)ceil(point.get_j());
555  double v1, v2;
556  if (x1 == x2) {
557  v1 = I(x1, y1);
558  v2 = I(x1, y2);
559  } else {
560  v1 = (x2 - point.get_i()) * I(x1, y1) + (point.get_i() - x1) * I(x2, y1);
561  v2 = (x2 - point.get_i()) * I(x1, y2) + (point.get_i() - x1) * I(x2, y2);
562  }
563  if (y1 == y2)
564  return v1;
565  return (y2 - point.get_j()) * v1 + (point.get_j() - y1) * v2;
566  }
567  case INTERPOLATION_CUBIC: {
569  "vpImageTools::interpolate(): bi-cubic interpolation is not implemented.");
570  }
571  default: {
572  throw vpException(vpException::notImplementedError, "vpImageTools::interpolate(): invalid interpolation type");
573  }
574  }
575 }
576 
584 {
585  unsigned int x_d = vpMath::round(r.getHeight());
586  unsigned int y_d = vpMath::round(r.getWidth());
587  double x1 = r.getTopLeft().get_i();
588  double y1 = r.getTopLeft().get_j();
589  double t = r.getOrientation();
590  Dst.resize(x_d, y_d);
591  for (unsigned int x = 0; x < x_d; ++x) {
592  for (unsigned int y = 0; y < y_d; ++y) {
593  Dst(x, y,
594  (unsigned char)interpolate(Src, vpImagePoint(x1 + x * cos(t) + y * sin(t), y1 - x * sin(t) + y * cos(t)),
596  }
597  }
598 }
599 
607 {
608  unsigned int x_d = vpMath::round(r.getHeight());
609  unsigned int y_d = vpMath::round(r.getWidth());
610  double x1 = r.getTopLeft().get_i();
611  double y1 = r.getTopLeft().get_j();
612  double t = r.getOrientation();
613  Dst.resize(x_d, y_d);
614  for (unsigned int x = 0; x < x_d; ++x) {
615  for (unsigned int y = 0; y < y_d; ++y) {
616  Dst(x, y,
617  interpolate(Src, vpImagePoint(x1 + x * cos(t) + y * sin(t), y1 - x * sin(t) + y * cos(t)),
619  }
620  }
621 }
622 
638  vpImage<double> &I_score, unsigned int step_u, unsigned int step_v,
639  bool useOptimized)
640 {
641  if (I.getSize() == 0) {
642  std::cerr << "Error, input image is empty." << std::endl;
643  return;
644  }
645 
646  if (I_tpl.getSize() == 0) {
647  std::cerr << "Error, template image is empty." << std::endl;
648  return;
649  }
650 
651  if (I_tpl.getHeight() > I.getHeight() || I_tpl.getWidth() > I.getWidth()) {
652  std::cerr << "Error, template image is bigger than input image." << std::endl;
653  return;
654  }
655 
656  vpImage<double> I_double, I_tpl_double;
657  vpImageConvert::convert(I, I_double);
658  vpImageConvert::convert(I_tpl, I_tpl_double);
659 
660  unsigned int height_tpl = I_tpl.getHeight(), width_tpl = I_tpl.getWidth();
661  I_score.resize(I.getHeight() - height_tpl, I.getWidth() - width_tpl, 0.0);
662 
663  if (useOptimized) {
664  vpImage<double> II, IIsq;
665  integralImage(I, II, IIsq);
666 
667  vpImage<double> II_tpl, IIsq_tpl;
668  integralImage(I_tpl, II_tpl, IIsq_tpl);
669 
670  // zero-mean template image
671  const double sum2 = (II_tpl[height_tpl][width_tpl] + II_tpl[0][0] - II_tpl[0][width_tpl] - II_tpl[height_tpl][0]);
672  const double mean2 = sum2 / I_tpl.getSize();
673  for (unsigned int cpt = 0; cpt < I_tpl_double.getSize(); cpt++) {
674  I_tpl_double.bitmap[cpt] -= mean2;
675  }
676 
677 #if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
678 #pragma omp parallel for schedule(dynamic)
679  for (unsigned int i = 0; i < I.getHeight() - height_tpl; i += step_v) {
680  for (unsigned int j = 0; j < I.getWidth() - width_tpl; j += step_u) {
681  I_score[i][j] = normalizedCorrelation(I_double, I_tpl_double, II, IIsq, II_tpl, IIsq_tpl, i, j);
682  }
683  }
684 #else
685  // error C3016: 'i': index variable in OpenMP 'for' statement must have signed integral type
686  int end = (int)((I.getHeight() - height_tpl) / step_v) + 1;
687  std::vector<unsigned int> vec_step_v((size_t)end);
688  for (unsigned int cpt = 0, idx = 0; cpt < I.getHeight() - height_tpl; cpt += step_v, idx++) {
689  vec_step_v[(size_t)idx] = cpt;
690  }
691 #if defined _OPENMP // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
692 #pragma omp parallel for schedule(dynamic)
693 #endif
694  for (int cpt = 0; cpt < end; cpt++) {
695  for (unsigned int j = 0; j < I.getWidth() - width_tpl; j += step_u) {
696  I_score[vec_step_v[cpt]][j] =
697  normalizedCorrelation(I_double, I_tpl_double, II, IIsq, II_tpl, IIsq_tpl, vec_step_v[cpt], j);
698  }
699  }
700 #endif
701  } else {
702  vpImage<double> I_cur;
703 
704  for (unsigned int i = 0; i < I.getHeight() - height_tpl; i += step_v) {
705  for (unsigned int j = 0; j < I.getWidth() - width_tpl; j += step_u) {
706  vpRect roi(vpImagePoint(i, j), vpImagePoint(i + height_tpl - 1, j + width_tpl - 1));
707  vpImageTools::crop(I_double, roi, I_cur);
708 
709  I_score[i][j] = vpImageTools::normalizedCorrelation(I_cur, I_tpl_double, useOptimized);
710  }
711  }
712  }
713 }
714 
715 // Reference:
716 // http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
717 // t is a value that goes from 0 to 1 to interpolate in a C1 continuous way
718 // across uniformly sampled data points. when t is 0, this will return B.
719 // When t is 1, this will return C. In between values will return an
720 // interpolation between B and C. A and B are used to calculate the slopes at
721 // the edges.
722 float vpImageTools::cubicHermite(const float A, const float B, const float C, const float D, const float t)
723 {
724  float a = (-A + 3.0f * B - 3.0f * C + D) / 2.0f;
725  float b = A + 2.0f * C - (5.0f * B + D) / 2.0f;
726  float c = (-A + C) / 2.0f;
727  float d = B;
728 
729  return a * t * t * t + b * t * t + c * t + d;
730 }
731 
732 int vpImageTools::coordCast(double x) { return x < 0 ? -1 : static_cast<int>(x); }
733 
734 double vpImageTools::lerp(double A, double B, double t) { return A * (1.0 - t) + B * t; }
735 
736 float vpImageTools::lerp(float A, float B, float t) { return A * (1.0f - t) + B * t; }
737 
738 int64_t vpImageTools::lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1) { return A * t_1 + B * t; }
739 
741  const vpImage<double> &II, const vpImage<double> &IIsq,
742  const vpImage<double> &II_tpl, const vpImage<double> &IIsq_tpl,
743  unsigned int i0, unsigned int j0)
744 {
745  double ab = 0.0;
746  SimdNormalizedCorrelation2(I1.bitmap, I1.getWidth(), I2.bitmap, I2.getWidth(), I2.getHeight(), i0, j0, ab);
747 
748  unsigned int height_tpl = I2.getHeight(), width_tpl = I2.getWidth();
749  const double sum1 =
750  (II[i0 + height_tpl][j0 + width_tpl] + II[i0][j0] - II[i0][j0 + width_tpl] - II[i0 + height_tpl][j0]);
751  const double sum2 = (II_tpl[height_tpl][width_tpl] + II_tpl[0][0] - II_tpl[0][width_tpl] - II_tpl[height_tpl][0]);
752 
753  double a2 = ((IIsq[i0 + I2.getHeight()][j0 + I2.getWidth()] + IIsq[i0][j0] - IIsq[i0][j0 + I2.getWidth()] -
754  IIsq[i0 + I2.getHeight()][j0]) -
755  (1.0 / I2.getSize()) * vpMath::sqr(sum1));
756 
757  double b2 = ((IIsq_tpl[I2.getHeight()][I2.getWidth()] + IIsq_tpl[0][0] - IIsq_tpl[0][I2.getWidth()] -
758  IIsq_tpl[I2.getHeight()][0]) -
759  (1.0 / I2.getSize()) * vpMath::sqr(sum2));
760  return ab / sqrt(a2 * b2);
761 }
762 
774  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<unsigned char> &Iundist)
775 {
776  Iundist.resize(I.getHeight(), I.getWidth());
777 
778 #if defined _OPENMP // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
779 #pragma omp parallel for schedule(dynamic)
780 #endif
781  for (int i_ = 0; i_ < static_cast<int>(I.getHeight()); i_++) {
782  const unsigned int i = static_cast<unsigned int>(i_);
783  for (unsigned int j = 0; j < I.getWidth(); j++) {
784 
785  int u_round = mapU[i][j];
786  int v_round = mapV[i][j];
787 
788  float du = mapDu[i][j];
789  float dv = mapDv[i][j];
790 
791  if (0 <= u_round && 0 <= v_round && u_round < static_cast<int>(I.getWidth()) - 1 &&
792  v_round < static_cast<int>(I.getHeight()) - 1) {
793  // process interpolation
794  float col0 = lerp(I[v_round][u_round], I[v_round][u_round + 1], du);
795  float col1 = lerp(I[v_round + 1][u_round], I[v_round + 1][u_round + 1], du);
796  float value = lerp(col0, col1, dv);
797 
798  Iundist[i][j] = static_cast<unsigned char>(value);
799  } else {
800  Iundist[i][j] = 0;
801  }
802  }
803  }
804 }
805 
816 void vpImageTools::remap(const vpImage<vpRGBa> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
817  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<vpRGBa> &Iundist)
818 {
819  Iundist.resize(I.getHeight(), I.getWidth());
820 
821 #if defined _OPENMP // only to disable warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
822 #pragma omp parallel for schedule(dynamic)
823 #endif
824  for (int i = 0; i < static_cast<int>(I.getHeight()); i++) {
825  SimdRemap(reinterpret_cast<unsigned char *>(I.bitmap), 4, I.getWidth(), I.getHeight(), i * I.getWidth(), mapU.data,
826  mapV.data, mapDu.data, mapDv.data, reinterpret_cast<unsigned char *>(Iundist.bitmap));
827  }
828 }
829 
830 void vpImageTools::resizeSimdlib(const vpImage<vpRGBa> &Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
831  vpImage<vpRGBa> &Idst, int method)
832 {
833  Idst.resize(resizeHeight, resizeWidth);
834 
835  typedef Simd::View<Simd::Allocator> View;
836  View src(Isrc.getWidth(), Isrc.getHeight(), Isrc.getWidth() * sizeof(vpRGBa), View::Bgra32, Isrc.bitmap);
837  View dst(Idst.getWidth(), Idst.getHeight(), Idst.getWidth() * sizeof(vpRGBa), View::Bgra32, Idst.bitmap);
838 
839  Simd::Resize(src, dst, method == INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
840 }
841 
842 void vpImageTools::resizeSimdlib(const vpImage<unsigned char> &Isrc, unsigned int resizeWidth,
843  unsigned int resizeHeight, vpImage<unsigned char> &Idst, int method)
844 {
845  Idst.resize(resizeHeight, resizeWidth);
846 
847  typedef Simd::View<Simd::Allocator> View;
848  View src(Isrc.getWidth(), Isrc.getHeight(), Isrc.getWidth(), View::Gray8, Isrc.bitmap);
849  View dst(Idst.getWidth(), Idst.getHeight(), Idst.getWidth(), View::Gray8, Idst.bitmap);
850 
851  Simd::Resize(src, dst, method == INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
852 }
853 
854 bool vpImageTools::checkFixedPoint(unsigned int x, unsigned int y, const vpMatrix &T, bool affine)
855 {
856  double a0 = T[0][0];
857  double a1 = T[0][1];
858  double a2 = T[0][2];
859  double a3 = T[1][0];
860  double a4 = T[1][1];
861  double a5 = T[1][2];
862  double a6 = affine ? 0.0 : T[2][0];
863  double a7 = affine ? 0.0 : T[2][1];
864  double a8 = affine ? 1.0 : T[2][2];
865 
866  double w = a6 * x + a7 * y + a8;
867  double x2 = (a0 * x + a1 * y + a2) / w;
868  double y2 = (a3 * x + a4 * y + a5) / w;
869 
870  const double limit = 1 << 15;
871  return (vpMath::abs(x2) < limit) && (vpMath::abs(y2) < limit);
872 }
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition: vpArray2D.h:131
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:144
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:305
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
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ dimensionError
Bad dimension.
Definition: vpException.h:83
@ notImplementedError
Not implemented.
Definition: vpException.h:81
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Error that can be emitted by the vpImage class and its derivatives.
@ 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:301
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 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 void extract(const vpImage< unsigned char > &Src, vpImage< unsigned char > &Dst, const vpRectOriented &r)
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:78
@ INTERPOLATION_NEAREST
Definition: vpImageTools.h:77
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 void imageDifferenceAbsolute(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Idiff)
Type getMeanValue() const
Return the mean value of the bitmap.
Definition: vpImage.h:963
unsigned int getWidth() const
Definition: vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:795
double getSum() const
Definition: vpImage.h:1885
unsigned int getSize() const
Definition: vpImage.h:223
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
unsigned int getHeight() const
Definition: vpImage.h:184
static double sqr(double x)
Definition: vpMath.h:124
static Type abs(const Type &x)
Definition: vpMath.h:187
static int round(double x)
Definition: vpMath.h:323
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:152
Definition: vpRGBa.h:61
unsigned char B
Blue component.
Definition: vpRGBa.h:140
unsigned char R
Red component.
Definition: vpRGBa.h:138
unsigned char G
Green component.
Definition: vpRGBa.h:139
unsigned char A
Additionnal component.
Definition: vpRGBa.h:141
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:76
Implementation of row vector and the associated operations.
Definition: vpRowVector.h:111
void resize(unsigned int i, bool flagNullify=true)
Definition: vpRowVector.h:266
#define vpERROR_TRACE
Definition: vpDebug.h:388