41#ifndef VP_IMAGE_TOOLS_H
42#define VP_IMAGE_TOOLS_H
44#ifdef VISP_HAVE_THREADS
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>
88 static inline void binarise(
vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
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);
101 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
102 template <
class Type>
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);
126 bool saturate =
false);
158 const unsigned char inRangeVal = 255;
159 return inMask(I, mask, I_mask, inRangeVal,
vpRGBa(0, 0, 0));
174 return inMask(I, mask, I_mask,
true,
static_cast<unsigned char>(0));
189 const unsigned char inRangeVal = 255;
190 return inMask(I, mask, I_mask, inRangeVal,
static_cast<unsigned char>(0));
193#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
204 template <
typename ArithmeticType,
bool useFullScale>
208 return inMask(I, mask, I_mask,
true, black);
221 template <
typename ArithmeticType,
bool useFullScale>
224 const unsigned char inRangeVal = 255;
226 return inMask(I, mask, I_mask, inRangeVal, black);
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>
258 return inRange(Iin, hsv_range, out,
true,
false);
280 template <
typename ArithmeticType,
bool useFullScale,
typename RangeType>
284 const unsigned char inRangeVal = 255;
285 return inRange(Iin, hsv_range, out, inRangeVal,
static_cast<unsigned char>(0));
306 template <
typename ArithmeticType,
bool useFullScale>
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]);
315 return inRange(Iin, range, out,
true,
false);
336 template <
typename ArithmeticType,
bool useFullScale>
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]);
346 return inRange(Iin, range, out, inRangeVal,
static_cast<unsigned char>(0));
352 static void initUndistortMap(
const vpCameraParameters &cam,
unsigned int width,
unsigned int height,
357 const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
370 template <
class Type>
372 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
374 template <
class Type>
376 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
380 bool useOptimized =
true);
382 template <
class Type>
384 unsigned int nThreads = 2);
386 template <
class Type>
390 template <
class Type>
392 const vpImageInterpolationType &interpolation = INTERPOLATION_NEAREST,
393 bool fixedPointArithmetic =
true,
bool pixelCenter =
false);
395#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
400 template <class Type>
402 unsigned int nrow_sub,
unsigned int ncol_sub,
vpImage<Type> &S);
404 template <
class Type>
411 static float cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t);
413 template <
class Type>
static Type getPixelClamped(
const vpImage<Type> &I,
float u,
float v);
415 static int coordCast(
double x);
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);
426 template <
class Type>
428 float v,
float xFrac,
float yFrac);
430 template <
class Type>
432 float v,
float xFrac,
float yFrac);
434 template <
class Type>
438#if defined(VISP_HAVE_SIMDLIB)
439 static void resizeSimdlib(
const vpImage<vpRGBa> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
441 static void resizeSimdlib(
const vpImage<unsigned char> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
445 template <
class Type>
449 template <
class Type>
451 bool centerCorner,
bool fixedPoint);
453 static bool checkFixedPoint(
unsigned int x,
unsigned int y,
const vpMatrix &T,
bool affine);
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)
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()));
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;
484#if defined(VISP_HAVE_OPENMP)
485#pragma omp parallel for reduction(+:cpt_in_range)
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;
496 mask.
bitmap[
i] = valueOutRange;
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)
509 "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
515 int size_ =
static_cast<int>(I.
getSize());
517#pragma omp parallel for reduction(+:cpt_in_mask)
519 for (
int i = 0;
i < size_; ++
i) {
520 if (mask.
bitmap[i] == inRangeCheck) {
525 I_mask.
bitmap[
i] = outRangeValue;
533#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
606 unsigned int roi_width,
vpImage<Type> &
crop,
unsigned int v_scale,
unsigned int h_scale)
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));
613 unsigned int i_min_u =
static_cast<unsigned int>(i_min);
614 unsigned int j_min_u =
static_cast<unsigned int>(j_min);
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);
619 crop.resize(r_height, r_width);
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));
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));
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];
663 unsigned int roi_width,
vpImage<Type> &
crop,
unsigned int v_scale,
unsigned int h_scale)
686 unsigned int h_scale)
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));
718 unsigned int i_min_u =
static_cast<unsigned int>(i_min);
719 unsigned int j_min_u =
static_cast<unsigned int>(j_min);
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);
724 crop.resize(r_height, r_width);
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));
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));
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));
764 Type value3,
bool useLUT)
767 std::cerr <<
"LUT not available for this type ! Will use the iteration method." << std::endl;
772 Type *pend = I.bitmap + (I.getWidth() * I.getHeight());
773 for (; p < pend; ++p) {
775 if (v < threshold1) {
778 else if (v > threshold2) {
799 unsigned char value1,
unsigned char value2,
unsigned char value3,
bool useLUT)
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);
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) {
819 else if (v > threshold2) {
829#ifdef VISP_HAVE_THREADS
831#ifndef DOXYGEN_SHOULD_SKIP_THIS
832template <
class Type>
class vpUndistortInternalType
840 unsigned int nthreads;
841 unsigned int threadid;
844 vpUndistortInternalType() : src(nullptr), dst(nullptr), width(0), height(0), cam(), nthreads(0), threadid(0) { }
846 vpUndistortInternalType(
const vpUndistortInternalType<Type> &u) { *
this =
u; }
847 vpUndistortInternalType &operator=(
const vpUndistortInternalType<Type> &u)
854 nthreads =
u.nthreads;
855 threadid =
u.threadid;
860 static void vpUndistort_threaded(vpUndistortInternalType<Type> &undistortSharedData);
863template <
class Type>
void vpUndistortInternalType<Type>::vpUndistort_threaded(vpUndistortInternalType<Type> &undistortSharedData)
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);
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();
876 double invpx = 1.0 / px;
877 double invpy = 1.0 / py;
879 double kud_px2 = kud * invpx * invpx;
880 double kud_py2 = kud * invpy * invpy;
882 Type *dst = undistortSharedData.dst + (
height / nthreads * offset) * width;
883 Type *src = undistortSharedData.src;
885 for (
double v = height / nthreads * offset;
v <
height / nthreads * (offset + 1); ++
v) {
886 double deltav =
v - v0;
888 double fr1 = 1.0 + kud_py2 * deltav * deltav;
890 for (
double u = 0;
u <
width; ++
u) {
892 double deltau =
u - u0;
894 double fr2 = fr1 + kud_px2 * deltau * deltau;
896 double u_double = deltau * fr2 + u0;
897 double v_double = deltav * fr2 + v0;
902 int u_round =
static_cast<int>(u_double);
903 int v_round =
static_cast<int>(v_double);
910 double du_double = (u_double)-
static_cast<double>(u_round);
911 double dv_double = (v_double)-
static_cast<double>(v_round);
914 if ((0 <= u_round) && (0 <= v_round) && (u_round < (width-1)) && (v_round < (height-1))) {
916 const Type *_mp = &src[v_round *
width + u_round];
917 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
919 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
920 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
957 unsigned int nThreads)
959#if defined(VISP_HAVE_THREADS)
963 unsigned int width = I.getWidth();
964 unsigned int height = I.getHeight();
966 undistI.
resize(height, width);
968 double kud = cam.get_kud();
971 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
977 unsigned int nthreads = nThreads;
978 std::vector<std::thread *> threadpool;
980 vpUndistortInternalType<Type> *undistortSharedData =
new vpUndistortInternalType<Type>[nthreads];
982 for (
unsigned int i = 0; i < nthreads; ++i) {
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);
996 for (
unsigned int i = 0; i < nthreads; ++i) {
997 threadpool[i]->join();
1000 for (
unsigned int i = 0; i < nthreads; ++i) {
1001 delete threadpool[i];
1004 delete[] undistortSharedData;
1010 unsigned int width = I.getWidth();
1011 unsigned int height = I.getHeight();
1013 undistI.
resize(height, width);
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();
1024 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
1030 double invpx = 1.0 / px;
1031 double invpy = 1.0 / py;
1033 double kud_px2 = kud * invpx * invpx;
1034 double kud_py2 = kud * invpy * invpy;
1036 Type *dst = undistI.
bitmap;
1037 for (
double v = 0; v < height; ++v) {
1038 double deltav = v - v0;
1042 double fr1 = 1.0 + (kud_py2 * deltav * deltav);
1044 for (
double u = 0; u < width; ++u) {
1048 double deltau = u - u0;
1052 double fr2 = fr1 + (kud_px2 * deltau * deltau);
1054 double u_double = (deltau * fr2) + u0;
1055 double v_double = (deltav * fr2) + v0;
1062 int u_round =
static_cast<int>(u_double);
1063 int v_round =
static_cast<int>(v_double);
1064 if (u_round < 0.f) {
1067 if (v_round < 0.f) {
1070 double du_double = u_double-
static_cast<double>(u_round);
1071 double dv_double = v_double-
static_cast<double>(v_round);
1074 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((
static_cast<int>(width)) - 1)) && (v_round < ((
static_cast<int>(height)) - 1))) {
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));
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));
1108template <
class Type>
1112 remap(I, mapU, mapV, mapDu, mapDv, newI);
1123 unsigned int height = I.getHeight(), width = I.getWidth();
1124 newI.
resize(height, width);
1126 for (
unsigned int i = 0; i < height; ++i) {
1127 memcpy(newI.
bitmap + (i * width), I.bitmap + ((height - 1 - i) * width), width *
sizeof(Type));
1168 unsigned int height = I.getHeight(), width = I.getWidth();
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));
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));
1181template <
class Type> Type vpImageTools::getPixelClamped(
const vpImage<Type> &I,
float u,
float 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));
1193template <
class Type>
1195 float v,
float xFrac,
float yFrac)
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);
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);
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);
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);
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);
1231 float u,
float v,
float xFrac,
float yFrac)
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);
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);
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);
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);
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);
1281template <
class Type>
1283 float v,
float xFrac,
float yFrac)
1285 int u0 =
static_cast<int>(u);
1286 int v0 =
static_cast<int>(v);
1288 int u1 = std::min<int>(
static_cast<int>(I.getWidth()) - 1, u0 + 1);
1292 int v2 = std::min<int>(
static_cast<int>(I.getHeight()) - 1, v0 + 1);
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);
1306 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
1308 int u0 =
static_cast<int>(u);
1309 int v0 =
static_cast<int>(v);
1311 int u1 = std::min<int>(
static_cast<int>(I.getWidth()) - 1, u0 + 1);
1315 int v2 = std::min<int>(
static_cast<int>(I.getHeight()) - 1, v0 + 1);
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);
1332template <
class Type>
1336 Ires[i][j] = getPixelClamped(I, u, v);
1357template <
class Type>
1361 Ires.
resize(height, width);
1383template <
class Type>
1385 unsigned int nThreads)
1387#if !defined(_OPENMP)
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;
1397 std::cerr <<
"INTERPOLATION_AREA is not implemented for this type." << std::endl;
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());
1407 omp_set_num_threads(
static_cast<int>(nThreads));
1409#pragma omp parallel for schedule(dynamic)
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;
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;
1423 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1426 resizeBilinear(I, Ires,
static_cast<unsigned int>(i), j, u0, v0, xFrac, yFrac);
1429 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1435#if defined(VISP_HAVE_SIMDLIB)
1445 const unsigned int minWidth = 2, minHeight = 2;
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;
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());
1465 omp_set_num_threads(
static_cast<int>(nThreads));
1467#pragma omp parallel for schedule(dynamic)
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)));
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)));
1479 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1482 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1498 const unsigned int minWidth = 2, minHeight = 2;
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;
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());
1518 omp_set_num_threads(
static_cast<int>(nThreads));
1520#pragma omp parallel for schedule(dynamic)
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)));
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)));
1532 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1535 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1543#ifdef ENABLE_IMAGE_TOOLS_WARP
1544#include <visp3/core/vpImageTools_warp.h>
Implementation of a generic 2D array used as base class for matrices and vectors.
unsigned int getRows() const
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
Class implementing the HSV pixel format.
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 ...
Definition of the vpImage class member functions.
unsigned int getWidth() const
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
unsigned int getSize() const
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
static Tp saturate(unsigned char v)
static int round(double x)
Implementation of a matrix and operations on matrices.
Defines an oriented rectangle in the plane.
Defines a rectangle in the plane.
Implementation of row vector and the associated operations.