Visual Servoing Platform  version 3.0.0
vpImageTools.h
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 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 
78 public:
79  template<class Type>
80  static void createSubImage(const vpImage<Type> &I,
81  unsigned int i_sub, unsigned int j_sub,
82  unsigned int nrow_sub, unsigned int ncol_sub,
83  vpImage<Type> &S);
84 
85  template<class Type>
86  static void createSubImage(const vpImage<Type> &I,
87  const vpRect &rect,
88  vpImage<Type> &S);
89 
90  template<class Type>
91  static inline void binarise(vpImage<Type> &I,
92  Type threshold1, Type threshold2,
93  Type value1, Type value2, Type value3, const bool useLUT=false);
94 
95  static void changeLUT(vpImage<unsigned char>& I,
96  unsigned char A,
97  unsigned char newA,
98  unsigned char B,
99  unsigned char newB);
100 
101  template<class Type>
102  static void undistort(const vpImage<Type> &I,
103  const vpCameraParameters &cam,
104  vpImage<Type> &newI);
105 
106  template<class Type>
107  static void flip(const vpImage<Type> &I,
108  vpImage<Type> &newI);
109 
110  template<class Type>
111  static void flip(vpImage<Type> &I);
112 
113 
114  static void imageDifference(const vpImage<unsigned char> &I1,
115  const vpImage<unsigned char> &I2,
116  vpImage<unsigned char> &Idiff) ;
117 
118  static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1,
119  const vpImage<unsigned char> &I2,
120  vpImage<unsigned char> &Idiff);
121 } ;
122 
131 template<class Type>
133  unsigned int i_sub, unsigned int j_sub,
134  unsigned int nrow_sub, unsigned int ncol_sub,
135  vpImage<Type> &S)
136 {
137  unsigned int i,j ;
138  unsigned int imax = i_sub + nrow_sub ;
139  unsigned int jmax = j_sub + ncol_sub ;
140 
141  if (imax > I.getHeight())
142  {
143  imax = I.getHeight() -1 ;
144  nrow_sub = imax-i_sub ;
145  }
146  if (jmax > I.getWidth())
147  {
148  jmax = I.getWidth() -1 ;
149  ncol_sub = jmax -j_sub ;
150  }
151 
152  S.resize(nrow_sub, ncol_sub) ;
153  for (i=i_sub ; i < imax ; i++)
154  for (j=j_sub ; j < jmax ; j++)
155  {
156  S[i-i_sub][j-j_sub] = I[i][j] ;
157  }
158 }
159 
170 template<class Type>
172  const vpRect &rect,
173  vpImage<Type> &S)
174 {
175  double dleft = rect.getLeft();
176  double dtop = rect.getTop();
177  double dright = ceil( rect.getRight() );
178  double dbottom = ceil( rect.getBottom() );
179 
180  if (dleft < 0.0) dleft = 0.0;
181  else if (dleft >= I.getWidth()) dleft = I.getWidth() - 1;
182 
183  if (dright < 0.0) dright = 0.0;
184  else if (dright >= I.getWidth()) dright = I.getWidth() - 1;
185 
186  if (dtop < 0.0) dtop = 0.0;
187  else if (dtop >= I.getHeight()) dtop = I.getHeight() - 1;
188 
189  if (dbottom < 0.0) dbottom = 0.0;
190  else if (dbottom >= I.getHeight()) dbottom = I.getHeight() - 1;
191 
192  // Convert the double-precision rectangle coordinates into integer positions
193  unsigned int left = (unsigned int) dleft;
194  unsigned int top = (unsigned int) dtop;
195  unsigned int bottom = (unsigned int) dbottom;
196  unsigned int right = (unsigned int) dright;
197 
198  unsigned int width = right - left + 1;;
199  unsigned int height = bottom - top + 1;
200 
201  S.resize(height, width) ;
202  for (unsigned int i=top ; i <= bottom ; i++) {
203  for (unsigned int j=left ; j <= right ; j++) {
204  S[i-top][j-left] = I[i][j] ;
205  }
206  }
207 }
208 
221 template<class Type>
223  Type threshold1, Type threshold2,
224  Type value1, Type value2, Type value3, const bool useLUT)
225 {
226  if(useLUT) {
227  std::cerr << "LUT not available for this type ! Will use the iteration method." << std::endl;
228  }
229 
230  Type v;
231  Type *p = I.bitmap;
232  Type *pend = I.bitmap + I.getWidth()*I.getHeight();
233  for (; p < pend; p ++) {
234  v = *p;
235  if (v < threshold1) *p = value1;
236  else if (v > threshold2) *p = value3;
237  else *p = value2;
238  }
239 }
240 
253 template<>
255  unsigned char threshold1, unsigned char threshold2,
256  unsigned char value1, unsigned char value2, unsigned char value3, const bool useLUT)
257 {
258  if(useLUT) {
259  //Construct the LUT
260  unsigned char lut[256];
261  for(unsigned int i = 0; i < 256; i++) {
262  lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
263  }
264 
265  I.performLut(lut);
266  } else {
267  unsigned char v;
268  unsigned char *p = I.bitmap;
269  unsigned char *pend = I.bitmap + I.getWidth()*I.getHeight();
270  for (; p < pend; p ++) {
271  v = *p;
272  if (v < threshold1) *p = value1;
273  else if (v > threshold2) *p = value3;
274  else *p = value2;
275  }
276  }
277 }
278 
279 #ifdef VISP_HAVE_PTHREAD
280 
281 #ifndef DOXYGEN_SHOULD_SKIP_THIS
282 template<class Type>
283 class vpUndistortInternalType
284 {
285 public:
286  Type *src;
287  Type *dst;
288  unsigned int width;
289  unsigned int height;
290  vpCameraParameters cam;
291  unsigned int nthreads;
292  unsigned int threadid;
293 public:
294  vpUndistortInternalType()
295  : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0)
296  {};
297 
298  vpUndistortInternalType(const vpUndistortInternalType<Type> &u) {
299  *this = u;
300  };
301  vpUndistortInternalType &operator=(const vpUndistortInternalType<Type> &u) {
302  src = u.src;
303  dst = u.dst;
304  width = u.width;
305  height = u.height;
306  cam = u.cam;
307  nthreads = u.nthreads;
308  threadid = u.threadid;
309  }
310 
311  static void *vpUndistort_threaded(void *arg);
312 };
313 
314 
315 template<class Type>
316 void *vpUndistortInternalType<Type>::vpUndistort_threaded(void *arg)
317 {
318  vpUndistortInternalType<Type> *undistortSharedData = (vpUndistortInternalType<Type>*)arg;
319  int offset = (int)undistortSharedData->threadid;
320  int width = (int)undistortSharedData->width;
321  int height = (int)undistortSharedData->height;
322  int nthreads = (int)undistortSharedData->nthreads;
323 
324  double u0 = undistortSharedData->cam.get_u0();
325  double v0 = undistortSharedData->cam.get_v0();
326  double px = undistortSharedData->cam.get_px();
327  double py = undistortSharedData->cam.get_py();
328  double kud = undistortSharedData->cam.get_kud();
329 
330  double invpx = 1.0/px;
331  double invpy = 1.0/py;
332 
333  double kud_px2 = kud * invpx * invpx;
334  double kud_py2 = kud * invpy * invpy;
335 
336  Type *dst = undistortSharedData->dst+(height/nthreads*offset)*width;
337  Type *src = undistortSharedData->src;
338 
339  for (double v = height/nthreads*offset;v < height/nthreads*(offset+1) ; v++) {
340  double deltav = v - v0;
341  //double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
342  double fr1 = 1.0 + kud_py2 * deltav * deltav;
343 
344  for (double u = 0 ; u < width ; u++) {
345  //computation of u,v : corresponding pixel coordinates in I.
346  double deltau = u - u0;
347  //double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
348  double fr2 = fr1 + kud_px2 * deltau * deltau;
349 
350  double u_double = deltau * fr2 + u0;
351  double v_double = deltav * fr2 + v0;
352 
353  //computation of the bilinear interpolation
354 
355  //declarations
356  int u_round = (int) (u_double);
357  int v_round = (int) (v_double);
358  if (u_round < 0.f) u_round = -1;
359  if (v_round < 0.f) v_round = -1;
360  double du_double = (u_double) - (double) u_round;
361  double dv_double = (v_double) - (double) v_round;
362  Type v01;
363  Type v23;
364  if ( (0 <= u_round) && (0 <= v_round) &&
365  (u_round < ((width) - 1)) && (v_round < ((height) - 1)) ) {
366  //process interpolation
367  const Type* _mp = &src[v_round*width+u_round];
368  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
369  _mp += width;
370  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
371  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
372  }
373  else {
374  *dst = 0;
375  }
376  dst++;
377  }
378  }
379 
380  pthread_exit((void*) 0);
381  return NULL;
382 }
383 #endif // DOXYGEN_SHOULD_SKIP_THIS
384 #endif // VISP_HAVE_PTHREAD
385 
405 template<class Type>
407  const vpCameraParameters &cam,
408  vpImage<Type> &undistI)
409 {
410 #ifdef VISP_HAVE_PTHREAD
411  //
412  // Optimized version using pthreads
413  //
414  unsigned int width = I.getWidth();
415  unsigned int height = I.getHeight();
416 
417  undistI.resize(height, width);
418 
419  double kud = cam.get_kud();
420 
421  //if (kud == 0) {
422  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
423  // There is no need to undistort the image
424  undistI = I;
425  return;
426  }
427 
428  unsigned int nthreads = 2;
429  pthread_attr_t attr;
430  pthread_t *callThd = new pthread_t [nthreads];
431  pthread_attr_init(&attr);
432  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
433 
434  vpUndistortInternalType<Type> *undistortSharedData;
435  undistortSharedData = new vpUndistortInternalType<Type> [nthreads];
436 
437  for(unsigned int i=0;i<nthreads;i++) {
438  // Each thread works on a different set of data.
439  // vpTRACE("create thread %d", i);
440  undistortSharedData[i].src = I.bitmap;
441  undistortSharedData[i].dst = undistI.bitmap;
442  undistortSharedData[i].width = I.getWidth();
443  undistortSharedData[i].height = I.getHeight();
444  undistortSharedData[i].cam = cam;
445  undistortSharedData[i].nthreads = nthreads;
446  undistortSharedData[i].threadid = i;
447  pthread_create( &callThd[i], &attr,
448  &vpUndistortInternalType<Type>::vpUndistort_threaded,
449  &undistortSharedData[i]);
450  }
451  pthread_attr_destroy(&attr);
452  /* Wait on the other threads */
453 
454  for(unsigned int i=0;i<nthreads;i++) {
455  // vpTRACE("join thread %d", i);
456  pthread_join( callThd[i], NULL);
457  }
458 
459  delete [] callThd;
460  delete [] undistortSharedData;
461 #else // VISP_HAVE_PTHREAD
462  //
463  // optimized version without pthreads
464  //
465  unsigned int width = I.getWidth();
466  unsigned int height = I.getHeight();
467 
468  undistI.resize(height, width);
469 
470  double u0 = cam.get_u0();
471  double v0 = cam.get_v0();
472  double px = cam.get_px();
473  double py = cam.get_py();
474  double kud = cam.get_kud();
475 
476  //if (kud == 0) {
477  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
478  // There is no need to undistort the image
479  undistI = I;
480  return;
481  }
482 
483  double invpx = 1.0/px;
484  double invpy = 1.0/py;
485 
486  double kud_px2 = kud * invpx * invpx;
487  double kud_py2 = kud * invpy * invpy;
488 
489  Type *dst = undistI.bitmap;
490  for (double v = 0;v < height ; v++) {
491  double deltav = v - v0;
492  //double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
493  double fr1 = 1.0 + kud_py2 * deltav * deltav;
494 
495  for (double u = 0 ; u < width ; u++) {
496  //computation of u,v : corresponding pixel coordinates in I.
497  double deltau = u - u0;
498  //double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
499  double fr2 = fr1 + kud_px2 * deltau * deltau;
500 
501  double u_double = deltau * fr2 + u0;
502  double v_double = deltav * fr2 + v0;
503 
504  //printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
505 
506  //computation of the bilinear interpolation
507 
508  //declarations
509  int u_round = (int) (u_double);
510  int v_round = (int) (v_double);
511  if (u_round < 0.f) u_round = -1;
512  if (v_round < 0.f) v_round = -1;
513  double du_double = (u_double) - (double) u_round;
514  double dv_double = (v_double) - (double) v_round;
515  Type v01;
516  Type v23;
517  if ( (0 <= u_round) && (0 <= v_round) &&
518  (u_round < (((int)width) - 1)) && (v_round < (((int)height) - 1)) ) {
519  //process interpolation
520  const Type* _mp = &I[(unsigned int)v_round][(unsigned int)u_round];
521  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
522  _mp += width;
523  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
524  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
525  //printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
526  }
527  else {
528  *dst = 0;
529  }
530  dst++;
531  }
532  }
533 #endif // VISP_HAVE_PTHREAD
534 
535 
536 
537 
538 #if 0
539  // non optimized version
540  int width = I.getWidth();
541  int height = I.getHeight();
542 
543  undistI.resize(height,width);
544 
545  double u0 = cam.get_u0();
546  double v0 = cam.get_v0();
547  double px = cam.get_px();
548  double py = cam.get_py();
549  double kd = cam.get_kud();
550 
551  if (kd == 0) {
552  // There is no need to undistort the image
553  undistI = I;
554  return;
555  }
556 
557  for(int v = 0 ; v < height; v++){
558  for(int u = 0; u < height; u++){
559  double r2 = vpMath::sqr(((double)u - u0)/px) +
560  vpMath::sqr(((double)v-v0)/py);
561  double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
562  double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
563  undistI[v][u] = I.getPixelBI((float)u_double,(float)v_double);
564  }
565  }
566 #endif
567 }
568 
576 template<class Type>
578  vpImage<Type> &newI)
579 {
580  unsigned int height = 0, width = 0;
581 
582  height = I.getHeight();
583  width = I.getWidth();
584  newI.resize(height, width);
585 
586  for (unsigned int i = 0; i < height; i++)
587  {
588  memcpy(newI.bitmap+i*width, I.bitmap+(height-1-i)*width,
589  width*sizeof(Type));
590  }
591 }
592 
593 
624 template<class Type>
626 {
627  unsigned int height = 0, width = 0;
628  unsigned int i = 0;
629  vpImage<Type> Ibuf;
630 
631  height = I.getHeight();
632  width = I.getWidth();
633  Ibuf.resize(1, width);
634 
635  for ( i = 0; i < height/2; i++)
636  {
637  memcpy(Ibuf.bitmap, I.bitmap+i*width,
638  width*sizeof(Type));
639 
640  memcpy(I.bitmap+i*width, I.bitmap+(height-1-i)*width,
641  width*sizeof(Type));
642  memcpy(I.bitmap+(height-1-i)*width, Ibuf.bitmap,
643  width*sizeof(Type));
644  }
645 }
646 
647 #endif
648 
649 
650 /*
651  * Local variables:
652  * c-basic-offset: 2
653  * End:
654  */
double getTop() const
Definition: vpRect.h:176
double get_u0() const
unsigned int getWidth() const
Definition: vpImage.h:161
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, const bool useLUT=false)
Definition: vpImageTools.h:222
Type * bitmap
points toward the bitmap
Definition: vpImage.h:116
double get_py() const
double getRight() const
Definition: vpRect.h:163
void performLut(const Type(&lut)[256])
Definition: vpImage.h:1544
double getBottom() const
Definition: vpRect.h:99
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)
set the size of the image without initializing it.
Definition: vpImage.h:616
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI)
Definition: vpImageTools.h:406
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
Definition: vpImageTools.h:577
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 createSubImage(const vpImage< Type > &I, unsigned int i_sub, unsigned int j_sub, unsigned int nrow_sub, unsigned int ncol_sub, vpImage< Type > &S)
Definition: vpImageTools.h:132
unsigned int getHeight() const
Definition: vpImage.h:152
Defines a rectangle in the plane.
Definition: vpRect.h:81
double getLeft() const
Definition: vpRect.h:157
Definition of the vpImage class member functions.
Definition: vpImage.h:111