Visual Servoing Platform  version 3.3.1 under development (2020-10-22)
vpImageTools.h
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Authors:
35  * Fabien Spindler
36  *
37  *****************************************************************************/
38 
39 #ifndef vpImageTools_H
40 #define vpImageTools_H
41 
49 #include <visp3/core/vpImage.h>
50 
51 #ifdef VISP_HAVE_PTHREAD
52 #include <pthread.h>
53 #endif
54 
55 #include <visp3/core/vpCameraParameters.h>
56 #include <visp3/core/vpImageException.h>
57 #include <visp3/core/vpMath.h>
58 #include <visp3/core/vpRect.h>
59 #include <visp3/core/vpRectOriented.h>
60 
61 #include <fstream>
62 #include <iostream>
63 #include <math.h>
64 #include <string.h>
65 
66 #if defined _OPENMP
67 #include <omp.h>
68 #endif
69 
78 class VISP_EXPORT vpImageTools
79 {
80 public:
85  INTERPOLATION_AREA
86  };
87 
88  template <class Type>
89  static inline void binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
90  bool useLUT = true);
91  static void changeLUT(vpImage<unsigned char> &I, unsigned char A, unsigned char newA, unsigned char B,
92  unsigned char newB);
93 
94  template <class Type>
95  static void crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
96  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
97 
98  static void columnMean(const vpImage<double> &I, vpRowVector &result);
99 
100  template <class Type>
101  static void crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height, unsigned int roi_width,
102  vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
103  template <class Type>
104  static void crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale = 1,
105  unsigned int h_scale = 1);
106  template <class Type>
107  static void crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
108  vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
109 
110  static void extract(const vpImage<unsigned char> &Src, vpImage<unsigned char> &Dst, const vpRectOriented &r);
111  static void extract(const vpImage<unsigned char> &Src, vpImage<double> &Dst, const vpRectOriented &r);
112 
113  template <class Type> static void flip(const vpImage<Type> &I, vpImage<Type> &newI);
114 
115  template <class Type> static void flip(vpImage<Type> &I);
116 
117  static void imageDifference(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
118  vpImage<unsigned char> &Idiff);
119  static void imageDifference(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
120 
121  static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
122  vpImage<unsigned char> &Idiff);
123  static void imageDifferenceAbsolute(const vpImage<double> &I1, const vpImage<double> &I2, vpImage<double> &Idiff);
124  static void imageDifferenceAbsolute(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
125 
126  static void imageAdd(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2, vpImage<unsigned char> &Ires,
127  bool saturate = false);
128 
129  static void imageSubtract(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
130  vpImage<unsigned char> &Ires, bool saturate = false);
131 
132  static void initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height,
133  vpArray2D<int> &mapU, vpArray2D<int> &mapV,
134  vpArray2D<float> &mapDu, vpArray2D<float> &mapDv);
135 
136  static double interpolate(const vpImage<unsigned char> &I, const vpImagePoint &point,
137  const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
138 
139  static void integralImage(const vpImage<unsigned char> &I, vpImage<double> &II, vpImage<double> &IIsq);
140 
141  static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2,
142  bool useOptimized = true);
143 
144  static void normalize(vpImage<double> &I);
145 
146  static void remap(const vpImage<unsigned char> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
147  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<unsigned char> &Iundist);
148  static void remap(const vpImage<vpRGBa> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
149  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<vpRGBa> &Iundist);
150 
151  template <class Type>
152  static void resize(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int width, unsigned int height,
153  const vpImageInterpolationType &method = INTERPOLATION_NEAREST, unsigned int nThreads=0);
154 
155  template <class Type>
156  static void resize(const vpImage<Type> &I, vpImage<Type> &Ires,
157  const vpImageInterpolationType &method = INTERPOLATION_NEAREST, unsigned int nThreads=0);
158 
159  static void templateMatching(const vpImage<unsigned char> &I, const vpImage<unsigned char> &I_tpl,
160  vpImage<double> &I_score, unsigned int step_u, unsigned int step_v,
161  bool useOptimized = true);
162 
163  template <class Type>
164  static void undistort(const vpImage<Type> &I, const vpCameraParameters &cam, vpImage<Type> &newI,
165  unsigned int nThreads=2);
166 
167  template <class Type>
168  static void undistort(const vpImage<Type> &I, vpArray2D<int> mapU, vpArray2D<int> mapV, vpArray2D<float> mapDu,
169  vpArray2D<float> mapDv, vpImage<Type> &newI);
170 
171  template <class Type>
172  static void warpImage(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst,
173  const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST,
174  bool fixedPointArithmetic=true, bool pixelCenter=false);
175 
176 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
177 
181  template <class Type>
182  vp_deprecated static void createSubImage(const vpImage<Type> &I, unsigned int i_sub, unsigned int j_sub,
183  unsigned int nrow_sub, unsigned int ncol_sub, vpImage<Type> &S);
184 
185  template <class Type>
186  vp_deprecated static void createSubImage(const vpImage<Type> &I, const vpRect &rect, vpImage<Type> &S);
188 #endif
189 
190 private:
191  // Cubic interpolation
192  static float cubicHermite(const float A, const float B, const float C, const float D, const float t);
193 
194  template <class Type> static Type getPixelClamped(const vpImage<Type> &I, float u, float v);
195 
196  static int coordCast(double x);
197 
198  // Linear interpolation
199  static double lerp(double A, double B, double t);
200  static float lerp(float A, float B, float t);
201  static int64_t lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1);
202 
203  static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, const vpImage<double> &II,
204  const vpImage<double> &IIsq, const vpImage<double> &II_tpl,
205  const vpImage<double> &IIsq_tpl, unsigned int i0, unsigned int j0);
206 
207  template <class Type>
208  static void resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j,
209  float u, float v, float xFrac, float yFrac);
210 
211  template <class Type>
212  static void resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j,
213  float u, float v, float xFrac, float yFrac);
214 
215  template <class Type>
216  static void resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j,
217  float u, float v);
218 
219  static void resizeSimdlib(const vpImage<vpRGBa>& Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
220  vpImage<vpRGBa>& Idst, int method);
221  static void resizeSimdlib(const vpImage<unsigned char>& Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
222  vpImage<unsigned char>& Idst, int method);
223 
224  template <class Type>
225  static void warpNN(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine, bool centerCorner, bool fixedPoint);
226 
227  template <class Type>
228  static void warpLinear(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine, bool centerCorner, bool fixedPoint);
229 
230  static bool checkFixedPoint(unsigned int x, unsigned int y, const vpMatrix &T, bool affine);
231 };
232 
233 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
234 
253 template <class Type>
254 void vpImageTools::createSubImage(const vpImage<Type> &I, unsigned int roi_top, unsigned int roi_left,
255  unsigned int roi_height, unsigned int roi_width, vpImage<Type> &crop)
256 {
257  vpImageTools::crop(I, roi_top, roi_left, roi_height, roi_width, crop);
258 }
259 
275 template <class Type> void vpImageTools::createSubImage(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop)
276 {
277  vpImageTools::crop(I, roi, crop);
278 }
279 
280 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
281 
304 template <class Type>
305 void vpImageTools::crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
306  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
307 {
308  int i_min = (std::max)((int)(ceil(roi_top / v_scale)), 0);
309  int j_min = (std::max)((int)(ceil(roi_left / h_scale)), 0);
310  int i_max = (std::min)((int)(ceil((roi_top + roi_height)) / v_scale), (int)(I.getHeight() / v_scale));
311  int j_max = (std::min)((int)(ceil((roi_left + roi_width) / h_scale)), (int)(I.getWidth() / h_scale));
312 
313  unsigned int i_min_u = (unsigned int)i_min;
314  unsigned int j_min_u = (unsigned int)j_min;
315 
316  unsigned int r_width = (unsigned int)(j_max - j_min);
317  unsigned int r_height = (unsigned int)(i_max - i_min);
318 
319  crop.resize(r_height, r_width);
320 
321  if (v_scale == 1 && h_scale == 1) {
322  for (unsigned int i = 0; i < r_height; i++) {
323  void *src = (void *)(I[i + i_min_u] + j_min_u);
324  void *dst = (void *)crop[i];
325  memcpy(dst, src, r_width * sizeof(Type));
326  }
327  } else if (h_scale == 1) {
328  for (unsigned int i = 0; i < r_height; i++) {
329  void *src = (void *)(I[(i + i_min_u) * v_scale] + j_min_u);
330  void *dst = (void *)crop[i];
331  memcpy(dst, src, r_width * sizeof(Type));
332  }
333  } else {
334  for (unsigned int i = 0; i < r_height; i++) {
335  for (unsigned int j = 0; j < r_width; j++) {
336  crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
337  }
338  }
339  }
340 }
341 
359 template <class Type>
360 void vpImageTools::crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height,
361  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
362 {
363  vpImageTools::crop(I, topLeft.get_i(), topLeft.get_j(), roi_height, roi_width, crop, v_scale, h_scale);
364 }
365 
382 template <class Type>
383 void vpImageTools::crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale,
384  unsigned int h_scale)
385 {
386  vpImageTools::crop(I, roi.getTop(), roi.getLeft(), (unsigned int)roi.getHeight(), (unsigned int)roi.getWidth(), crop,
387  v_scale, h_scale);
388 }
389 
407 template <class Type>
408 void vpImageTools::crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
409  vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
410 {
411  int i_min = (std::max)((int)(ceil(roi.getTop() / v_scale)), 0);
412  int j_min = (std::max)((int)(ceil(roi.getLeft() / h_scale)), 0);
413  int i_max = (std::min)((int)(ceil((roi.getTop() + roi.getHeight()) / v_scale)), (int)(height / v_scale));
414  int j_max = (std::min)((int)(ceil((roi.getLeft() + roi.getWidth()) / h_scale)), (int)(width / h_scale));
415 
416  unsigned int i_min_u = (unsigned int)i_min;
417  unsigned int j_min_u = (unsigned int)j_min;
418 
419  unsigned int r_width = (unsigned int)(j_max - j_min);
420  unsigned int r_height = (unsigned int)(i_max - i_min);
421 
422  crop.resize(r_height, r_width);
423 
424  if (v_scale == 1 && h_scale == 1) {
425  for (unsigned int i = 0; i < r_height; i++) {
426  void *src = (void *)(bitmap + ((i + i_min_u) * width + j_min_u) * sizeof(Type));
427  void *dst = (void *)crop[i];
428  memcpy(dst, src, r_width * sizeof(Type));
429  }
430  } else if (h_scale == 1) {
431  for (unsigned int i = 0; i < r_height; i++) {
432  void *src = (void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) * sizeof(Type));
433  void *dst = (void *)crop[i];
434  memcpy(dst, src, r_width * sizeof(Type));
435  }
436  } else {
437  for (unsigned int i = 0; i < r_height; i++) {
438  unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
439  for (unsigned int j = 0; j < r_width; j++) {
440  void *src = (void *)(bitmap + (i_src + j * h_scale) * sizeof(Type));
441  void *dst = (void *)&crop[i][j];
442  memcpy(dst, src, sizeof(Type));
443  }
444  }
445  }
446 }
447 
458 template <class Type>
459 inline void vpImageTools::binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2,
460  Type value3, bool useLUT)
461 {
462  if (useLUT) {
463  std::cerr << "LUT not available for this type ! Will use the iteration method." << std::endl;
464  }
465 
466  Type v;
467  Type *p = I.bitmap;
468  Type *pend = I.bitmap + I.getWidth() * I.getHeight();
469  for (; p < pend; p++) {
470  v = *p;
471  if (v < threshold1)
472  *p = value1;
473  else if (v > threshold2)
474  *p = value3;
475  else
476  *p = value2;
477  }
478 }
479 
490 template <>
491 inline void vpImageTools::binarise(vpImage<unsigned char> &I, unsigned char threshold1, unsigned char threshold2,
492  unsigned char value1, unsigned char value2, unsigned char value3, bool useLUT)
493 {
494  if (useLUT) {
495  // Construct the LUT
496  unsigned char lut[256];
497  for (unsigned int i = 0; i < 256; i++) {
498  lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
499  }
500 
501  I.performLut(lut);
502  } else {
503  unsigned char *p = I.bitmap;
504  unsigned char *pend = I.bitmap + I.getWidth() * I.getHeight();
505  for (; p < pend; p++) {
506  unsigned char v = *p;
507  if (v < threshold1)
508  *p = value1;
509  else if (v > threshold2)
510  *p = value3;
511  else
512  *p = value2;
513  }
514  }
515 }
516 
517 #ifdef VISP_HAVE_PTHREAD
518 
519 #ifndef DOXYGEN_SHOULD_SKIP_THIS
520 template <class Type> class vpUndistortInternalType
521 {
522 public:
523  Type *src;
524  Type *dst;
525  unsigned int width;
526  unsigned int height;
527  vpCameraParameters cam;
528  unsigned int nthreads;
529  unsigned int threadid;
530 
531 public:
532  vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0) {}
533 
534  vpUndistortInternalType(const vpUndistortInternalType<Type> &u) { *this = u; }
535  vpUndistortInternalType &operator=(const vpUndistortInternalType<Type> &u)
536  {
537  src = u.src;
538  dst = u.dst;
539  width = u.width;
540  height = u.height;
541  cam = u.cam;
542  nthreads = u.nthreads;
543  threadid = u.threadid;
544 
545  return *this;
546  }
547 
548  static void *vpUndistort_threaded(void *arg);
549 };
550 
551 template <class Type> void *vpUndistortInternalType<Type>::vpUndistort_threaded(void *arg)
552 {
553  vpUndistortInternalType<Type> *undistortSharedData = static_cast<vpUndistortInternalType<Type> *>(arg);
554  int offset = (int)undistortSharedData->threadid;
555  int width = (int)undistortSharedData->width;
556  int height = (int)undistortSharedData->height;
557  int nthreads = (int)undistortSharedData->nthreads;
558 
559  double u0 = undistortSharedData->cam.get_u0();
560  double v0 = undistortSharedData->cam.get_v0();
561  double px = undistortSharedData->cam.get_px();
562  double py = undistortSharedData->cam.get_py();
563  double kud = undistortSharedData->cam.get_kud();
564 
565  double invpx = 1.0 / px;
566  double invpy = 1.0 / py;
567 
568  double kud_px2 = kud * invpx * invpx;
569  double kud_py2 = kud * invpy * invpy;
570 
571  Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
572  Type *src = undistortSharedData->src;
573 
574  for (double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
575  double deltav = v - v0;
576  // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
577  double fr1 = 1.0 + kud_py2 * deltav * deltav;
578 
579  for (double u = 0; u < width; u++) {
580  // computation of u,v : corresponding pixel coordinates in I.
581  double deltau = u - u0;
582  // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
583  double fr2 = fr1 + kud_px2 * deltau * deltau;
584 
585  double u_double = deltau * fr2 + u0;
586  double v_double = deltav * fr2 + v0;
587 
588  // computation of the bilinear interpolation
589 
590  // declarations
591  int u_round = (int)(u_double);
592  int v_round = (int)(v_double);
593  if (u_round < 0.f)
594  u_round = -1;
595  if (v_round < 0.f)
596  v_round = -1;
597  double du_double = (u_double) - (double)u_round;
598  double dv_double = (v_double) - (double)v_round;
599  Type v01;
600  Type v23;
601  if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
602  // process interpolation
603  const Type *_mp = &src[v_round * width + u_round];
604  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
605  _mp += width;
606  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
607  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
608  } else {
609  *dst = 0;
610  }
611  dst++;
612  }
613  }
614 
615  pthread_exit((void *)0);
616  return NULL;
617 }
618 #endif // DOXYGEN_SHOULD_SKIP_THIS
619 #endif // VISP_HAVE_PTHREAD
620 
647 template <class Type>
649  unsigned int nThreads)
650 {
651 #ifdef VISP_HAVE_PTHREAD
652  //
653  // Optimized version using pthreads
654  //
655  unsigned int width = I.getWidth();
656  unsigned int height = I.getHeight();
657 
658  undistI.resize(height, width);
659 
660  double kud = cam.get_kud();
661 
662  // if (kud == 0) {
663  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
664  // There is no need to undistort the image
665  undistI = I;
666  return;
667  }
668 
669  unsigned int nthreads = nThreads;
670  pthread_attr_t attr;
671  pthread_t *callThd = new pthread_t[nthreads];
672  pthread_attr_init(&attr);
673  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
674 
675  vpUndistortInternalType<Type> *undistortSharedData;
676  undistortSharedData = new vpUndistortInternalType<Type>[nthreads];
677 
678  for (unsigned int i = 0; i < nthreads; i++) {
679  // Each thread works on a different set of data.
680  // vpTRACE("create thread %d", i);
681  undistortSharedData[i].src = I.bitmap;
682  undistortSharedData[i].dst = undistI.bitmap;
683  undistortSharedData[i].width = I.getWidth();
684  undistortSharedData[i].height = I.getHeight();
685  undistortSharedData[i].cam = cam;
686  undistortSharedData[i].nthreads = nthreads;
687  undistortSharedData[i].threadid = i;
688  pthread_create(&callThd[i], &attr, &vpUndistortInternalType<Type>::vpUndistort_threaded, &undistortSharedData[i]);
689  }
690  pthread_attr_destroy(&attr);
691  /* Wait on the other threads */
692 
693  for (unsigned int i = 0; i < nthreads; i++) {
694  // vpTRACE("join thread %d", i);
695  pthread_join(callThd[i], NULL);
696  }
697 
698  delete[] callThd;
699  delete[] undistortSharedData;
700 #else // VISP_HAVE_PTHREAD
701  (void)nThreads;
702  //
703  // optimized version without pthreads
704  //
705  unsigned int width = I.getWidth();
706  unsigned int height = I.getHeight();
707 
708  undistI.resize(height, width);
709 
710  double u0 = cam.get_u0();
711  double v0 = cam.get_v0();
712  double px = cam.get_px();
713  double py = cam.get_py();
714  double kud = cam.get_kud();
715 
716  // if (kud == 0) {
717  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
718  // There is no need to undistort the image
719  undistI = I;
720  return;
721  }
722 
723  double invpx = 1.0 / px;
724  double invpy = 1.0 / py;
725 
726  double kud_px2 = kud * invpx * invpx;
727  double kud_py2 = kud * invpy * invpy;
728 
729  Type *dst = undistI.bitmap;
730  for (double v = 0; v < height; v++) {
731  double deltav = v - v0;
732  // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
733  double fr1 = 1.0 + kud_py2 * deltav * deltav;
734 
735  for (double u = 0; u < width; u++) {
736  // computation of u,v : corresponding pixel coordinates in I.
737  double deltau = u - u0;
738  // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
739  double fr2 = fr1 + kud_px2 * deltau * deltau;
740 
741  double u_double = deltau * fr2 + u0;
742  double v_double = deltav * fr2 + v0;
743 
744  // printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
745 
746  // computation of the bilinear interpolation
747 
748  // declarations
749  int u_round = (int)(u_double);
750  int v_round = (int)(v_double);
751  if (u_round < 0.f)
752  u_round = -1;
753  if (v_round < 0.f)
754  v_round = -1;
755  double du_double = (u_double) - (double)u_round;
756  double dv_double = (v_double) - (double)v_round;
757  Type v01;
758  Type v23;
759  if ((0 <= u_round) && (0 <= v_round) && (u_round < (((int)width) - 1)) && (v_round < (((int)height) - 1))) {
760  // process interpolation
761  const Type *_mp = &I[(unsigned int)v_round][(unsigned int)u_round];
762  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
763  _mp += width;
764  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
765  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
766  // printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
767  } else {
768  *dst = 0;
769  }
770  dst++;
771  }
772  }
773 #endif // VISP_HAVE_PTHREAD
774 
775 #if 0
776  // non optimized version
777  int width = I.getWidth();
778  int height = I.getHeight();
779 
780  undistI.resize(height,width);
781 
782  double u0 = cam.get_u0();
783  double v0 = cam.get_v0();
784  double px = cam.get_px();
785  double py = cam.get_py();
786  double kd = cam.get_kud();
787 
788  if (kd == 0) {
789  // There is no need to undistort the image
790  undistI = I;
791  return;
792  }
793 
794  for(int v = 0 ; v < height; v++){
795  for(int u = 0; u < height; u++){
796  double r2 = vpMath::sqr(((double)u - u0)/px) +
797  vpMath::sqr(((double)v-v0)/py);
798  double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
799  double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
800  undistI[v][u] = I.getPixelBI((float)u_double,(float)v_double);
801  }
802  }
803 #endif
804 }
805 
820 template <class Type>
822  vpArray2D<float> mapDv, vpImage<Type> &newI)
823 {
824  remap(I, mapU, mapV, mapDu, mapDv, newI);
825 }
826 
833 template <class Type> void vpImageTools::flip(const vpImage<Type> &I, vpImage<Type> &newI)
834 {
835  unsigned int height = 0, width = 0;
836 
837  height = I.getHeight();
838  width = I.getWidth();
839  newI.resize(height, width);
840 
841  for (unsigned int i = 0; i < height; i++) {
842  memcpy(newI.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
843  }
844 }
845 
877 template <class Type> void vpImageTools::flip(vpImage<Type> &I)
878 {
879  unsigned int height = 0, width = 0;
880  unsigned int i = 0;
881  vpImage<Type> Ibuf;
882 
883  height = I.getHeight();
884  width = I.getWidth();
885  Ibuf.resize(1, width);
886 
887  for (i = 0; i < height / 2; i++) {
888  memcpy(Ibuf.bitmap, I.bitmap + i * width, width * sizeof(Type));
889 
890  memcpy(I.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
891  memcpy(I.bitmap + (height - 1 - i) * width, Ibuf.bitmap, width * sizeof(Type));
892  }
893 }
894 
895 template <class Type> Type vpImageTools::getPixelClamped(const vpImage<Type> &I, float u, float v)
896 {
897  int x = vpMath::round(u);
898  int y = vpMath::round(v);
899  x = (std::max)(0, (std::min)(x, static_cast<int>(I.getWidth())-1));
900  y = (std::max)(0, (std::min)(y, static_cast<int>(I.getHeight())-1));
901 
902  return I[y][x];
903 }
904 
905 // Reference:
906 // http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
907 template <class Type>
908 void vpImageTools::resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i,
909  unsigned int j, float u, float v, float xFrac, float yFrac)
910 {
911  // 1st row
912  Type p00 = getPixelClamped(I, u - 1, v - 1);
913  Type p01 = getPixelClamped(I, u + 0, v - 1);
914  Type p02 = getPixelClamped(I, u + 1, v - 1);
915  Type p03 = getPixelClamped(I, u + 2, v - 1);
916 
917  // 2nd row
918  Type p10 = getPixelClamped(I, u - 1, v + 0);
919  Type p11 = getPixelClamped(I, u + 0, v + 0);
920  Type p12 = getPixelClamped(I, u + 1, v + 0);
921  Type p13 = getPixelClamped(I, u + 2, v + 0);
922 
923  // 3rd row
924  Type p20 = getPixelClamped(I, u - 1, v + 1);
925  Type p21 = getPixelClamped(I, u + 0, v + 1);
926  Type p22 = getPixelClamped(I, u + 1, v + 1);
927  Type p23 = getPixelClamped(I, u + 2, v + 1);
928 
929  // 4th row
930  Type p30 = getPixelClamped(I, u - 1, v + 2);
931  Type p31 = getPixelClamped(I, u + 0, v + 2);
932  Type p32 = getPixelClamped(I, u + 1, v + 2);
933  Type p33 = getPixelClamped(I, u + 2, v + 2);
934 
935  float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
936  float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
937  float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
938  float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
939  float value = cubicHermite(col0, col1, col2, col3, yFrac);
940  Ires[i][j] = vpMath::saturate<Type>(value);
941 }
942 
943 template <>
944 inline void vpImageTools::resizeBicubic(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, unsigned int i,
945  unsigned int j, float u, float v, float xFrac, float yFrac)
946 {
947  // 1st row
948  vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
949  vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
950  vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
951  vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
952 
953  // 2nd row
954  vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
955  vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
956  vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
957  vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
958 
959  // 3rd row
960  vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
961  vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
962  vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
963  vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
964 
965  // 4th row
966  vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
967  vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
968  vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
969  vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
970 
971  for (int c = 0; c < 3; c++) {
972  float col0 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p00)[c]),
973  static_cast<float>(reinterpret_cast<unsigned char *>(&p01)[c]),
974  static_cast<float>(reinterpret_cast<unsigned char *>(&p02)[c]),
975  static_cast<float>(reinterpret_cast<unsigned char *>(&p03)[c]), xFrac);
976  float col1 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p10)[c]),
977  static_cast<float>(reinterpret_cast<unsigned char *>(&p11)[c]),
978  static_cast<float>(reinterpret_cast<unsigned char *>(&p12)[c]),
979  static_cast<float>(reinterpret_cast<unsigned char *>(&p13)[c]), xFrac);
980  float col2 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p20)[c]),
981  static_cast<float>(reinterpret_cast<unsigned char *>(&p21)[c]),
982  static_cast<float>(reinterpret_cast<unsigned char *>(&p22)[c]),
983  static_cast<float>(reinterpret_cast<unsigned char *>(&p23)[c]), xFrac);
984  float col3 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p30)[c]),
985  static_cast<float>(reinterpret_cast<unsigned char *>(&p31)[c]),
986  static_cast<float>(reinterpret_cast<unsigned char *>(&p32)[c]),
987  static_cast<float>(reinterpret_cast<unsigned char *>(&p33)[c]), xFrac);
988  float value = cubicHermite(col0, col1, col2, col3, yFrac);
989 
990  reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
991  }
992 }
993 
994 template <class Type>
995 void vpImageTools::resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i,
996  unsigned int j, float u, float v, float xFrac, float yFrac)
997 {
998  int u0 = static_cast<int>(u);
999  int v0 = static_cast<int>(v);
1000 
1001  int u1 = (std::min)(static_cast<int>(I.getWidth()) - 1, u0 + 1);
1002  int v1 = v0;
1003 
1004  int u2 = u0;
1005  int v2 = (std::min)(static_cast<int>(I.getHeight()) - 1, v0 + 1);
1006 
1007  int u3 = u1;
1008  int v3 = v2;
1009 
1010  float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
1011  float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
1012  float value = lerp(col0, col1, yFrac);
1013 
1014  Ires[i][j] = vpMath::saturate<Type>(value);
1015 }
1016 
1017 template <>
1018 inline void vpImageTools::resizeBilinear(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, unsigned int i,
1019  unsigned int j, float u, float v, float xFrac, float yFrac)
1020 {
1021  int u0 = static_cast<int>(u);
1022  int v0 = static_cast<int>(v);
1023 
1024  int u1 = (std::min)(static_cast<int>(I.getWidth()) - 1, u0 + 1);
1025  int v1 = v0;
1026 
1027  int u2 = u0;
1028  int v2 = (std::min)(static_cast<int>(I.getHeight()) - 1, v0 + 1);
1029 
1030  int u3 = u1;
1031  int v3 = v2;
1032 
1033  for (int c = 0; c < 3; c++) {
1034  float col0 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v0][u0])[c]),
1035  static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v1][u1])[c]), xFrac);
1036  float col1 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v2][u2])[c]),
1037  static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v3][u3])[c]), xFrac);
1038  float value = lerp(col0, col1, yFrac);
1039 
1040  reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1041  }
1042 }
1043 
1044 template <class Type>
1045 void vpImageTools::resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i,
1046  unsigned int j, float u, float v)
1047 {
1048  Ires[i][j] = getPixelClamped(I, u, v);
1049 }
1050 
1069 template <class Type>
1070 void vpImageTools::resize(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int width,
1071  unsigned int height, const vpImageInterpolationType &method,
1072  unsigned int nThreads)
1073 {
1074  Ires.resize(height, width);
1075 
1076  vpImageTools::resize(I, Ires, method, nThreads);
1077 }
1078 
1096 template <class Type>
1098  unsigned int
1099  #if defined _OPENMP
1100  nThreads
1101  #endif
1102  )
1103 {
1104  if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1105  std::cerr << "Input or output image is too small!" << std::endl;
1106  return;
1107  }
1108 
1109  if (method == INTERPOLATION_AREA) {
1110  std::cerr << "INTERPOLATION_AREA is not implemented for this type." << std::endl;
1111  return;
1112  }
1113 
1114  const float scaleY = I.getHeight() / static_cast<float>(Ires.getHeight());
1115  const float scaleX = I.getWidth() / static_cast<float>(Ires.getWidth());
1116  const float half = 0.5f;
1117 
1118 #if defined _OPENMP
1119  if (nThreads > 0) {
1120  omp_set_num_threads(static_cast<int>(nThreads));
1121  }
1122  #pragma omp parallel for schedule(dynamic)
1123 #endif
1124  for (int i = 0; i < static_cast<int>(Ires.getHeight()); i++) {
1125  const float v = (i + half) * scaleY - half;
1126  const int v0 = static_cast<int>(v);
1127  const float yFrac = v - v0;
1128 
1129  for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1130  const float u = (j + half) * scaleX - half;
1131  const int u0 = static_cast<int>(u);
1132  const float xFrac = u - u0;
1133 
1134  if (method == INTERPOLATION_NEAREST) {
1135  resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1136  } else if (method == INTERPOLATION_LINEAR) {
1137  resizeBilinear(I, Ires, static_cast<unsigned int>(i), j, u0, v0, xFrac, yFrac);
1138  } else if (method == INTERPOLATION_CUBIC) {
1139  resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1140  }
1141  }
1142  }
1143 }
1144 
1145 template <> inline
1147  const vpImageInterpolationType &method, unsigned int
1148  #if defined _OPENMP
1149  nThreads
1150  #endif
1151  )
1152 {
1153  if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1154  std::cerr << "Input or output image is too small!" << std::endl;
1155  return;
1156  }
1157 
1158  if (method == INTERPOLATION_AREA) {
1159  resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_AREA);
1160  } else if (method == INTERPOLATION_LINEAR) {
1161  resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_LINEAR);
1162  } else {
1163  const float scaleY = I.getHeight() / static_cast<float>(Ires.getHeight());
1164  const float scaleX = I.getWidth() / static_cast<float>(Ires.getWidth());
1165  const float half = 0.5f;
1166 
1167 #if defined _OPENMP
1168  if (nThreads > 0) {
1169  omp_set_num_threads(static_cast<int>(nThreads));
1170  }
1171 #pragma omp parallel for schedule(dynamic)
1172 #endif
1173  for (int i = 0; i < static_cast<int>(Ires.getHeight()); i++) {
1174  float v = (i + half) * scaleY - half;
1175  float yFrac = v - static_cast<int>(v);
1176 
1177  for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1178  float u = (j + half) * scaleX - half;
1179  float xFrac = u - static_cast<int>(u);
1180 
1181  if (method == INTERPOLATION_NEAREST) {
1182  resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1183  } else if (method == INTERPOLATION_CUBIC) {
1184  resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1185  }
1186  }
1187  }
1188  }
1189 }
1190 
1191 template <> inline
1193  const vpImageInterpolationType &method, unsigned int
1194  #if defined _OPENMP
1195  nThreads
1196  #endif
1197  )
1198 {
1199  if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1200  std::cerr << "Input or output image is too small!" << std::endl;
1201  return;
1202  }
1203 
1204  if (method == INTERPOLATION_AREA) {
1205  resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_AREA);
1206  } else if (method == INTERPOLATION_LINEAR) {
1207  resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_LINEAR);
1208  } else {
1209  const float scaleY = I.getHeight() / static_cast<float>(Ires.getHeight());
1210  const float scaleX = I.getWidth() / static_cast<float>(Ires.getWidth());
1211  const float half = 0.5f;
1212 
1213  #if defined _OPENMP
1214  if (nThreads > 0) {
1215  omp_set_num_threads(static_cast<int>(nThreads));
1216  }
1217  #pragma omp parallel for schedule(dynamic)
1218  #endif
1219  for (int i = 0; i < static_cast<int>(Ires.getHeight()); i++) {
1220  float v = (i + half) * scaleY - half;
1221  float yFrac = v - static_cast<int>(v);
1222 
1223  for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1224  float u = (j + half) * scaleX - half;
1225  float xFrac = u - static_cast<int>(u);
1226 
1227  if (method == INTERPOLATION_NEAREST) {
1228  resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1229  } else if (method == INTERPOLATION_CUBIC) {
1230  resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1231  }
1232  }
1233  }
1234  }
1235 }
1236 
1251 template <class Type>
1253  const vpImageInterpolationType &interpolation,
1254  bool fixedPointArithmetic, bool pixelCenter)
1255 {
1256  if ((T.getRows() != 2 && T.getRows() != 3) || T.getCols() != 3) {
1257  std::cerr << "Input transformation must be a (2x3) or (3x3) matrix." << std::endl;
1258  return;
1259  }
1260 
1261  if (src.getSize() == 0) {
1262  return;
1263  }
1264 
1265  const bool affine = (T.getRows() == 2);
1266  const bool interp_NN = (interpolation == INTERPOLATION_NEAREST) || (interpolation == INTERPOLATION_CUBIC);
1267 
1268  if (dst.getSize() == 0) {
1269  dst.resize(src.getHeight(), src.getWidth(), Type(0));
1270  }
1271 
1272  vpMatrix M = T;
1273  if (affine) {
1274  double D = M[0][0] * M[1][1] - M[0][1] * M[1][0];
1275  D = !vpMath::nul(D, std::numeric_limits<double>::epsilon()) ? 1.0 / D : 0;
1276  double A11 = M[1][1] * D, A22 = M[0][0] * D;
1277  M[0][0] = A11; M[0][1] *= -D;
1278  M[1][0] *= -D; M[1][1] = A22;
1279  double b1 = -M[0][0] * M[0][2] - M[0][1] * M[1][2];
1280  double b2 = -M[1][0] * M[0][2] - M[1][1] * M[1][2];
1281  M[0][2] = b1; M[1][2] = b2;
1282  } else {
1283  M = T.inverseByLU();
1284  }
1285 
1286  if (fixedPointArithmetic && !pixelCenter) {
1287  fixedPointArithmetic = checkFixedPoint(0, 0, M, affine) &&
1288  checkFixedPoint(dst.getWidth()-1, 0, M, affine) &&
1289  checkFixedPoint(0, dst.getHeight()-1, M, affine) &&
1290  checkFixedPoint(dst.getWidth() - 1, dst.getHeight() - 1, M, affine);
1291  }
1292 
1293  if (interp_NN) {
1294  //nearest neighbor interpolation
1295  warpNN(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1296  } else {
1297  //bilinear interpolation
1298  warpLinear(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1299  }
1300 }
1301 
1302 template <class Type>
1303 void vpImageTools::warpNN(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine,
1304  bool centerCorner, bool fixedPoint)
1305 {
1306  if (fixedPoint && !centerCorner) {
1307  const int nbits = 16;
1308  const int32_t precision = 1 << nbits;
1309  const float precision_1 = 1 / static_cast<float>(precision);
1310 
1311  int32_t a0_i32 = static_cast<int32_t>(T[0][0] * precision);
1312  int32_t a1_i32 = static_cast<int32_t>(T[0][1] * precision);
1313  int32_t a2_i32 = static_cast<int32_t>(T[0][2] * precision);
1314  int32_t a3_i32 = static_cast<int32_t>(T[1][0] * precision);
1315  int32_t a4_i32 = static_cast<int32_t>(T[1][1] * precision);
1316  int32_t a5_i32 = static_cast<int32_t>(T[1][2] * precision);
1317  int32_t a6_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[2][0] * precision) : 0;
1318  int32_t a7_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[2][1] * precision) : 0;
1319  int32_t a8_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[2][2] * precision) : 1;
1320 
1321  int32_t height_1_i32 = static_cast<int32_t>((src.getHeight() - 1) * precision) + 0x8000;
1322  int32_t width_1_i32 = static_cast<int32_t>((src.getWidth() - 1) * precision) + 0x8000;
1323 
1324  if (affine) {
1325  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1326  int32_t xi = a2_i32;
1327  int32_t yi = a5_i32;
1328 
1329  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1330  if (yi >= 0 && yi < height_1_i32 && xi >= 0 && xi < width_1_i32) {
1331  float x_ = (xi >> nbits) + (xi & 0xFFFF) * precision_1;
1332  float y_ = (yi >> nbits) + (yi & 0xFFFF) * precision_1;
1333 
1334  int x = vpMath::round(x_);
1335  int y = vpMath::round(y_);
1336  dst[i][j] = src[y][x];
1337  }
1338 
1339  xi += a0_i32;
1340  yi += a3_i32;
1341  }
1342 
1343  a2_i32 += a1_i32;
1344  a5_i32 += a4_i32;
1345  }
1346  } else {
1347  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1348  int64_t xi = a2_i32;
1349  int64_t yi = a5_i32;
1350  int64_t wi = a8_i32;
1351 
1352  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1353  if (wi != 0 && yi >= 0 && yi <= (static_cast<int>(src.getHeight()) - 1)*wi &&
1354  xi >= 0 && xi <= (static_cast<int>(src.getWidth()) - 1)*wi) {
1355  float w_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1356  float x_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / w_;
1357  float y_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / w_;
1358 
1359  int x = vpMath::round(x_);
1360  int y = vpMath::round(y_);
1361 
1362  dst[i][j] = src[y][x];
1363  }
1364 
1365  xi += a0_i32;
1366  yi += a3_i32;
1367  wi += a6_i32;
1368  }
1369 
1370  a2_i32 += a1_i32;
1371  a5_i32 += a4_i32;
1372  a8_i32 += a7_i32;
1373  }
1374  }
1375  } else {
1376  double a0 = T[0][0]; double a1 = T[0][1]; double a2 = T[0][2];
1377  double a3 = T[1][0]; double a4 = T[1][1]; double a5 = T[1][2];
1378  double a6 = affine ? 0.0 : T[2][0];
1379  double a7 = affine ? 0.0 : T[2][1];
1380  double a8 = affine ? 1.0 : T[2][2];
1381 
1382  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1383  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1384  double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1385  double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1386  double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1387 
1388  if (vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1389  w = 1.0;
1390  }
1391 
1392  int x_ = centerCorner ? coordCast(x / w) : vpMath::round(x / w);
1393  int y_ = centerCorner ? coordCast(y / w) : vpMath::round(y / w);
1394 
1395  if (x_ >= 0 && x_ < static_cast<int>(src.getWidth()) &&
1396  y_ >= 0 && y_ < static_cast<int>(src.getHeight())) {
1397  dst[i][j] = src[y_][x_];
1398  }
1399  }
1400  }
1401  }
1402 }
1403 
1404 template <class Type>
1405 void vpImageTools::warpLinear(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine,
1406  bool centerCorner, bool fixedPoint)
1407 {
1408  if (fixedPoint && !centerCorner) {
1409  const int nbits = 16;
1410  const int64_t precision = 1 << nbits;
1411  const float precision_1 = 1 / static_cast<float>(precision);
1412  const int64_t precision2 = 1ULL << (2 * nbits);
1413  const float precision_2 = 1 / static_cast<float>(precision2);
1414 
1415  int64_t a0_i64 = static_cast<int64_t>(T[0][0] * precision);
1416  int64_t a1_i64 = static_cast<int64_t>(T[0][1] * precision);
1417  int64_t a2_i64 = static_cast<int64_t>(T[0][2] * precision);
1418  int64_t a3_i64 = static_cast<int64_t>(T[1][0] * precision);
1419  int64_t a4_i64 = static_cast<int64_t>(T[1][1] * precision);
1420  int64_t a5_i64 = static_cast<int64_t>(T[1][2] * precision);
1421  int64_t a6_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][0] * precision) : 0;
1422  int64_t a7_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][1] * precision) : 0;
1423  int64_t a8_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][2] * precision) : 1;
1424 
1425  int64_t height_i64 = static_cast<int64_t>(src.getHeight() * precision);
1426  int64_t width_i64 = static_cast<int64_t>(src.getWidth() * precision);
1427 
1428  if (affine) {
1429  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1430  int64_t xi_ = a2_i64;
1431  int64_t yi_ = a5_i64;
1432 
1433  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1434  if (yi_ >= 0 && yi_ < height_i64 && xi_ >= 0 && xi_ < width_i64) {
1435  const int64_t xi_lower = xi_ & (~0xFFFF);
1436  const int64_t yi_lower = yi_ & (~0xFFFF);
1437 
1438  const int64_t t = yi_ - yi_lower;
1439  const int64_t t_1 = precision - t;
1440  const int64_t s = xi_ - xi_lower;
1441  const int64_t s_1 = precision - s;
1442 
1443  const int x_ = static_cast<int>(xi_ >> nbits);
1444  const int y_ = static_cast<int>(yi_ >> nbits);
1445 
1446  if (y_ < static_cast<int>(src.getHeight())-1 && x_ < static_cast<int>(src.getWidth())-1) {
1447  const Type val00 = src[y_][x_];
1448  const Type val01 = src[y_][x_+1];
1449  const Type val10 = src[y_+1][x_];
1450  const Type val11 = src[y_+1][x_+1];
1451  const int64_t interp_i64 = static_cast<int64_t>(s_1*t_1*val00 + s*t_1*val01 + s_1*t*val10 + s*t*val11);
1452  const float interp = (interp_i64 >> (nbits*2)) + (interp_i64 & 0xFFFFFFFF) * precision_2;
1453  dst[i][j] = vpMath::saturate<Type>(interp);
1454  } else if (y_ < static_cast<int>(src.getHeight())-1) {
1455  const Type val00 = src[y_][x_];
1456  const Type val10 = src[y_+1][x_];
1457  const int64_t interp_i64 = static_cast<int64_t>(t_1*val00 + t*val10);
1458  const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1459  dst[i][j] = vpMath::saturate<Type>(interp);
1460  } else if (x_ < static_cast<int>(src.getWidth())-1) {
1461  const Type val00 = src[y_][x_];
1462  const Type val01 = src[y_][x_+1];
1463  const int64_t interp_i64 = static_cast<int64_t>(s_1*val00 + s*val01);
1464  const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1465  dst[i][j] = vpMath::saturate<Type>(interp);
1466  } else {
1467  dst[i][j] = src[y_][x_];
1468  }
1469  }
1470 
1471  xi_ += a0_i64;
1472  yi_ += a3_i64;
1473  }
1474 
1475  a2_i64 += a1_i64;
1476  a5_i64 += a4_i64;
1477  }
1478  } else {
1479  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1480  int64_t xi = a2_i64;
1481  int64_t yi = a5_i64;
1482  int64_t wi = a8_i64;
1483 
1484  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1485  if (wi != 0 && yi >= 0 && yi <= (static_cast<int>(src.getHeight()) - 1)*wi &&
1486  xi >= 0 && xi <= (static_cast<int>(src.getWidth()) - 1)*wi) {
1487  const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1488  const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1489  const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1490 
1491  const int x_ = static_cast<int>(xi_);
1492  const int y_ = static_cast<int>(yi_);
1493 
1494  const float t = yi_ - y_;
1495  const float s = xi_ - x_;
1496 
1497  if (y_ < static_cast<int>(src.getHeight()) - 1 && x_ < static_cast<int>(src.getWidth()) - 1) {
1498  const Type val00 = src[y_][x_];
1499  const Type val01 = src[y_][x_ + 1];
1500  const Type val10 = src[y_ + 1][x_];
1501  const Type val11 = src[y_ + 1][x_ + 1];
1502  const float col0 = lerp(val00, val01, s);
1503  const float col1 = lerp(val10, val11, s);
1504  const float interp = lerp(col0, col1, t);
1505  dst[i][j] = vpMath::saturate<Type>(interp);
1506  } else if (y_ < static_cast<int>(src.getHeight()) - 1) {
1507  const Type val00 = src[y_][x_];
1508  const Type val10 = src[y_ + 1][x_];
1509  const float interp = lerp(val00, val10, t);
1510  dst[i][j] = vpMath::saturate<Type>(interp);
1511  } else if (x_ < static_cast<int>(src.getWidth()) - 1) {
1512  const Type val00 = src[y_][x_];
1513  const Type val01 = src[y_][x_ + 1];
1514  const float interp = lerp(val00, val01, s);
1515  dst[i][j] = vpMath::saturate<Type>(interp);
1516  } else {
1517  dst[i][j] = src[y_][x_];
1518  }
1519  }
1520 
1521  xi += a0_i64;
1522  yi += a3_i64;
1523  wi += a6_i64;
1524  }
1525 
1526  a2_i64 += a1_i64;
1527  a5_i64 += a4_i64;
1528  a8_i64 += a7_i64;
1529  }
1530  }
1531  } else {
1532  double a0 = T[0][0]; double a1 = T[0][1]; double a2 = T[0][2];
1533  double a3 = T[1][0]; double a4 = T[1][1]; double a5 = T[1][2];
1534  double a6 = affine ? 0.0 : T[2][0];
1535  double a7 = affine ? 0.0 : T[2][1];
1536  double a8 = affine ? 1.0 : T[2][2];
1537 
1538  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1539  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1540  double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1541  double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1542  double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1543  if (vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1544  w = 1;
1545  }
1546 
1547  x = x / w - (centerCorner ? 0.5 : 0);
1548  y = y / w - (centerCorner ? 0.5 : 0);
1549 
1550  int x_lower = static_cast<int>(x);
1551  int y_lower = static_cast<int>(y);
1552 
1553  if (y_lower >= static_cast<int>(src.getHeight()) || x_lower >= static_cast<int>(src.getWidth()) ||
1554  y < 0 || x < 0) {
1555  continue;
1556  }
1557 
1558  double s = x - x_lower;
1559  double t = y - y_lower;
1560 
1561  if (y_lower < static_cast<int>(src.getHeight())-1 && x_lower < static_cast<int>(src.getWidth())-1) {
1562  const Type val00 = src[y_lower][x_lower];
1563  const Type val01 = src[y_lower][x_lower + 1];
1564  const Type val10 = src[y_lower + 1][x_lower];
1565  const Type val11 = src[y_lower + 1][x_lower + 1];
1566  const double col0 = lerp(val00, val01, s);
1567  const double col1 = lerp(val10, val11, s);
1568  const double interp = lerp(col0, col1, t);
1569  dst[i][j] = vpMath::saturate<Type>(interp);
1570  } else if (y_lower < static_cast<int>(src.getHeight())-1) {
1571  const Type val00 = src[y_lower][x_lower];
1572  const Type val10 = src[y_lower + 1][x_lower];
1573  const double interp = lerp(val00, val10, t);
1574  dst[i][j] = vpMath::saturate<Type>(interp);
1575  } else if (x_lower < static_cast<int>(src.getWidth())-1) {
1576  const Type val00 = src[y_lower][x_lower];
1577  const Type val01 = src[y_lower][x_lower + 1];
1578  const double interp = lerp(val00, val01, s);
1579  dst[i][j] = vpMath::saturate<Type>(interp);
1580  } else {
1581  dst[i][j] = src[y_lower][x_lower];
1582  }
1583  }
1584  }
1585  }
1586 }
1587 
1588 template <> inline
1589 void vpImageTools::warpLinear(const vpImage<vpRGBa> &src, const vpMatrix &T, vpImage<vpRGBa> &dst, bool affine,
1590  bool centerCorner, bool fixedPoint)
1591 {
1592  if (fixedPoint && !centerCorner) {
1593  const int nbits = 16;
1594  const int64_t precision = 1 << nbits;
1595  const float precision_1 = 1 / static_cast<float>(precision);
1596  const int64_t precision2 = 1ULL << (2 * nbits);
1597  const float precision_2 = 1 / static_cast<float>(precision2);
1598 
1599  int64_t a0_i64 = static_cast<int64_t>(T[0][0] * precision);
1600  int64_t a1_i64 = static_cast<int64_t>(T[0][1] * precision);
1601  int64_t a2_i64 = static_cast<int64_t>(T[0][2] * precision);
1602  int64_t a3_i64 = static_cast<int64_t>(T[1][0] * precision);
1603  int64_t a4_i64 = static_cast<int64_t>(T[1][1] * precision);
1604  int64_t a5_i64 = static_cast<int64_t>(T[1][2] * precision);
1605  int64_t a6_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][0] * precision) : 0;
1606  int64_t a7_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][1] * precision) : 0;
1607  int64_t a8_i64 = precision;
1608 
1609  int64_t height_i64 = static_cast<int64_t>(src.getHeight() * precision);
1610  int64_t width_i64 = static_cast<int64_t>(src.getWidth() * precision);
1611 
1612  if (affine) {
1613  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1614  int64_t xi = a2_i64;
1615  int64_t yi = a5_i64;
1616 
1617  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1618  if (yi >= 0 && yi < height_i64 && xi >= 0 && xi < width_i64) {
1619  const int64_t xi_lower = xi & (~0xFFFF);
1620  const int64_t yi_lower = yi & (~0xFFFF);
1621 
1622  const int64_t t = yi - yi_lower;
1623  const int64_t t_1 = precision - t;
1624  const int64_t s = xi - xi_lower;
1625  const int64_t s_1 = precision - s;
1626 
1627  const int x_ = static_cast<int>(xi >> nbits);
1628  const int y_ = static_cast<int>(yi >> nbits);
1629 
1630  if (y_ < static_cast<int>(src.getHeight())-1 && x_ < static_cast<int>(src.getWidth())-1) {
1631  const vpRGBa val00 = src[y_][x_];
1632  const vpRGBa val01 = src[y_][x_+1];
1633  const vpRGBa val10 = src[y_+1][x_];
1634  const vpRGBa val11 = src[y_+1][x_+1];
1635  const int64_t interpR_i64 = static_cast<int64_t>(s_1*t_1*val00.R + s * t_1*val01.R + s_1 * t*val10.R + s * t*val11.R);
1636  const float interpR = (interpR_i64 >> (nbits*2)) + (interpR_i64 & 0xFFFFFFFF) * precision_2;
1637 
1638  const int64_t interpG_i64 = static_cast<int64_t>(s_1*t_1*val00.G + s * t_1*val01.G + s_1 * t*val10.G + s * t*val11.G);
1639  const float interpG = (interpG_i64 >> (nbits * 2)) + (interpG_i64 & 0xFFFFFFFF) * precision_2;
1640 
1641  const int64_t interpB_i64 = static_cast<int64_t>(s_1*t_1*val00.B + s * t_1*val01.B + s_1 * t*val10.B + s * t*val11.B);
1642  const float interpB = (interpB_i64 >> (nbits * 2)) + (interpB_i64 & 0xFFFFFFFF) * precision_2;
1643 
1644  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1645  vpMath::saturate<unsigned char>(interpG),
1646  vpMath::saturate<unsigned char>(interpB),
1647  255);
1648  } else if (y_ < static_cast<int>(src.getHeight())-1) {
1649  const vpRGBa val00 = src[y_][x_];
1650  const vpRGBa val10 = src[y_+1][x_];
1651  const int64_t interpR_i64 = static_cast<int64_t>(t_1*val00.R + t*val10.R);
1652  const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1653 
1654  const int64_t interpG_i64 = static_cast<int64_t>(t_1*val00.G + t * val10.G);
1655  const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1656 
1657  const int64_t interpB_i64 = static_cast<int64_t>(t_1*val00.B + t * val10.B);
1658  const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1659 
1660  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1661  vpMath::saturate<unsigned char>(interpG),
1662  vpMath::saturate<unsigned char>(interpB),
1663  255);
1664  } else if (x_ < static_cast<int>(src.getWidth())-1) {
1665  const vpRGBa val00 = src[y_][x_];
1666  const vpRGBa val01 = src[y_][x_+1];
1667  const int64_t interpR_i64 = static_cast<int64_t>(s_1*val00.R + s*val01.R);
1668  const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1669 
1670  const int64_t interpG_i64 = static_cast<int64_t>(s_1*val00.G + s * val01.G);
1671  const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1672 
1673  const int64_t interpB_i64 = static_cast<int64_t>(s_1*val00.B + s * val01.B);
1674  const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1675 
1676  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1677  vpMath::saturate<unsigned char>(interpG),
1678  vpMath::saturate<unsigned char>(interpB),
1679  255);
1680  } else {
1681  dst[i][j] = src[y_][x_];
1682  }
1683  }
1684 
1685  xi += a0_i64;
1686  yi += a3_i64;
1687  }
1688 
1689  a2_i64 += a1_i64;
1690  a5_i64 += a4_i64;
1691  }
1692  } else {
1693  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1694  int64_t xi = a2_i64;
1695  int64_t yi = a5_i64;
1696  int64_t wi = a8_i64;
1697 
1698  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1699  if (yi >= 0 && yi <= (static_cast<int>(src.getHeight()) - 1)*wi &&
1700  xi >= 0 && xi <= (static_cast<int>(src.getWidth()) - 1)*wi) {
1701  const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1702  const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1703  const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1704 
1705  const int x_ = static_cast<int>(xi_);
1706  const int y_ = static_cast<int>(yi_);
1707 
1708  const float t = yi_ - y_;
1709  const float s = xi_ - x_;
1710 
1711  if (y_ < static_cast<int>(src.getHeight()) - 1 && x_ < static_cast<int>(src.getWidth()) - 1) {
1712  const vpRGBa val00 = src[y_][x_];
1713  const vpRGBa val01 = src[y_][x_ + 1];
1714  const vpRGBa val10 = src[y_ + 1][x_];
1715  const vpRGBa val11 = src[y_ + 1][x_ + 1];
1716  const float colR0 = lerp(val00.R, val01.R, s);
1717  const float colR1 = lerp(val10.R, val11.R, s);
1718  const float interpR = lerp(colR0, colR1, t);
1719 
1720  const float colG0 = lerp(val00.G, val01.G, s);
1721  const float colG1 = lerp(val10.G, val11.G, s);
1722  const float interpG = lerp(colG0, colG1, t);
1723 
1724  const float colB0 = lerp(val00.B, val01.B, s);
1725  const float colB1 = lerp(val10.B, val11.B, s);
1726  const float interpB = lerp(colB0, colB1, t);
1727 
1728  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1729  vpMath::saturate<unsigned char>(interpG),
1730  vpMath::saturate<unsigned char>(interpB),
1731  255);
1732  } else if (y_ < static_cast<int>(src.getHeight()) - 1) {
1733  const vpRGBa val00 = src[y_][x_];
1734  const vpRGBa val10 = src[y_ + 1][x_];
1735  const float interpR = lerp(val00.R, val10.R, t);
1736  const float interpG = lerp(val00.G, val10.G, t);
1737  const float interpB = lerp(val00.B, val10.B, t);
1738 
1739  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1740  vpMath::saturate<unsigned char>(interpG),
1741  vpMath::saturate<unsigned char>(interpB),
1742  255);
1743  } else if (x_ < static_cast<int>(src.getWidth()) - 1) {
1744  const vpRGBa val00 = src[y_][x_];
1745  const vpRGBa val01 = src[y_][x_ + 1];
1746  const float interpR = lerp(val00.R, val01.R, s);
1747  const float interpG = lerp(val00.G, val01.G, s);
1748  const float interpB = lerp(val00.B, val01.B, s);
1749 
1750  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1751  vpMath::saturate<unsigned char>(interpG),
1752  vpMath::saturate<unsigned char>(interpB),
1753  255);
1754  } else {
1755  dst[i][j] = src[y_][x_];
1756  }
1757  }
1758 
1759  xi += a0_i64;
1760  yi += a3_i64;
1761  wi += a6_i64;
1762  }
1763 
1764  a2_i64 += a1_i64;
1765  a5_i64 += a4_i64;
1766  a8_i64 += a7_i64;
1767  }
1768  }
1769  } else {
1770  double a0 = T[0][0]; double a1 = T[0][1]; double a2 = T[0][2];
1771  double a3 = T[1][0]; double a4 = T[1][1]; double a5 = T[1][2];
1772  double a6 = affine ? 0.0 : T[2][0];
1773  double a7 = affine ? 0.0 : T[2][1];
1774  double a8 = affine ? 1.0 : T[2][2];
1775 
1776  for (unsigned int i = 0; i < dst.getHeight(); i++) {
1777  for (unsigned int j = 0; j < dst.getWidth(); j++) {
1778  double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1779  double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1780  double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1781 
1782  x = x / w - (centerCorner ? 0.5 : 0);
1783  y = y / w - (centerCorner ? 0.5 : 0);
1784 
1785  int x_lower = static_cast<int>(x);
1786  int y_lower = static_cast<int>(y);
1787 
1788  if (y_lower >= static_cast<int>(src.getHeight()) || x_lower >= static_cast<int>(src.getWidth()) ||
1789  y < 0 || x < 0) {
1790  continue;
1791  }
1792 
1793  double s = x - x_lower;
1794  double t = y - y_lower;
1795 
1796  if (y_lower < static_cast<int>(src.getHeight())-1 && x_lower < static_cast<int>(src.getWidth())-1) {
1797  const vpRGBa val00 = src[y_lower][x_lower];
1798  const vpRGBa val01 = src[y_lower][x_lower +1];
1799  const vpRGBa val10 = src[y_lower +1][x_lower];
1800  const vpRGBa val11 = src[y_lower +1][x_lower +1];
1801  const double colR0 = lerp(val00.R, val01.R, s);
1802  const double colR1 = lerp(val10.R, val11.R, s);
1803  const double interpR = lerp(colR0, colR1, t);
1804 
1805  const double colG0 = lerp(val00.G, val01.G, s);
1806  const double colG1 = lerp(val10.G, val11.G, s);
1807  const double interpG = lerp(colG0, colG1, t);
1808 
1809  const double colB0 = lerp(val00.B, val01.B, s);
1810  const double colB1 = lerp(val10.B, val11.B, s);
1811  const double interpB = lerp(colB0, colB1, t);
1812 
1813  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1814  vpMath::saturate<unsigned char>(interpG),
1815  vpMath::saturate<unsigned char>(interpB),
1816  255);
1817  } else if (y_lower < static_cast<int>(src.getHeight())-1) {
1818  const vpRGBa val00 = src[y_lower][x_lower];
1819  const vpRGBa val10 = src[y_lower +1][x_lower];
1820  const double interpR = lerp(val00.R, val10.R, t);
1821  const double interpG = lerp(val00.G, val10.G, t);
1822  const double interpB = lerp(val00.B, val10.B, t);
1823 
1824  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1825  vpMath::saturate<unsigned char>(interpG),
1826  vpMath::saturate<unsigned char>(interpB),
1827  255);
1828  } else if (x_lower < static_cast<int>(src.getWidth())-1) {
1829  const vpRGBa val00 = src[y_lower][x_lower];
1830  const vpRGBa val01 = src[y_lower][x_lower +1];
1831  const double interpR = lerp(val00.R, val01.R, s);
1832  const double interpG = lerp(val00.G, val01.G, s);
1833  const double interpB = lerp(val00.B, val01.B, s);
1834 
1835  dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1836  vpMath::saturate<unsigned char>(interpG),
1837  vpMath::saturate<unsigned char>(interpB),
1838  255);
1839  } else {
1840  dst[i][j] = src[y_lower][x_lower];
1841  }
1842  }
1843  }
1844  }
1845 }
1846 
1847 #endif
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:156
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:1678
double get_i() const
Definition: vpImagePoint.h:203
double getTop() const
Definition: vpRect.h:193
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
unsigned char B
Blue component.
Definition: vpRGBa.h:150
Implementation of row vector and the associated operations.
Definition: vpRowVector.h:115
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
vpMatrix inverseByLU() const
unsigned int getRows() const
Definition: vpArray2D.h:289
Implementation of a generic 2D array used as base class for matrices and vectors. ...
Definition: vpArray2D.h:131
unsigned char G
Green component.
Definition: vpRGBa.h:149
Definition: vpRGBa.h:66
unsigned int getCols() const
Definition: vpArray2D.h:279
double getWidth() const
Definition: vpRect.h:228
static bool nul(double x, double s=0.001)
Definition: vpMath.h:291
static double sqr(double x)
Definition: vpMath.h:116
double get_j() const
Definition: vpImagePoint.h:214
Generic class defining intrinsic camera parameters.
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, bool useLUT=true)
Definition: vpImageTools.h:459
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
Definition: vpImageTools.h:833
double getLeft() const
Definition: vpRect.h:174
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI, unsigned int nThreads=2)
Definition: vpImageTools.h:648
static int round(double x)
Definition: vpMath.h:245
Various image tools; sub-image extraction, modification of the look up table, binarisation...
Definition: vpImageTools.h:78
static void warpImage(const vpImage< Type > &src, const vpMatrix &T, vpImage< Type > &dst, const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST, bool fixedPointArithmetic=true, bool pixelCenter=false)
unsigned int getHeight() const
Definition: vpImage.h:188
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:305
unsigned int getSize() const
Definition: vpImage.h:227
unsigned char R
Red component.
Definition: vpRGBa.h:148
static vp_deprecated void createSubImage(const vpImage< Type > &I, unsigned int i_sub, unsigned int j_sub, unsigned int nrow_sub, unsigned int ncol_sub, vpImage< Type > &S)
double getHeight() const
Definition: vpRect.h:167
double get_kud() const
Defines a rectangle in the plane.
Definition: vpRect.h:79
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:87
unsigned int getWidth() const
Definition: vpImage.h:246
Definition of the vpImage class member functions.
Definition: vpImage.h:126
Defines an oriented rectangle in the plane.
static void resize(const vpImage< Type > &I, vpImage< Type > &Ires, unsigned int width, unsigned int height, const vpImageInterpolationType &method=INTERPOLATION_NEAREST, unsigned int nThreads=0)