Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpImageTools.h
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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 https://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
40
41#ifndef VP_IMAGE_TOOLS_H
42#define VP_IMAGE_TOOLS_H
43
44#ifdef VISP_HAVE_THREADS
45#include <thread>
46#endif
47
48#include <visp3/core/vpConfig.h>
49#include <visp3/core/vpCameraParameters.h>
50#include <visp3/core/vpHSV.h>
51#include <visp3/core/vpImage.h>
52#include <visp3/core/vpImageException.h>
53#include <visp3/core/vpMath.h>
54#include <visp3/core/vpRect.h>
55#include <visp3/core/vpRectOriented.h>
56
57#include <fstream>
58#include <iostream>
59#include <math.h>
60#include <string.h>
61#include <cmath>
62
63#if defined(_OPENMP)
64#include <omp.h>
65#endif
66
76class VISP_EXPORT vpImageTools
77{
78public:
86
87 template <class Type>
88 static inline void binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
89 bool useLUT = true);
90 static void changeLUT(vpImage<unsigned char> &I, unsigned char A, unsigned char newA, unsigned char B,
91 unsigned char newB);
92
93 template <class Type>
94 static void crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
95 unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
96
97 static void columnMean(const vpImage<double> &I, vpRowVector &result);
98
99 template <class Type>
100 static void crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height, unsigned int roi_width,
101 vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
102 template <class Type>
103 static void crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale = 1,
104 unsigned int h_scale = 1);
105 template <class Type>
106 static void crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
107 vpImage<Type> &crop, unsigned int v_scale = 1, unsigned int h_scale = 1);
108
109 static void extract(const vpImage<unsigned char> &src, vpImage<unsigned char> &dst, const vpRectOriented &r);
110 static void extract(const vpImage<unsigned char> &src, vpImage<double> &dst, const vpRectOriented &r);
111
112 template <class Type> static void flip(const vpImage<Type> &I, vpImage<Type> &newI);
113
114 template <class Type> static void flip(vpImage<Type> &I);
115
116 static void imageDifference(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
118 static void imageDifference(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
119
120 static void imageDifferenceAbsolute(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
122 static void imageDifferenceAbsolute(const vpImage<double> &I1, const vpImage<double> &I2, vpImage<double> &Idiff);
123 static void imageDifferenceAbsolute(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, vpImage<vpRGBa> &Idiff);
124
125 static void imageAdd(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2, vpImage<unsigned char> &Ires,
126 bool saturate = false);
127
128 static void imageSubtract(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
129 vpImage<unsigned char> &Ires, bool saturate = false);
130
141 inline static int inMask(const vpImage<vpRGBa> &I, const vpImage<bool> &mask, vpImage<vpRGBa> &I_mask)
142 {
143 return inMask(I, mask, I_mask, true, vpRGBa(0, 0, 0));
144 }
145
156 inline static int inMask(const vpImage<vpRGBa> &I, const vpImage<unsigned char> &mask, vpImage<vpRGBa> &I_mask)
157 {
158 const unsigned char inRangeVal = 255;
159 return inMask(I, mask, I_mask, inRangeVal, vpRGBa(0, 0, 0));
160 }
161
172 inline static int inMask(const vpImage<unsigned char> &I, const vpImage<bool> &mask, vpImage<unsigned char> &I_mask)
173 {
174 return inMask(I, mask, I_mask, true, static_cast<unsigned char>(0));
175 }
176
187 inline static int inMask(const vpImage<unsigned char> &I, const vpImage<unsigned char> &mask, vpImage<unsigned char> &I_mask)
188 {
189 const unsigned char inRangeVal = 255;
190 return inMask(I, mask, I_mask, inRangeVal, static_cast<unsigned char>(0));
191 }
192
193#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
204 template <typename ArithmeticType, bool useFullScale>
206 {
207 vpHSV<ArithmeticType, useFullScale> black(static_cast<ArithmeticType>(0), static_cast<ArithmeticType>(0), static_cast<ArithmeticType>(0));
208 return inMask(I, mask, I_mask, true, black);
209 }
210
221 template <typename ArithmeticType, bool useFullScale>
223 {
224 const unsigned char inRangeVal = 255;
225 vpHSV<ArithmeticType, useFullScale> black(static_cast<ArithmeticType>(0), static_cast<ArithmeticType>(0), static_cast<ArithmeticType>(0));
226 return inMask(I, mask, I_mask, inRangeVal, black);
227 }
228#endif
229
230 static int inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
231 const vpColVector &hsv_range, unsigned char *mask, unsigned int size);
232 static int inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
233 const std::vector<int> &hsv_range, unsigned char *mask, unsigned int size);
234#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
254 template <typename ArithmeticType, bool useFullScale, typename RangeType>
256 const std::vector<RangeType> &hsv_range, vpImage<bool> &out)
257 {
258 return inRange(Iin, hsv_range, out, true, false);
259 }
260
280 template <typename ArithmeticType, bool useFullScale, typename RangeType>
282 const std::vector<RangeType> &hsv_range, vpImage<unsigned char> &out)
283 {
284 const unsigned char inRangeVal = 255;
285 return inRange(Iin, hsv_range, out, inRangeVal, static_cast<unsigned char>(0));
286 }
287
306 template <typename ArithmeticType, bool useFullScale>
308 const vpColVector &hsv_range, vpImage<bool> &out)
309 {
310 const unsigned int nbItems = hsv_range.getRows();
311 std::vector<ArithmeticType> range(nbItems);
312 for (unsigned int r = 0; r < nbItems; ++r) {
313 range[r] = static_cast<ArithmeticType>(hsv_range[r]);
314 }
315 return inRange(Iin, range, out, true, false);
316 }
317
336 template <typename ArithmeticType, bool useFullScale>
338 const vpColVector &hsv_range, vpImage<unsigned char> &out)
339 {
340 const unsigned char inRangeVal = 255;
341 const unsigned int nbItems = hsv_range.getRows();
342 std::vector<ArithmeticType> range(nbItems);
343 for (unsigned int r = 0; r < nbItems; ++r) {
344 range[r] = static_cast<ArithmeticType>(hsv_range[r]);
345 }
346 return inRange(Iin, range, out, inRangeVal, static_cast<unsigned char>(0));
347 }
348#endif
349
350
351
352 static void initUndistortMap(const vpCameraParameters &cam, unsigned int width, unsigned int height,
354 vpArray2D<float> &mapDv);
355
356 static double interpolate(const vpImage<unsigned char> &I, const vpImagePoint &point,
357 const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
358
359 static void integralImage(const vpImage<unsigned char> &I, vpImage<double> &II, vpImage<double> &IIsq);
360
361 static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, bool useOptimized = true);
362
363 static void normalize(vpImage<double> &I);
364
365 static void remap(const vpImage<unsigned char> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
366 const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<unsigned char> &Iundist);
367 static void remap(const vpImage<vpRGBa> &I, const vpArray2D<int> &mapU, const vpArray2D<int> &mapV,
368 const vpArray2D<float> &mapDu, const vpArray2D<float> &mapDv, vpImage<vpRGBa> &Iundist);
369
370 template <class Type>
371 static void resize(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int width, unsigned int height,
372 const vpImageInterpolationType &method = INTERPOLATION_NEAREST, unsigned int nThreads = 0);
373
374 template <class Type>
375 static void resize(const vpImage<Type> &I, vpImage<Type> &Ires,
376 const vpImageInterpolationType &method = INTERPOLATION_NEAREST, unsigned int nThreads = 0);
377
378 static void templateMatching(const vpImage<unsigned char> &I, const vpImage<unsigned char> &I_tpl,
379 vpImage<double> &I_score, unsigned int step_u, unsigned int step_v,
380 bool useOptimized = true);
381
382 template <class Type>
383 static void undistort(const vpImage<Type> &I, const vpCameraParameters &cam, vpImage<Type> &newI,
384 unsigned int nThreads = 2);
385
386 template <class Type>
387 static void undistort(const vpImage<Type> &I, vpArray2D<int> mapU, vpArray2D<int> mapV, vpArray2D<float> mapDu,
388 vpArray2D<float> mapDv, vpImage<Type> &newI);
389
390 template <class Type>
391 static void warpImage(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst,
392 const vpImageInterpolationType &interpolation = INTERPOLATION_NEAREST,
393 bool fixedPointArithmetic = true, bool pixelCenter = false);
394
395#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
400 template <class Type>
401 VP_DEPRECATED static void createSubImage(const vpImage<Type> &I, unsigned int i_sub, unsigned int j_sub,
402 unsigned int nrow_sub, unsigned int ncol_sub, vpImage<Type> &S);
403
404 template <class Type>
405 VP_DEPRECATED static void createSubImage(const vpImage<Type> &I, const vpRect &rect, vpImage<Type> &S);
407#endif
408
409private:
410 // Cubic interpolation
411 static float cubicHermite(const float A, const float B, const float C, const float D, const float t);
412
413 template <class Type> static Type getPixelClamped(const vpImage<Type> &I, float u, float v);
414
415 static int coordCast(double x);
416
417 // Linear interpolation
418 static double lerp(double A, double B, double t);
419 static float lerp(float A, float B, float t);
420 static int64_t lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1);
421
422 static double normalizedCorrelation(const vpImage<double> &I1, const vpImage<double> &I2, const vpImage<double> &II,
423 const vpImage<double> &IIsq, const vpImage<double> &II_tpl,
424 const vpImage<double> &IIsq_tpl, unsigned int i0, unsigned int j0);
425
426 template <class Type>
427 static void resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j, float u,
428 float v, float xFrac, float yFrac);
429
430 template <class Type>
431 static void resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j, float u,
432 float v, float xFrac, float yFrac);
433
434 template <class Type>
435 static void resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j, float u,
436 float v);
437
438#if defined(VISP_HAVE_SIMDLIB)
439 static void resizeSimdlib(const vpImage<vpRGBa> &Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
440 vpImage<vpRGBa> &Idst, int method);
441 static void resizeSimdlib(const vpImage<unsigned char> &Isrc, unsigned int resizeWidth, unsigned int resizeHeight,
442 vpImage<unsigned char> &Idst, int method);
443#endif
444
445 template <class Type>
446 static void warpNN(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine, bool centerCorner,
447 bool fixedPoint);
448
449 template <class Type>
450 static void warpLinear(const vpImage<Type> &src, const vpMatrix &T, vpImage<Type> &dst, bool affine,
451 bool centerCorner, bool fixedPoint);
452
453 static bool checkFixedPoint(unsigned int x, unsigned int y, const vpMatrix &T, bool affine);
454
455 static void warpLinearFixedPointNotCenter(const vpImage<vpRGBa> &src, const vpMatrix &T, vpImage<vpRGBa> &dst, bool affine);
456
457#ifndef DOXYGEN_SHOULD_SKIP_THIS
458#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
459 template <typename ArithmeticType, bool useFullScale, typename RangeType, typename OutType>
461 const std::vector<RangeType> &hsv_range, vpImage<OutType> &mask, const OutType &valueInRange, const OutType &valueOutRange)
462 {
463 const std::size_t val_6 = 6;
464 if (hsv_range.size() != val_6) {
466 "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.size()));
467 }
468 const unsigned int index_0 = 0;
469 const unsigned int index_1 = 1;
470 const unsigned int index_2 = 2;
471 const unsigned int index_3 = 3;
472 const unsigned int index_4 = 4;
473 const unsigned int index_5 = 5;
474 ArithmeticType h_low = static_cast<ArithmeticType>(hsv_range[index_0]);
475 ArithmeticType h_high = static_cast<ArithmeticType>(hsv_range[index_1]);
476 ArithmeticType s_low = static_cast<ArithmeticType>(hsv_range[index_2]);
477 ArithmeticType s_high = static_cast<ArithmeticType>(hsv_range[index_3]);
478 ArithmeticType v_low = static_cast<ArithmeticType>(hsv_range[index_4]);
479 ArithmeticType v_high = static_cast<ArithmeticType>(hsv_range[index_5]);
480 int size_ = Iin.getSize();
481 mask.resize(Iin.getRows(), Iin.getCols());
482 int cpt_in_range = 0;
483
484#if defined(VISP_HAVE_OPENMP)
485#pragma omp parallel for reduction(+:cpt_in_range)
486#endif
487 for (int i = 0; i < size_; ++i) {
488 bool check_h_low_high_hue = (h_low <= Iin.bitmap[i].H) && (Iin.bitmap[i].H <= h_high);
489 bool check_s_low_high_saturation = (s_low <= Iin.bitmap[i].S) && (Iin.bitmap[i].S <= s_high);
490 bool check_v_low_high_value = (v_low <= Iin.bitmap[i].V) && (Iin.bitmap[i].V <= v_high);
491 if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
492 mask.bitmap[i] = valueInRange;
493 ++cpt_in_range;
494 }
495 else {
496 mask.bitmap[i] = valueOutRange;
497 }
498 }
499 return cpt_in_range;
500 }
501#endif
502
503 template <typename ImageType, typename MaskType>
504 static int inMask(const vpImage<ImageType> &I, const vpImage<MaskType> &mask, vpImage<ImageType> &I_mask
505 , const MaskType &inRangeCheck, const ImageType &outRangeValue)
506 {
507 if ((I.getHeight() != mask.getHeight()) || (I.getWidth() != mask.getWidth())) {
509 "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
510 I.getWidth(), I.getHeight(), mask.getWidth(), mask.getHeight()));
511 }
512
513 I_mask.resize(I.getHeight(), I.getWidth());
514 int cpt_in_mask = 0;
515 int size_ = static_cast<int>(I.getSize());
516#if defined(_OPENMP)
517#pragma omp parallel for reduction(+:cpt_in_mask)
518#endif
519 for (int i = 0; i < size_; ++i) {
520 if (mask.bitmap[i] == inRangeCheck) {
521 I_mask.bitmap[i] = I.bitmap[i];
522 ++cpt_in_mask;
523 }
524 else {
525 I_mask.bitmap[i] = outRangeValue;
526 }
527 }
528 return cpt_in_mask;
529 }
530#endif
531};
532
533#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
553template <class Type>
554void vpImageTools::createSubImage(const vpImage<Type> &I, unsigned int roi_top, unsigned int roi_left,
555 unsigned int roi_height, unsigned int roi_width, vpImage<Type> &crop)
556{
557 vpImageTools::crop(I, roi_top, roi_left, roi_height, roi_width, crop);
558}
559
575template <class Type> void vpImageTools::createSubImage(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop)
576{
577 vpImageTools::crop(I, roi, crop);
578}
579
580#endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
581
604template <class Type>
605void vpImageTools::crop(const vpImage<Type> &I, double roi_top, double roi_left, unsigned int roi_height,
606 unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
607{
608 int i_min = std::max<int>(static_cast<int>(ceil(roi_top / v_scale)), 0);
609 int j_min = std::max<int>(static_cast<int>(ceil(roi_left / h_scale)), 0);
610 int i_max = std::min<int>(static_cast<int>(ceil(roi_top + roi_height) / v_scale), static_cast<int>(I.getHeight() / v_scale));
611 int j_max = std::min<int>(static_cast<int>(ceil(roi_left + roi_width) / h_scale), static_cast<int>(I.getWidth() / h_scale));
612
613 unsigned int i_min_u = static_cast<unsigned int>(i_min);
614 unsigned int j_min_u = static_cast<unsigned int>(j_min);
615
616 unsigned int r_width = static_cast<unsigned int>(j_max - j_min);
617 unsigned int r_height = static_cast<unsigned int>(i_max - i_min);
618
619 crop.resize(r_height, r_width);
620
621 if ((v_scale == 1) && (h_scale == 1)) {
622 for (unsigned int i = 0; i < r_height; ++i) {
623 void *src = (void *)(I[i + i_min_u] + j_min_u);
624 void *dst = static_cast<void *>(crop[i]);
625 memcpy(dst, src, r_width * sizeof(Type));
626 }
627 }
628 else if (h_scale == 1) {
629 for (unsigned int i = 0; i < r_height; ++i) {
630 void *src = (void *)(I[(i + i_min_u) * v_scale] + j_min_u);
631 void *dst = static_cast<void *>(crop[i]);
632 memcpy(dst, src, r_width * sizeof(Type));
633 }
634 }
635 else {
636 for (unsigned int i = 0; i < r_height; ++i) {
637 for (unsigned int j = 0; j < r_width; ++j) {
638 crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
639 }
640 }
641 }
642}
643
661template <class Type>
662void vpImageTools::crop(const vpImage<Type> &I, const vpImagePoint &topLeft, unsigned int roi_height,
663 unsigned int roi_width, vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
664{
665 vpImageTools::crop(I, topLeft.get_i(), topLeft.get_j(), roi_height, roi_width, crop, v_scale, h_scale);
666}
667
684template <class Type>
685void vpImageTools::crop(const vpImage<Type> &I, const vpRect &roi, vpImage<Type> &crop, unsigned int v_scale,
686 unsigned int h_scale)
687{
688 vpImageTools::crop(I, roi.getTop(), roi.getLeft(), static_cast<unsigned int>(roi.getHeight()), static_cast<unsigned int>(roi.getWidth()), crop,
689 v_scale, h_scale);
690}
691
709template <class Type>
710void vpImageTools::crop(const unsigned char *bitmap, unsigned int width, unsigned int height, const vpRect &roi,
711 vpImage<Type> &crop, unsigned int v_scale, unsigned int h_scale)
712{
713 int i_min = std::max<int>(static_cast<int>(ceil(roi.getTop() / v_scale)), 0);
714 int j_min = std::max<int>(static_cast<int>(ceil(roi.getLeft() / h_scale)), 0);
715 int i_max = std::min<int>(static_cast<int>(ceil((roi.getTop() + roi.getHeight()) / v_scale)), static_cast<int>(height / v_scale));
716 int j_max = std::min<int>(static_cast<int>(ceil((roi.getLeft() + roi.getWidth()) / h_scale)), static_cast<int>(width / h_scale));
717
718 unsigned int i_min_u = static_cast<unsigned int>(i_min);
719 unsigned int j_min_u = static_cast<unsigned int>(j_min);
720
721 unsigned int r_width = static_cast<unsigned int>(j_max - j_min);
722 unsigned int r_height = static_cast<unsigned int>(i_max - i_min);
723
724 crop.resize(r_height, r_width);
725
726 if (v_scale == 1 && h_scale == 1) {
727 for (unsigned int i = 0; i < r_height; ++i) {
728 void *src = (void *)(bitmap + ((((i + i_min_u) * width) + j_min_u) * sizeof(Type)));
729 void *dst = (void *)(crop[i]);
730 memcpy(dst, src, r_width * sizeof(Type));
731 }
732 }
733 else if (h_scale == 1) {
734 for (unsigned int i = 0; i < r_height; ++i) {
735 void *src = (void *)(bitmap + (((((i + i_min_u) * width) * v_scale) + j_min_u) * sizeof(Type)));
736 void *dst = (void *)(crop[i]);
737 memcpy(dst, src, r_width * sizeof(Type));
738 }
739 }
740 else {
741 for (unsigned int i = 0; i < r_height; ++i) {
742 unsigned int i_src = (((i + i_min_u) * width) * v_scale) + (j_min_u * h_scale);
743 for (unsigned int j = 0; j < r_width; ++j) {
744 void *src = (void *)(bitmap + ((i_src + (j * h_scale)) * sizeof(Type)));
745 void *dst = (void *)(&crop[i][j]);
746 memcpy(dst, src, sizeof(Type));
747 }
748 }
749 }
750}
751
762template <class Type>
763inline void vpImageTools::binarise(vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2,
764 Type value3, bool useLUT)
765{
766 if (useLUT) {
767 std::cerr << "LUT not available for this type ! Will use the iteration method." << std::endl;
768 }
769
770 Type v;
771 Type *p = I.bitmap;
772 Type *pend = I.bitmap + (I.getWidth() * I.getHeight());
773 for (; p < pend; ++p) {
774 v = *p;
775 if (v < threshold1) {
776 *p = value1;
777 }
778 else if (v > threshold2) {
779 *p = value3;
780 }
781 else {
782 *p = value2;
783 }
784 }
785}
786
797template <>
798inline void vpImageTools::binarise(vpImage<unsigned char> &I, unsigned char threshold1, unsigned char threshold2,
799 unsigned char value1, unsigned char value2, unsigned char value3, bool useLUT)
800{
801 if (useLUT) {
802 // Construct the LUT
803 const unsigned int sizeLut = 256;
804 unsigned char lut[sizeLut];
805 for (unsigned int i = 0; i < sizeLut; ++i) {
806 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
807 }
808
809 I.performLut(lut);
810 }
811 else {
812 unsigned char *p = I.bitmap;
813 unsigned char *pend = I.bitmap + (I.getWidth() * I.getHeight());
814 for (; p < pend; ++p) {
815 unsigned char v = *p;
816 if (v < threshold1) {
817 *p = value1;
818 }
819 else if (v > threshold2) {
820 *p = value3;
821 }
822 else {
823 *p = value2;
824 }
825 }
826 }
827}
828
829#ifdef VISP_HAVE_THREADS
830
831#ifndef DOXYGEN_SHOULD_SKIP_THIS
832template <class Type> class vpUndistortInternalType
833{
834public:
835 Type *src;
836 Type *dst;
837 unsigned int width;
838 unsigned int height;
840 unsigned int nthreads;
841 unsigned int threadid;
842
843public:
844 vpUndistortInternalType() : src(nullptr), dst(nullptr), width(0), height(0), cam(), nthreads(0), threadid(0) { }
845
846 vpUndistortInternalType(const vpUndistortInternalType<Type> &u) { *this = u; }
847 vpUndistortInternalType &operator=(const vpUndistortInternalType<Type> &u)
848 {
849 src = u.src;
850 dst = u.dst;
851 width = u.width;
852 height = u.height;
853 cam = u.cam;
854 nthreads = u.nthreads;
855 threadid = u.threadid;
856
857 return *this;
858 }
859
860 static void vpUndistort_threaded(vpUndistortInternalType<Type> &undistortSharedData);
861};
862
863template <class Type> void vpUndistortInternalType<Type>::vpUndistort_threaded(vpUndistortInternalType<Type> &undistortSharedData)
864{
865 int offset = static_cast<int>(undistortSharedData.threadid);
866 int width = static_cast<int>(undistortSharedData.width);
867 int height = static_cast<int>(undistortSharedData.height);
868 int nthreads = static_cast<int>(undistortSharedData.nthreads);
869
870 double u0 = undistortSharedData.cam.get_u0();
871 double v0 = undistortSharedData.cam.get_v0();
872 double px = undistortSharedData.cam.get_px();
873 double py = undistortSharedData.cam.get_py();
874 double kud = undistortSharedData.cam.get_kud();
875
876 double invpx = 1.0 / px;
877 double invpy = 1.0 / py;
878
879 double kud_px2 = kud * invpx * invpx;
880 double kud_py2 = kud * invpy * invpy;
881
882 Type *dst = undistortSharedData.dst + (height / nthreads * offset) * width;
883 Type *src = undistortSharedData.src;
884
885 for (double v = height / nthreads * offset; v < height / nthreads * (offset + 1); ++v) {
886 double deltav = v - v0;
887 // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
888 double fr1 = 1.0 + kud_py2 * deltav * deltav;
889
890 for (double u = 0; u < width; ++u) {
891 // computation of u,v : corresponding pixel coordinates in I.
892 double deltau = u - u0;
893 // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
894 double fr2 = fr1 + kud_px2 * deltau * deltau;
895
896 double u_double = deltau * fr2 + u0;
897 double v_double = deltav * fr2 + v0;
898
899 // computation of the bilinear interpolation
900
901 // declarations
902 int u_round = static_cast<int>(u_double);
903 int v_round = static_cast<int>(v_double);
904 if (u_round < 0) {
905 u_round = -1;
906 }
907 if (v_round < 0) {
908 v_round = -1;
909 }
910 double du_double = (u_double)-static_cast<double>(u_round);
911 double dv_double = (v_double)-static_cast<double>(v_round);
912 Type v01;
913 Type v23;
914 if ((0 <= u_round) && (0 <= v_round) && (u_round < (width-1)) && (v_round < (height-1))) {
915 // process interpolation
916 const Type *_mp = &src[v_round * width + u_round];
917 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
918 _mp += width;
919 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
920 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
921 }
922 else {
923 *dst = 0;
924 }
925 dst++;
926 }
927 }
928}
929#endif // DOXYGEN_SHOULD_SKIP_THIS
930#endif // VISP_HAVE_THREADS
931
955template <class Type>
957 unsigned int nThreads)
958{
959#if defined(VISP_HAVE_THREADS)
960 //
961 // Optimized version using pthreads
962 //
963 unsigned int width = I.getWidth();
964 unsigned int height = I.getHeight();
965
966 undistI.resize(height, width);
967
968 double kud = cam.get_kud();
969
970 // if (kud == 0) {
971 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
972 // There is no need to undistort the image
973 undistI = I;
974 return;
975 }
976
977 unsigned int nthreads = nThreads;
978 std::vector<std::thread *> threadpool;
979
980 vpUndistortInternalType<Type> *undistortSharedData = new vpUndistortInternalType<Type>[nthreads];
981
982 for (unsigned int i = 0; i < nthreads; ++i) {
983 // Each thread works on a different set of data.
984 undistortSharedData[i].src = I.bitmap;
985 undistortSharedData[i].dst = undistI.bitmap;
986 undistortSharedData[i].width = I.getWidth();
987 undistortSharedData[i].height = I.getHeight();
988 undistortSharedData[i].cam = cam;
989 undistortSharedData[i].nthreads = nthreads;
990 undistortSharedData[i].threadid = i;
991 std::thread *undistort_thread = new std::thread(&vpUndistortInternalType<Type>::vpUndistort_threaded, std::ref(undistortSharedData[i]));
992 threadpool.push_back(undistort_thread);
993 }
994 /* Wait on the other threads */
995
996 for (unsigned int i = 0; i < nthreads; ++i) {
997 threadpool[i]->join();
998 }
999
1000 for (unsigned int i = 0; i < nthreads; ++i) {
1001 delete threadpool[i];
1002 }
1003
1004 delete[] undistortSharedData;
1005#else // VISP_HAVE_THREADS
1006 (void)nThreads;
1007 //
1008 // optimized version without pthreads
1009 //
1010 unsigned int width = I.getWidth();
1011 unsigned int height = I.getHeight();
1012
1013 undistI.resize(height, width);
1014
1015 double u0 = cam.get_u0();
1016 double v0 = cam.get_v0();
1017 double px = cam.get_px();
1018 double py = cam.get_py();
1019 double kud = cam.get_kud();
1020
1021 /*
1022 // if (kud == 0) {
1023 */
1024 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
1025 // There is no need to undistort the image
1026 undistI = I;
1027 return;
1028 }
1029
1030 double invpx = 1.0 / px;
1031 double invpy = 1.0 / py;
1032
1033 double kud_px2 = kud * invpx * invpx;
1034 double kud_py2 = kud * invpy * invpy;
1035
1036 Type *dst = undistI.bitmap;
1037 for (double v = 0; v < height; ++v) {
1038 double deltav = v - v0;
1039 /*
1040 // double fr1 = 1.0 + kd * (vpMath::sqr(deltav * invpy));
1041 */
1042 double fr1 = 1.0 + (kud_py2 * deltav * deltav);
1043
1044 for (double u = 0; u < width; ++u) {
1045 /*
1046 // computation of u,v : corresponding pixel coordinates in I.
1047 */
1048 double deltau = u - u0;
1049 /*
1050 // double fr2 = fr1 + kd * (vpMath::sqr(deltau * invpx));
1051 */
1052 double fr2 = fr1 + (kud_px2 * deltau * deltau);
1053
1054 double u_double = (deltau * fr2) + u0;
1055 double v_double = (deltav * fr2) + v0;
1056
1057 // printf("[%g][%g] %g %g : ", u, v, u_double, v_double );
1058
1059 // computation of the bilinear interpolation
1060
1061 // declarations
1062 int u_round = static_cast<int>(u_double);
1063 int v_round = static_cast<int>(v_double);
1064 if (u_round < 0.f) {
1065 u_round = -1;
1066 }
1067 if (v_round < 0.f) {
1068 v_round = -1;
1069 }
1070 double du_double = u_double-static_cast<double>(u_round);
1071 double dv_double = v_double-static_cast<double>(v_round);
1072 Type v01;
1073 Type v23;
1074 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((static_cast<int>(width)) - 1)) && (v_round < ((static_cast<int>(height)) - 1))) {
1075 // process interpolation
1076 const Type *v_mp = &I[static_cast<unsigned int>(v_round)][static_cast<unsigned int>(u_round)];
1077 v01 = static_cast<Type>(v_mp[0] + ((v_mp[1] - v_mp[0]) * du_double));
1078 v_mp += width;
1079 v23 = static_cast<Type>(v_mp[0] + ((v_mp[1] - v_mp[0]) * du_double));
1080 *dst = static_cast<Type>(v01 + ((v23 - v01) * dv_double));
1081 /*
1082 // printf("R %d G %d B %d\n", dst->R, dst->G, dst->B);
1083 */
1084 }
1085 else {
1086 *dst = 0;
1087 }
1088 ++dst;
1089 }
1090 }
1091#endif // VISP_HAVE_THREADS
1092}
1093
1108template <class Type>
1110 vpArray2D<float> mapDv, vpImage<Type> &newI)
1111{
1112 remap(I, mapU, mapV, mapDu, mapDv, newI);
1113}
1114
1121template <class Type> void vpImageTools::flip(const vpImage<Type> &I, vpImage<Type> &newI)
1122{
1123 unsigned int height = I.getHeight(), width = I.getWidth();
1124 newI.resize(height, width);
1125
1126 for (unsigned int i = 0; i < height; ++i) {
1127 memcpy(newI.bitmap + (i * width), I.bitmap + ((height - 1 - i) * width), width * sizeof(Type));
1128 }
1129}
1130
1166template <class Type> void vpImageTools::flip(vpImage<Type> &I)
1167{
1168 unsigned int height = I.getHeight(), width = I.getWidth();
1169 vpImage<Type> Ibuf;
1170 Ibuf.resize(1, width);
1171
1172 const unsigned int halfHeight = height / 2;
1173 for (unsigned int i = 0; i < halfHeight; ++i) {
1174 memcpy(Ibuf.bitmap, I.bitmap + (i * width), width * sizeof(Type));
1175
1176 memcpy(I.bitmap + (i * width), I.bitmap + ((height - 1 - i) * width), width * sizeof(Type));
1177 memcpy(I.bitmap + ((height - 1 - i) * width), Ibuf.bitmap, width * sizeof(Type));
1178 }
1179}
1180
1181template <class Type> Type vpImageTools::getPixelClamped(const vpImage<Type> &I, float u, float v)
1182{
1183 int x = vpMath::round(static_cast<double>(u));
1184 int y = vpMath::round(static_cast<double>(v));
1185 x = std::max<int>(0, std::min<int>(x, static_cast<int>(I.getWidth()) - 1));
1186 y = std::max<int>(0, std::min<int>(y, static_cast<int>(I.getHeight()) - 1));
1187
1188 return I[y][x];
1189}
1190
1191// Reference:
1192// http://blog.demofox.org/2015/08/15/resizing-images-with-bicubic-interpolation/
1193template <class Type>
1194void vpImageTools::resizeBicubic(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j, float u,
1195 float v, float xFrac, float yFrac)
1196{
1197 // 1st row
1198 Type p00 = getPixelClamped(I, u - 1, v - 1);
1199 Type p01 = getPixelClamped(I, u + 0, v - 1);
1200 Type p02 = getPixelClamped(I, u + 1, v - 1);
1201 Type p03 = getPixelClamped(I, u + 2, v - 1);
1202
1203 // 2nd row
1204 Type p10 = getPixelClamped(I, u - 1, v + 0);
1205 Type p11 = getPixelClamped(I, u + 0, v + 0);
1206 Type p12 = getPixelClamped(I, u + 1, v + 0);
1207 Type p13 = getPixelClamped(I, u + 2, v + 0);
1208
1209 // 3rd row
1210 Type p20 = getPixelClamped(I, u - 1, v + 1);
1211 Type p21 = getPixelClamped(I, u + 0, v + 1);
1212 Type p22 = getPixelClamped(I, u + 1, v + 1);
1213 Type p23 = getPixelClamped(I, u + 2, v + 1);
1214
1215 // 4th row
1216 Type p30 = getPixelClamped(I, u - 1, v + 2);
1217 Type p31 = getPixelClamped(I, u + 0, v + 2);
1218 Type p32 = getPixelClamped(I, u + 1, v + 2);
1219 Type p33 = getPixelClamped(I, u + 2, v + 2);
1220
1221 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
1222 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
1223 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
1224 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
1225 float value = cubicHermite(col0, col1, col2, col3, yFrac);
1226 Ires[i][j] = vpMath::saturate<Type>(value);
1227}
1228
1229template <>
1230inline void vpImageTools::resizeBicubic(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, unsigned int i, unsigned int j,
1231 float u, float v, float xFrac, float yFrac)
1232{
1233 // 1st row
1234 vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
1235 vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
1236 vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
1237 vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
1238
1239 // 2nd row
1240 vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
1241 vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
1242 vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
1243 vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
1244
1245 // 3rd row
1246 vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
1247 vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
1248 vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
1249 vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
1250
1251 // 4th row
1252 vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
1253 vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
1254 vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
1255 vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
1256
1257 const int nbChannels = 3;
1258 for (int c = 0; c < nbChannels; ++c) {
1259 float col0 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p00)[c]),
1260 static_cast<float>(reinterpret_cast<unsigned char *>(&p01)[c]),
1261 static_cast<float>(reinterpret_cast<unsigned char *>(&p02)[c]),
1262 static_cast<float>(reinterpret_cast<unsigned char *>(&p03)[c]), xFrac);
1263 float col1 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p10)[c]),
1264 static_cast<float>(reinterpret_cast<unsigned char *>(&p11)[c]),
1265 static_cast<float>(reinterpret_cast<unsigned char *>(&p12)[c]),
1266 static_cast<float>(reinterpret_cast<unsigned char *>(&p13)[c]), xFrac);
1267 float col2 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p20)[c]),
1268 static_cast<float>(reinterpret_cast<unsigned char *>(&p21)[c]),
1269 static_cast<float>(reinterpret_cast<unsigned char *>(&p22)[c]),
1270 static_cast<float>(reinterpret_cast<unsigned char *>(&p23)[c]), xFrac);
1271 float col3 = cubicHermite(static_cast<float>(reinterpret_cast<unsigned char *>(&p30)[c]),
1272 static_cast<float>(reinterpret_cast<unsigned char *>(&p31)[c]),
1273 static_cast<float>(reinterpret_cast<unsigned char *>(&p32)[c]),
1274 static_cast<float>(reinterpret_cast<unsigned char *>(&p33)[c]), xFrac);
1275 float value = cubicHermite(col0, col1, col2, col3, yFrac);
1276
1277 reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1278 }
1279}
1280
1281template <class Type>
1282void vpImageTools::resizeBilinear(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j, float u,
1283 float v, float xFrac, float yFrac)
1284{
1285 int u0 = static_cast<int>(u);
1286 int v0 = static_cast<int>(v);
1287
1288 int u1 = std::min<int>(static_cast<int>(I.getWidth()) - 1, u0 + 1);
1289 int v1 = v0;
1290
1291 int u2 = u0;
1292 int v2 = std::min<int>(static_cast<int>(I.getHeight()) - 1, v0 + 1);
1293
1294 int u3 = u1;
1295 int v3 = v2;
1296
1297 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
1298 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
1299 float value = lerp(col0, col1, yFrac);
1300
1301 Ires[i][j] = vpMath::saturate<Type>(value);
1302}
1303
1304template <>
1305inline void vpImageTools::resizeBilinear(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, unsigned int i,
1306 unsigned int j, float u, float v, float xFrac, float yFrac)
1307{
1308 int u0 = static_cast<int>(u);
1309 int v0 = static_cast<int>(v);
1310
1311 int u1 = std::min<int>(static_cast<int>(I.getWidth()) - 1, u0 + 1);
1312 int v1 = v0;
1313
1314 int u2 = u0;
1315 int v2 = std::min<int>(static_cast<int>(I.getHeight()) - 1, v0 + 1);
1316
1317 int u3 = u1;
1318 int v3 = v2;
1319
1320 const int nbChannels = 3;
1321 for (int c = 0; c < nbChannels; ++c) {
1322 float col0 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v0][u0])[c]),
1323 static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v1][u1])[c]), xFrac);
1324 float col1 = lerp(static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v2][u2])[c]),
1325 static_cast<float>(reinterpret_cast<const unsigned char *>(&I[v3][u3])[c]), xFrac);
1326 float value = lerp(col0, col1, yFrac);
1327
1328 reinterpret_cast<unsigned char *>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1329 }
1330}
1331
1332template <class Type>
1333void vpImageTools::resizeNearest(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int i, unsigned int j, float u,
1334 float v)
1335{
1336 Ires[i][j] = getPixelClamped(I, u, v);
1337}
1338
1357template <class Type>
1358void vpImageTools::resize(const vpImage<Type> &I, vpImage<Type> &Ires, unsigned int width, unsigned int height,
1359 const vpImageInterpolationType &method, unsigned int nThreads)
1360{
1361 Ires.resize(height, width);
1362
1363 vpImageTools::resize(I, Ires, method, nThreads);
1364}
1365
1383template <class Type>
1385 unsigned int nThreads)
1386{
1387#if !defined(_OPENMP)
1388 (void)nThreads;
1389#endif
1390 const unsigned int minWidth = 2, minHeight = 2;
1391 if ((I.getWidth() < minWidth) || (I.getHeight() < minHeight) || (Ires.getWidth() < minWidth) || (Ires.getHeight() < minHeight)) {
1392 std::cerr << "Input or output image is too small!" << std::endl;
1393 return;
1394 }
1395
1396 if (method == INTERPOLATION_AREA) {
1397 std::cerr << "INTERPOLATION_AREA is not implemented for this type." << std::endl;
1398 return;
1399 }
1400
1401 const float scaleY = I.getHeight() / static_cast<float>(Ires.getHeight());
1402 const float scaleX = I.getWidth() / static_cast<float>(Ires.getWidth());
1403 const float half = 0.5f;
1404 const int ires_height = static_cast<int>(Ires.getHeight());
1405#if defined(_OPENMP)
1406 if (nThreads > 0) {
1407 omp_set_num_threads(static_cast<int>(nThreads));
1408 }
1409#pragma omp parallel for schedule(dynamic)
1410#endif
1411 for (int i = 0; i < ires_height; ++i) {
1412 const float v = ((i + half) * scaleY) - half;
1413 const float v0 = std::floor(v);
1414 const float yFrac = v - v0;
1415
1416 unsigned int ires_width = static_cast<unsigned int>(Ires.getWidth());
1417 for (unsigned int j = 0; j < ires_width; ++j) {
1418 const float u = ((j + half) * scaleX) - half;
1419 const float u0 = std::floor(u);
1420 const float xFrac = u - u0;
1421
1422 if (method == INTERPOLATION_NEAREST) {
1423 resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1424 }
1425 else if (method == INTERPOLATION_LINEAR) {
1426 resizeBilinear(I, Ires, static_cast<unsigned int>(i), j, u0, v0, xFrac, yFrac);
1427 }
1428 else if (method == INTERPOLATION_CUBIC) {
1429 resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1430 }
1431 }
1432 }
1433}
1434
1435#if defined(VISP_HAVE_SIMDLIB)
1436template <>
1438 const vpImageInterpolationType &method,
1439 unsigned int
1440#if defined(_OPENMP)
1441 nThreads
1442#endif
1443)
1444{
1445 const unsigned int minWidth = 2, minHeight = 2;
1446
1447 if ((I.getWidth() < minWidth) || (I.getHeight() < minHeight) || (Ires.getWidth() < minWidth) || (Ires.getHeight() < minHeight)) {
1448 std::cerr << "Input or output image is too small!" << std::endl;
1449 return;
1450 }
1451
1452 if (method == INTERPOLATION_AREA) {
1453 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_AREA);
1454 }
1455 else if (method == INTERPOLATION_LINEAR) {
1456 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_LINEAR);
1457 }
1458 else {
1459 const float scaleY = static_cast<float>(I.getHeight()) / static_cast<float>(Ires.getHeight());
1460 const float scaleX = static_cast<float>(I.getWidth()) / static_cast<float>(Ires.getWidth());
1461 const float half = 0.5f;
1462 const int ires_height = static_cast<int>(Ires.getHeight());
1463#if defined(_OPENMP)
1464 if (nThreads > 0) {
1465 omp_set_num_threads(static_cast<int>(nThreads));
1466 }
1467#pragma omp parallel for schedule(dynamic)
1468#endif
1469 for (int i = 0; i < ires_height; ++i) {
1470 float v = ((static_cast<float>(i) + half) * scaleY) - half;
1471 float yFrac = static_cast<float>(v - static_cast<float>(static_cast<int>(v)));
1472
1473 unsigned int ires_width = static_cast<unsigned int>(Ires.getWidth());
1474 for (unsigned int j = 0; j < ires_width; ++j) {
1475 float u = ((static_cast<float>(j) + half) * scaleX) - half;
1476 float xFrac = static_cast<float>(u - static_cast<float>(static_cast<int>(u)));
1477
1478 if (method == INTERPOLATION_NEAREST) {
1479 resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1480 }
1481 else if (method == INTERPOLATION_CUBIC) {
1482 resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1483 }
1484 }
1485 }
1486 }
1487}
1488
1489template <>
1491 const vpImageInterpolationType &method,
1492 unsigned int
1493#if defined(_OPENMP)
1494 nThreads
1495#endif
1496)
1497{
1498 const unsigned int minWidth = 2, minHeight = 2;
1499
1500 if ((I.getWidth() < minWidth) || (I.getHeight() < minHeight) || (Ires.getWidth() < minWidth) || (Ires.getHeight() < minHeight)) {
1501 std::cerr << "Input or output image is too small!" << std::endl;
1502 return;
1503 }
1504
1505 if (method == INTERPOLATION_AREA) {
1506 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_AREA);
1507 }
1508 else if (method == INTERPOLATION_LINEAR) {
1509 resizeSimdlib(I, Ires.getWidth(), Ires.getHeight(), Ires, INTERPOLATION_LINEAR);
1510 }
1511 else {
1512 const float scaleY = static_cast<float>(I.getHeight()) / static_cast<float>(Ires.getHeight());
1513 const float scaleX = static_cast<float>(I.getWidth()) / static_cast<float>(Ires.getWidth());
1514 const float half = 0.5f;
1515 const int ires_height = static_cast<int>(Ires.getHeight());
1516#if defined(_OPENMP)
1517 if (nThreads > 0) {
1518 omp_set_num_threads(static_cast<int>(nThreads));
1519 }
1520#pragma omp parallel for schedule(dynamic)
1521#endif
1522 for (int i = 0; i < ires_height; ++i) {
1523 float v = ((static_cast<float>(i) + half) * scaleY) - half;
1524 float yFrac = static_cast<float>(v - static_cast<float>(static_cast<int>(v)));
1525
1526 unsigned int ires_width = static_cast<unsigned int>(Ires.getWidth());
1527 for (unsigned int j = 0; j < ires_width; ++j) {
1528 float u = ((static_cast<float>(j) + half) * scaleX) - half;
1529 float xFrac = static_cast<float>(u - static_cast<float>(static_cast<int>(u)));
1530
1531 if (method == INTERPOLATION_NEAREST) {
1532 resizeNearest(I, Ires, static_cast<unsigned int>(i), j, u, v);
1533 }
1534 else if (method == INTERPOLATION_CUBIC) {
1535 resizeBicubic(I, Ires, static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1536 }
1537 }
1538 }
1539 }
1540}
1541#endif
1542
1543#ifdef ENABLE_IMAGE_TOOLS_WARP
1544#include <visp3/core/vpImageTools_warp.h>
1545#endif
1546
1547END_VISP_NAMESPACE
1548#endif
Implementation of a generic 2D array used as base class for matrices and vectors.
Definition vpArray2D.h:146
unsigned int getRows() const
Definition vpArray2D.h:433
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
Class implementing the HSV pixel format.
Definition vpHSV.h:135
Error that can be emitted by the vpImage class and its derivatives.
@ notInitializedError
Image not initialized.
@ incorrectInitializationError
Wrong image initialization.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double get_j() const
double get_i() const
Various image tools; sub-image extraction, modification of the look up table, binarisation....
static int inMask(const vpImage< vpRGBa > &I, const vpImage< unsigned char > &mask, vpImage< vpRGBa > &I_mask)
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)
static void flip(const vpImage< Type > &I, vpImage< Type > &newI)
static int inRange(const vpImage< vpHSV< ArithmeticType, useFullScale > > &Iin, const vpColVector &hsv_range, vpImage< bool > &out)
Create binary mask by checking if HSV (hue, saturation, value) channels lie between low and high HSV ...
static int inRange(const vpImage< vpHSV< ArithmeticType, useFullScale > > &Iin, const std::vector< RangeType > &hsv_range, vpImage< bool > &out)
Create binary mask by checking if HSV (hue, saturation, value) channels lie between low and high HSV ...
static VP_DEPRECATED void createSubImage(const vpImage< Type > &I, const vpRect &rect, vpImage< Type > &S)
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 int inRange(const vpImage< vpHSV< ArithmeticType, useFullScale > > &Iin, const vpColVector &hsv_range, vpImage< unsigned char > &out)
Create binary mask by checking if HSV (hue, saturation, value) channels lie between low and high HSV ...
static int inRange(const vpImage< vpHSV< ArithmeticType, useFullScale > > &Iin, const std::vector< RangeType > &hsv_range, vpImage< unsigned char > &out)
Create binary mask by checking if HSV (hue, saturation, value) channels lie between low and high HSV ...
static int inMask(const vpImage< vpHSV< ArithmeticType, useFullScale > > &I, const vpImage< bool > &mask, vpImage< vpHSV< ArithmeticType, useFullScale > > &I_mask)
static int inMask(const vpImage< vpRGBa > &I, const vpImage< bool > &mask, vpImage< vpRGBa > &I_mask)
static int inMask(const vpImage< unsigned char > &I, const vpImage< unsigned char > &mask, vpImage< unsigned char > &I_mask)
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 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 int inMask(const vpImage< vpHSV< ArithmeticType, useFullScale > > &I, const vpImage< unsigned char > &mask, vpImage< vpHSV< ArithmeticType, useFullScale > > &I_mask)
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, bool useLUT=true)
static double normalizedCorrelation(const vpImage< double > &I1, const vpImage< double > &I2, bool useOptimized=true)
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI, unsigned int nThreads=2)
static int inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value, const vpColVector &hsv_range, unsigned char *mask, unsigned int size)
static int inMask(const vpImage< unsigned char > &I, const vpImage< bool > &mask, vpImage< unsigned char > &I_mask)
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
unsigned int getSize() const
Definition vpImage.h:221
Type * bitmap
points toward the bitmap
Definition vpImage.h:135
unsigned int getHeight() const
Definition vpImage.h:181
static Tp saturate(unsigned char v)
Definition vpMath.h:306
static int round(double x)
Definition vpMath.h:413
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
Defines an oriented rectangle in the plane.
Defines a rectangle in the plane.
Definition vpRect.h:79
double getWidth() const
Definition vpRect.h:227
double getLeft() const
Definition vpRect.h:173
double getHeight() const
Definition vpRect.h:166
double getTop() const
Definition vpRect.h:192
Implementation of row vector and the associated operations.