Visual Servoing Platform  version 3.1.0
vpImageTools.h
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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 
61 #include <fstream>
62 #include <iostream>
63 #include <math.h>
64 #include <string.h>
65 
75 class VISP_EXPORT vpImageTools
76 {
77 public:
81  INTERPOLATION_CUBIC
82  };
83 
84  template <class Type>
85  static inline void binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
86  const bool useLUT = true);
87  static void changeLUT(vpImage<unsigned char> &I, unsigned char A, unsigned char newA, unsigned char B,
88  unsigned char newB);
89 
90  template <class Type>
91  static void crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
92  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
93 
94  template <class Type>
95  static void crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height, unsigned int roi_width,
96  vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
97  template <class Type>
98  static void crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale = 1,
99  unsigned int h_scale = 1);
100  template <class Type>
101  static void crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
102  vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
103 
104  template <class Type> static void flip(const vpImage<Type> &I, vpImage<Type> &newI);
105 
106  template <class Type> static void flip(vpImage<Type> &I);
107 
108  static void imageDifference(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
109  vpImage<unsigned char> &Idiff);
110  static void imageDifference(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
111 
112  static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
113  vpImage<unsigned char> &Idiff);
114  static void imageDifferenceAbsolute(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
115 
116  static void imageAdd(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2, vpImage<unsigned char> &Ires,
117  const bool saturate = false);
118 
119  static void imageSubtract(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
120  vpImage<unsigned char> &Ires, const bool saturate = false);
121 
122  template <class Type>
123  static void resize(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int width, const unsigned int height,
124  const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
125 
126  template <class Type>
127  static void resize(const vpImage<Type> &I, vpImage<Type> &Ires,
128  const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
129 
130  template <class Type>
131  static void undistort(const vpImage<Type> &I, const vpCameraParameters &cam, vpImage<Type> &newI);
132 
133 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
134 
138  template <class Type>
139  vp_deprecated static void createSubImage(const vpImage<Type> &I, unsigned int i_sub, unsigned int j_sub,
140  unsigned int nrow_sub, unsigned int ncol_sub, vpImage<Type> &S);
141 
142  template <class Type>
143  vp_deprecated static void createSubImage(const vpImage<Type> &I, const vpRect &rect, vpImage<Type> &S);
145 #endif
146 
147 private:
148  // Cubic interpolation
149  static float cubicHermite(const float A, const float B, const float C, const float D, const float t);
150 
151  template <class Type> static Type getPixelClamped(const vpImage<Type> &I, const float u, const float v);
152 
153  // Linear interpolation
154  static float lerp(const float A, const float B, const float t);
155 
156  template <class Type>
157  static void resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
158  const float u, const float v, const float xFrac, const float yFrac);
159 
160  template <class Type>
161  static void resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
162  const float u, const float v, const float xFrac, const float yFrac);
163 
164  template <class Type>
165  static void resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
166  const float u, const float v);
167 };
168 
169 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
170 
188 template <class Type>
189 void vpImageTools::createSubImage(const vpImage<Type> &I, unsigned int roi_top, unsigned int roi_left,
190  unsigned int roi_height, unsigned int roi_width, vpImage<Type> &crop)
191 {
192  vpImageTools::crop(I, roi_top, roi_left, roi_height, roi_width, crop);
193 }
194 
210 template <class Type> void vpImageTools::createSubImage(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop)
211 {
212  vpImageTools::crop(I, roi, crop);
213 }
214 
215 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
216 
236 template <class Type>
237 void vpImageTools::crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
238  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
239 {
240  int i_min = (std::max)((int)(ceil(roi_top / v_scale)), 0);
241  int j_min = (std::max)((int)(ceil(roi_left / h_scale)), 0);
242  int i_max = (std::min)((int)(ceil((roi_top + roi_height)) / v_scale), (int)(I.getHeight() / v_scale));
243  int j_max = (std::min)((int)(ceil((roi_left + roi_width) / h_scale)), (int)(I.getWidth() / h_scale));
244 
245  unsigned int i_min_u = (unsigned int)i_min;
246  unsigned int j_min_u = (unsigned int)j_min;
247 
248  unsigned int r_width = (unsigned int)(j_max - j_min);
249  unsigned int r_height = (unsigned int)(i_max - i_min);
250 
251  crop.resize(r_height, r_width);
252 
253  if (v_scale == 1 && h_scale == 1) {
254  for (unsigned int i = 0; i < r_height; i++) {
255  void *src = (void *)(I[i + i_min_u] + j_min_u);
256  void *dst = (void *)crop[i];
257  memcpy(dst, src, r_width * sizeof(Type));
258  }
259  } else if (h_scale == 1) {
260  for (unsigned int i = 0; i < r_height; i++) {
261  void *src = (void *)(I[(i + i_min_u) * v_scale] + j_min_u);
262  void *dst = (void *)crop[i];
263  memcpy(dst, src, r_width * sizeof(Type));
264  }
265  } else {
266  for (unsigned int i = 0; i < r_height; i++) {
267  for (unsigned int j = 0; j < r_width; j++) {
268  crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
269  }
270  }
271  }
272 }
273 
292 template <class Type>
293 void vpImageTools::crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height,
294  unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
295 {
296  vpImageTools::crop(I, topLeft.get_i(), topLeft.get_j(), roi_height, roi_width, crop, v_scale, h_scale);
297 }
298 
316 template <class Type>
317 void vpImageTools::crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale,
318  unsigned int h_scale)
319 {
320  vpImageTools::crop(I, roi.getTop(), roi.getLeft(), (unsigned int)roi.getHeight(), (unsigned int)roi.getWidth(), crop,
321  v_scale, h_scale);
322 }
323 
341 template <class Type>
342 void vpImageTools::crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
343  vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
344 {
345  int i_min = (std::max)((int)(ceil(roi.getTop() / v_scale)), 0);
346  int j_min = (std::max)((int)(ceil(roi.getLeft() / h_scale)), 0);
347  int i_max = (std::min)((int)(ceil((roi.getTop() + roi.getHeight())) / v_scale), (int)(height / v_scale));
348  int j_max = (std::min)((int)(ceil((roi.getLeft() + roi.getWidth()) / h_scale)), (int)(width / h_scale));
349 
350  unsigned int i_min_u = (unsigned int)i_min;
351  unsigned int j_min_u = (unsigned int)j_min;
352 
353  unsigned int r_width = (unsigned int)(j_max - j_min);
354  unsigned int r_height = (unsigned int)(i_max - i_min);
355 
356  crop.resize(r_height, r_width);
357 
358  if (v_scale == 1 && h_scale == 1) {
359  for (unsigned int i = 0; i < r_height; i++) {
360  void *src = (void *)(bitmap + ((i + i_min_u) * width + j_min_u) * sizeof(Type));
361  void *dst = (void *)crop[i];
362  memcpy(dst, src, r_width * sizeof(Type));
363  }
364  } else if (h_scale == 1) {
365  for (unsigned int i = 0; i < r_height; i++) {
366  void *src = (void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) * sizeof(Type));
367  void *dst = (void *)crop[i];
368  memcpy(dst, src, r_width * sizeof(Type));
369  }
370  } else {
371  for (unsigned int i = 0; i < r_height; i++) {
372  unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
373  for (unsigned int j = 0; j < r_width; j++) {
374  void *src = (void *)(bitmap + (i_src + j * h_scale) * sizeof(Type));
375  void *dst = (void *)&crop[i][j];
376  memcpy(dst, src, sizeof(Type));
377  }
378  }
379  }
380 }
381 
394 template <class Type>
395 inline void vpImageTools::binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2,
396  Type value3, const bool useLUT)
397 {
398  if (useLUT) {
399  std::cerr << "LUT not available for this type ! Will use the iteration method." << std::endl;
400  }
401 
402  Type v;
403  Type *p = I.bitmap;
404  Type *pend = I.bitmap + I.getWidth() * I.getHeight();
405  for (; p < pend; p++) {
406  v = *p;
407  if (v < threshold1)
408  *p = value1;
409  else if (v > threshold2)
410  *p = value3;
411  else
412  *p = value2;
413  }
414 }
415 
428 template <>
429 inline void vpImageTools::binarise(vpImage<unsigned char> &I, unsigned char threshold1, unsigned char threshold2,
430  unsigned char value1, unsigned char value2, unsigned char value3, const bool useLUT)
431 {
432  if (useLUT) {
433  // Construct the LUT
434  unsigned char lut[256];
435  for (unsigned int i = 0; i < 256; i++) {
436  lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
437  }
438 
439  I.performLut(lut);
440  } else {
441  unsigned char *p = I.bitmap;
442  unsigned char *pend = I.bitmap + I.getWidth() * I.getHeight();
443  for (; p < pend; p++) {
444  unsigned char v = *p;
445  if (v < threshold1)
446  *p = value1;
447  else if (v > threshold2)
448  *p = value3;
449  else
450  *p = value2;
451  }
452  }
453 }
454 
455 #ifdef VISP_HAVE_PTHREAD
456 
457 #ifndef DOXYGEN_SHOULD_SKIP_THIS
458 template <class Type> class vpUndistortInternalType
459 {
460 public:
461  Type *src;
462  Type *dst;
463  unsigned int width;
464  unsigned int height;
465  vpCameraParameters cam;
466  unsigned int nthreads;
467  unsigned int threadid;
468 
469 public:
470  vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0){};
471 
472  vpUndistortInternalType(const vpUndistortInternalType<Type> &u) { *this = u; };
473  vpUndistortInternalType &operator=(const vpUndistortInternalType<Type> &u)
474  {
475  src = u.src;
476  dst = u.dst;
477  width = u.width;
478  height = u.height;
479  cam = u.cam;
480  nthreads = u.nthreads;
481  threadid = u.threadid;
482 
483  return *this;
484  }
485 
486  static void *vpUndistort_threaded(void *arg);
487 };
488 
489 template <class Type> void *vpUndistortInternalType<Type>::vpUndistort_threaded(void *arg)
490 {
491  vpUndistortInternalType<Type> *undistortSharedData = static_cast<vpUndistortInternalType<Type> *>(arg);
492  int offset = (int)undistortSharedData->threadid;
493  int width = (int)undistortSharedData->width;
494  int height = (int)undistortSharedData->height;
495  int nthreads = (int)undistortSharedData->nthreads;
496 
497  double u0 = undistortSharedData->cam.get_u0();
498  double v0 = undistortSharedData->cam.get_v0();
499  double px = undistortSharedData->cam.get_px();
500  double py = undistortSharedData->cam.get_py();
501  double kud = undistortSharedData->cam.get_kud();
502 
503  double invpx = 1.0 / px;
504  double invpy = 1.0 / py;
505 
506  double kud_px2 = kud * invpx * invpx;
507  double kud_py2 = kud * invpy * invpy;
508 
509  Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
510  Type *src = undistortSharedData->src;
511 
512  for (double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
513  double deltav = v - v0;
514  // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
515  double fr1 = 1.0 + kud_py2 * deltav * deltav;
516 
517  for (double u = 0; u < width; u++) {
518  // computation of u,v : corresponding pixel coordinates in I.
519  double deltau = u - u0;
520  // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
521  double fr2 = fr1 + kud_px2 * deltau * deltau;
522 
523  double u_double = deltau * fr2 + u0;
524  double v_double = deltav * fr2 + v0;
525 
526  // computation of the bilinear interpolation
527 
528  // declarations
529  int u_round = (int)(u_double);
530  int v_round = (int)(v_double);
531  if (u_round < 0.f)
532  u_round = -1;
533  if (v_round < 0.f)
534  v_round = -1;
535  double du_double = (u_double) - (double)u_round;
536  double dv_double = (v_double) - (double)v_round;
537  Type v01;
538  Type v23;
539  if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
540  // process interpolation
541  const Type *_mp = &src[v_round * width + u_round];
542  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
543  _mp += width;
544  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
545  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
546  } else {
547  *dst = 0;
548  }
549  dst++;
550  }
551  }
552 
553  pthread_exit((void *)0);
554  return NULL;
555 }
556 #endif // DOXYGEN_SHOULD_SKIP_THIS
557 #endif // VISP_HAVE_PTHREAD
558 
578 template <class Type>
580 {
581 #ifdef VISP_HAVE_PTHREAD
582  //
583  // Optimized version using pthreads
584  //
585  unsigned int width = I.getWidth();
586  unsigned int height = I.getHeight();
587 
588  undistI.resize(height, width);
589 
590  double kud = cam.get_kud();
591 
592  // if (kud == 0) {
593  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
594  // There is no need to undistort the image
595  undistI = I;
596  return;
597  }
598 
599  unsigned int nthreads = 2;
600  pthread_attr_t attr;
601  pthread_t *callThd = new pthread_t[nthreads];
602  pthread_attr_init(&attr);
603  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
604 
605  vpUndistortInternalType<Type> *undistortSharedData;
606  undistortSharedData = new vpUndistortInternalType<Type>[nthreads];
607 
608  for (unsigned int i = 0; i < nthreads; i++) {
609  // Each thread works on a different set of data.
610  // vpTRACE("create thread %d", i);
611  undistortSharedData[i].src = I.bitmap;
612  undistortSharedData[i].dst = undistI.bitmap;
613  undistortSharedData[i].width = I.getWidth();
614  undistortSharedData[i].height = I.getHeight();
615  undistortSharedData[i].cam = cam;
616  undistortSharedData[i].nthreads = nthreads;
617  undistortSharedData[i].threadid = i;
618  pthread_create(&callThd[i], &attr, &vpUndistortInternalType<Type>::vpUndistort_threaded, &undistortSharedData[i]);
619  }
620  pthread_attr_destroy(&attr);
621  /* Wait on the other threads */
622 
623  for (unsigned int i = 0; i < nthreads; i++) {
624  // vpTRACE("join thread %d", i);
625  pthread_join(callThd[i], NULL);
626  }
627 
628  delete[] callThd;
629  delete[] undistortSharedData;
630 #else // VISP_HAVE_PTHREAD
631  //
632  // optimized version without pthreads
633  //
634  unsigned int width = I.getWidth();
635  unsigned int height = I.getHeight();
636 
637  undistI.resize(height, width);
638 
639  double u0 = cam.get_u0();
640  double v0 = cam.get_v0();
641  double px = cam.get_px();
642  double py = cam.get_py();
643  double kud = cam.get_kud();
644 
645  // if (kud == 0) {
646  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
647  // There is no need to undistort the image
648  undistI = I;
649  return;
650  }
651 
652  double invpx = 1.0 / px;
653  double invpy = 1.0 / py;
654 
655  double kud_px2 = kud * invpx * invpx;
656  double kud_py2 = kud * invpy * invpy;
657 
658  Type *dst = undistI.bitmap;
659  for (double v = 0; v < height; v++) {
660  double deltav = v - v0;
661  // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
662  double fr1 = 1.0 + kud_py2 * deltav * deltav;
663 
664  for (double u = 0; u < width; u++) {
665  // computation of u,v : corresponding pixel coordinates in I.
666  double deltau = u - u0;
667  // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
668  double fr2 = fr1 + kud_px2 * deltau * deltau;
669 
670  double u_double = deltau * fr2 + u0;
671  double v_double = deltav * fr2 + v0;
672 
673  // printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
674 
675  // computation of the bilinear interpolation
676 
677  // declarations
678  int u_round = (int)(u_double);
679  int v_round = (int)(v_double);
680  if (u_round < 0.f)
681  u_round = -1;
682  if (v_round < 0.f)
683  v_round = -1;
684  double du_double = (u_double) - (double)u_round;
685  double dv_double = (v_double) - (double)v_round;
686  Type v01;
687  Type v23;
688  if ((0 <= u_round) && (0 <= v_round) && (u_round < (((int)width) - 1)) && (v_round < (((int)height) - 1))) {
689  // process interpolation
690  const Type *_mp = &I[(unsigned int)v_round][(unsigned int)u_round];
691  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
692  _mp += width;
693  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
694  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
695  // printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
696  } else {
697  *dst = 0;
698  }
699  dst++;
700  }
701  }
702 #endif // VISP_HAVE_PTHREAD
703 
704 #if 0
705  // non optimized version
706  int width = I.getWidth();
707  int height = I.getHeight();
708 
709  undistI.resize(height,width);
710 
711  double u0 = cam.get_u0();
712  double v0 = cam.get_v0();
713  double px = cam.get_px();
714  double py = cam.get_py();
715  double kd = cam.get_kud();
716 
717  if (kd == 0) {
718  // There is no need to undistort the image
719  undistI = I;
720  return;
721  }
722 
723  for(int v = 0 ; v < height; v++){
724  for(int u = 0; u < height; u++){
725  double r2 = vpMath::sqr(((double)u - u0)/px) +
726  vpMath::sqr(((double)v-v0)/py);
727  double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
728  double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
729  undistI[v][u] = I.getPixelBI((float)u_double,(float)v_double);
730  }
731  }
732 #endif
733 }
734 
742 template <class Type> void vpImageTools::flip(const vpImage<Type> &I, vpImage<Type> &newI)
743 {
744  unsigned int height = 0, width = 0;
745 
746  height = I.getHeight();
747  width = I.getWidth();
748  newI.resize(height, width);
749 
750  for (unsigned int i = 0; i < height; i++) {
751  memcpy(newI.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
752  }
753 }
754 
786 template <class Type> void vpImageTools::flip(vpImage<Type> &I)
787 {
788  unsigned int height = 0, width = 0;
789  unsigned int i = 0;
790  vpImage<Type> Ibuf;
791 
792  height = I.getHeight();
793  width = I.getWidth();
794  Ibuf.resize(1, width);
795 
796  for (i = 0; i < height / 2; i++) {
797  memcpy(Ibuf.bitmap, I.bitmap + i * width, width * sizeof(Type));
798 
799  memcpy(I.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
800  memcpy(I.bitmap + (height - 1 - i) * width, Ibuf.bitmap, width * sizeof(Type));
801  }
802 }
803 
804 template <class Type> Type vpImageTools::getPixelClamped(const vpImage<Type> &I, const float u, const float v)
805 {
806  unsigned int i, j;
807  if (u < 0.)
808  j = 0;
809  else if (u > (float)I.getWidth() - 1.)
810  j = I.getWidth() - 1;
811  else
812  j = (unsigned int)u;
813 
814  if (v < 0.)
815  i = 0;
816  else if (v > (float)I.getHeight() - 1.)
817  i = I.getHeight() - 1;
818  else
819  i = (unsigned int)v;
820 
821  return I[i][j];
822 }
823 
824 // Reference:
825 // http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
826 template <class Type>
827 void vpImageTools::resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i,
828  const unsigned int j, const float u, const float v, const float xFrac,
829  const float yFrac)
830 {
831  // 1st row
832  Type p00 = getPixelClamped(I, u - 1, v - 1);
833  Type p01 = getPixelClamped(I, u + 0, v - 1);
834  Type p02 = getPixelClamped(I, u + 1, v - 1);
835  Type p03 = getPixelClamped(I, u + 2, v - 1);
836 
837  // 2nd row
838  Type p10 = getPixelClamped(I, u - 1, v + 0);
839  Type p11 = getPixelClamped(I, u + 0, v + 0);
840  Type p12 = getPixelClamped(I, u + 1, v + 0);
841  Type p13 = getPixelClamped(I, u + 2, v + 0);
842 
843  // 3rd row
844  Type p20 = getPixelClamped(I, u - 1, v + 1);
845  Type p21 = getPixelClamped(I, u + 0, v + 1);
846  Type p22 = getPixelClamped(I, u + 1, v + 1);
847  Type p23 = getPixelClamped(I, u + 2, v + 1);
848 
849  // 4th row
850  Type p30 = getPixelClamped(I, u - 1, v + 2);
851  Type p31 = getPixelClamped(I, u + 0, v + 2);
852  Type p32 = getPixelClamped(I, u + 1, v + 2);
853  Type p33 = getPixelClamped(I, u + 2, v + 2);
854 
855  float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
856  float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
857  float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
858  float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
859  float value = cubicHermite(col0, col1, col2, col3, yFrac);
860  Ires[i][j] = vpMath::saturate<Type>(value);
861 }
862 
863 template <>
864 inline void vpImageTools::resizeBicubic(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, const unsigned int i,
865  const unsigned int j, const float u, const float v, const float xFrac,
866  const float yFrac)
867 {
868  // 1st row
869  vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
870  vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
871  vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
872  vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
873 
874  // 2nd row
875  vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
876  vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
877  vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
878  vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
879 
880  // 3rd row
881  vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
882  vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
883  vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
884  vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
885 
886  // 4th row
887  vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
888  vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
889  vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
890  vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
891 
892  for (int c = 0; c < 3; c++) {
893  float col0 = cubicHermite(((unsigned char *)&p00)[c], ((unsigned char *)&p01)[c], ((unsigned char *)&p02)[c],
894  ((unsigned char *)&p03)[c], xFrac);
895  float col1 = cubicHermite(((unsigned char *)&p10)[c], ((unsigned char *)&p11)[c], ((unsigned char *)&p12)[c],
896  ((unsigned char *)&p13)[c], xFrac);
897  float col2 = cubicHermite(((unsigned char *)&p20)[c], ((unsigned char *)&p21)[c], ((unsigned char *)&p22)[c],
898  ((unsigned char *)&p23)[c], xFrac);
899  float col3 = cubicHermite(((unsigned char *)&p30)[c], ((unsigned char *)&p31)[c], ((unsigned char *)&p32)[c],
900  ((unsigned char *)&p33)[c], xFrac);
901  float value = cubicHermite(col0, col1, col2, col3, yFrac);
902 
903  ((unsigned char *)&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
904  }
905 }
906 
907 template <class Type>
908 void vpImageTools::resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i,
909  const unsigned int j, const float u, const float v, const float xFrac,
910  const float yFrac)
911 {
912  unsigned int u0 = (unsigned int)u;
913  unsigned int v0 = (unsigned int)v;
914 
915  unsigned int u1 = (std::min)(I.getWidth() - 1, (unsigned int)u + 1);
916  unsigned int v1 = v0;
917 
918  unsigned int u2 = u0;
919  unsigned int v2 = (std::min)(I.getHeight() - 1, (unsigned int)v + 1);
920 
921  unsigned int u3 = (std::min)(I.getWidth() - 1, (unsigned int)u + 1);
922  unsigned int v3 = (std::min)(I.getHeight() - 1, (unsigned int)v + 1);
923 
924  float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
925  float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
926  float value = lerp(col0, col1, yFrac);
927 
928  Ires[i][j] = vpMath::saturate<Type>(value);
929 }
930 
931 template <>
932 inline void vpImageTools::resizeBilinear(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, const unsigned int i,
933  const unsigned int j, const float u, const float v, const float xFrac,
934  const float yFrac)
935 {
936  unsigned int u0 = (unsigned int)u;
937  unsigned int v0 = (unsigned int)v;
938 
939  unsigned int u1 = (std::min)(I.getWidth() - 1, (unsigned int)u + 1);
940  unsigned int v1 = v0;
941 
942  unsigned int u2 = u0;
943  unsigned int v2 = (std::min)(I.getHeight() - 1, (unsigned int)v + 1);
944 
945  unsigned int u3 = (std::min)(I.getWidth() - 1, (unsigned int)u + 1);
946  unsigned int v3 = (std::min)(I.getHeight() - 1, (unsigned int)v + 1);
947 
948  for (int c = 0; c < 3; c++) {
949  float col0 = lerp(((unsigned char *)&I[v0][u0])[c], ((unsigned char *)&I[v1][u1])[c], xFrac);
950  float col1 = lerp(((unsigned char *)&I[v2][u2])[c], ((unsigned char *)&I[v3][u3])[c], xFrac);
951  float value = lerp(col0, col1, yFrac);
952 
953  ((unsigned char *)&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
954  }
955 }
956 
957 template <class Type>
958 void vpImageTools::resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i,
959  const unsigned int j, const float u, const float v)
960 {
961  Ires[i][j] = getPixelClamped(I, u, v);
962 }
963 
974 template <class Type>
975 void vpImageTools::resize(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int width,
976  const unsigned int height, const vpImageInterpolationType &method)
977 {
978  Ires.resize(height, width);
979 
980  vpImageTools::resize(I, Ires, method);
981 }
982 
991 template <class Type>
993 {
994  if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
995  std::cerr << "Input or output image is too small!" << std::endl;
996  return;
997  }
998 
999  float scaleY = (I.getHeight() - 1) / (float)(Ires.getHeight() - 1);
1000  float scaleX = (I.getWidth() - 1) / (float)(Ires.getWidth() - 1);
1001 
1002  if (method == INTERPOLATION_NEAREST) {
1003  scaleY = I.getHeight() / (float)(Ires.getHeight() - 1);
1004  scaleX = I.getWidth() / (float)(Ires.getWidth() - 1);
1005  }
1006 
1007  for (unsigned int i = 0; i < Ires.getHeight(); i++) {
1008  float v = i * scaleY;
1009  float yFrac = v - (int)v;
1010 
1011  for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1012  float u = j * scaleX;
1013  float xFrac = u - (int)u;
1014 
1015  if (method == INTERPOLATION_NEAREST) {
1016  resizeNearest(I, Ires, i, j, u, v);
1017  } else if (method == INTERPOLATION_LINEAR) {
1018  resizeBilinear(I, Ires, i, j, u, v, xFrac, yFrac);
1019  } else if (method == INTERPOLATION_CUBIC) {
1020  resizeBicubic(I, Ires, i, j, u, v, xFrac, yFrac);
1021  }
1022  }
1023  }
1024 }
1025 
1026 #endif
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, const bool useLUT=true)
Definition: vpImageTools.h:395
double get_i() const
Definition: vpImagePoint.h:204
double getTop() const
Definition: vpRect.h:175
Type * bitmap
points toward the bitmap
Definition: vpImage.h:133
Definition: vpRGBa.h:66
double getWidth() const
Definition: vpRect.h:197
static double sqr(double x)
Definition: vpMath.h:108
double get_j() const
Definition: vpImagePoint.h:215
Generic class defining intrinsic camera parameters.
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:856
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI)
Definition: vpImageTools.h:579
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
Definition: vpImageTools.h:742
double getLeft() const
Definition: vpRect.h:156
Various image tools; sub-image extraction, modification of the look up table, binarisation...
Definition: vpImageTools.h:75
unsigned int getHeight() const
Definition: vpImage.h:178
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:237
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:149
double get_kud() const
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)
Definition: vpImageTools.h:975
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:1670
unsigned int getWidth() const
Definition: vpImage.h:229
Definition of the vpImage class member functions.
Definition: vpImage.h:116