ViSP  2.9.0
vpImageTools.h
1 /****************************************************************************
2  *
3  * $Id: vpImageTools.h 4604 2014-01-21 14:15:23Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Image tools.
36  *
37  * Authors:
38  * Fabien Spindler
39  *
40  *****************************************************************************/
41 
42 
43 #ifndef vpImageTools_H
44 #define vpImageTools_H
45 
54 #include <visp/vpImage.h>
55 
56 #ifdef VISP_HAVE_PTHREAD
57 # include <pthread.h>
58 #endif
59 
60 #include <visp/vpImageException.h>
61 #include <visp/vpMath.h>
62 #include <visp/vpRect.h>
63 #include <visp/vpCameraParameters.h>
64 
65 #include <fstream>
66 #include <iostream>
67 #include <math.h>
68 #include <string.h>
69 
79 class VISP_EXPORT vpImageTools
80 {
81 
82 public:
83  template<class Type>
84  static void createSubImage(const vpImage<Type> &I,
85  unsigned int i_sub, unsigned int j_sub,
86  unsigned int nrow_sub, unsigned int ncol_sub,
87  vpImage<Type> &S);
88 
89  template<class Type>
90  static void createSubImage(const vpImage<Type> &I,
91  const vpRect &rect,
92  vpImage<Type> &S);
93  template<class Type>
94  static void binarise(vpImage<Type> &I,
95  Type threshold1, Type threshold2,
96  Type value1, Type value2, Type value3);
97  static void changeLUT(vpImage<unsigned char>& I,
98  unsigned char A,
99  unsigned char newA,
100  unsigned char B,
101  unsigned char newB);
102  template<class Type>
103  static void undistort(const vpImage<Type> &I,
104  const vpCameraParameters &cam,
105  vpImage<Type> &newI);
106 
107  template<class Type>
108  static void flip(const vpImage<Type> &I,
109  vpImage<Type> &newI);
110 
111  template<class Type>
112  static void flip(vpImage<Type> &I);
113 
114 
115  static void imageDifference(const vpImage<unsigned char> &I1,
116  const vpImage<unsigned char> &I2,
117  vpImage<unsigned char> &Idiff) ;
118 
119  static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1,
120  const vpImage<unsigned char> &I2,
121  vpImage<unsigned char> &Idiff);
122 } ;
123 
132 template<class Type>
134  unsigned int i_sub, unsigned int j_sub,
135  unsigned int nrow_sub, unsigned int ncol_sub,
136  vpImage<Type> &S)
137 {
138  unsigned int i,j ;
139  unsigned int imax = i_sub + nrow_sub ;
140  unsigned int jmax = j_sub + ncol_sub ;
141 
142  if (imax > I.getHeight())
143  {
144  imax = I.getHeight() -1 ;
145  nrow_sub = imax-i_sub ;
146  }
147  if (jmax > I.getWidth())
148  {
149  jmax = I.getWidth() -1 ;
150  ncol_sub = jmax -j_sub ;
151  }
152 
153  S.resize(nrow_sub, ncol_sub) ;
154  for (i=i_sub ; i < imax ; i++)
155  for (j=j_sub ; j < jmax ; j++)
156  {
157  S[i-i_sub][j-j_sub] = I[i][j] ;
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 }
220 template<class Type>
222  Type threshold1, Type threshold2,
223  Type value1, Type value2, Type value3)
224 {
225  unsigned char v;
226  unsigned char *p = I.bitmap;
227  unsigned char *pend = I.bitmap + I.getWidth()*I.getHeight();
228  for (; p < pend; p ++) {
229  v = *p;
230  if (v < threshold1) *p = value1;
231  else if (v > threshold2) *p = value3;
232  else *p = value2;
233  }
234 
235 }
236 
237 #ifdef VISP_HAVE_PTHREAD
238 
239 #ifndef DOXYGEN_SHOULD_SKIP_THIS
240 template<class Type>
241 class vpUndistortInternalType
242 {
243 public:
244  Type *src;
245  Type *dst;
246  unsigned int width;
247  unsigned int height;
248  vpCameraParameters cam;
249  unsigned int nthreads;
250  unsigned int threadid;
251 public:
252  vpUndistortInternalType() {
253  src = dst = NULL;
254  width = height = 0;
255  nthreads = threadid = 0;
256  };
257  vpUndistortInternalType(const vpUndistortInternalType<Type> &u) {
258  src = u.src;
259  dst = u.dst;
260  width = u.width;
261  height = u.height;
262  cam = u.cam;
263  nthreads = u.nthreads;
264  threadid = u.threadid;
265  };
266 
267  static void *vpUndistort_threaded(void *arg);
268 };
269 
270 
271 template<class Type>
272 void *vpUndistortInternalType<Type>::vpUndistort_threaded(void *arg)
273 {
274  vpUndistortInternalType<Type> *undistortSharedData = (vpUndistortInternalType<Type>*)arg;
275  int offset = (int)undistortSharedData->threadid;
276  int width = (int)undistortSharedData->width;
277  int height = (int)undistortSharedData->height;
278  int nthreads = (int)undistortSharedData->nthreads;
279 
280  double u0 = undistortSharedData->cam.get_u0();
281  double v0 = undistortSharedData->cam.get_v0();
282  double px = undistortSharedData->cam.get_px();
283  double py = undistortSharedData->cam.get_py();
284  double kud = undistortSharedData->cam.get_kud();
285 
286  double invpx = 1.0/px;
287  double invpy = 1.0/py;
288 
289  double kud_px2 = kud * invpx * invpx;
290  double kud_py2 = kud * invpy * invpy;
291 
292  Type *dst = undistortSharedData->dst+(height/nthreads*offset)*width;
293  Type *src = undistortSharedData->src;
294 
295  for (double v = height/nthreads*offset;v < height/nthreads*(offset+1) ; v++) {
296  double deltav = v - v0;
297  //double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
298  double fr1 = 1.0 + kud_py2 * deltav * deltav;
299 
300  for (double u = 0 ; u < width ; u++) {
301  //computation of u,v : corresponding pixel coordinates in I.
302  double deltau = u - u0;
303  //double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
304  double fr2 = fr1 + kud_px2 * deltau * deltau;
305 
306  double u_double = deltau * fr2 + u0;
307  double v_double = deltav * fr2 + v0;
308 
309  //computation of the bilinear interpolation
310 
311  //declarations
312  int u_round = (int) (u_double);
313  int v_round = (int) (v_double);
314  if (u_round < 0.f) u_round = -1;
315  if (v_round < 0.f) v_round = -1;
316  double du_double = (u_double) - (double) u_round;
317  double dv_double = (v_double) - (double) v_round;
318  Type v01;
319  Type v23;
320  if ( (0 <= u_round) && (0 <= v_round) &&
321  (u_round < ((width) - 1)) && (v_round < ((height) - 1)) ) {
322  //process interpolation
323  const Type* _mp = &src[v_round*width+u_round];
324  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
325  _mp += width;
326  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
327  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
328  }
329  else {
330  *dst = 0;
331  }
332  dst++;
333  }
334  }
335 
336  pthread_exit((void*) 0);
337  return NULL;
338 }
339 #endif // DOXYGEN_SHOULD_SKIP_THIS
340 #endif // VISP_HAVE_PTHREAD
341 
361 template<class Type>
363  const vpCameraParameters &cam,
364  vpImage<Type> &undistI)
365 {
366 #ifdef VISP_HAVE_PTHREAD
367  //
368  // Optimized version using pthreads
369  //
370  unsigned int width = I.getWidth();
371  unsigned int height = I.getHeight();
372 
373  undistI.resize(height, width);
374 
375  double kud = cam.get_kud();
376 
377  //if (kud == 0) {
378  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
379  // There is no need to undistort the image
380  undistI = I;
381  return;
382  }
383 
384  unsigned int nthreads = 2;
385  pthread_attr_t attr;
386  pthread_t *callThd = new pthread_t [nthreads];
387  pthread_attr_init(&attr);
388  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
389 
390  vpUndistortInternalType<Type> *undistortSharedData;
391  undistortSharedData = new vpUndistortInternalType<Type> [nthreads];
392 
393  for(unsigned int i=0;i<nthreads;i++) {
394  // Each thread works on a different set of data.
395  // vpTRACE("create thread %d", i);
396  undistortSharedData[i].src = I.bitmap;
397  undistortSharedData[i].dst = undistI.bitmap;
398  undistortSharedData[i].width = I.getWidth();
399  undistortSharedData[i].height = I.getHeight();
400  undistortSharedData[i].cam = cam;
401  undistortSharedData[i].nthreads = nthreads;
402  undistortSharedData[i].threadid = i;
403  pthread_create( &callThd[i], &attr,
404  &vpUndistortInternalType<Type>::vpUndistort_threaded,
405  &undistortSharedData[i]);
406  }
407  pthread_attr_destroy(&attr);
408  /* Wait on the other threads */
409 
410  for(unsigned int i=0;i<nthreads;i++) {
411  // vpTRACE("join thread %d", i);
412  pthread_join( callThd[i], NULL);
413  }
414 
415  delete [] callThd;
416  delete [] undistortSharedData;
417 #else // VISP_HAVE_PTHREAD
418  //
419  // optimized version without pthreads
420  //
421  unsigned int width = I.getWidth();
422  unsigned int height = I.getHeight();
423 
424  undistI.resize(height, width);
425 
426  double u0 = cam.get_u0();
427  double v0 = cam.get_v0();
428  double px = cam.get_px();
429  double py = cam.get_py();
430  double kud = cam.get_kud();
431 
432  //if (kud == 0) {
433  if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
434  // There is no need to undistort the image
435  undistI = I;
436  return;
437  }
438 
439  double invpx = 1.0/px;
440  double invpy = 1.0/py;
441 
442  double kud_px2 = kud * invpx * invpx;
443  double kud_py2 = kud * invpy * invpy;
444 
445  Type *dst = undistI.bitmap;
446  for (double v = 0;v < height ; v++) {
447  double deltav = v - v0;
448  //double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
449  double fr1 = 1.0 + kud_py2 * deltav * deltav;
450 
451  for (double u = 0 ; u < width ; u++) {
452  //computation of u,v : corresponding pixel coordinates in I.
453  double deltau = u - u0;
454  //double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
455  double fr2 = fr1 + kud_px2 * deltau * deltau;
456 
457  double u_double = deltau * fr2 + u0;
458  double v_double = deltav * fr2 + v0;
459 
460  //printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
461 
462  //computation of the bilinear interpolation
463 
464  //declarations
465  int u_round = (int) (u_double);
466  int v_round = (int) (v_double);
467  if (u_round < 0.f) u_round = -1;
468  if (v_round < 0.f) v_round = -1;
469  double du_double = (u_double) - (double) u_round;
470  double dv_double = (v_double) - (double) v_round;
471  Type v01;
472  Type v23;
473  if ( (0 <= u_round) && (0 <= v_round) &&
474  (u_round < (((int)width) - 1)) && (v_round < (((int)height) - 1)) ) {
475  //process interpolation
476  const Type* _mp = &I[(unsigned int)v_round][(unsigned int)u_round];
477  v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
478  _mp += width;
479  v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
480  *dst = (Type)(v01 + ((v23 - v01) * dv_double));
481  //printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
482  }
483  else {
484  *dst = 0;
485  }
486  dst++;
487  }
488  }
489 #endif // VISP_HAVE_PTHREAD
490 
491 
492 
493 
494 #if 0
495  // non optimized version
496  int width = I.getWidth();
497  int height = I.getHeight();
498 
499  undistI.resize(height,width);
500 
501  double u0 = cam.get_u0();
502  double v0 = cam.get_v0();
503  double px = cam.get_px();
504  double py = cam.get_py();
505  double kd = cam.get_kud();
506 
507  if (kd == 0) {
508  // There is no need to undistort the image
509  undistI = I;
510  return;
511  }
512 
513  for(int v = 0 ; v < height; v++){
514  for(int u = 0; u < height; u++){
515  double r2 = vpMath::sqr(((double)u - u0)/px) +
516  vpMath::sqr(((double)v-v0)/py);
517  double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
518  double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
519  undistI[v][u] = I.getPixelBI((float)u_double,(float)v_double);
520  }
521  }
522 #endif
523 }
524 
532 template<class Type>
534  vpImage<Type> &newI)
535 {
536  unsigned int height = 0, width = 0;
537  int i = 0;
538 
539  height = I.getHeight();
540  width = I.getWidth();
541  newI.resize(height, width);
542 
543  for ( i = 0; i < height; i++)
544  {
545  memcpy(newI.bitmap+i*width, I.bitmap+(height-1-i)*width,
546  width*sizeof(Type));
547  }
548 }
549 
550 
581 template<class Type>
583 {
584  unsigned int height = 0, width = 0;
585  unsigned int i = 0;
586  vpImage<Type> Ibuf;
587 
588  height = I.getHeight();
589  width = I.getWidth();
590  Ibuf.resize(1, width);
591 
592  for ( i = 0; i < height/2; i++)
593  {
594  memcpy(Ibuf.bitmap, I.bitmap+i*width,
595  width*sizeof(Type));
596 
597  memcpy(I.bitmap+i*width, I.bitmap+(height-1-i)*width,
598  width*sizeof(Type));
599  memcpy(I.bitmap+(height-1-i)*width, Ibuf.bitmap,
600  width*sizeof(Type));
601  }
602 }
603 
604 #endif
605 
606 
607 /*
608  * Local variables:
609  * c-basic-offset: 2
610  * End:
611  */
double getTop() const
Definition: vpRect.h:174
double get_u0() const
unsigned int getWidth() const
Definition: vpImage.h:159
Type * bitmap
points toward the bitmap
Definition: vpImage.h:120
double get_py() const
double getRight() const
Definition: vpRect.h:167
double getBottom() const
Definition: vpRect.h:103
double get_v0() const
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3)
Definition: vpImageTools.h:221
static double sqr(double x)
Definition: vpMath.h:106
Generic class defining intrinsic camera parameters.
void resize(const unsigned int h, const unsigned int w)
set the size of the image
Definition: vpImage.h:532
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI)
Definition: vpImageTools.h:362
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
Definition: vpImageTools.h:533
double get_px() const
double get_kud() const
Various image tools; sub-image extraction, modification of the look up table, binarisation...
Definition: vpImageTools.h:79
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:133
unsigned int getHeight() const
Definition: vpImage.h:150
Defines a rectangle in the plane.
Definition: vpRect.h:85
double getLeft() const
Definition: vpRect.h:161
Definition of the vpImage class member functions.
Definition: vpImage.h:115