Visual Servoing Platform  version 3.2.0 under development (2019-01-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 
50 #include <visp3/core/vpImage.h>
51 
52 #ifdef VISP_HAVE_PTHREAD
53 #include <pthread.h>
54 #endif
55 
56 #include <visp3/core/vpCameraParameters.h>
57 #include <visp3/core/vpImageException.h>
58 #include <visp3/core/vpMath.h>
59 #include <visp3/core/vpRect.h>
60 #include <visp3/core/vpRectOriented.h>
61 
62 #include <fstream>
63 #include <iostream>
64 #include <math.h>
65 #include <string.h>
66 
76 class VISP_EXPORT vpImageTools
77 {
78 public:
82  INTERPOLATION_CUBIC
83  };
84 
85  template <class Type>
86  static inline void binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
87  const bool useLUT = true);
88  static void changeLUT(vpImage<unsigned char> &I, unsigned char A, unsigned char newA, unsigned char B,
89  unsigned char newB);
90 
91  template <class Type>
92  static void crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
93  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
94 
95  static void columnMean(const vpImage<double> &I, vpRowVector &result);
96 
97  template <class Type>
98  static void crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height, unsigned int roi_width,
99  vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
100  template <class Type>
101  static void crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale = 1,
102  unsigned int h_scale = 1);
103  template <class Type>
104  static void crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
105  vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
106 
107  static void extract(const vpImage<unsigned char> &Src, vpImage<unsigned char> &Dst, const vpRectOriented &r);
108  static void extract(const vpImage<unsigned char> &Src, vpImage<double> &Dst, const vpRectOriented &r);
109 
110  template <class Type> static void flip(const vpImage<Type> &I, vpImage<Type> &newI);
111 
112  template <class Type> static void flip(vpImage<Type> &I);
113 
114  static void imageDifference(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
115  vpImage<unsigned char> &Idiff);
116  static void imageDifference(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
117 
118  static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
119  vpImage<unsigned char> &Idiff);
120  static void imageDifferenceAbsolute(const vpImage<double> &I1, const vpImage<double> &I2, vpImage<double> &Idiff);
121  static void imageDifferenceAbsolute(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
122 
123  static void imageAdd(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2, vpImage<unsigned char> &Ires,
124  const bool saturate = false);
125 
126  static void imageSubtract(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
127  vpImage<unsigned char> &Ires, const bool saturate = false);
128 
129  static void initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height,
130  vpArray2D<int> &mapU, vpArray2D<int> &mapV,
131  vpArray2D<float> &mapDu, vpArray2D<float> &mapDv);
132 
133  static double interpolate(const vpImage<unsigned char> &I, const vpImagePoint &point,
134  const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
135 
136  static void integralImage(const vpImage<unsigned char> &I, vpImage<double> &II, vpImage<double> &IIsq);
137 
138  static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2,
139  const bool useOptimized = true);
140 
141  static void normalize(vpImage<double> &I);
142 
143  static void remap(const vpImage<unsigned char> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
144  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<unsigned char> &Iundist);
145  static void remap(const vpImage<vpRGBa> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
146  const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<vpRGBa> &Iundist);
147 
148  template <class Type>
149  static void resize(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int width, const unsigned int height,
150  const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
151 
152  template <class Type>
153  static void resize(const vpImage<Type> &I, vpImage<Type> &Ires,
154  const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
155 
156  static void templateMatching(const vpImage<unsigned char> &I, const vpImage<unsigned char> &I_tpl,
157  vpImage<double> &I_score, const unsigned int step_u, const unsigned int step_v,
158  const bool useOptimized = true);
159 
160  template <class Type>
161  static void undistort(const vpImage<Type> &I, const vpCameraParameters &cam, vpImage<Type> &newI,
162  unsigned int nThreads=2);
163 
164 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
165 
169  template <class Type>
170  vp_deprecated static void createSubImage(const vpImage<Type> &I, unsigned int i_sub, unsigned int j_sub,
171  unsigned int nrow_sub, unsigned int ncol_sub, vpImage<Type> &S);
172 
173  template <class Type>
174  vp_deprecated static void createSubImage(const vpImage<Type> &I, const vpRect &rect, vpImage<Type> &S);
176 #endif
177 
178 private:
179  // Cubic interpolation
180  static float cubicHermite(const float A, const float B, const float C, const float D, const float t);
181 
182  template <class Type> static Type getPixelClamped(const vpImage<Type> &I, const float u, const float v);
183 
184  // Linear interpolation
185  static float lerp(const float A, const float B, const float t);
186 
187  static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, const vpImage<double> &II,
188  const vpImage<double> &IIsq, const vpImage<double> &II_tpl,
189  const vpImage<double> &IIsq_tpl, const unsigned int i0, const unsigned int j0);
190 
191  template <class Type>
192  static void resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
193  const float u, const float v, const float xFrac, const float yFrac);
194 
195  template <class Type>
196  static void resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
197  const float u, const float v, const float xFrac, const float yFrac);
198 
199  template <class Type>
200  static void resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
201  const float u, const float v);
202 };
203 
204 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
205 
223 template <class Type>
224 void vpImageTools::createSubImage(const vpImage<Type> &I, unsigned int roi_top, unsigned int roi_left,
225  unsigned int roi_height, unsigned int roi_width, vpImage<Type> &crop)
226 {
227  vpImageTools::crop(I, roi_top, roi_left, roi_height, roi_width, crop);
228 }
229 
245 template <class Type> void vpImageTools::createSubImage(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop)
246 {
247  vpImageTools::crop(I, roi, crop);
248 }
249 
250 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
251 
271 template <class Type>
272 void vpImageTools::crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
273  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
274 {
275  int i_min = (std::max)((int)(ceil(roi_top / v_scale)), 0);
276  int j_min = (std::max)((int)(ceil(roi_left / h_scale)), 0);
277  int i_max = (std::min)((int)(ceil((roi_top + roi_height)) / v_scale), (int)(I.getHeight() / v_scale));
278  int j_max = (std::min)((int)(ceil((roi_left + roi_width) / h_scale)), (int)(I.getWidth() / h_scale));
279 
280  unsigned int i_min_u = (unsigned int)i_min;
281  unsigned int j_min_u = (unsigned int)j_min;
282 
283  unsigned int r_width = (unsigned int)(j_max - j_min);
284  unsigned int r_height = (unsigned int)(i_max - i_min);
285 
286  crop.resize(r_height, r_width);
287 
288  if (v_scale == 1 && h_scale == 1) {
289  for (unsigned int i = 0; i < r_height; i++) {
290  void *src = (void *)(I[i + i_min_u] + j_min_u);
291  void *dst = (void *)crop[i];
292  memcpy(dst, src, r_width * sizeof(Type));
293  }
294  } else if (h_scale == 1) {
295  for (unsigned int i = 0; i < r_height; i++) {
296  void *src = (void *)(I[(i + i_min_u) * v_scale] + j_min_u);
297  void *dst = (void *)crop[i];
298  memcpy(dst, src, r_width * sizeof(Type));
299  }
300  } else {
301  for (unsigned int i = 0; i < r_height; i++) {
302  for (unsigned int j = 0; j < r_width; j++) {
303  crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
304  }
305  }
306  }
307 }
308 
327 template <class Type>
328 void vpImageTools::crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height,
329  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
330 {
331  vpImageTools::crop(I, topLeft.get_i(), topLeft.get_j(), roi_height, roi_width, crop, v_scale, h_scale);
332 }
333 
351 template <class Type>
352 void vpImageTools::crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale,
353  unsigned int h_scale)
354 {
355  vpImageTools::crop(I, roi.getTop(), roi.getLeft(), (unsigned int)roi.getHeight(), (unsigned int)roi.getWidth(), crop,
356  v_scale, h_scale);
357 }
358 
376 template <class Type>
377 void vpImageTools::crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
378  vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
379 {
380  int i_min = (std::max)((int)(ceil(roi.getTop() / v_scale)), 0);
381  int j_min = (std::max)((int)(ceil(roi.getLeft() / h_scale)), 0);
382  int i_max = (std::min)((int)(ceil((roi.getTop() + roi.getHeight()) / v_scale)), (int)(height / v_scale));
383  int j_max = (std::min)((int)(ceil((roi.getLeft() + roi.getWidth()) / h_scale)), (int)(width / h_scale));
384 
385  unsigned int i_min_u = (unsigned int)i_min;
386  unsigned int j_min_u = (unsigned int)j_min;
387 
388  unsigned int r_width = (unsigned int)(j_max - j_min);
389  unsigned int r_height = (unsigned int)(i_max - i_min);
390 
391  crop.resize(r_height, r_width);
392 
393  if (v_scale == 1 && h_scale == 1) {
394  for (unsigned int i = 0; i < r_height; i++) {
395  void *src = (void *)(bitmap + ((i + i_min_u) * width + j_min_u) * sizeof(Type));
396  void *dst = (void *)crop[i];
397  memcpy(dst, src, r_width * sizeof(Type));
398  }
399  } else if (h_scale == 1) {
400  for (unsigned int i = 0; i < r_height; i++) {
401  void *src = (void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) * sizeof(Type));
402  void *dst = (void *)crop[i];
403  memcpy(dst, src, r_width * sizeof(Type));
404  }
405  } else {
406  for (unsigned int i = 0; i < r_height; i++) {
407  unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
408  for (unsigned int j = 0; j < r_width; j++) {
409  void *src = (void *)(bitmap + (i_src + j * h_scale) * sizeof(Type));
410  void *dst = (void *)&crop[i][j];
411  memcpy(dst, src, sizeof(Type));
412  }
413  }
414  }
415 }
416 
429 template <class Type>
430 inline void vpImageTools::binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2,
431  Type value3, const bool useLUT)
432 {
433  if (useLUT) {
434  std::cerr << "LUT not available for this type ! Will use the iteration method." << std::endl;
435  }
436 
437  Type v;
438  Type *p = I.bitmap;
439  Type *pend = I.bitmap + I.getWidth() * I.getHeight();
440  for (; p < pend; p++) {
441  v = *p;
442  if (v < threshold1)
443  *p = value1;
444  else if (v > threshold2)
445  *p = value3;
446  else
447  *p = value2;
448  }
449 }
450 
463 template <>
464 inline void vpImageTools::binarise(vpImage<unsigned char> &I, unsigned char threshold1, unsigned char threshold2,
465  unsigned char value1, unsigned char value2, unsigned char value3, const bool useLUT)
466 {
467  if (useLUT) {
468  // Construct the LUT
469  unsigned char lut[256];
470  for (unsigned int i = 0; i < 256; i++) {
471  lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
472  }
473 
474  I.performLut(lut);
475  } else {
476  unsigned char *p = I.bitmap;
477  unsigned char *pend = I.bitmap + I.getWidth() * I.getHeight();
478  for (; p < pend; p++) {
479  unsigned char v = *p;
480  if (v < threshold1)
481  *p = value1;
482  else if (v > threshold2)
483  *p = value3;
484  else
485  *p = value2;
486  }
487  }
488 }
489 
490 #ifdef VISP_HAVE_PTHREAD
491 
492 #ifndef DOXYGEN_SHOULD_SKIP_THIS
493 template <class Type> class vpUndistortInternalType
494 {
495 public:
496  Type *src;
497  Type *dst;
498  unsigned int width;
499  unsigned int height;
500  vpCameraParameters cam;
501  unsigned int nthreads;
502  unsigned int threadid;
503 
504 public:
505  vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0) {}
506 
507  vpUndistortInternalType(const vpUndistortInternalType<Type> &u) { *this = u; }
508  vpUndistortInternalType &operator=(const vpUndistortInternalType<Type> &u)
509  {
510  src = u.src;
511  dst = u.dst;
512  width = u.width;
513  height = u.height;
514  cam = u.cam;
515  nthreads = u.nthreads;
516  threadid = u.threadid;
517 
518  return *this;
519  }
520 
521  static void *vpUndistort_threaded(void *arg);
522 };
523 
524 template <class Type> void *vpUndistortInternalType<Type>::vpUndistort_threaded(void *arg)
525 {
526  vpUndistortInternalType<Type> *undistortSharedData = static_cast<vpUndistortInternalType<Type> *>(arg);
527  int offset = (int)undistortSharedData->threadid;
528  int width = (int)undistortSharedData->width;
529  int height = (int)undistortSharedData->height;
530  int nthreads = (int)undistortSharedData->nthreads;
531 
532  double u0 = undistortSharedData->cam.get_u0();
533  double v0 = undistortSharedData->cam.get_v0();
534  double px = undistortSharedData->cam.get_px();
535  double py = undistortSharedData->cam.get_py();
536  double kud = undistortSharedData->cam.get_kud();
537 
538  double invpx = 1.0 / px;
539  double invpy = 1.0 / py;
540 
541  double kud_px2 = kud * invpx * invpx;
542  double kud_py2 = kud * invpy * invpy;
543 
544  Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
545  Type *src = undistortSharedData->src;
546 
547  for (double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
548  double deltav = v - v0;
549  // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
550  double fr1 = 1.0 + kud_py2 * deltav * deltav;
551 
552  for (double u = 0; u < width; u++) {
553  // computation of u,v : corresponding pixel coordinates in I.
554  double deltau = u - u0;
555  // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
556  double fr2 = fr1 + kud_px2 * deltau * deltau;
557 
558  double u_double = deltau * fr2 + u0;
559  double v_double = deltav * fr2 + v0;
560 
561  // computation of the bilinear interpolation
562 
563  // declarations
564  int u_round = (int)(u_double);
565  int v_round = (int)(v_double);
566  if (u_round < 0.f)
567  u_round = -1;
568  if (v_round < 0.f)
569  v_round = -1;
570  double du_double = (u_double) - (double)u_round;
571  double dv_double = (v_double) - (double)v_round;
572  Type v01;
573  Type v23;
574  if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
575  // process interpolation
576  const Type *_mp = &src[v_round * width + u_round];
577  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
578  _mp += width;
579  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
580  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
581  } else {
582  *dst = 0;
583  }
584  dst++;
585  }
586  }
587 
588  pthread_exit((void *)0);
589  return NULL;
590 }
591 #endif // DOXYGEN_SHOULD_SKIP_THIS
592 #endif // VISP_HAVE_PTHREAD
593 
620 template <class Type>
622  unsigned int nThreads)
623 {
624 #ifdef VISP_HAVE_PTHREAD
625  //
626  // Optimized version using pthreads
627  //
628  unsigned int width = I.getWidth();
629  unsigned int height = I.getHeight();
630 
631  undistI.resize(height, width);
632 
633  double kud = cam.get_kud();
634 
635  // if (kud == 0) {
636  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
637  // There is no need to undistort the image
638  undistI = I;
639  return;
640  }
641 
642  unsigned int nthreads = nThreads;
643  pthread_attr_t attr;
644  pthread_t *callThd = new pthread_t[nthreads];
645  pthread_attr_init(&attr);
646  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
647 
648  vpUndistortInternalType<Type> *undistortSharedData;
649  undistortSharedData = new vpUndistortInternalType<Type>[nthreads];
650 
651  for (unsigned int i = 0; i < nthreads; i++) {
652  // Each thread works on a different set of data.
653  // vpTRACE("create thread %d", i);
654  undistortSharedData[i].src = I.bitmap;
655  undistortSharedData[i].dst = undistI.bitmap;
656  undistortSharedData[i].width = I.getWidth();
657  undistortSharedData[i].height = I.getHeight();
658  undistortSharedData[i].cam = cam;
659  undistortSharedData[i].nthreads = nthreads;
660  undistortSharedData[i].threadid = i;
661  pthread_create(&callThd[i], &attr, &vpUndistortInternalType<Type>::vpUndistort_threaded, &undistortSharedData[i]);
662  }
663  pthread_attr_destroy(&attr);
664  /* Wait on the other threads */
665 
666  for (unsigned int i = 0; i < nthreads; i++) {
667  // vpTRACE("join thread %d", i);
668  pthread_join(callThd[i], NULL);
669  }
670 
671  delete[] callThd;
672  delete[] undistortSharedData;
673 #else // VISP_HAVE_PTHREAD
674  //
675  // optimized version without pthreads
676  //
677  unsigned int width = I.getWidth();
678  unsigned int height = I.getHeight();
679 
680  undistI.resize(height, width);
681 
682  double u0 = cam.get_u0();
683  double v0 = cam.get_v0();
684  double px = cam.get_px();
685  double py = cam.get_py();
686  double kud = cam.get_kud();
687 
688  // if (kud == 0) {
689  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
690  // There is no need to undistort the image
691  undistI = I;
692  return;
693  }
694 
695  double invpx = 1.0 / px;
696  double invpy = 1.0 / py;
697 
698  double kud_px2 = kud * invpx * invpx;
699  double kud_py2 = kud * invpy * invpy;
700 
701  Type *dst = undistI.bitmap;
702  for (double v = 0; v < height; v++) {
703  double deltav = v - v0;
704  // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
705  double fr1 = 1.0 + kud_py2 * deltav * deltav;
706 
707  for (double u = 0; u < width; u++) {
708  // computation of u,v : corresponding pixel coordinates in I.
709  double deltau = u - u0;
710  // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
711  double fr2 = fr1 + kud_px2 * deltau * deltau;
712 
713  double u_double = deltau * fr2 + u0;
714  double v_double = deltav * fr2 + v0;
715 
716  // printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
717 
718  // computation of the bilinear interpolation
719 
720  // declarations
721  int u_round = (int)(u_double);
722  int v_round = (int)(v_double);
723  if (u_round < 0.f)
724  u_round = -1;
725  if (v_round < 0.f)
726  v_round = -1;
727  double du_double = (u_double) - (double)u_round;
728  double dv_double = (v_double) - (double)v_round;
729  Type v01;
730  Type v23;
731  if ((0 <= u_round) && (0 <= v_round) && (u_round < (((int)width) - 1)) && (v_round < (((int)height) - 1))) {
732  // process interpolation
733  const Type *_mp = &I[(unsigned int)v_round][(unsigned int)u_round];
734  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
735  _mp += width;
736  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
737  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
738  // printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
739  } else {
740  *dst = 0;
741  }
742  dst++;
743  }
744  }
745 #endif // VISP_HAVE_PTHREAD
746 
747 #if 0
748  // non optimized version
749  int width = I.getWidth();
750  int height = I.getHeight();
751 
752  undistI.resize(height,width);
753 
754  double u0 = cam.get_u0();
755  double v0 = cam.get_v0();
756  double px = cam.get_px();
757  double py = cam.get_py();
758  double kd = cam.get_kud();
759 
760  if (kd == 0) {
761  // There is no need to undistort the image
762  undistI = I;
763  return;
764  }
765 
766  for(int v = 0 ; v < height; v++){
767  for(int u = 0; u < height; u++){
768  double r2 = vpMath::sqr(((double)u - u0)/px) +
769  vpMath::sqr(((double)v-v0)/py);
770  double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
771  double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
772  undistI[v][u] = I.getPixelBI((float)u_double,(float)v_double);
773  }
774  }
775 #endif
776 }
777 
785 template <class Type> void vpImageTools::flip(const vpImage<Type> &I, vpImage<Type> &newI)
786 {
787  unsigned int height = 0, width = 0;
788 
789  height = I.getHeight();
790  width = I.getWidth();
791  newI.resize(height, width);
792 
793  for (unsigned int i = 0; i < height; i++) {
794  memcpy(newI.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
795  }
796 }
797 
829 template <class Type> void vpImageTools::flip(vpImage<Type> &I)
830 {
831  unsigned int height = 0, width = 0;
832  unsigned int i = 0;
833  vpImage<Type> Ibuf;
834 
835  height = I.getHeight();
836  width = I.getWidth();
837  Ibuf.resize(1, width);
838 
839  for (i = 0; i < height / 2; i++) {
840  memcpy(Ibuf.bitmap, I.bitmap + i * width, width * sizeof(Type));
841 
842  memcpy(I.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
843  memcpy(I.bitmap + (height - 1 - i) * width, Ibuf.bitmap, width * sizeof(Type));
844  }
845 }
846 
847 template <class Type> Type vpImageTools::getPixelClamped(const vpImage<Type> &I, const float u, const float v)
848 {
849  unsigned int i, j;
850  if (u < 0.)
851  j = 0;
852  else if (u > (float)I.getWidth() - 1.)
853  j = I.getWidth() - 1;
854  else
855  j = (unsigned int)u;
856 
857  if (v < 0.)
858  i = 0;
859  else if (v > (float)I.getHeight() - 1.)
860  i = I.getHeight() - 1;
861  else
862  i = (unsigned int)v;
863 
864  return I[i][j];
865 }
866 
867 // Reference:
868 // http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
869 template <class Type>
870 void vpImageTools::resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i,
871  const unsigned int j, const float u, const float v, const float xFrac,
872  const float yFrac)
873 {
874  // 1st row
875  Type p00 = getPixelClamped(I, u - 1, v - 1);
876  Type p01 = getPixelClamped(I, u + 0, v - 1);
877  Type p02 = getPixelClamped(I, u + 1, v - 1);
878  Type p03 = getPixelClamped(I, u + 2, v - 1);
879 
880  // 2nd row
881  Type p10 = getPixelClamped(I, u - 1, v + 0);
882  Type p11 = getPixelClamped(I, u + 0, v + 0);
883  Type p12 = getPixelClamped(I, u + 1, v + 0);
884  Type p13 = getPixelClamped(I, u + 2, v + 0);
885 
886  // 3rd row
887  Type p20 = getPixelClamped(I, u - 1, v + 1);
888  Type p21 = getPixelClamped(I, u + 0, v + 1);
889  Type p22 = getPixelClamped(I, u + 1, v + 1);
890  Type p23 = getPixelClamped(I, u + 2, v + 1);
891 
892  // 4th row
893  Type p30 = getPixelClamped(I, u - 1, v + 2);
894  Type p31 = getPixelClamped(I, u + 0, v + 2);
895  Type p32 = getPixelClamped(I, u + 1, v + 2);
896  Type p33 = getPixelClamped(I, u + 2, v + 2);
897 
898  float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
899  float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
900  float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
901  float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
902  float value = cubicHermite(col0, col1, col2, col3, yFrac);
903  Ires[i][j] = vpMath::saturate<Type>(value);
904 }
905 
906 template <>
907 inline void vpImageTools::resizeBicubic(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, const unsigned int i,
908  const unsigned int j, const float u, const float v, const float xFrac,
909  const float yFrac)
910 {
911  // 1st row
912  vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
913  vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
914  vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
915  vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
916 
917  // 2nd row
918  vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
919  vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
920  vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
921  vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
922 
923  // 3rd row
924  vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
925  vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
926  vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
927  vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
928 
929  // 4th row
930  vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
931  vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
932  vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
933  vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
934 
935  for (int c = 0; c < 3; c++) {
936  float col0 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p00)[c]),
937  static_cast<float>(reinterpret_cast<unsigned char *>(&p01)[c]),
938  static_cast<float>(reinterpret_cast<unsigned char *>(&p02)[c]),
939  static_cast<float>(reinterpret_cast<unsigned char *>(&p03)[c]), xFrac);
940  float col1 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p10)[c]),
941  static_cast<float>(reinterpret_cast<unsigned char *>(&p11)[c]),
942  static_cast<float>(reinterpret_cast<unsigned char *>(&p12)[c]),
943  static_cast<float>(reinterpret_cast<unsigned char *>(&p13)[c]), xFrac);
944  float col2 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p20)[c]),
945  static_cast<float>(reinterpret_cast<unsigned char *>(&p21)[c]),
946  static_cast<float>(reinterpret_cast<unsigned char *>(&p22)[c]),
947  static_cast<float>(reinterpret_cast<unsigned char *>(&p23)[c]), xFrac);
948  float col3 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p30)[c]),
949  static_cast<float>(reinterpret_cast<unsigned char *>(&p31)[c]),
950  static_cast<float>(reinterpret_cast<unsigned char *>(&p32)[c]),
951  static_cast<float>(reinterpret_cast<unsigned char *>(&p33)[c]), xFrac);
952  float value = cubicHermite(col0, col1, col2, col3, yFrac);
953 
954  reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
955  }
956 }
957 
958 template <class Type>
959 void vpImageTools::resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i,
960  const unsigned int j, const float u, const float v, const float xFrac,
961  const float yFrac)
962 {
963  unsigned int u0 = (unsigned int)u;
964  unsigned int v0 = (unsigned int)v;
965 
966  unsigned int u1 = (std::min)(I.getWidth() - 1, (unsigned int)u + 1);
967  unsigned int v1 = v0;
968 
969  unsigned int u2 = u0;
970  unsigned int v2 = (std::min)(I.getHeight() - 1, (unsigned int)v + 1);
971 
972  unsigned int u3 = u1;
973  unsigned int v3 = v2;
974 
975  float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
976  float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
977  float value = lerp(col0, col1, yFrac);
978 
979  Ires[i][j] = vpMath::saturate<Type>(value);
980 }
981 
982 template <>
983 inline void vpImageTools::resizeBilinear(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, const unsigned int i,
984  const unsigned int j, const float u, const float v, const float xFrac,
985  const float yFrac)
986 {
987  unsigned int u0 = (unsigned int)u;
988  unsigned int v0 = (unsigned int)v;
989 
990  unsigned int u1 = (std::min)(I.getWidth() - 1, (unsigned int)u + 1);
991  unsigned int v1 = v0;
992 
993  unsigned int u2 = u0;
994  unsigned int v2 = (std::min)(I.getHeight() - 1, (unsigned int)v + 1);
995 
996  unsigned int u3 = (std::min)(I.getWidth() - 1, (unsigned int)u + 1);
997  unsigned int v3 = (std::min)(I.getHeight() - 1, (unsigned int)v + 1);
998 
999  for (int c = 0; c < 3; c++) {
1000  float col0 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v0][u0])[c]),
1001  static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v1][u1])[c]), xFrac);
1002  float col1 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v2][u2])[c]),
1003  static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v3][u3])[c]), xFrac);
1004  float value = lerp(col0, col1, yFrac);
1005 
1006  reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1007  }
1008 }
1009 
1010 template <class Type>
1011 void vpImageTools::resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i,
1012  const unsigned int j, const float u, const float v)
1013 {
1014  Ires[i][j] = getPixelClamped(I, u, v);
1015 }
1016 
1029 template <class Type>
1030 void vpImageTools::resize(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int width,
1031  const unsigned int height, const vpImageInterpolationType &method)
1032 {
1033  Ires.resize(height, width);
1034 
1035  vpImageTools::resize(I, Ires, method);
1036 }
1037 
1048 template <class Type>
1050 {
1051  if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1052  std::cerr << "Input or output image is too small!" << std::endl;
1053  return;
1054  }
1055 
1056  float scaleY = (I.getHeight() - 1) / (float)(Ires.getHeight() - 1);
1057  float scaleX = (I.getWidth() - 1) / (float)(Ires.getWidth() - 1);
1058 
1059  if (method == INTERPOLATION_NEAREST) {
1060  scaleY = I.getHeight() / (float)(Ires.getHeight() - 1);
1061  scaleX = I.getWidth() / (float)(Ires.getWidth() - 1);
1062  }
1063 
1064  for (unsigned int i = 0; i < Ires.getHeight(); i++) {
1065  float v = i * scaleY;
1066  float yFrac = v - (int)v;
1067 
1068  for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1069  float u = j * scaleX;
1070  float xFrac = u - (int)u;
1071 
1072  if (method == INTERPOLATION_NEAREST) {
1073  resizeNearest(I, Ires, i, j, u, v);
1074  } else if (method == INTERPOLATION_LINEAR) {
1075  resizeBilinear(I, Ires, i, j, u, v, xFrac, yFrac);
1076  } else if (method == INTERPOLATION_CUBIC) {
1077  resizeBicubic(I, Ires, i, j, u, v, xFrac, yFrac);
1078  }
1079  }
1080  }
1081 }
1082 
1083 #endif
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, const bool useLUT=true)
Definition: vpImageTools.h:430
double getTop() const
Definition: vpRect.h:175
double get_u0() const
double get_i() const
Definition: vpImagePoint.h:204
unsigned int getWidth() const
Definition: vpImage.h:239
Implementation of row vector and the associated operations.
Definition: vpRowVector.h:72
Type * bitmap
points toward the bitmap
Definition: vpImage.h:133
double getHeight() const
Definition: vpRect.h:149
Implementation of a generic 2D array used as vase class of matrices and vectors.
Definition: vpArray2D.h:70
double get_py() const
double get_j() const
Definition: vpImagePoint.h:215
Definition: vpRGBa.h:66
double getWidth() const
Definition: vpRect.h:197
double get_v0() const
static double sqr(double x)
Definition: vpMath.h:108
Generic class defining intrinsic camera parameters.
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:866
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
Definition: vpImageTools.h:785
double get_px() const
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI, unsigned int nThreads=2)
Definition: vpImageTools.h:621
double get_kud() const
Various image tools; sub-image extraction, modification of the look up table, binarisation...
Definition: vpImageTools.h:76
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:272
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)
unsigned int getHeight() const
Definition: vpImage.h:178
Defines a rectangle in the plane.
Definition: vpRect.h:78
static void resize(const vpImage< Type > &I, vpImage< Type > &Ires, const unsigned int width, const unsigned int height, const vpImageInterpolationType &method=INTERPOLATION_NEAREST)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
void performLut(const Type(&lut)[256], const unsigned int nbThreads=1)
Definition: vpImage.h:1800
double getLeft() const
Definition: vpRect.h:156
Definition of the vpImage class member functions.
Definition: vpImage.h:116
Defines an oriented rectangle in the plane.