Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See http://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Image tools.
32  *
33  * Authors:
34  * Fabien Spindler
35  *
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/vpImageException.h>
57 #include <visp3/core/vpMath.h>
58 #include <visp3/core/vpRect.h>
59 #include <visp3/core/vpCameraParameters.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,
86  Type threshold1, Type threshold2,
87  Type value1, Type value2, Type value3, const bool useLUT=true);
88  static void changeLUT(vpImage<unsigned char>& I,
89  unsigned char A,
90  unsigned char newA,
91  unsigned char B,
92  unsigned char newB);
93 
94  template<class Type>
95  static void crop(const vpImage<Type> &I,
96  double roi_top, double roi_left,
97  unsigned int roi_height, unsigned int roi_width,
98  vpImage<Type> &crop, unsigned int v_scale=1, unsigned int h_scale=1);
99 
100  template<class Type>
101  static void crop(const vpImage<Type> &I,
102  const vpImagePoint &topLeft,
103  unsigned int roi_height, unsigned int roi_width,
104  vpImage<Type> &crop, unsigned int v_scale=1, unsigned int h_scale=1);
105  template<class Type>
106  static void crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale=1, unsigned int h_scale=1);
107  template<class Type>
108  static void crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi, vpImage<Type> &crop,
109  unsigned int v_scale=1, unsigned int h_scale=1);
110 
111  template<class Type>
112  static void flip(const vpImage<Type> &I, vpImage<Type> &newI);
113 
114  template<class Type>
115  static void flip(vpImage<Type> &I);
116 
117 
118  static void imageDifference(const vpImage<unsigned char> &I1,
119  const vpImage<unsigned char> &I2,
120  vpImage<unsigned char> &Idiff);
121  static void imageDifference(const vpImage<vpRGBa> &I1,
122  const vpImage<vpRGBa> &I2,
123  vpImage<vpRGBa> &Idiff);
124 
125  static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1,
126  const vpImage<unsigned char> &I2,
127  vpImage<unsigned char> &Idiff);
128  static void imageDifferenceAbsolute(const vpImage<vpRGBa> &I1,
129  const vpImage<vpRGBa> &I2,
130  vpImage<vpRGBa> &Idiff);
131 
132  static void imageAdd(const vpImage<unsigned char> &I1,
133  const vpImage<unsigned char> &I2,
135  const bool saturate=false);
136 
137  static void imageSubtract(const vpImage<unsigned char> &I1,
138  const vpImage<unsigned char> &I2,
140  const bool saturate=false);
141 
142  template<class Type>
143  static void resize(const vpImage<Type> &I,
144  vpImage<Type> &Ires,
145  const unsigned int width, const unsigned int height,
146  const vpImageInterpolationType &method=INTERPOLATION_NEAREST);
147 
148  template<class Type>
149  static void resize(const vpImage<Type> &I,
150  vpImage<Type> &Ires,
151  const vpImageInterpolationType &method=INTERPOLATION_NEAREST);
152 
153  template<class Type>
154  static void undistort(const vpImage<Type> &I,
155  const vpCameraParameters &cam,
156  vpImage<Type> &newI);
157 
158 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
159 
163  template<class Type>
164  vp_deprecated static void createSubImage(const vpImage<Type> &I,
165  unsigned int i_sub, unsigned int j_sub,
166  unsigned int nrow_sub, unsigned int ncol_sub,
167  vpImage<Type> &S);
168 
169  template<class Type>
170  vp_deprecated static void createSubImage(const vpImage<Type> &I, const vpRect &rect, vpImage<Type> &S);
172 #endif
173 
174 private:
175  //Cubic interpolation
176  static float cubicHermite (const float A, const float B, const float C, const float D, const float t);
177 
178  template<class Type>
179  static Type getPixelClamped(const vpImage<Type> &I, const float u, const float v);
180 
181  //Linear interpolation
182  static float lerp(const float A, const float B, const float t);
183 
184  template<class Type>
185  static void resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
186  const float u, const float v, const float xFrac, const float yFrac);
187 
188  template<class Type>
189  static void resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
190  const float u, const float v, const float xFrac, const float yFrac);
191 
192  template<class Type>
193  static void resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
194  const float u, const float v);
195 } ;
196 
197 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
198 
214 template<class Type>
216  unsigned int roi_top, unsigned int roi_left,
217  unsigned int roi_height, unsigned int roi_width,
218  vpImage<Type> &crop)
219 {
220  vpImageTools::crop(I, roi_top, roi_left, roi_height, roi_width, crop);
221 }
222 
238 template<class Type>
240  const vpRect &roi,
241  vpImage<Type> &crop)
242 {
243  vpImageTools::crop(I, roi, crop);
244 }
245 
246 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
247 
265 template<class Type>
267  double roi_top, double roi_left,
268  unsigned int roi_height, unsigned int roi_width,
269  vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
270 {
271  int i_min = std::max((int)(ceil(roi_top/v_scale)), 0);
272  int j_min = std::max((int)(ceil(roi_left/h_scale)), 0);
273  int i_max = std::min((int)(ceil((roi_top + roi_height))/v_scale), (int)(I.getHeight()/v_scale));
274  int j_max = std::min((int)(ceil((roi_left + roi_width)/h_scale)), (int)(I.getWidth()/h_scale));
275 
276  unsigned int i_min_u = (unsigned int)i_min;
277  unsigned int j_min_u = (unsigned int)j_min;
278 
279  unsigned int r_width = (unsigned int)(j_max-j_min);
280  unsigned int r_height = (unsigned int)(i_max-i_min);
281 
282  crop.resize(r_height, r_width) ;
283 
284  if (v_scale == 1 && h_scale == 1) {
285  for (unsigned int i=0 ; i < r_height ; i++) {
286  void *src = (void *)(I[i+i_min_u] + j_min_u);
287  void *dst = (void *)crop[i];
288  memcpy(dst, src, r_width*sizeof(Type));
289  }
290  }
291  else if (h_scale == 1) {
292  for (unsigned int i=0 ; i < r_height ; i++) {
293  void *src = (void *)(I[(i + i_min_u)*v_scale]+j_min_u);
294  void *dst = (void *)crop[i];
295  memcpy(dst, src, r_width*sizeof(Type));
296  }
297  }
298  else {
299  for (unsigned int i=0 ; i < r_height ; i++) {
300  for (unsigned int j=0 ; j < r_width ; j++) {
301  crop[i][j] = I[(i + i_min_u)*v_scale][(j + j_min_u)*h_scale];
302  }
303  }
304  }
305 }
306 
323 template<class Type>
325  const vpImagePoint &topLeft,
326  unsigned int roi_height, unsigned int roi_width,
327  vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
328 {
329  vpImageTools::crop(I, topLeft.get_i(), topLeft.get_j(), roi_height, roi_width, crop, v_scale, h_scale);
330 }
331 
347 template<class Type>
348 void vpImageTools::crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
349 {
350  vpImageTools::crop(I, roi.getTop(), roi.getLeft(), (unsigned int)roi.getHeight(), (unsigned int)roi.getWidth(), crop, v_scale, h_scale);
351 }
352 
367 template<class Type>
368 void vpImageTools::crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi, vpImage<Type> &crop,
369  unsigned int v_scale, unsigned int h_scale)
370 {
371  int i_min = std::max((int)(ceil(roi.getTop()/v_scale)), 0);
372  int j_min = std::max((int)(ceil(roi.getLeft()/h_scale)), 0);
373  int i_max = std::min((int)(ceil((roi.getTop() + roi.getHeight()))/v_scale), (int)(height/v_scale));
374  int j_max = std::min((int)(ceil((roi.getLeft() + roi.getWidth())/h_scale)), (int)(width/h_scale));
375 
376  unsigned int i_min_u = (unsigned int)i_min;
377  unsigned int j_min_u = (unsigned int)j_min;
378 
379  unsigned int r_width = (unsigned int)(j_max-j_min);
380  unsigned int r_height = (unsigned int)(i_max-i_min);
381 
382  crop.resize(r_height, r_width) ;
383 
384  if (v_scale == 1 && h_scale == 1) {
385  for (unsigned int i=0 ; i < r_height ; i++) {
386  void *src = (void *)(bitmap + ( (i+i_min_u)*width + j_min_u ) * sizeof(Type));
387  void *dst = (void *)crop[i];
388  memcpy(dst, src, r_width*sizeof(Type));
389  }
390  }
391  else if (h_scale == 1) {
392  for (unsigned int i=0 ; i < r_height ; i++) {
393  void *src = (void *)(bitmap + ( (i+i_min_u)*width*v_scale + j_min_u ) * sizeof(Type) );
394  void *dst = (void *)crop[i];
395  memcpy(dst, src, r_width*sizeof(Type));
396  }
397  }
398  else {
399  for (unsigned int i=0 ; i < r_height ; i++) {
400  unsigned int i_src = (i+i_min_u)*width*v_scale + j_min_u*h_scale;
401  for (unsigned int j=0 ; j < r_width ; j++) {
402  void *src = (void *)(bitmap + (i_src + j*h_scale)*sizeof(Type));
403  void *dst = (void *)&crop[i][j];
404  memcpy(dst, src, sizeof(Type));
405  }
406  }
407  }
408 }
409 
422 template<class Type>
424  Type threshold1, Type threshold2,
425  Type value1, Type value2, Type value3, const bool useLUT)
426 {
427  if(useLUT) {
428  std::cerr << "LUT not available for this type ! Will use the iteration method." << std::endl;
429  }
430 
431  Type v;
432  Type *p = I.bitmap;
433  Type *pend = I.bitmap + I.getWidth()*I.getHeight();
434  for (; p < pend; p ++) {
435  v = *p;
436  if (v < threshold1) *p = value1;
437  else if (v > threshold2) *p = value3;
438  else *p = value2;
439  }
440 }
441 
454 template<>
456  unsigned char threshold1, unsigned char threshold2,
457  unsigned char value1, unsigned char value2, unsigned char value3, const bool useLUT)
458 {
459  if(useLUT) {
460  //Construct the LUT
461  unsigned char lut[256];
462  for(unsigned int i = 0; i < 256; i++) {
463  lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
464  }
465 
466  I.performLut(lut);
467  } else {
468  unsigned char v;
469  unsigned char *p = I.bitmap;
470  unsigned char *pend = I.bitmap + I.getWidth()*I.getHeight();
471  for (; p < pend; p ++) {
472  v = *p;
473  if (v < threshold1) *p = value1;
474  else if (v > threshold2) *p = value3;
475  else *p = value2;
476  }
477  }
478 }
479 
480 #ifdef VISP_HAVE_PTHREAD
481 
482 #ifndef DOXYGEN_SHOULD_SKIP_THIS
483 template<class Type>
484 class vpUndistortInternalType
485 {
486 public:
487  Type *src;
488  Type *dst;
489  unsigned int width;
490  unsigned int height;
491  vpCameraParameters cam;
492  unsigned int nthreads;
493  unsigned int threadid;
494 public:
495  vpUndistortInternalType()
496  : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0)
497  {};
498 
499  vpUndistortInternalType(const vpUndistortInternalType<Type> &u) {
500  *this = u;
501  };
502  vpUndistortInternalType &operator=(const vpUndistortInternalType<Type> &u) {
503  src = u.src;
504  dst = u.dst;
505  width = u.width;
506  height = u.height;
507  cam = u.cam;
508  nthreads = u.nthreads;
509  threadid = u.threadid;
510 
511  return *this;
512  }
513 
514  static void *vpUndistort_threaded(void *arg);
515 };
516 
517 
518 template<class Type>
519 void *vpUndistortInternalType<Type>::vpUndistort_threaded(void *arg)
520 {
521  vpUndistortInternalType<Type> *undistortSharedData = (vpUndistortInternalType<Type>*)arg;
522  int offset = (int)undistortSharedData->threadid;
523  int width = (int)undistortSharedData->width;
524  int height = (int)undistortSharedData->height;
525  int nthreads = (int)undistortSharedData->nthreads;
526 
527  double u0 = undistortSharedData->cam.get_u0();
528  double v0 = undistortSharedData->cam.get_v0();
529  double px = undistortSharedData->cam.get_px();
530  double py = undistortSharedData->cam.get_py();
531  double kud = undistortSharedData->cam.get_kud();
532 
533  double invpx = 1.0/px;
534  double invpy = 1.0/py;
535 
536  double kud_px2 = kud * invpx * invpx;
537  double kud_py2 = kud * invpy * invpy;
538 
539  Type *dst = undistortSharedData->dst+(height/nthreads*offset)*width;
540  Type *src = undistortSharedData->src;
541 
542  for (double v = height/nthreads*offset;v < height/nthreads*(offset+1) ; v++) {
543  double deltav = v - v0;
544  //double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
545  double fr1 = 1.0 + kud_py2 * deltav * deltav;
546 
547  for (double u = 0 ; u < width ; u++) {
548  //computation of u,v : corresponding pixel coordinates in I.
549  double deltau = u - u0;
550  //double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
551  double fr2 = fr1 + kud_px2 * deltau * deltau;
552 
553  double u_double = deltau * fr2 + u0;
554  double v_double = deltav * fr2 + v0;
555 
556  //computation of the bilinear interpolation
557 
558  //declarations
559  int u_round = (int) (u_double);
560  int v_round = (int) (v_double);
561  if (u_round < 0.f) u_round = -1;
562  if (v_round < 0.f) v_round = -1;
563  double du_double = (u_double) - (double) u_round;
564  double dv_double = (v_double) - (double) v_round;
565  Type v01;
566  Type v23;
567  if ( (0 <= u_round) && (0 <= v_round) &&
568  (u_round < ((width) - 1)) && (v_round < ((height) - 1)) ) {
569  //process interpolation
570  const Type* _mp = &src[v_round*width+u_round];
571  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
572  _mp += width;
573  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
574  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
575  }
576  else {
577  *dst = 0;
578  }
579  dst++;
580  }
581  }
582 
583  pthread_exit((void*) 0);
584  return NULL;
585 }
586 #endif // DOXYGEN_SHOULD_SKIP_THIS
587 #endif // VISP_HAVE_PTHREAD
588 
608 template<class Type>
610  const vpCameraParameters &cam,
611  vpImage<Type> &undistI)
612 {
613 #ifdef VISP_HAVE_PTHREAD
614  //
615  // Optimized version using pthreads
616  //
617  unsigned int width = I.getWidth();
618  unsigned int height = I.getHeight();
619 
620  undistI.resize(height, width);
621 
622  double kud = cam.get_kud();
623 
624  //if (kud == 0) {
625  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
626  // There is no need to undistort the image
627  undistI = I;
628  return;
629  }
630 
631  unsigned int nthreads = 2;
632  pthread_attr_t attr;
633  pthread_t *callThd = new pthread_t [nthreads];
634  pthread_attr_init(&attr);
635  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
636 
637  vpUndistortInternalType<Type> *undistortSharedData;
638  undistortSharedData = new vpUndistortInternalType<Type> [nthreads];
639 
640  for(unsigned int i=0;i<nthreads;i++) {
641  // Each thread works on a different set of data.
642  // vpTRACE("create thread %d", i);
643  undistortSharedData[i].src = I.bitmap;
644  undistortSharedData[i].dst = undistI.bitmap;
645  undistortSharedData[i].width = I.getWidth();
646  undistortSharedData[i].height = I.getHeight();
647  undistortSharedData[i].cam = cam;
648  undistortSharedData[i].nthreads = nthreads;
649  undistortSharedData[i].threadid = i;
650  pthread_create( &callThd[i], &attr,
651  &vpUndistortInternalType<Type>::vpUndistort_threaded,
652  &undistortSharedData[i]);
653  }
654  pthread_attr_destroy(&attr);
655  /* Wait on the other threads */
656 
657  for(unsigned int i=0;i<nthreads;i++) {
658  // vpTRACE("join thread %d", i);
659  pthread_join( callThd[i], NULL);
660  }
661 
662  delete [] callThd;
663  delete [] undistortSharedData;
664 #else // VISP_HAVE_PTHREAD
665  //
666  // optimized version without pthreads
667  //
668  unsigned int width = I.getWidth();
669  unsigned int height = I.getHeight();
670 
671  undistI.resize(height, width);
672 
673  double u0 = cam.get_u0();
674  double v0 = cam.get_v0();
675  double px = cam.get_px();
676  double py = cam.get_py();
677  double kud = cam.get_kud();
678 
679  //if (kud == 0) {
680  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
681  // There is no need to undistort the image
682  undistI = I;
683  return;
684  }
685 
686  double invpx = 1.0/px;
687  double invpy = 1.0/py;
688 
689  double kud_px2 = kud * invpx * invpx;
690  double kud_py2 = kud * invpy * invpy;
691 
692  Type *dst = undistI.bitmap;
693  for (double v = 0;v < height ; v++) {
694  double deltav = v - v0;
695  //double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
696  double fr1 = 1.0 + kud_py2 * deltav * deltav;
697 
698  for (double u = 0 ; u < width ; u++) {
699  //computation of u,v : corresponding pixel coordinates in I.
700  double deltau = u - u0;
701  //double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
702  double fr2 = fr1 + kud_px2 * deltau * deltau;
703 
704  double u_double = deltau * fr2 + u0;
705  double v_double = deltav * fr2 + v0;
706 
707  //printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
708 
709  //computation of the bilinear interpolation
710 
711  //declarations
712  int u_round = (int) (u_double);
713  int v_round = (int) (v_double);
714  if (u_round < 0.f) u_round = -1;
715  if (v_round < 0.f) v_round = -1;
716  double du_double = (u_double) - (double) u_round;
717  double dv_double = (v_double) - (double) v_round;
718  Type v01;
719  Type v23;
720  if ( (0 <= u_round) && (0 <= v_round) &&
721  (u_round < (((int)width) - 1)) && (v_round < (((int)height) - 1)) ) {
722  //process interpolation
723  const Type* _mp = &I[(unsigned int)v_round][(unsigned int)u_round];
724  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
725  _mp += width;
726  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
727  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
728  //printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
729  }
730  else {
731  *dst = 0;
732  }
733  dst++;
734  }
735  }
736 #endif // VISP_HAVE_PTHREAD
737 
738 
739 
740 
741 #if 0
742  // non optimized version
743  int width = I.getWidth();
744  int height = I.getHeight();
745 
746  undistI.resize(height,width);
747 
748  double u0 = cam.get_u0();
749  double v0 = cam.get_v0();
750  double px = cam.get_px();
751  double py = cam.get_py();
752  double kd = cam.get_kud();
753 
754  if (kd == 0) {
755  // There is no need to undistort the image
756  undistI = I;
757  return;
758  }
759 
760  for(int v = 0 ; v < height; v++){
761  for(int u = 0; u < height; u++){
762  double r2 = vpMath::sqr(((double)u - u0)/px) +
763  vpMath::sqr(((double)v-v0)/py);
764  double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
765  double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
766  undistI[v][u] = I.getPixelBI((float)u_double,(float)v_double);
767  }
768  }
769 #endif
770 }
771 
779 template<class Type>
781  vpImage<Type> &newI)
782 {
783  unsigned int height = 0, width = 0;
784 
785  height = I.getHeight();
786  width = I.getWidth();
787  newI.resize(height, width);
788 
789  for (unsigned int i = 0; i < height; i++)
790  {
791  memcpy(newI.bitmap+i*width, I.bitmap+(height-1-i)*width,
792  width*sizeof(Type));
793  }
794 }
795 
796 
827 template<class Type>
829 {
830  unsigned int height = 0, width = 0;
831  unsigned int i = 0;
832  vpImage<Type> Ibuf;
833 
834  height = I.getHeight();
835  width = I.getWidth();
836  Ibuf.resize(1, width);
837 
838  for ( i = 0; i < height/2; i++)
839  {
840  memcpy(Ibuf.bitmap, I.bitmap+i*width,
841  width*sizeof(Type));
842 
843  memcpy(I.bitmap+i*width, I.bitmap+(height-1-i)*width,
844  width*sizeof(Type));
845  memcpy(I.bitmap+(height-1-i)*width, Ibuf.bitmap,
846  width*sizeof(Type));
847  }
848 }
849 
850 template<class Type>
851 Type vpImageTools::getPixelClamped(const vpImage<Type> &I, const float u, const float v) {
852  unsigned int j = std::min(std::max(0u, (unsigned int) u), I.getWidth()-1);
853  unsigned int i = std::min(std::max(0u, (unsigned int) v), I.getHeight()-1);
854 
855  return I[i][j];
856 }
857 
858 // Reference: http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
859 template<class Type> void
860 vpImageTools::resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
861  const float u, const float v, const float xFrac, const float yFrac) {
862  // 1st row
863  Type p00 = getPixelClamped(I, u-1, v-1);
864  Type p01 = getPixelClamped(I, u+0, v-1);
865  Type p02 = getPixelClamped(I, u+1, v-1);
866  Type p03 = getPixelClamped(I, u+2, v-1);
867 
868  // 2nd row
869  Type p10 = getPixelClamped(I, u-1, v+0);
870  Type p11 = getPixelClamped(I, u+0, v+0);
871  Type p12 = getPixelClamped(I, u+1, v+0);
872  Type p13 = getPixelClamped(I, u+2, v+0);
873 
874  // 3rd row
875  Type p20 = getPixelClamped(I, u-1, v+1);
876  Type p21 = getPixelClamped(I, u+0, v+1);
877  Type p22 = getPixelClamped(I, u+1, v+1);
878  Type p23 = getPixelClamped(I, u+2, v+1);
879 
880  // 4th row
881  Type p30 = getPixelClamped(I, u-1, v+2);
882  Type p31 = getPixelClamped(I, u+0, v+2);
883  Type p32 = getPixelClamped(I, u+1, v+2);
884  Type p33 = getPixelClamped(I, u+2, v+2);
885 
886  float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
887  float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
888  float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
889  float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
890  float value = cubicHermite(col0, col1, col2, col3, yFrac);
891  Ires[i][j] = vpMath::saturate<Type>(value);
892 }
893 
894 template<> inline void
895 vpImageTools::resizeBicubic(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, const unsigned int i, const unsigned int j,
896  const float u, const float v, const float xFrac, const float yFrac) {
897  // 1st row
898  vpRGBa p00 = getPixelClamped(I, u-1, v-1);
899  vpRGBa p01 = getPixelClamped(I, u+0, v-1);
900  vpRGBa p02 = getPixelClamped(I, u+1, v-1);
901  vpRGBa p03 = getPixelClamped(I, u+2, v-1);
902 
903  // 2nd row
904  vpRGBa p10 = getPixelClamped(I, u-1, v+0);
905  vpRGBa p11 = getPixelClamped(I, u+0, v+0);
906  vpRGBa p12 = getPixelClamped(I, u+1, v+0);
907  vpRGBa p13 = getPixelClamped(I, u+2, v+0);
908 
909  // 3rd row
910  vpRGBa p20 = getPixelClamped(I, u-1, v+1);
911  vpRGBa p21 = getPixelClamped(I, u+0, v+1);
912  vpRGBa p22 = getPixelClamped(I, u+1, v+1);
913  vpRGBa p23 = getPixelClamped(I, u+2, v+1);
914 
915  // 4th row
916  vpRGBa p30 = getPixelClamped(I, u-1, v+2);
917  vpRGBa p31 = getPixelClamped(I, u+0, v+2);
918  vpRGBa p32 = getPixelClamped(I, u+1, v+2);
919  vpRGBa p33 = getPixelClamped(I, u+2, v+2);
920 
921  for (int c = 0; c < 3; c++) {
922  float col0 = cubicHermite( ((unsigned char *) &p00)[c], ((unsigned char *) &p01)[c], ((unsigned char *) &p02)[c], ((unsigned char *) &p03)[c], xFrac );
923  float col1 = cubicHermite( ((unsigned char *) &p10)[c], ((unsigned char *) &p11)[c], ((unsigned char *) &p12)[c], ((unsigned char *) &p13)[c], xFrac );
924  float col2 = cubicHermite( ((unsigned char *) &p20)[c], ((unsigned char *) &p21)[c], ((unsigned char *) &p22)[c], ((unsigned char *) &p23)[c], xFrac );
925  float col3 = cubicHermite( ((unsigned char *) &p30)[c], ((unsigned char *) &p31)[c], ((unsigned char *) &p32)[c], ((unsigned char *) &p33)[c], xFrac );
926  float value = cubicHermite(col0, col1, col2, col3, yFrac);
927 
928  ((unsigned char *) &Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
929  }
930 }
931 
932 template<class Type> void
933 vpImageTools::resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
934  const float u, const float v, const float xFrac, const float yFrac) {
935  unsigned int u0 = (unsigned int) u;
936  unsigned int v0 = (unsigned int) v;
937 
938  unsigned int u1 = std::min(I.getWidth()-1, (unsigned int) u+1);
939  unsigned int v1 = v0;
940 
941  unsigned int u2 = u0;
942  unsigned int v2 = std::min(I.getHeight()-1, (unsigned int) v+1);
943 
944  unsigned int u3 = std::min(I.getWidth()-1, (unsigned int) u+1);
945  unsigned int v3 = std::min(I.getHeight()-1, (unsigned int) v+1);
946 
947  float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
948  float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
949  float value = lerp(col0, col1, yFrac);
950 
951  Ires[i][j] = vpMath::saturate<Type>(value);
952 }
953 
954 template<> inline void
955 vpImageTools::resizeBilinear(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, const unsigned int i, const unsigned int j,
956  const float u, const float v, const float xFrac, const float yFrac) {
957  unsigned int u0 = (unsigned int) u;
958  unsigned int v0 = (unsigned int) v;
959 
960  unsigned int u1 = std::min(I.getWidth()-1, (unsigned int) u+1);
961  unsigned int v1 = v0;
962 
963  unsigned int u2 = u0;
964  unsigned int v2 = std::min(I.getHeight()-1, (unsigned int) v+1);
965 
966  unsigned int u3 = std::min(I.getWidth()-1, (unsigned int) u+1);
967  unsigned int v3 = std::min(I.getHeight()-1, (unsigned int) v+1);
968 
969  for (int c = 0; c < 3; c++) {
970  float col0 = lerp( ((unsigned char *) &I[v0][u0])[c], ((unsigned char *) &I[v1][u1])[c], xFrac );
971  float col1 = lerp( ((unsigned char *) &I[v2][u2])[c], ((unsigned char *) &I[v3][u3])[c], xFrac );
972  float value = lerp(col0, col1, yFrac);
973 
974  ((unsigned char *) &Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
975  }
976 }
977 
978 template<class Type> void
979 vpImageTools::resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int i, const unsigned int j,
980  const float u, const float v) {
981  Ires[i][j] = getPixelClamped(I, u, v);
982 }
983 
993 template<class Type> void
994 vpImageTools::resize(const vpImage<Type> &I, vpImage<Type> &Ires, const unsigned int width, const unsigned int height, const vpImageInterpolationType &method) {
995  Ires.resize(height, width);
996 
997  vpImageTools::resize(I, Ires, method);
998 }
999 
1007 template<class Type> void
1009  if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1010  std::cerr << "Input or output image is too small!" << std::endl;
1011  return;
1012  }
1013 
1014  float scaleY = (I.getHeight() - 1) / (float) (Ires.getHeight() - 1);
1015  float scaleX = (I.getWidth() - 1) / (float) (Ires.getWidth() - 1);
1016 
1017  if (method == INTERPOLATION_NEAREST) {
1018  scaleY = I.getHeight() / (float) (Ires.getHeight() - 1);
1019  scaleX = I.getWidth() / (float) (Ires.getWidth() - 1);
1020  }
1021 
1022  for (unsigned int i = 0; i < Ires.getHeight(); i++) {
1023  float v = i * scaleY;
1024  float yFrac = v - (int) v;
1025 
1026  for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1027  float u = j * scaleX;
1028  float xFrac = u - (int) u;
1029 
1030  if (method == INTERPOLATION_NEAREST) {
1031  resizeNearest(I, Ires, i, j, u, v);
1032  } else if (method == INTERPOLATION_LINEAR) {
1033  resizeBilinear(I, Ires, i, j, u, v, xFrac, yFrac);
1034  } else if (method == INTERPOLATION_CUBIC) {
1035  resizeBicubic(I, Ires, i, j, u, v, xFrac, yFrac);
1036  }
1037  }
1038  }
1039 }
1040 
1041 #endif
1042 
1043 
1044 /*
1045  * Local variables:
1046  * c-basic-offset: 2
1047  * End:
1048  */
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, const bool useLUT=true)
Definition: vpImageTools.h:423
double getTop() const
Definition: vpRect.h:178
double get_u0() const
double get_i() const
Definition: vpImagePoint.h:199
unsigned int getWidth() const
Definition: vpImage.h:226
Type * bitmap
points toward the bitmap
Definition: vpImage.h:134
double getHeight() const
Definition: vpRect.h:152
double get_py() const
double get_j() const
Definition: vpImagePoint.h:210
Definition: vpRGBa.h:66
double getWidth() const
Definition: vpRect.h:199
double get_v0() const
static double sqr(double x)
Definition: vpMath.h:110
Generic class defining intrinsic camera parameters.
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:903
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI)
Definition: vpImageTools.h:609
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
Definition: vpImageTools.h:780
double get_px() const
double get_kud() const
Various image tools; sub-image extraction, modification of the look up table, binarisation...
Definition: vpImageTools.h:75
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:266
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:175
Defines a rectangle in the plane.
Definition: vpRect.h:82
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:994
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:1846
double getLeft() const
Definition: vpRect.h:159
Definition of the vpImage class member functions.
Definition: vpImage.h:117