Visual Servoing Platform version 3.5.0
vpImageTools.h
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See http://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Image tools.
33 *
34 * Authors:
35 * Fabien Spindler
36 *
37 *****************************************************************************/
38
39#ifndef vpImageTools_H
40#define vpImageTools_H
41
49#include <visp3/core/vpImage.h>
50
51#ifdef VISP_HAVE_PTHREAD
52#include <pthread.h>
53#endif
54
55#include <visp3/core/vpCameraParameters.h>
56#include <visp3/core/vpImageException.h>
57#include <visp3/core/vpMath.h>
58#include <visp3/core/vpRect.h>
59#include <visp3/core/vpRectOriented.h>
60
61#include <fstream>
62#include <iostream>
63#include <math.h>
64#include <string.h>
65
66#if defined _OPENMP
67#include <omp.h>
68#endif
69
78class VISP_EXPORT vpImageTools
79{
80public:
85 INTERPOLATION_AREA
86 };
87
88 template <class Type>
89 static inline void binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
90 bool useLUT = true);
91 static void changeLUT(vpImage<unsigned char> &I, unsigned char A, unsigned char newA, unsigned char B,
92 unsigned char newB);
93
94 template <class Type>
95 static void crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
96 unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
97
98 static void columnMean(const vpImage<double> &I, vpRowVector &result);
99
100 template <class Type>
101 static void crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height, unsigned int roi_width,
102 vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
103 template <class Type>
104 static void crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale = 1,
105 unsigned int h_scale = 1);
106 template <class Type>
107 static void crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
108 vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
109
110 static void extract(const vpImage<unsigned char> &Src, vpImage<unsigned char> &Dst, const vpRectOriented &r);
111 static void extract(const vpImage<unsigned char> &Src, vpImage<double> &Dst, const vpRectOriented &r);
112
113 template <class Type> static void flip(const vpImage<Type> &I, vpImage<Type> &newI);
114
115 template <class Type> static void flip(vpImage<Type> &I);
116
117 static void imageDifference(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
119 static void imageDifference(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
120
121 static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
123 static void imageDifferenceAbsolute(const vpImage<double> &I1, const vpImage<double> &I2, vpImage<double> &Idiff);
124 static void imageDifferenceAbsolute(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
125
126 static void imageAdd(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2, vpImage<unsigned char> &Ires,
127 bool saturate = false);
128
129 static void imageSubtract(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
130 vpImage<unsigned char> &Ires, bool saturate = false);
131
132 static void initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height,
133 vpArray2D<int> &mapU, vpArray2D<int> &mapV,
134 vpArray2D<float> &mapDu, vpArray2D<float> &mapDv);
135
136 static double interpolate(const vpImage<unsigned char> &I, const vpImagePoint &point,
137 const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
138
139 static void integralImage(const vpImage<unsigned char> &I, vpImage<double> &II, vpImage<double> &IIsq);
140
141 static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2,
142 bool useOptimized = true);
143
144 static void normalize(vpImage<double> &I);
145
146 static void remap(const vpImage<unsigned char> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
147 const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<unsigned char> &Iundist);
148 static void remap(const vpImage<vpRGBa> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
149 const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<vpRGBa> &Iundist);
150
151 template <class Type>
152 static void resize(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int width, unsigned int height,
153 const vpImageInterpolationType &method = INTERPOLATION_NEAREST, unsigned int nThreads=0);
154
155 template <class Type>
156 static void resize(const vpImage<Type> &I, vpImage<Type> &Ires,
157 const vpImageInterpolationType &method = INTERPOLATION_NEAREST, unsigned int nThreads=0);
158
159 static void templateMatching(const vpImage<unsigned char> &I, const vpImage<unsigned char> &I_tpl,
160 vpImage<double> &I_score, unsigned int step_u, unsigned int step_v,
161 bool useOptimized = true);
162
163 template <class Type>
164 static void undistort(const vpImage<Type> &I, const vpCameraParameters &cam, vpImage<Type> &newI,
165 unsigned int nThreads=2);
166
167 template <class Type>
168 static void undistort(const vpImage<Type> &I, vpArray2D<int> mapU, vpArray2D<int> mapV, vpArray2D<float> mapDu,
169 vpArray2D<float> mapDv, vpImage<Type> &newI);
170
171 template <class Type>
172 static void warpImage(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst,
173 const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST,
174 bool fixedPointArithmetic=true, bool pixelCenter=false);
175
176#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
181 template <class Type>
182 vp_deprecated static void createSubImage(const vpImage<Type> &I, unsigned int i_sub, unsigned int j_sub,
183 unsigned int nrow_sub, unsigned int ncol_sub, vpImage<Type> &S);
184
185 template <class Type>
186 vp_deprecated static void createSubImage(const vpImage<Type> &I, const vpRect &rect, vpImage<Type> &S);
188#endif
189
190private:
191 // Cubic interpolation
192 static float cubicHermite(const float A, const float B, const float C, const float D, const float t);
193
194 template <class Type> static Type getPixelClamped(const vpImage<Type> &I, float u, float v);
195
196 static int coordCast(double x);
197
198 // Linear interpolation
199 static double lerp(double A, double B, double t);
200 static float lerp(float A, float B, float t);
201 static int64_t lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1);
202
203 static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, const vpImage<double> &II,
204 const vpImage<double> &IIsq, const vpImage<double> &II_tpl,
205 const vpImage<double> &IIsq_tpl, unsigned int i0, unsigned int j0);
206
207 template <class Type>
208 static void resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j,
209 float u, float v, float xFrac, float yFrac);
210
211 template <class Type>
212 static void resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j,
213 float u, float v, float xFrac, float yFrac);
214
215 template <class Type>
216 static void resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j,
217 float u, float v);
218
219 static void resizeSimdlib(const vpImage<vpRGBa>& Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
220 vpImage<vpRGBa>& Idst, int method);
221 static void resizeSimdlib(const vpImage<unsigned char>& Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
222 vpImage<unsigned char>& Idst, int method);
223
224 template <class Type>
225 static void warpNN(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine, bool centerCorner, bool fixedPoint);
226
227 template <class Type>
228 static void warpLinear(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine, bool centerCorner, bool fixedPoint);
229
230 static bool checkFixedPoint(unsigned int x, unsigned int y, const vpMatrix &T, bool affine);
231};
232
233#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
253template <class Type>
254void vpImageTools::createSubImage(const vpImage<Type> &I, unsigned int roi_top, unsigned int roi_left,
255 unsigned int roi_height, unsigned int roi_width, vpImage<Type> &crop)
256{
257 vpImageTools::crop(I, roi_top, roi_left, roi_height, roi_width, crop);
258}
259
275template <class Type> void vpImageTools::createSubImage(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop)
276{
277 vpImageTools::crop(I, roi, crop);
278}
279
280#endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
281
304template <class Type>
305void vpImageTools::crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
306 unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
307{
308 int i_min = (std::max)((int)(ceil(roi_top / v_scale)), 0);
309 int j_min = (std::max)((int)(ceil(roi_left / h_scale)), 0);
310 int i_max = (std::min)((int)(ceil((roi_top + roi_height)) / v_scale), (int)(I.getHeight() / v_scale));
311 int j_max = (std::min)((int)(ceil((roi_left + roi_width) / h_scale)), (int)(I.getWidth() / h_scale));
312
313 unsigned int i_min_u = (unsigned int)i_min;
314 unsigned int j_min_u = (unsigned int)j_min;
315
316 unsigned int r_width = (unsigned int)(j_max - j_min);
317 unsigned int r_height = (unsigned int)(i_max - i_min);
318
319 crop.resize(r_height, r_width);
320
321 if (v_scale == 1 && h_scale == 1) {
322 for (unsigned int i = 0; i < r_height; i++) {
323 void *src = (void *)(I[i + i_min_u] + j_min_u);
324 void *dst = (void *)crop[i];
325 memcpy(dst, src, r_width * sizeof(Type));
326 }
327 } else if (h_scale == 1) {
328 for (unsigned int i = 0; i < r_height; i++) {
329 void *src = (void *)(I[(i + i_min_u) * v_scale] + j_min_u);
330 void *dst = (void *)crop[i];
331 memcpy(dst, src, r_width * sizeof(Type));
332 }
333 } else {
334 for (unsigned int i = 0; i < r_height; i++) {
335 for (unsigned int j = 0; j < r_width; j++) {
336 crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
337 }
338 }
339 }
340}
341
359template <class Type>
360void vpImageTools::crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height,
361 unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
362{
363 vpImageTools::crop(I, topLeft.get_i(), topLeft.get_j(), roi_height, roi_width, crop, v_scale, h_scale);
364}
365
382template <class Type>
383void vpImageTools::crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale,
384 unsigned int h_scale)
385{
386 vpImageTools::crop(I, roi.getTop(), roi.getLeft(), (unsigned int)roi.getHeight(), (unsigned int)roi.getWidth(), crop,
387 v_scale, h_scale);
388}
389
407template <class Type>
408void vpImageTools::crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
409 vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
410{
411 int i_min = (std::max)((int)(ceil(roi.getTop() / v_scale)), 0);
412 int j_min = (std::max)((int)(ceil(roi.getLeft() / h_scale)), 0);
413 int i_max = (std::min)((int)(ceil((roi.getTop() + roi.getHeight()) / v_scale)), (int)(height / v_scale));
414 int j_max = (std::min)((int)(ceil((roi.getLeft() + roi.getWidth()) / h_scale)), (int)(width / h_scale));
415
416 unsigned int i_min_u = (unsigned int)i_min;
417 unsigned int j_min_u = (unsigned int)j_min;
418
419 unsigned int r_width = (unsigned int)(j_max - j_min);
420 unsigned int r_height = (unsigned int)(i_max - i_min);
421
422 crop.resize(r_height, r_width);
423
424 if (v_scale == 1 && h_scale == 1) {
425 for (unsigned int i = 0; i < r_height; i++) {
426 void *src = (void *)(bitmap + ((i + i_min_u) * width + j_min_u) * sizeof(Type));
427 void *dst = (void *)crop[i];
428 memcpy(dst, src, r_width * sizeof(Type));
429 }
430 } else if (h_scale == 1) {
431 for (unsigned int i = 0; i < r_height; i++) {
432 void *src = (void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) * sizeof(Type));
433 void *dst = (void *)crop[i];
434 memcpy(dst, src, r_width * sizeof(Type));
435 }
436 } else {
437 for (unsigned int i = 0; i < r_height; i++) {
438 unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
439 for (unsigned int j = 0; j < r_width; j++) {
440 void *src = (void *)(bitmap + (i_src + j * h_scale) * sizeof(Type));
441 void *dst = (void *)&crop[i][j];
442 memcpy(dst, src, sizeof(Type));
443 }
444 }
445 }
446}
447
458template <class Type>
459inline void vpImageTools::binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2,
460 Type value3, bool useLUT)
461{
462 if (useLUT) {
463 std::cerr << "LUT not available for this type ! Will use the iteration method." << std::endl;
464 }
465
466 Type v;
467 Type *p = I.bitmap;
468 Type *pend = I.bitmap + I.getWidth() * I.getHeight();
469 for (; p < pend; p++) {
470 v = *p;
471 if (v < threshold1)
472 *p = value1;
473 else if (v > threshold2)
474 *p = value3;
475 else
476 *p = value2;
477 }
478}
479
490template <>
491inline void vpImageTools::binarise(vpImage<unsigned char> &I, unsigned char threshold1, unsigned char threshold2,
492 unsigned char value1, unsigned char value2, unsigned char value3, bool useLUT)
493{
494 if (useLUT) {
495 // Construct the LUT
496 unsigned char lut[256];
497 for (unsigned int i = 0; i < 256; i++) {
498 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
499 }
500
501 I.performLut(lut);
502 } else {
503 unsigned char *p = I.bitmap;
504 unsigned char *pend = I.bitmap + I.getWidth() * I.getHeight();
505 for (; p < pend; p++) {
506 unsigned char v = *p;
507 if (v < threshold1)
508 *p = value1;
509 else if (v > threshold2)
510 *p = value3;
511 else
512 *p = value2;
513 }
514 }
515}
516
517#ifdef VISP_HAVE_PTHREAD
518
519#ifndef DOXYGEN_SHOULD_SKIP_THIS
520template <class Type> class vpUndistortInternalType
521{
522public:
523 Type *src;
524 Type *dst;
525 unsigned int width;
526 unsigned int height;
528 unsigned int nthreads;
529 unsigned int threadid;
530
531public:
532 vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0) {}
533
534 vpUndistortInternalType(const vpUndistortInternalType<Type> &u) { *this = u; }
535 vpUndistortInternalType &operator=(const vpUndistortInternalType<Type> &u)
536 {
537 src = u.src;
538 dst = u.dst;
539 width = u.width;
540 height = u.height;
541 cam = u.cam;
542 nthreads = u.nthreads;
543 threadid = u.threadid;
544
545 return *this;
546 }
547
548 static void *vpUndistort_threaded(void *arg);
549};
550
551template <class Type> void *vpUndistortInternalType<Type>::vpUndistort_threaded(void *arg)
552{
553 vpUndistortInternalType<Type> *undistortSharedData = static_cast<vpUndistortInternalType<Type> *>(arg);
554 int offset = (int)undistortSharedData->threadid;
555 int width = (int)undistortSharedData->width;
556 int height = (int)undistortSharedData->height;
557 int nthreads = (int)undistortSharedData->nthreads;
558
559 double u0 = undistortSharedData->cam.get_u0();
560 double v0 = undistortSharedData->cam.get_v0();
561 double px = undistortSharedData->cam.get_px();
562 double py = undistortSharedData->cam.get_py();
563 double kud = undistortSharedData->cam.get_kud();
564
565 double invpx = 1.0 / px;
566 double invpy = 1.0 / py;
567
568 double kud_px2 = kud * invpx * invpx;
569 double kud_py2 = kud * invpy * invpy;
570
571 Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
572 Type *src = undistortSharedData->src;
573
574 for (double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
575 double deltav = v - v0;
576 // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
577 double fr1 = 1.0 + kud_py2 * deltav * deltav;
578
579 for (double u = 0; u < width; u++) {
580 // computation of u,v : corresponding pixel coordinates in I.
581 double deltau = u - u0;
582 // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
583 double fr2 = fr1 + kud_px2 * deltau * deltau;
584
585 double u_double = deltau * fr2 + u0;
586 double v_double = deltav * fr2 + v0;
587
588 // computation of the bilinear interpolation
589
590 // declarations
591 int u_round = (int)(u_double);
592 int v_round = (int)(v_double);
593 if (u_round < 0.f)
594 u_round = -1;
595 if (v_round < 0.f)
596 v_round = -1;
597 double du_double = (u_double) - (double)u_round;
598 double dv_double = (v_double) - (double)v_round;
599 Type v01;
600 Type v23;
601 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
602 // process interpolation
603 const Type *_mp = &src[v_round * width + u_round];
604 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
605 _mp += width;
606 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
607 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
608 } else {
609 *dst = 0;
610 }
611 dst++;
612 }
613 }
614
615 pthread_exit((void *)0);
616 return NULL;
617}
618#endif // DOXYGEN_SHOULD_SKIP_THIS
619#endif // VISP_HAVE_PTHREAD
620
644template <class Type>
646 unsigned int nThreads)
647{
648#ifdef VISP_HAVE_PTHREAD
649 //
650 // Optimized version using pthreads
651 //
652 unsigned int width = I.getWidth();
653 unsigned int height = I.getHeight();
654
655 undistI.resize(height, width);
656
657 double kud = cam.get_kud();
658
659 // if (kud == 0) {
660 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
661 // There is no need to undistort the image
662 undistI = I;
663 return;
664 }
665
666 unsigned int nthreads = nThreads;
667 pthread_attr_t attr;
668 pthread_t *callThd = new pthread_t[nthreads];
669 pthread_attr_init(&attr);
670 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
671
672 vpUndistortInternalType<Type> *undistortSharedData;
673 undistortSharedData = new vpUndistortInternalType<Type>[nthreads];
674
675 for (unsigned int i = 0; i < nthreads; i++) {
676 // Each thread works on a different set of data.
677 // vpTRACE("create thread %d", i);
678 undistortSharedData[i].src = I.bitmap;
679 undistortSharedData[i].dst = undistI.bitmap;
680 undistortSharedData[i].width = I.getWidth();
681 undistortSharedData[i].height = I.getHeight();
682 undistortSharedData[i].cam = cam;
683 undistortSharedData[i].nthreads = nthreads;
684 undistortSharedData[i].threadid = i;
685 pthread_create(&callThd[i], &attr, &vpUndistortInternalType<Type>::vpUndistort_threaded, &undistortSharedData[i]);
686 }
687 pthread_attr_destroy(&attr);
688 /* Wait on the other threads */
689
690 for (unsigned int i = 0; i < nthreads; i++) {
691 // vpTRACE("join thread %d", i);
692 pthread_join(callThd[i], NULL);
693 }
694
695 delete[] callThd;
696 delete[] undistortSharedData;
697#else // VISP_HAVE_PTHREAD
698 (void)nThreads;
699 //
700 // optimized version without pthreads
701 //
702 unsigned int width = I.getWidth();
703 unsigned int height = I.getHeight();
704
705 undistI.resize(height, width);
706
707 double u0 = cam.get_u0();
708 double v0 = cam.get_v0();
709 double px = cam.get_px();
710 double py = cam.get_py();
711 double kud = cam.get_kud();
712
713 // if (kud == 0) {
714 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
715 // There is no need to undistort the image
716 undistI = I;
717 return;
718 }
719
720 double invpx = 1.0 / px;
721 double invpy = 1.0 / py;
722
723 double kud_px2 = kud * invpx * invpx;
724 double kud_py2 = kud * invpy * invpy;
725
726 Type *dst = undistI.bitmap;
727 for (double v = 0; v < height; v++) {
728 double deltav = v - v0;
729 // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
730 double fr1 = 1.0 + kud_py2 * deltav * deltav;
731
732 for (double u = 0; u < width; u++) {
733 // computation of u,v : corresponding pixel coordinates in I.
734 double deltau = u - u0;
735 // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
736 double fr2 = fr1 + kud_px2 * deltau * deltau;
737
738 double u_double = deltau * fr2 + u0;
739 double v_double = deltav * fr2 + v0;
740
741 // printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
742
743 // computation of the bilinear interpolation
744
745 // declarations
746 int u_round = (int)(u_double);
747 int v_round = (int)(v_double);
748 if (u_round < 0.f)
749 u_round = -1;
750 if (v_round < 0.f)
751 v_round = -1;
752 double du_double = (u_double) - (double)u_round;
753 double dv_double = (v_double) - (double)v_round;
754 Type v01;
755 Type v23;
756 if ((0 <= u_round) && (0 <= v_round) && (u_round < (((int)width) - 1)) && (v_round < (((int)height) - 1))) {
757 // process interpolation
758 const Type *_mp = &I[(unsigned int)v_round][(unsigned int)u_round];
759 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
760 _mp += width;
761 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
762 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
763 // printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
764 } else {
765 *dst = 0;
766 }
767 dst++;
768 }
769 }
770#endif // VISP_HAVE_PTHREAD
771
772#if 0
773 // non optimized version
774 int width = I.getWidth();
775 int height = I.getHeight();
776
777 undistI.resize(height,width);
778
779 double u0 = cam.get_u0();
780 double v0 = cam.get_v0();
781 double px = cam.get_px();
782 double py = cam.get_py();
783 double kd = cam.get_kud();
784
785 if (kd == 0) {
786 // There is no need to undistort the image
787 undistI = I;
788 return;
789 }
790
791 for(int v = 0 ; v < height; v++){
792 for(int u = 0; u < height; u++){
793 double r2 = vpMath::sqr(((double)u - u0)/px) +
794 vpMath::sqr(((double)v-v0)/py);
795 double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
796 double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
797 undistI[v][u] = I.getPixelBI((float)u_double,(float)v_double);
798 }
799 }
800#endif
801}
802
817template <class Type>
819 vpArray2D<float> mapDv, vpImage<Type> &newI)
820{
821 remap(I, mapU, mapV, mapDu, mapDv, newI);
822}
823
830template <class Type> void vpImageTools::flip(const vpImage<Type> &I, vpImage<Type> &newI)
831{
832 unsigned int height = I.getHeight(), width = I.getWidth();
833 newI.resize(height, width);
834
835 for (unsigned int i = 0; i < height; i++) {
836 memcpy(newI.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
837 }
838}
839
871template <class Type> void vpImageTools::flip(vpImage<Type> &I)
872{
873 unsigned int height = I.getHeight(), width = I.getWidth();
874 vpImage<Type> Ibuf;
875 Ibuf.resize(1, width);
876
877 for (unsigned int i = 0; i < height / 2; i++) {
878 memcpy(Ibuf.bitmap, I.bitmap + i * width, width * sizeof(Type));
879
880 memcpy(I.bitmap + i * width, I.bitmap + (height - 1 - i) * width, width * sizeof(Type));
881 memcpy(I.bitmap + (height - 1 - i) * width, Ibuf.bitmap, width * sizeof(Type));
882 }
883}
884
885template <class Type> Type vpImageTools::getPixelClamped(const vpImage<Type> &I, float u, float v)
886{
887 int x = vpMath::round(u);
888 int y = vpMath::round(v);
889 x = (std::max)(0, (std::min)(x, static_cast<int>(I.getWidth())-1));
890 y = (std::max)(0, (std::min)(y, static_cast<int>(I.getHeight())-1));
891
892 return I[y][x];
893}
894
895// Reference:
896// http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
897template <class Type>
898void vpImageTools::resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i,
899 unsigned int j, float u, float v, float xFrac, float yFrac)
900{
901 // 1st row
902 Type p00 = getPixelClamped(I, u - 1, v - 1);
903 Type p01 = getPixelClamped(I, u + 0, v - 1);
904 Type p02 = getPixelClamped(I, u + 1, v - 1);
905 Type p03 = getPixelClamped(I, u + 2, v - 1);
906
907 // 2nd row
908 Type p10 = getPixelClamped(I, u - 1, v + 0);
909 Type p11 = getPixelClamped(I, u + 0, v + 0);
910 Type p12 = getPixelClamped(I, u + 1, v + 0);
911 Type p13 = getPixelClamped(I, u + 2, v + 0);
912
913 // 3rd row
914 Type p20 = getPixelClamped(I, u - 1, v + 1);
915 Type p21 = getPixelClamped(I, u + 0, v + 1);
916 Type p22 = getPixelClamped(I, u + 1, v + 1);
917 Type p23 = getPixelClamped(I, u + 2, v + 1);
918
919 // 4th row
920 Type p30 = getPixelClamped(I, u - 1, v + 2);
921 Type p31 = getPixelClamped(I, u + 0, v + 2);
922 Type p32 = getPixelClamped(I, u + 1, v + 2);
923 Type p33 = getPixelClamped(I, u + 2, v + 2);
924
925 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
926 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
927 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
928 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
929 float value = cubicHermite(col0, col1, col2, col3, yFrac);
930 Ires[i][j] = vpMath::saturate<Type>(value);
931}
932
933template <>
934inline void vpImageTools::resizeBicubic(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, unsigned int i,
935 unsigned int j, float u, float v, float xFrac, float yFrac)
936{
937 // 1st row
938 vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
939 vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
940 vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
941 vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
942
943 // 2nd row
944 vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
945 vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
946 vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
947 vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
948
949 // 3rd row
950 vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
951 vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
952 vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
953 vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
954
955 // 4th row
956 vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
957 vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
958 vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
959 vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
960
961 for (int c = 0; c < 3; c++) {
962 float col0 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p00)[c]),
963 static_cast<float>(reinterpret_cast<unsigned char *>(&p01)[c]),
964 static_cast<float>(reinterpret_cast<unsigned char *>(&p02)[c]),
965 static_cast<float>(reinterpret_cast<unsigned char *>(&p03)[c]), xFrac);
966 float col1 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p10)[c]),
967 static_cast<float>(reinterpret_cast<unsigned char *>(&p11)[c]),
968 static_cast<float>(reinterpret_cast<unsigned char *>(&p12)[c]),
969 static_cast<float>(reinterpret_cast<unsigned char *>(&p13)[c]), xFrac);
970 float col2 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p20)[c]),
971 static_cast<float>(reinterpret_cast<unsigned char *>(&p21)[c]),
972 static_cast<float>(reinterpret_cast<unsigned char *>(&p22)[c]),
973 static_cast<float>(reinterpret_cast<unsigned char *>(&p23)[c]), xFrac);
974 float col3 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p30)[c]),
975 static_cast<float>(reinterpret_cast<unsigned char *>(&p31)[c]),
976 static_cast<float>(reinterpret_cast<unsigned char *>(&p32)[c]),
977 static_cast<float>(reinterpret_cast<unsigned char *>(&p33)[c]), xFrac);
978 float value = cubicHermite(col0, col1, col2, col3, yFrac);
979
980 reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
981 }
982}
983
984template <class Type>
985void vpImageTools::resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i,
986 unsigned int j, float u, float v, float xFrac, float yFrac)
987{
988 int u0 = static_cast<int>(u);
989 int v0 = static_cast<int>(v);
990
991 int u1 = (std::min)(static_cast<int>(I.getWidth()) - 1, u0 + 1);
992 int v1 = v0;
993
994 int u2 = u0;
995 int v2 = (std::min)(static_cast<int>(I.getHeight()) - 1, v0 + 1);
996
997 int u3 = u1;
998 int v3 = v2;
999
1000 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
1001 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
1002 float value = lerp(col0, col1, yFrac);
1003
1004 Ires[i][j] = vpMath::saturate<Type>(value);
1005}
1006
1007template <>
1008inline void vpImageTools::resizeBilinear(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, unsigned int i,
1009 unsigned int j, float u, float v, float xFrac, float yFrac)
1010{
1011 int u0 = static_cast<int>(u);
1012 int v0 = static_cast<int>(v);
1013
1014 int u1 = (std::min)(static_cast<int>(I.getWidth()) - 1, u0 + 1);
1015 int v1 = v0;
1016
1017 int u2 = u0;
1018 int v2 = (std::min)(static_cast<int>(I.getHeight()) - 1, v0 + 1);
1019
1020 int u3 = u1;
1021 int v3 = v2;
1022
1023 for (int c = 0; c < 3; c++) {
1024 float col0 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v0][u0])[c]),
1025 static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v1][u1])[c]), xFrac);
1026 float col1 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v2][u2])[c]),
1027 static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v3][u3])[c]), xFrac);
1028 float value = lerp(col0, col1, yFrac);
1029
1030 reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1031 }
1032}
1033
1034template <class Type>
1035void vpImageTools::resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i,
1036 unsigned int j, float u, float v)
1037{
1038 Ires[i][j] = getPixelClamped(I, u, v);
1039}
1040
1059template <class Type>
1060void vpImageTools::resize(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int width,
1061 unsigned int height, const vpImageInterpolationType &method,
1062 unsigned int nThreads)
1063{
1064 Ires.resize(height, width);
1065
1066 vpImageTools::resize(I, Ires, method, nThreads);
1067}
1068
1086template <class Type>
1088 unsigned int
1089 #if defined _OPENMP
1090 nThreads
1091 #endif
1092 )
1093{
1094 if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1095 std::cerr << "Input or output image is too small!" << std::endl;
1096 return;
1097 }
1098
1099 if (method == INTERPOLATION_AREA) {
1100 std::cerr << "INTERPOLATION_AREA is not implemented for this type." << std::endl;
1101 return;
1102 }
1103
1104 const float scaleY = I.getHeight() / static_cast<float>(Ires.getHeight());
1105 const float scaleX = I.getWidth() / static_cast<float>(Ires.getWidth());
1106 const float half = 0.5f;
1107
1108#if defined _OPENMP
1109 if (nThreads > 0) {
1110 omp_set_num_threads(static_cast<int>(nThreads));
1111 }
1112 #pragma omp parallel for schedule(dynamic)
1113#endif
1114 for (int i = 0; i < static_cast<int>(Ires.getHeight()); i++) {
1115 const float v = (i + half) * scaleY - half;
1116 const int v0 = static_cast<int>(v);
1117 const float yFrac = v - v0;
1118
1119 for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1120 const float u = (j + half) * scaleX - half;
1121 const int u0 = static_cast<int>(u);
1122 const float xFrac = u - u0;
1123
1124 if (method == INTERPOLATION_NEAREST) {
1125 resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1126 } else if (method == INTERPOLATION_LINEAR) {
1127 resizeBilinear(I, Ires, static_cast<unsigned int>(i), j, u0, v0, xFrac, yFrac);
1128 } else if (method == INTERPOLATION_CUBIC) {
1129 resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1130 }
1131 }
1132 }
1133}
1134
1135template <> inline
1137 const vpImageInterpolationType &method, unsigned int
1138 #if defined _OPENMP
1139 nThreads
1140 #endif
1141 )
1142{
1143 if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1144 std::cerr << "Input or output image is too small!" << std::endl;
1145 return;
1146 }
1147
1148 if (method == INTERPOLATION_AREA) {
1149 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_AREA);
1150 } else if (method == INTERPOLATION_LINEAR) {
1151 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_LINEAR);
1152 } else {
1153 const float scaleY = I.getHeight() / static_cast<float>(Ires.getHeight());
1154 const float scaleX = I.getWidth() / static_cast<float>(Ires.getWidth());
1155 const float half = 0.5f;
1156
1157#if defined _OPENMP
1158 if (nThreads > 0) {
1159 omp_set_num_threads(static_cast<int>(nThreads));
1160 }
1161#pragma omp parallel for schedule(dynamic)
1162#endif
1163 for (int i = 0; i < static_cast<int>(Ires.getHeight()); i++) {
1164 float v = (i + half) * scaleY - half;
1165 float yFrac = v - static_cast<int>(v);
1166
1167 for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1168 float u = (j + half) * scaleX - half;
1169 float xFrac = u - static_cast<int>(u);
1170
1171 if (method == INTERPOLATION_NEAREST) {
1172 resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1173 } else if (method == INTERPOLATION_CUBIC) {
1174 resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1175 }
1176 }
1177 }
1178 }
1179}
1180
1181template <> inline
1183 const vpImageInterpolationType &method, unsigned int
1184 #if defined _OPENMP
1185 nThreads
1186 #endif
1187 )
1188{
1189 if (I.getWidth() < 2 || I.getHeight() < 2 || Ires.getWidth() < 2 || Ires.getHeight() < 2) {
1190 std::cerr << "Input or output image is too small!" << std::endl;
1191 return;
1192 }
1193
1194 if (method == INTERPOLATION_AREA) {
1195 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_AREA);
1196 } else if (method == INTERPOLATION_LINEAR) {
1197 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_LINEAR);
1198 } else {
1199 const float scaleY = I.getHeight() / static_cast<float>(Ires.getHeight());
1200 const float scaleX = I.getWidth() / static_cast<float>(Ires.getWidth());
1201 const float half = 0.5f;
1202
1203 #if defined _OPENMP
1204 if (nThreads > 0) {
1205 omp_set_num_threads(static_cast<int>(nThreads));
1206 }
1207 #pragma omp parallel for schedule(dynamic)
1208 #endif
1209 for (int i = 0; i < static_cast<int>(Ires.getHeight()); i++) {
1210 float v = (i + half) * scaleY - half;
1211 float yFrac = v - static_cast<int>(v);
1212
1213 for (unsigned int j = 0; j < Ires.getWidth(); j++) {
1214 float u = (j + half) * scaleX - half;
1215 float xFrac = u - static_cast<int>(u);
1216
1217 if (method == INTERPOLATION_NEAREST) {
1218 resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1219 } else if (method == INTERPOLATION_CUBIC) {
1220 resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1221 }
1222 }
1223 }
1224 }
1225}
1226
1241template <class Type>
1243 const vpImageInterpolationType &interpolation,
1244 bool fixedPointArithmetic, bool pixelCenter)
1245{
1246 if ((T.getRows() != 2 && T.getRows() != 3) || T.getCols() != 3) {
1247 std::cerr << "Input transformation must be a (2x3) or (3x3) matrix." << std::endl;
1248 return;
1249 }
1250
1251 if (src.getSize() == 0) {
1252 return;
1253 }
1254
1255 const bool affine = (T.getRows() == 2);
1256 const bool interp_NN = (interpolation == INTERPOLATION_NEAREST) || (interpolation == INTERPOLATION_CUBIC);
1257
1258 if (dst.getSize() == 0) {
1259 dst.resize(src.getHeight(), src.getWidth(), Type(0));
1260 }
1261
1262 vpMatrix M = T;
1263 if (affine) {
1264 double D = M[0][0] * M[1][1] - M[0][1] * M[1][0];
1265 D = !vpMath::nul(D, std::numeric_limits<double>::epsilon()) ? 1.0 / D : 0;
1266 double A11 = M[1][1] * D, A22 = M[0][0] * D;
1267 M[0][0] = A11; M[0][1] *= -D;
1268 M[1][0] *= -D; M[1][1] = A22;
1269 double b1 = -M[0][0] * M[0][2] - M[0][1] * M[1][2];
1270 double b2 = -M[1][0] * M[0][2] - M[1][1] * M[1][2];
1271 M[0][2] = b1; M[1][2] = b2;
1272 } else {
1273 M = T.inverseByLU();
1274 }
1275
1276 if (fixedPointArithmetic && !pixelCenter) {
1277 fixedPointArithmetic = checkFixedPoint(0, 0, M, affine) &&
1278 checkFixedPoint(dst.getWidth()-1, 0, M, affine) &&
1279 checkFixedPoint(0, dst.getHeight()-1, M, affine) &&
1280 checkFixedPoint(dst.getWidth() - 1, dst.getHeight() - 1, M, affine);
1281 }
1282
1283 if (interp_NN) {
1284 //nearest neighbor interpolation
1285 warpNN(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1286 } else {
1287 //bilinear interpolation
1288 warpLinear(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1289 }
1290}
1291
1292template <class Type>
1293void vpImageTools::warpNN(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine,
1294 bool centerCorner, bool fixedPoint)
1295{
1296 if (fixedPoint && !centerCorner) {
1297 const int nbits = 16;
1298 const int32_t precision = 1 << nbits;
1299 const float precision_1 = 1 / static_cast<float>(precision);
1300
1301 int32_t a0_i32 = static_cast<int32_t>(T[0][0] * precision);
1302 int32_t a1_i32 = static_cast<int32_t>(T[0][1] * precision);
1303 int32_t a2_i32 = static_cast<int32_t>(T[0][2] * precision);
1304 int32_t a3_i32 = static_cast<int32_t>(T[1][0] * precision);
1305 int32_t a4_i32 = static_cast<int32_t>(T[1][1] * precision);
1306 int32_t a5_i32 = static_cast<int32_t>(T[1][2] * precision);
1307 int32_t a6_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[2][0] * precision) : 0;
1308 int32_t a7_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[2][1] * precision) : 0;
1309 int32_t a8_i32 = T.getRows() == 3 ? static_cast<int32_t>(T[2][2] * precision) : 1;
1310
1311 int32_t height_1_i32 = static_cast<int32_t>((src.getHeight() - 1) * precision) + 0x8000;
1312 int32_t width_1_i32 = static_cast<int32_t>((src.getWidth() - 1) * precision) + 0x8000;
1313
1314 if (affine) {
1315 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1316 int32_t xi = a2_i32;
1317 int32_t yi = a5_i32;
1318
1319 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1320 if (yi >= 0 && yi < height_1_i32 && xi >= 0 && xi < width_1_i32) {
1321 float x_ = (xi >> nbits) + (xi & 0xFFFF) * precision_1;
1322 float y_ = (yi >> nbits) + (yi & 0xFFFF) * precision_1;
1323
1324 int x = vpMath::round(x_);
1325 int y = vpMath::round(y_);
1326 dst[i][j] = src[y][x];
1327 }
1328
1329 xi += a0_i32;
1330 yi += a3_i32;
1331 }
1332
1333 a2_i32 += a1_i32;
1334 a5_i32 += a4_i32;
1335 }
1336 } else {
1337 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1338 int64_t xi = a2_i32;
1339 int64_t yi = a5_i32;
1340 int64_t wi = a8_i32;
1341
1342 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1343 if (wi != 0 && yi >= 0 && yi <= (static_cast<int>(src.getHeight()) - 1)*wi &&
1344 xi >= 0 && xi <= (static_cast<int>(src.getWidth()) - 1)*wi) {
1345 float w_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1346 float x_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / w_;
1347 float y_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / w_;
1348
1349 int x = vpMath::round(x_);
1350 int y = vpMath::round(y_);
1351
1352 dst[i][j] = src[y][x];
1353 }
1354
1355 xi += a0_i32;
1356 yi += a3_i32;
1357 wi += a6_i32;
1358 }
1359
1360 a2_i32 += a1_i32;
1361 a5_i32 += a4_i32;
1362 a8_i32 += a7_i32;
1363 }
1364 }
1365 } else {
1366 double a0 = T[0][0]; double a1 = T[0][1]; double a2 = T[0][2];
1367 double a3 = T[1][0]; double a4 = T[1][1]; double a5 = T[1][2];
1368 double a6 = affine ? 0.0 : T[2][0];
1369 double a7 = affine ? 0.0 : T[2][1];
1370 double a8 = affine ? 1.0 : T[2][2];
1371
1372 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1373 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1374 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1375 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1376 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1377
1378 if (vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1379 w = 1.0;
1380 }
1381
1382 int x_ = centerCorner ? coordCast(x / w) : vpMath::round(x / w);
1383 int y_ = centerCorner ? coordCast(y / w) : vpMath::round(y / w);
1384
1385 if (x_ >= 0 && x_ < static_cast<int>(src.getWidth()) &&
1386 y_ >= 0 && y_ < static_cast<int>(src.getHeight())) {
1387 dst[i][j] = src[y_][x_];
1388 }
1389 }
1390 }
1391 }
1392}
1393
1394template <class Type>
1395void vpImageTools::warpLinear(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine,
1396 bool centerCorner, bool fixedPoint)
1397{
1398 if (fixedPoint && !centerCorner) {
1399 const int nbits = 16;
1400 const int64_t precision = 1 << nbits;
1401 const float precision_1 = 1 / static_cast<float>(precision);
1402 const int64_t precision2 = 1ULL << (2 * nbits);
1403 const float precision_2 = 1 / static_cast<float>(precision2);
1404
1405 int64_t a0_i64 = static_cast<int64_t>(T[0][0] * precision);
1406 int64_t a1_i64 = static_cast<int64_t>(T[0][1] * precision);
1407 int64_t a2_i64 = static_cast<int64_t>(T[0][2] * precision);
1408 int64_t a3_i64 = static_cast<int64_t>(T[1][0] * precision);
1409 int64_t a4_i64 = static_cast<int64_t>(T[1][1] * precision);
1410 int64_t a5_i64 = static_cast<int64_t>(T[1][2] * precision);
1411 int64_t a6_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][0] * precision) : 0;
1412 int64_t a7_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][1] * precision) : 0;
1413 int64_t a8_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][2] * precision) : 1;
1414
1415 int64_t height_i64 = static_cast<int64_t>(src.getHeight() * precision);
1416 int64_t width_i64 = static_cast<int64_t>(src.getWidth() * precision);
1417
1418 if (affine) {
1419 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1420 int64_t xi_ = a2_i64;
1421 int64_t yi_ = a5_i64;
1422
1423 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1424 if (yi_ >= 0 && yi_ < height_i64 && xi_ >= 0 && xi_ < width_i64) {
1425 const int64_t xi_lower = xi_ & (~0xFFFF);
1426 const int64_t yi_lower = yi_ & (~0xFFFF);
1427
1428 const int64_t t = yi_ - yi_lower;
1429 const int64_t t_1 = precision - t;
1430 const int64_t s = xi_ - xi_lower;
1431 const int64_t s_1 = precision - s;
1432
1433 const int x_ = static_cast<int>(xi_ >> nbits);
1434 const int y_ = static_cast<int>(yi_ >> nbits);
1435
1436 if (y_ < static_cast<int>(src.getHeight())-1 && x_ < static_cast<int>(src.getWidth())-1) {
1437 const Type val00 = src[y_][x_];
1438 const Type val01 = src[y_][x_+1];
1439 const Type val10 = src[y_+1][x_];
1440 const Type val11 = src[y_+1][x_+1];
1441 const int64_t interp_i64 = static_cast<int64_t>(s_1*t_1*val00 + s*t_1*val01 + s_1*t*val10 + s*t*val11);
1442 const float interp = (interp_i64 >> (nbits*2)) + (interp_i64 & 0xFFFFFFFF) * precision_2;
1443 dst[i][j] = vpMath::saturate<Type>(interp);
1444 } else if (y_ < static_cast<int>(src.getHeight())-1) {
1445 const Type val00 = src[y_][x_];
1446 const Type val10 = src[y_+1][x_];
1447 const int64_t interp_i64 = static_cast<int64_t>(t_1*val00 + t*val10);
1448 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1449 dst[i][j] = vpMath::saturate<Type>(interp);
1450 } else if (x_ < static_cast<int>(src.getWidth())-1) {
1451 const Type val00 = src[y_][x_];
1452 const Type val01 = src[y_][x_+1];
1453 const int64_t interp_i64 = static_cast<int64_t>(s_1*val00 + s*val01);
1454 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1455 dst[i][j] = vpMath::saturate<Type>(interp);
1456 } else {
1457 dst[i][j] = src[y_][x_];
1458 }
1459 }
1460
1461 xi_ += a0_i64;
1462 yi_ += a3_i64;
1463 }
1464
1465 a2_i64 += a1_i64;
1466 a5_i64 += a4_i64;
1467 }
1468 } else {
1469 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1470 int64_t xi = a2_i64;
1471 int64_t yi = a5_i64;
1472 int64_t wi = a8_i64;
1473
1474 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1475 if (wi != 0 && yi >= 0 && yi <= (static_cast<int>(src.getHeight()) - 1)*wi &&
1476 xi >= 0 && xi <= (static_cast<int>(src.getWidth()) - 1)*wi) {
1477 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1478 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1479 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1480
1481 const int x_ = static_cast<int>(xi_);
1482 const int y_ = static_cast<int>(yi_);
1483
1484 const float t = yi_ - y_;
1485 const float s = xi_ - x_;
1486
1487 if (y_ < static_cast<int>(src.getHeight()) - 1 && x_ < static_cast<int>(src.getWidth()) - 1) {
1488 const Type val00 = src[y_][x_];
1489 const Type val01 = src[y_][x_ + 1];
1490 const Type val10 = src[y_ + 1][x_];
1491 const Type val11 = src[y_ + 1][x_ + 1];
1492 const float col0 = lerp(val00, val01, s);
1493 const float col1 = lerp(val10, val11, s);
1494 const float interp = lerp(col0, col1, t);
1495 dst[i][j] = vpMath::saturate<Type>(interp);
1496 } else if (y_ < static_cast<int>(src.getHeight()) - 1) {
1497 const Type val00 = src[y_][x_];
1498 const Type val10 = src[y_ + 1][x_];
1499 const float interp = lerp(val00, val10, t);
1500 dst[i][j] = vpMath::saturate<Type>(interp);
1501 } else if (x_ < static_cast<int>(src.getWidth()) - 1) {
1502 const Type val00 = src[y_][x_];
1503 const Type val01 = src[y_][x_ + 1];
1504 const float interp = lerp(val00, val01, s);
1505 dst[i][j] = vpMath::saturate<Type>(interp);
1506 } else {
1507 dst[i][j] = src[y_][x_];
1508 }
1509 }
1510
1511 xi += a0_i64;
1512 yi += a3_i64;
1513 wi += a6_i64;
1514 }
1515
1516 a2_i64 += a1_i64;
1517 a5_i64 += a4_i64;
1518 a8_i64 += a7_i64;
1519 }
1520 }
1521 } else {
1522 double a0 = T[0][0]; double a1 = T[0][1]; double a2 = T[0][2];
1523 double a3 = T[1][0]; double a4 = T[1][1]; double a5 = T[1][2];
1524 double a6 = affine ? 0.0 : T[2][0];
1525 double a7 = affine ? 0.0 : T[2][1];
1526 double a8 = affine ? 1.0 : T[2][2];
1527
1528 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1529 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1530 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1531 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1532 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1533 if (vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1534 w = 1;
1535 }
1536
1537 x = x / w - (centerCorner ? 0.5 : 0);
1538 y = y / w - (centerCorner ? 0.5 : 0);
1539
1540 int x_lower = static_cast<int>(x);
1541 int y_lower = static_cast<int>(y);
1542
1543 if (y_lower >= static_cast<int>(src.getHeight()) || x_lower >= static_cast<int>(src.getWidth()) ||
1544 y < 0 || x < 0) {
1545 continue;
1546 }
1547
1548 double s = x - x_lower;
1549 double t = y - y_lower;
1550
1551 if (y_lower < static_cast<int>(src.getHeight())-1 && x_lower < static_cast<int>(src.getWidth())-1) {
1552 const Type val00 = src[y_lower][x_lower];
1553 const Type val01 = src[y_lower][x_lower + 1];
1554 const Type val10 = src[y_lower + 1][x_lower];
1555 const Type val11 = src[y_lower + 1][x_lower + 1];
1556 const double col0 = lerp(val00, val01, s);
1557 const double col1 = lerp(val10, val11, s);
1558 const double interp = lerp(col0, col1, t);
1559 dst[i][j] = vpMath::saturate<Type>(interp);
1560 } else if (y_lower < static_cast<int>(src.getHeight())-1) {
1561 const Type val00 = src[y_lower][x_lower];
1562 const Type val10 = src[y_lower + 1][x_lower];
1563 const double interp = lerp(val00, val10, t);
1564 dst[i][j] = vpMath::saturate<Type>(interp);
1565 } else if (x_lower < static_cast<int>(src.getWidth())-1) {
1566 const Type val00 = src[y_lower][x_lower];
1567 const Type val01 = src[y_lower][x_lower + 1];
1568 const double interp = lerp(val00, val01, s);
1569 dst[i][j] = vpMath::saturate<Type>(interp);
1570 } else {
1571 dst[i][j] = src[y_lower][x_lower];
1572 }
1573 }
1574 }
1575 }
1576}
1577
1578template <> inline
1579void vpImageTools::warpLinear(const vpImage<vpRGBa> &src, const vpMatrix &T, vpImage<vpRGBa> &dst, bool affine,
1580 bool centerCorner, bool fixedPoint)
1581{
1582 if (fixedPoint && !centerCorner) {
1583 const int nbits = 16;
1584 const int64_t precision = 1 << nbits;
1585 const float precision_1 = 1 / static_cast<float>(precision);
1586 const int64_t precision2 = 1ULL << (2 * nbits);
1587 const float precision_2 = 1 / static_cast<float>(precision2);
1588
1589 int64_t a0_i64 = static_cast<int64_t>(T[0][0] * precision);
1590 int64_t a1_i64 = static_cast<int64_t>(T[0][1] * precision);
1591 int64_t a2_i64 = static_cast<int64_t>(T[0][2] * precision);
1592 int64_t a3_i64 = static_cast<int64_t>(T[1][0] * precision);
1593 int64_t a4_i64 = static_cast<int64_t>(T[1][1] * precision);
1594 int64_t a5_i64 = static_cast<int64_t>(T[1][2] * precision);
1595 int64_t a6_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][0] * precision) : 0;
1596 int64_t a7_i64 = T.getRows() == 3 ? static_cast<int64_t>(T[2][1] * precision) : 0;
1597 int64_t a8_i64 = precision;
1598
1599 int64_t height_i64 = static_cast<int64_t>(src.getHeight() * precision);
1600 int64_t width_i64 = static_cast<int64_t>(src.getWidth() * precision);
1601
1602 if (affine) {
1603 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1604 int64_t xi = a2_i64;
1605 int64_t yi = a5_i64;
1606
1607 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1608 if (yi >= 0 && yi < height_i64 && xi >= 0 && xi < width_i64) {
1609 const int64_t xi_lower = xi & (~0xFFFF);
1610 const int64_t yi_lower = yi & (~0xFFFF);
1611
1612 const int64_t t = yi - yi_lower;
1613 const int64_t t_1 = precision - t;
1614 const int64_t s = xi - xi_lower;
1615 const int64_t s_1 = precision - s;
1616
1617 const int x_ = static_cast<int>(xi >> nbits);
1618 const int y_ = static_cast<int>(yi >> nbits);
1619
1620 if (y_ < static_cast<int>(src.getHeight())-1 && x_ < static_cast<int>(src.getWidth())-1) {
1621 const vpRGBa val00 = src[y_][x_];
1622 const vpRGBa val01 = src[y_][x_+1];
1623 const vpRGBa val10 = src[y_+1][x_];
1624 const vpRGBa val11 = src[y_+1][x_+1];
1625 const int64_t interpR_i64 = static_cast<int64_t>(s_1*t_1*val00.R + s * t_1*val01.R + s_1 * t*val10.R + s * t*val11.R);
1626 const float interpR = (interpR_i64 >> (nbits*2)) + (interpR_i64 & 0xFFFFFFFF) * precision_2;
1627
1628 const int64_t interpG_i64 = static_cast<int64_t>(s_1*t_1*val00.G + s * t_1*val01.G + s_1 * t*val10.G + s * t*val11.G);
1629 const float interpG = (interpG_i64 >> (nbits * 2)) + (interpG_i64 & 0xFFFFFFFF) * precision_2;
1630
1631 const int64_t interpB_i64 = static_cast<int64_t>(s_1*t_1*val00.B + s * t_1*val01.B + s_1 * t*val10.B + s * t*val11.B);
1632 const float interpB = (interpB_i64 >> (nbits * 2)) + (interpB_i64 & 0xFFFFFFFF) * precision_2;
1633
1634 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1635 vpMath::saturate<unsigned char>(interpG),
1636 vpMath::saturate<unsigned char>(interpB),
1637 255);
1638 } else if (y_ < static_cast<int>(src.getHeight())-1) {
1639 const vpRGBa val00 = src[y_][x_];
1640 const vpRGBa val10 = src[y_+1][x_];
1641 const int64_t interpR_i64 = static_cast<int64_t>(t_1*val00.R + t*val10.R);
1642 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1643
1644 const int64_t interpG_i64 = static_cast<int64_t>(t_1*val00.G + t * val10.G);
1645 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1646
1647 const int64_t interpB_i64 = static_cast<int64_t>(t_1*val00.B + t * val10.B);
1648 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1649
1650 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1651 vpMath::saturate<unsigned char>(interpG),
1652 vpMath::saturate<unsigned char>(interpB),
1653 255);
1654 } else if (x_ < static_cast<int>(src.getWidth())-1) {
1655 const vpRGBa val00 = src[y_][x_];
1656 const vpRGBa val01 = src[y_][x_+1];
1657 const int64_t interpR_i64 = static_cast<int64_t>(s_1*val00.R + s*val01.R);
1658 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1659
1660 const int64_t interpG_i64 = static_cast<int64_t>(s_1*val00.G + s * val01.G);
1661 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1662
1663 const int64_t interpB_i64 = static_cast<int64_t>(s_1*val00.B + s * val01.B);
1664 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1665
1666 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1667 vpMath::saturate<unsigned char>(interpG),
1668 vpMath::saturate<unsigned char>(interpB),
1669 255);
1670 } else {
1671 dst[i][j] = src[y_][x_];
1672 }
1673 }
1674
1675 xi += a0_i64;
1676 yi += a3_i64;
1677 }
1678
1679 a2_i64 += a1_i64;
1680 a5_i64 += a4_i64;
1681 }
1682 } else {
1683 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1684 int64_t xi = a2_i64;
1685 int64_t yi = a5_i64;
1686 int64_t wi = a8_i64;
1687
1688 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1689 if (yi >= 0 && yi <= (static_cast<int>(src.getHeight()) - 1)*wi &&
1690 xi >= 0 && xi <= (static_cast<int>(src.getWidth()) - 1)*wi) {
1691 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1692 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1693 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1694
1695 const int x_ = static_cast<int>(xi_);
1696 const int y_ = static_cast<int>(yi_);
1697
1698 const float t = yi_ - y_;
1699 const float s = xi_ - x_;
1700
1701 if (y_ < static_cast<int>(src.getHeight()) - 1 && x_ < static_cast<int>(src.getWidth()) - 1) {
1702 const vpRGBa val00 = src[y_][x_];
1703 const vpRGBa val01 = src[y_][x_ + 1];
1704 const vpRGBa val10 = src[y_ + 1][x_];
1705 const vpRGBa val11 = src[y_ + 1][x_ + 1];
1706 const float colR0 = lerp(val00.R, val01.R, s);
1707 const float colR1 = lerp(val10.R, val11.R, s);
1708 const float interpR = lerp(colR0, colR1, t);
1709
1710 const float colG0 = lerp(val00.G, val01.G, s);
1711 const float colG1 = lerp(val10.G, val11.G, s);
1712 const float interpG = lerp(colG0, colG1, t);
1713
1714 const float colB0 = lerp(val00.B, val01.B, s);
1715 const float colB1 = lerp(val10.B, val11.B, s);
1716 const float interpB = lerp(colB0, colB1, t);
1717
1718 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1719 vpMath::saturate<unsigned char>(interpG),
1720 vpMath::saturate<unsigned char>(interpB),
1721 255);
1722 } else if (y_ < static_cast<int>(src.getHeight()) - 1) {
1723 const vpRGBa val00 = src[y_][x_];
1724 const vpRGBa val10 = src[y_ + 1][x_];
1725 const float interpR = lerp(val00.R, val10.R, t);
1726 const float interpG = lerp(val00.G, val10.G, t);
1727 const float interpB = lerp(val00.B, val10.B, t);
1728
1729 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1730 vpMath::saturate<unsigned char>(interpG),
1731 vpMath::saturate<unsigned char>(interpB),
1732 255);
1733 } else if (x_ < static_cast<int>(src.getWidth()) - 1) {
1734 const vpRGBa val00 = src[y_][x_];
1735 const vpRGBa val01 = src[y_][x_ + 1];
1736 const float interpR = lerp(val00.R, val01.R, s);
1737 const float interpG = lerp(val00.G, val01.G, s);
1738 const float interpB = lerp(val00.B, val01.B, s);
1739
1740 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1741 vpMath::saturate<unsigned char>(interpG),
1742 vpMath::saturate<unsigned char>(interpB),
1743 255);
1744 } else {
1745 dst[i][j] = src[y_][x_];
1746 }
1747 }
1748
1749 xi += a0_i64;
1750 yi += a3_i64;
1751 wi += a6_i64;
1752 }
1753
1754 a2_i64 += a1_i64;
1755 a5_i64 += a4_i64;
1756 a8_i64 += a7_i64;
1757 }
1758 }
1759 } else {
1760 double a0 = T[0][0]; double a1 = T[0][1]; double a2 = T[0][2];
1761 double a3 = T[1][0]; double a4 = T[1][1]; double a5 = T[1][2];
1762 double a6 = affine ? 0.0 : T[2][0];
1763 double a7 = affine ? 0.0 : T[2][1];
1764 double a8 = affine ? 1.0 : T[2][2];
1765
1766 for (unsigned int i = 0; i < dst.getHeight(); i++) {
1767 for (unsigned int j = 0; j < dst.getWidth(); j++) {
1768 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1769 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1770 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1771
1772 x = x / w - (centerCorner ? 0.5 : 0);
1773 y = y / w - (centerCorner ? 0.5 : 0);
1774
1775 int x_lower = static_cast<int>(x);
1776 int y_lower = static_cast<int>(y);
1777
1778 if (y_lower >= static_cast<int>(src.getHeight()) || x_lower >= static_cast<int>(src.getWidth()) ||
1779 y < 0 || x < 0) {
1780 continue;
1781 }
1782
1783 double s = x - x_lower;
1784 double t = y - y_lower;
1785
1786 if (y_lower < static_cast<int>(src.getHeight())-1 && x_lower < static_cast<int>(src.getWidth())-1) {
1787 const vpRGBa val00 = src[y_lower][x_lower];
1788 const vpRGBa val01 = src[y_lower][x_lower +1];
1789 const vpRGBa val10 = src[y_lower +1][x_lower];
1790 const vpRGBa val11 = src[y_lower +1][x_lower +1];
1791 const double colR0 = lerp(val00.R, val01.R, s);
1792 const double colR1 = lerp(val10.R, val11.R, s);
1793 const double interpR = lerp(colR0, colR1, t);
1794
1795 const double colG0 = lerp(val00.G, val01.G, s);
1796 const double colG1 = lerp(val10.G, val11.G, s);
1797 const double interpG = lerp(colG0, colG1, t);
1798
1799 const double colB0 = lerp(val00.B, val01.B, s);
1800 const double colB1 = lerp(val10.B, val11.B, s);
1801 const double interpB = lerp(colB0, colB1, t);
1802
1803 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1804 vpMath::saturate<unsigned char>(interpG),
1805 vpMath::saturate<unsigned char>(interpB),
1806 255);
1807 } else if (y_lower < static_cast<int>(src.getHeight())-1) {
1808 const vpRGBa val00 = src[y_lower][x_lower];
1809 const vpRGBa val10 = src[y_lower +1][x_lower];
1810 const double interpR = lerp(val00.R, val10.R, t);
1811 const double interpG = lerp(val00.G, val10.G, t);
1812 const double interpB = lerp(val00.B, val10.B, t);
1813
1814 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1815 vpMath::saturate<unsigned char>(interpG),
1816 vpMath::saturate<unsigned char>(interpB),
1817 255);
1818 } else if (x_lower < static_cast<int>(src.getWidth())-1) {
1819 const vpRGBa val00 = src[y_lower][x_lower];
1820 const vpRGBa val01 = src[y_lower][x_lower +1];
1821 const double interpR = lerp(val00.R, val01.R, s);
1822 const double interpG = lerp(val00.G, val01.G, s);
1823 const double interpB = lerp(val00.B, val01.B, s);
1824
1825 dst[i][j] = vpRGBa(vpMath::saturate<unsigned char>(interpR),
1826 vpMath::saturate<unsigned char>(interpG),
1827 vpMath::saturate<unsigned char>(interpB),
1828 255);
1829 } else {
1830 dst[i][j] = src[y_lower][x_lower];
1831 }
1832 }
1833 }
1834 }
1835}
1836
1837#endif
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition: vpArray2D.h:132
unsigned int getCols() const
Definition: vpArray2D.h:279
unsigned int getRows() const
Definition: vpArray2D.h:289
Generic class defining intrinsic camera parameters.
double get_kud() const
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
double get_j() const
Definition: vpImagePoint.h:214
double get_i() const
Definition: vpImagePoint.h:203
Various image tools; sub-image extraction, modification of the look up table, binarisation....
Definition: vpImageTools.h:79
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:305
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
Definition: vpImageTools.h:830
static void warpImage(const vpImage< Type > &src, const vpMatrix &T, vpImage< Type > &dst, const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST, bool fixedPointArithmetic=true, bool pixelCenter=false)
static void resize(const vpImage< Type > &I, vpImage< Type > &Ires, unsigned int width, unsigned int height, const vpImageInterpolationType &method=INTERPOLATION_NEAREST, unsigned int nThreads=0)
static vp_deprecated void createSubImage(const vpImage< Type > &I, const vpRect &rect, vpImage< Type > &S)
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)
static void remap(const vpImage< unsigned char > &I, const vpArray2D< int > &mapU, const vpArray2D< int > &mapV, const vpArray2D< float > &mapDu, const vpArray2D< float > &mapDv, vpImage< unsigned char > &Iundist)
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, bool useLUT=true)
Definition: vpImageTools.h:459
@ INTERPOLATION_LINEAR
Definition: vpImageTools.h:83
@ INTERPOLATION_NEAREST
Definition: vpImageTools.h:82
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI, unsigned int nThreads=2)
Definition: vpImageTools.h:645
Definition of the vpImage class member functions.
Definition: vpImage.h:139
unsigned int getWidth() const
Definition: vpImage.h:246
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:1679
unsigned int getSize() const
Definition: vpImage.h:227
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
unsigned int getHeight() const
Definition: vpImage.h:188
Provides simple mathematics computation tools that are not available in the C mathematics library (ma...
Definition: vpMath.h:95
static double sqr(double x)
Definition: vpMath.h:116
static bool nul(double x, double s=0.001)
Definition: vpMath.h:286
static int round(double x)
Definition: vpMath.h:247
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:154
vpMatrix inverseByLU() const
Definition: vpRGBa.h:67
unsigned char B
Blue component.
Definition: vpRGBa.h:150
unsigned char R
Red component.
Definition: vpRGBa.h:148
unsigned char G
Green component.
Definition: vpRGBa.h:149
Defines an oriented rectangle in the plane.
Defines a rectangle in the plane.
Definition: vpRect.h:80
double getWidth() const
Definition: vpRect.h:228
double getLeft() const
Definition: vpRect.h:174
double getHeight() const
Definition: vpRect.h:167
double getTop() const
Definition: vpRect.h:193
Implementation of row vector and the associated operations.
Definition: vpRowVector.h:116