34 #ifndef vpImageTools_H
35 #define vpImageTools_H
44 #include <visp3/core/vpImage.h>
46 #ifdef VISP_HAVE_THREADS
50 #include <visp3/core/vpCameraParameters.h>
51 #include <visp3/core/vpImageException.h>
52 #include <visp3/core/vpMath.h>
53 #include <visp3/core/vpRect.h>
54 #include <visp3/core/vpRectOriented.h>
86 static inline void binarise(
vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
92 static void crop(
const vpImage<Type> &I,
double roi_top,
double roi_left,
unsigned int roi_height,
93 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
99 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
100 template <
class Type>
102 unsigned int h_scale = 1);
103 template <
class Type>
104 static void crop(
const unsigned char *bitmap,
unsigned int width,
unsigned int height,
const vpRect &roi,
105 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
124 bool saturate =
false);
132 static int inRange(
const unsigned char *hue,
const unsigned char *saturation,
const unsigned char *value,
133 const vpColVector &hsv_range,
unsigned char *mask,
unsigned int size);
134 static int inRange(
const unsigned char *hue,
const unsigned char *saturation,
const unsigned char *value,
135 const std::vector<int> &hsv_range,
unsigned char *mask,
unsigned int size);
136 static void initUndistortMap(
const vpCameraParameters &cam,
unsigned int width,
unsigned int height,
141 const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
154 template <
class Type>
156 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
158 template <
class Type>
160 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
164 bool useOptimized =
true);
166 template <
class Type>
168 unsigned int nThreads = 2);
170 template <
class Type>
174 template <
class Type>
176 const vpImageInterpolationType &interpolation = INTERPOLATION_NEAREST,
177 bool fixedPointArithmetic =
true,
bool pixelCenter =
false);
179 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
184 template <
class Type>
186 unsigned int nrow_sub,
unsigned int ncol_sub,
vpImage<Type> &S);
188 template <
class Type>
195 static float cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t);
197 template <
class Type>
static Type getPixelClamped(
const vpImage<Type> &I,
float u,
float v);
199 static int coordCast(
double x);
202 static double lerp(
double A,
double B,
double t);
203 static float lerp(
float A,
float B,
float t);
204 static int64_t lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1);
210 template <
class Type>
212 float v,
float xFrac,
float yFrac);
214 template <
class Type>
216 float v,
float xFrac,
float yFrac);
218 template <
class Type>
222 #if defined(VISP_HAVE_SIMDLIB)
223 static void resizeSimdlib(
const vpImage<vpRGBa> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
225 static void resizeSimdlib(
const vpImage<unsigned char> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
229 template <
class Type>
233 template <
class Type>
235 bool centerCorner,
bool fixedPoint);
237 static bool checkFixedPoint(
unsigned int x,
unsigned int y,
const vpMatrix &T,
bool affine);
240 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
260 template <
class Type>
262 unsigned int roi_height,
unsigned int roi_width,
vpImage<Type> &crop)
311 template <
class Type>
313 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
315 int i_min = std::max<int>((
int)(ceil(roi_top / v_scale)), 0);
316 int j_min = std::max<int>((
int)(ceil(roi_left / h_scale)), 0);
317 int i_max = std::min<int>((
int)(ceil((roi_top + roi_height)) / v_scale), (
int)(I.
getHeight() / v_scale));
318 int j_max = std::min<int>((
int)(ceil((roi_left + roi_width) / h_scale)), (
int)(I.
getWidth() / h_scale));
320 unsigned int i_min_u = (
unsigned int)i_min;
321 unsigned int j_min_u = (
unsigned int)j_min;
323 unsigned int r_width = (
unsigned int)(j_max - j_min);
324 unsigned int r_height = (
unsigned int)(i_max - i_min);
326 crop.resize(r_height, r_width);
328 if (v_scale == 1 && h_scale == 1) {
329 for (
unsigned int i = 0; i < r_height; ++i) {
330 void *src = (
void *)(I[i + i_min_u] + j_min_u);
331 void *dst = (
void *)
crop[i];
332 memcpy(dst, src, r_width *
sizeof(Type));
335 else if (h_scale == 1) {
336 for (
unsigned int i = 0; i < r_height; ++i) {
337 void *src = (
void *)(I[(i + i_min_u) * v_scale] + j_min_u);
338 void *dst = (
void *)
crop[i];
339 memcpy(dst, src, r_width *
sizeof(Type));
343 for (
unsigned int i = 0; i < r_height; ++i) {
344 for (
unsigned int j = 0; j < r_width; ++j) {
345 crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
368 template <
class Type>
370 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
391 template <
class Type>
393 unsigned int h_scale)
416 template <
class Type>
418 vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
420 int i_min = std::max<int>((
int)(ceil(roi.
getTop() / v_scale)), 0);
421 int j_min = std::max<int>((
int)(ceil(roi.
getLeft() / h_scale)), 0);
422 int i_max = std::min<int>((
int)(ceil((roi.
getTop() + roi.
getHeight()) / v_scale)), (
int)(height / v_scale));
423 int j_max = std::min<int>((
int)(ceil((roi.
getLeft() + roi.
getWidth()) / h_scale)), (
int)(width / h_scale));
425 unsigned int i_min_u = (
unsigned int)i_min;
426 unsigned int j_min_u = (
unsigned int)j_min;
428 unsigned int r_width = (
unsigned int)(j_max - j_min);
429 unsigned int r_height = (
unsigned int)(i_max - i_min);
431 crop.resize(r_height, r_width);
433 if (v_scale == 1 && h_scale == 1) {
434 for (
unsigned int i = 0; i < r_height; ++i) {
435 void *src = (
void *)(bitmap + ((i + i_min_u) * width + j_min_u) *
sizeof(Type));
436 void *dst = (
void *)
crop[i];
437 memcpy(dst, src, r_width *
sizeof(Type));
440 else if (h_scale == 1) {
441 for (
unsigned int i = 0; i < r_height; ++i) {
442 void *src = (
void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) *
sizeof(Type));
443 void *dst = (
void *)
crop[i];
444 memcpy(dst, src, r_width *
sizeof(Type));
448 for (
unsigned int i = 0; i < r_height; ++i) {
449 unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
450 for (
unsigned int j = 0; j < r_width; ++j) {
451 void *src = (
void *)(bitmap + (i_src + j * h_scale) *
sizeof(Type));
452 void *dst = (
void *)&
crop[i][j];
453 memcpy(dst, src,
sizeof(Type));
469 template <
class Type>
471 Type value3,
bool useLUT)
474 std::cerr <<
"LUT not available for this type ! Will use the iteration method." << std::endl;
480 for (; p < pend; ++p) {
484 else if (v > threshold2)
503 unsigned char value1,
unsigned char value2,
unsigned char value3,
bool useLUT)
507 unsigned char lut[256];
508 for (
unsigned int i = 0; i < 256; ++i) {
509 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
515 unsigned char *p = I.
bitmap;
517 for (; p < pend; ++p) {
518 unsigned char v = *p;
521 else if (v > threshold2)
529 #ifdef VISP_HAVE_THREADS
531 #ifndef DOXYGEN_SHOULD_SKIP_THIS
532 template <
class Type>
class vpUndistortInternalType
540 unsigned int nthreads;
541 unsigned int threadid;
544 vpUndistortInternalType() : src(nullptr), dst(nullptr), width(0), height(0), cam(), nthreads(0), threadid(0) { }
546 vpUndistortInternalType(
const vpUndistortInternalType<Type> &u) { *
this = u; }
547 vpUndistortInternalType &operator=(
const vpUndistortInternalType<Type> &u)
554 nthreads = u.nthreads;
555 threadid = u.threadid;
560 static void vpUndistort_threaded(vpUndistortInternalType<Type> &undistortSharedData);
563 template <
class Type>
void vpUndistortInternalType<Type>::vpUndistort_threaded(vpUndistortInternalType<Type> &undistortSharedData)
565 int offset = (int)undistortSharedData.threadid;
566 int width = (
int)undistortSharedData.width;
567 int height = (int)undistortSharedData.height;
568 int nthreads = (
int)undistortSharedData.nthreads;
570 double u0 = undistortSharedData.cam.get_u0();
571 double v0 = undistortSharedData.cam.get_v0();
572 double px = undistortSharedData.cam.get_px();
573 double py = undistortSharedData.cam.get_py();
574 double kud = undistortSharedData.cam.get_kud();
576 double invpx = 1.0 / px;
577 double invpy = 1.0 / py;
579 double kud_px2 = kud * invpx * invpx;
580 double kud_py2 = kud * invpy * invpy;
582 Type *dst = undistortSharedData.dst + (height / nthreads * offset) * width;
583 Type *src = undistortSharedData.src;
585 for (
double v = height / nthreads * offset; v < height / nthreads * (offset + 1); ++v) {
586 double deltav = v - v0;
588 double fr1 = 1.0 + kud_py2 * deltav * deltav;
590 for (
double u = 0; u < width; ++u) {
592 double deltau = u - u0;
594 double fr2 = fr1 + kud_px2 * deltau * deltau;
596 double u_double = deltau * fr2 + u0;
597 double v_double = deltav * fr2 + v0;
602 int u_round = (int)(u_double);
603 int v_round = (int)(v_double);
608 double du_double = (u_double)-(
double)u_round;
609 double dv_double = (v_double)-(
double)v_round;
612 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
614 const Type *_mp = &src[v_round * width + u_round];
615 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
617 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
618 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
653 template <
class Type>
655 unsigned int nThreads)
657 #if defined(VISP_HAVE_THREADS)
664 undistI.
resize(height, width);
669 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
675 unsigned int nthreads = nThreads;
676 std::vector<std::thread *> threadpool;
678 vpUndistortInternalType<Type> *undistortSharedData =
new vpUndistortInternalType<Type>[nthreads];
680 for (
unsigned int i = 0; i < nthreads; ++i) {
683 undistortSharedData[i].src = I.
bitmap;
684 undistortSharedData[i].dst = undistI.
bitmap;
685 undistortSharedData[i].width = I.
getWidth();
686 undistortSharedData[i].height = I.
getHeight();
687 undistortSharedData[i].cam = cam;
688 undistortSharedData[i].nthreads = nthreads;
689 undistortSharedData[i].threadid = i;
690 std::thread *undistort_thread =
new std::thread(&vpUndistortInternalType<Type>::vpUndistort_threaded, std::ref(undistortSharedData[i]));
691 threadpool.push_back(undistort_thread);
695 for (
unsigned int i = 0; i < nthreads; ++i) {
697 threadpool[i]->join();
700 for (
unsigned int i = 0; i < nthreads; ++i) {
701 delete threadpool[i];
704 delete[] undistortSharedData;
713 undistI.
resize(height, width);
722 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
728 double invpx = 1.0 / px;
729 double invpy = 1.0 / py;
731 double kud_px2 = kud * invpx * invpx;
732 double kud_py2 = kud * invpy * invpy;
734 Type *dst = undistI.
bitmap;
735 for (
double v = 0; v < height; ++v) {
736 double deltav = v - v0;
738 double fr1 = 1.0 + kud_py2 * deltav * deltav;
740 for (
double u = 0; u < width; ++u) {
742 double deltau = u - u0;
744 double fr2 = fr1 + kud_px2 * deltau * deltau;
746 double u_double = deltau * fr2 + u0;
747 double v_double = deltav * fr2 + v0;
754 int u_round = (int)(u_double);
755 int v_round = (int)(v_double);
760 double du_double = (u_double)-(
double)u_round;
761 double dv_double = (v_double)-(
double)v_round;
764 if ((0 <= u_round) && (0 <= v_round) && (u_round < (((
int)width) - 1)) && (v_round < (((
int)height) - 1))) {
766 const Type *_mp = &I[(
unsigned int)v_round][(
unsigned int)u_round];
767 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
769 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
770 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
786 undistI.
resize(height, width);
800 for (
int v = 0; v < height; ++v) {
801 for (
int u = 0; u < height; ++u) {
802 double r2 =
vpMath::sqr((
static_cast<double>(u) - u0) / px) +
804 double u_double = (
static_cast<double>(u) - u0) * (1.0 + kd * r2) + u0;
805 double v_double = (
static_cast<double>(v) - v0) * (1.0 + kd * r2) + v0;
806 undistI[v][u] = I.getPixelBI((
float)u_double, (float)v_double);
826 template <
class Type>
830 remap(I, mapU, mapV, mapDu, mapDv, newI);
842 newI.
resize(height, width);
844 for (
unsigned int i = 0; i < height; ++i) {
845 memcpy(newI.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
886 for (
unsigned int i = 0; i < height / 2; ++i) {
887 memcpy(Ibuf.
bitmap, I.
bitmap + i * width, width *
sizeof(Type));
889 memcpy(I.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
890 memcpy(I.
bitmap + (height - 1 - i) * width, Ibuf.
bitmap, width *
sizeof(Type));
894 template <
class Type> Type vpImageTools::getPixelClamped(
const vpImage<Type> &I,
float u,
float v)
898 x = std::max<int>(0, std::min<int>(x,
static_cast<int>(I.
getWidth()) - 1));
899 y = std::max<int>(0, std::min<int>(y,
static_cast<int>(I.
getHeight()) - 1));
906 template <
class Type>
908 float v,
float xFrac,
float yFrac)
911 Type p00 = getPixelClamped(I, u - 1, v - 1);
912 Type p01 = getPixelClamped(I, u + 0, v - 1);
913 Type p02 = getPixelClamped(I, u + 1, v - 1);
914 Type p03 = getPixelClamped(I, u + 2, v - 1);
917 Type p10 = getPixelClamped(I, u - 1, v + 0);
918 Type p11 = getPixelClamped(I, u + 0, v + 0);
919 Type p12 = getPixelClamped(I, u + 1, v + 0);
920 Type p13 = getPixelClamped(I, u + 2, v + 0);
923 Type p20 = getPixelClamped(I, u - 1, v + 1);
924 Type p21 = getPixelClamped(I, u + 0, v + 1);
925 Type p22 = getPixelClamped(I, u + 1, v + 1);
926 Type p23 = getPixelClamped(I, u + 2, v + 1);
929 Type p30 = getPixelClamped(I, u - 1, v + 2);
930 Type p31 = getPixelClamped(I, u + 0, v + 2);
931 Type p32 = getPixelClamped(I, u + 1, v + 2);
932 Type p33 = getPixelClamped(I, u + 2, v + 2);
934 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
935 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
936 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
937 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
938 float value = cubicHermite(col0, col1, col2, col3, yFrac);
939 Ires[i][j] = vpMath::saturate<Type>(value);
944 float u,
float v,
float xFrac,
float yFrac)
947 vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
948 vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
949 vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
950 vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
953 vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
954 vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
955 vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
956 vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
959 vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
960 vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
961 vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
962 vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
965 vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
966 vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
967 vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
968 vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
970 for (
int c = 0; c < 3; ++c) {
971 float col0 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p00)[c]),
972 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p01)[c]),
973 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p02)[c]),
974 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p03)[c]), xFrac);
975 float col1 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p10)[c]),
976 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p11)[c]),
977 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p12)[c]),
978 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p13)[c]), xFrac);
979 float col2 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p20)[c]),
980 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p21)[c]),
981 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p22)[c]),
982 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p23)[c]), xFrac);
983 float col3 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p30)[c]),
984 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p31)[c]),
985 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p32)[c]),
986 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p33)[c]), xFrac);
987 float value = cubicHermite(col0, col1, col2, col3, yFrac);
989 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
993 template <
class Type>
995 float v,
float xFrac,
float yFrac)
997 int u0 =
static_cast<int>(u);
998 int v0 =
static_cast<int>(v);
1000 int u1 = std::min<int>(
static_cast<int>(I.
getWidth()) - 1, u0 + 1);
1004 int v2 = std::min<int>(
static_cast<int>(I.
getHeight()) - 1, v0 + 1);
1009 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
1010 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
1011 float value = lerp(col0, col1, yFrac);
1013 Ires[i][j] = vpMath::saturate<Type>(value);
1018 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
1020 int u0 =
static_cast<int>(u);
1021 int v0 =
static_cast<int>(v);
1023 int u1 = std::min<int>(
static_cast<int>(I.
getWidth()) - 1, u0 + 1);
1027 int v2 = std::min<int>(
static_cast<int>(I.
getHeight()) - 1, v0 + 1);
1032 for (
int c = 0; c < 3; ++c) {
1033 float col0 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v0][u0])[c]),
1034 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v1][u1])[c]), xFrac);
1035 float col1 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v2][u2])[c]),
1036 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v3][u3])[c]), xFrac);
1037 float value = lerp(col0, col1, yFrac);
1039 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1043 template <
class Type>
1047 Ires[i][j] = getPixelClamped(I, u, v);
1068 template <
class Type>
1072 Ires.
resize(height, width);
1094 template <
class Type>
1097 #
if defined(_OPENMP)
1103 std::cerr <<
"Input or output image is too small!" << std::endl;
1108 std::cerr <<
"INTERPOLATION_AREA is not implemented for this type." << std::endl;
1114 const float half = 0.5f;
1116 #if defined(_OPENMP)
1118 omp_set_num_threads(
static_cast<int>(nThreads));
1120 #pragma omp parallel for schedule(dynamic)
1122 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); ++i) {
1123 const float v = (i + half) * scaleY - half;
1124 const float v0 = std::floor(v);
1125 const float yFrac = v - v0;
1127 for (
unsigned int j = 0; j < Ires.
getWidth(); ++j) {
1128 const float u = (j + half) * scaleX - half;
1129 const float u0 = std::floor(u);
1130 const float xFrac = u - u0;
1133 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1136 resizeBilinear(I, Ires,
static_cast<unsigned int>(i), j, u0, v0, xFrac, yFrac);
1139 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1145 #if defined(VISP_HAVE_SIMDLIB)
1150 #
if defined(_OPENMP)
1156 std::cerr <<
"Input or output image is too small!" << std::endl;
1169 const float half = 0.5f;
1171 #if defined(_OPENMP)
1173 omp_set_num_threads(
static_cast<int>(nThreads));
1175 #pragma omp parallel for schedule(dynamic)
1177 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); ++i) {
1178 float v = (i + half) * scaleY - half;
1179 float yFrac = v -
static_cast<int>(v);
1181 for (
unsigned int j = 0; j < Ires.
getWidth(); ++j) {
1182 float u = (j + half) * scaleX - half;
1183 float xFrac = u -
static_cast<int>(u);
1186 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1189 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1200 #
if defined(_OPENMP)
1206 std::cerr <<
"Input or output image is too small!" << std::endl;
1219 const float half = 0.5f;
1221 #if defined(_OPENMP)
1223 omp_set_num_threads(
static_cast<int>(nThreads));
1225 #pragma omp parallel for schedule(dynamic)
1227 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); ++i) {
1228 float v = (i + half) * scaleY - half;
1229 float yFrac = v -
static_cast<int>(v);
1231 for (
unsigned int j = 0; j < Ires.
getWidth(); ++j) {
1232 float u = (j + half) * scaleX - half;
1233 float xFrac = u -
static_cast<int>(u);
1236 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1239 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1261 template <
class Type>
1266 std::cerr <<
"Input transformation must be a (2x3) or (3x3) matrix." << std::endl;
1274 const bool affine = (T.
getRows() == 2);
1283 double D = M[0][0] * M[1][1] - M[0][1] * M[1][0];
1284 D = !
vpMath::nul(D, std::numeric_limits<double>::epsilon()) ? 1.0 / D : 0;
1285 double A11 = M[1][1] * D, A22 = M[0][0] * D;
1290 double b1 = -M[0][0] * M[0][2] - M[0][1] * M[1][2];
1291 double b2 = -M[1][0] * M[0][2] - M[1][1] * M[1][2];
1299 if (fixedPointArithmetic && !pixelCenter) {
1300 fixedPointArithmetic = checkFixedPoint(0, 0, M, affine) && checkFixedPoint(dst.
getWidth() - 1, 0, M, affine) &&
1301 checkFixedPoint(0, dst.
getHeight() - 1, M, affine) &&
1307 warpNN(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1311 warpLinear(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1315 template <
class Type>
1317 bool centerCorner,
bool fixedPoint)
1319 if (fixedPoint && !centerCorner) {
1320 const int nbits = 16;
1321 const int32_t precision = 1 << nbits;
1322 const float precision_1 = 1 /
static_cast<float>(precision);
1324 int32_t a0_i32 =
static_cast<int32_t
>(T[0][0] * precision);
1325 int32_t a1_i32 =
static_cast<int32_t
>(T[0][1] * precision);
1326 int32_t a2_i32 =
static_cast<int32_t
>(T[0][2] * precision);
1327 int32_t a3_i32 =
static_cast<int32_t
>(T[1][0] * precision);
1328 int32_t a4_i32 =
static_cast<int32_t
>(T[1][1] * precision);
1329 int32_t a5_i32 =
static_cast<int32_t
>(T[1][2] * precision);
1330 int32_t a6_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][0] * precision) : 0;
1331 int32_t a7_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][1] * precision) : 0;
1332 int32_t a8_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][2] * precision) : 1;
1334 int32_t height_1_i32 =
static_cast<int32_t
>((src.
getHeight() - 1) * precision) + 0x8000;
1335 int32_t width_1_i32 =
static_cast<int32_t
>((src.
getWidth() - 1) * precision) + 0x8000;
1338 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1339 int32_t xi = a2_i32;
1340 int32_t yi = a5_i32;
1342 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1343 if (yi >= 0 && yi < height_1_i32 && xi >= 0 && xi < width_1_i32) {
1344 float x_ = (xi >> nbits) + (xi & 0xFFFF) * precision_1;
1345 float y_ = (yi >> nbits) + (yi & 0xFFFF) * precision_1;
1349 dst[i][j] = src[y][x];
1361 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1362 int64_t xi = a2_i32;
1363 int64_t yi = a5_i32;
1364 int64_t wi = a8_i32;
1366 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1367 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1368 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1369 float w_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1370 float x_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / w_;
1371 float y_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / w_;
1376 dst[i][j] = src[y][x];
1391 double a0 = T[0][0];
1392 double a1 = T[0][1];
1393 double a2 = T[0][2];
1394 double a3 = T[1][0];
1395 double a4 = T[1][1];
1396 double a5 = T[1][2];
1397 double a6 = affine ? 0.0 : T[2][0];
1398 double a7 = affine ? 0.0 : T[2][1];
1399 double a8 = affine ? 1.0 : T[2][2];
1401 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1402 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1403 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1404 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1405 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1407 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1411 int x_ = centerCorner ? coordCast(x / w) :
vpMath::round(x / w);
1412 int y_ = centerCorner ? coordCast(y / w) :
vpMath::round(y / w);
1414 if (x_ >= 0 && x_ <
static_cast<int>(src.
getWidth()) && y_ >= 0 && y_ <
static_cast<int>(src.
getHeight())) {
1415 dst[i][j] = src[y_][x_];
1422 template <
class Type>
1424 bool centerCorner,
bool fixedPoint)
1426 if (fixedPoint && !centerCorner) {
1427 const int nbits = 16;
1428 const int64_t precision = 1 << nbits;
1429 const float precision_1 = 1 /
static_cast<float>(precision);
1430 const int64_t precision2 = 1ULL << (2 * nbits);
1431 const float precision_2 = 1 /
static_cast<float>(precision2);
1433 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1434 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1435 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1436 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1437 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1438 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1439 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1440 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1441 int64_t a8_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][2] * precision) : 1;
1443 int64_t height_i64 =
static_cast<int64_t
>(src.
getHeight() * precision);
1444 int64_t width_i64 =
static_cast<int64_t
>(src.
getWidth() * precision);
1447 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1448 int64_t xi_ = a2_i64;
1449 int64_t yi_ = a5_i64;
1451 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1452 if (yi_ >= 0 && yi_ < height_i64 && xi_ >= 0 && xi_ < width_i64) {
1453 const int64_t xi_lower = xi_ & (~0xFFFF);
1454 const int64_t yi_lower = yi_ & (~0xFFFF);
1456 const int64_t t = yi_ - yi_lower;
1457 const int64_t t_1 = precision - t;
1458 const int64_t s = xi_ - xi_lower;
1459 const int64_t s_1 = precision - s;
1461 const int x_ =
static_cast<int>(xi_ >> nbits);
1462 const int y_ =
static_cast<int>(yi_ >> nbits);
1464 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1465 const Type val00 = src[y_][x_];
1466 const Type val01 = src[y_][x_ + 1];
1467 const Type val10 = src[y_ + 1][x_];
1468 const Type val11 = src[y_ + 1][x_ + 1];
1469 const int64_t interp_i64 =
1470 static_cast<int64_t
>(s_1 * t_1 * val00 + s * t_1 * val01 + s_1 * t * val10 + s * t * val11);
1471 const float interp = (interp_i64 >> (nbits * 2)) + (interp_i64 & 0xFFFFFFFF) * precision_2;
1472 dst[i][j] = vpMath::saturate<Type>(interp);
1474 else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1475 const Type val00 = src[y_][x_];
1476 const Type val10 = src[y_ + 1][x_];
1477 const int64_t interp_i64 =
static_cast<int64_t
>(t_1 * val00 + t * val10);
1478 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1479 dst[i][j] = vpMath::saturate<Type>(interp);
1481 else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1482 const Type val00 = src[y_][x_];
1483 const Type val01 = src[y_][x_ + 1];
1484 const int64_t interp_i64 =
static_cast<int64_t
>(s_1 * val00 + s * val01);
1485 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1486 dst[i][j] = vpMath::saturate<Type>(interp);
1489 dst[i][j] = src[y_][x_];
1502 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1503 int64_t xi = a2_i64;
1504 int64_t yi = a5_i64;
1505 int64_t wi = a8_i64;
1507 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1508 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1509 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1510 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1511 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1512 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1514 const int x_ =
static_cast<int>(xi_);
1515 const int y_ =
static_cast<int>(yi_);
1517 const float t = yi_ - y_;
1518 const float s = xi_ - x_;
1520 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1521 const float val00 =
static_cast<float>(src[y_][x_]);
1522 const float val01 =
static_cast<float>(src[y_][x_ + 1]);
1523 const float val10 =
static_cast<float>(src[y_ + 1][x_]);
1524 const float val11 =
static_cast<float>(src[y_ + 1][x_ + 1]);
1525 const float col0 = lerp(val00, val01, s);
1526 const float col1 = lerp(val10, val11, s);
1527 const float interp = lerp(col0, col1, t);
1528 dst[i][j] = vpMath::saturate<Type>(interp);
1530 else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1531 const float val00 =
static_cast<float>(src[y_][x_]);
1532 const float val10 =
static_cast<float>(src[y_ + 1][x_]);
1533 const float interp = lerp(val00, val10, t);
1534 dst[i][j] = vpMath::saturate<Type>(interp);
1536 else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1537 const float val00 =
static_cast<float>(src[y_][x_]);
1538 const float val01 =
static_cast<float>(src[y_][x_ + 1]);
1539 const float interp = lerp(val00, val01, s);
1540 dst[i][j] = vpMath::saturate<Type>(interp);
1543 dst[i][j] = src[y_][x_];
1559 double a0 = T[0][0];
1560 double a1 = T[0][1];
1561 double a2 = T[0][2];
1562 double a3 = T[1][0];
1563 double a4 = T[1][1];
1564 double a5 = T[1][2];
1565 double a6 = affine ? 0.0 : T[2][0];
1566 double a7 = affine ? 0.0 : T[2][1];
1567 double a8 = affine ? 1.0 : T[2][2];
1569 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1570 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1571 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1572 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1573 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1574 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1578 x = x / w - (centerCorner ? 0.5 : 0);
1579 y = y / w - (centerCorner ? 0.5 : 0);
1581 int x_lower =
static_cast<int>(x);
1582 int y_lower =
static_cast<int>(y);
1584 if (y_lower >=
static_cast<int>(src.
getHeight()) || x_lower >=
static_cast<int>(src.
getWidth()) || y < 0 ||
1589 double s = x - x_lower;
1590 double t = y - y_lower;
1592 if (y_lower <
static_cast<int>(src.
getHeight()) - 1 && x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1593 const double val00 =
static_cast<double>(src[y_lower][x_lower]);
1594 const double val01 =
static_cast<double>(src[y_lower][x_lower + 1]);
1595 const double val10 =
static_cast<double>(src[y_lower + 1][x_lower]);
1596 const double val11 =
static_cast<double>(src[y_lower + 1][x_lower + 1]);
1597 const double col0 = lerp(val00, val01, s);
1598 const double col1 = lerp(val10, val11, s);
1599 const double interp = lerp(col0, col1, t);
1600 dst[i][j] = vpMath::saturate<Type>(interp);
1602 else if (y_lower <
static_cast<int>(src.
getHeight()) - 1) {
1603 const double val00 =
static_cast<double>(src[y_lower][x_lower]);
1604 const double val10 =
static_cast<double>(src[y_lower + 1][x_lower]);
1605 const double interp = lerp(val00, val10, t);
1606 dst[i][j] = vpMath::saturate<Type>(interp);
1608 else if (x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1609 const double val00 =
static_cast<double>(src[y_lower][x_lower]);
1610 const double val01 =
static_cast<double>(src[y_lower][x_lower + 1]);
1611 const double interp = lerp(val00, val01, s);
1612 dst[i][j] = vpMath::saturate<Type>(interp);
1615 dst[i][j] = src[y_lower][x_lower];
1624 bool centerCorner,
bool fixedPoint)
1626 if (fixedPoint && !centerCorner) {
1627 const int nbits = 16;
1628 const int64_t precision = 1 << nbits;
1629 const float precision_1 = 1 /
static_cast<float>(precision);
1630 const int64_t precision2 = 1ULL << (2 * nbits);
1631 const float precision_2 = 1 /
static_cast<float>(precision2);
1633 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1634 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1635 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1636 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1637 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1638 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1639 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1640 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1641 int64_t a8_i64 = precision;
1643 int64_t height_i64 =
static_cast<int64_t
>(src.
getHeight() * precision);
1644 int64_t width_i64 =
static_cast<int64_t
>(src.
getWidth() * precision);
1647 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1648 int64_t xi = a2_i64;
1649 int64_t yi = a5_i64;
1651 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1652 if (yi >= 0 && yi < height_i64 && xi >= 0 && xi < width_i64) {
1653 const int64_t xi_lower = xi & (~0xFFFF);
1654 const int64_t yi_lower = yi & (~0xFFFF);
1656 const int64_t t = yi - yi_lower;
1657 const int64_t t_1 = precision - t;
1658 const int64_t s = xi - xi_lower;
1659 const int64_t s_1 = precision - s;
1661 const int x_ =
static_cast<int>(xi >> nbits);
1662 const int y_ =
static_cast<int>(yi >> nbits);
1664 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1665 const vpRGBa val00 = src[y_][x_];
1666 const vpRGBa val01 = src[y_][x_ + 1];
1667 const vpRGBa val10 = src[y_ + 1][x_];
1668 const vpRGBa val11 = src[y_ + 1][x_ + 1];
1669 const int64_t interpR_i64 =
1670 static_cast<int64_t
>(s_1 * t_1 * val00.
R + s * t_1 * val01.
R + s_1 * t * val10.
R + s * t * val11.
R);
1671 const float interpR = (interpR_i64 >> (nbits * 2)) + (interpR_i64 & 0xFFFFFFFF) * precision_2;
1673 const int64_t interpG_i64 =
1674 static_cast<int64_t
>(s_1 * t_1 * val00.
G + s * t_1 * val01.
G + s_1 * t * val10.
G + s * t * val11.
G);
1675 const float interpG = (interpG_i64 >> (nbits * 2)) + (interpG_i64 & 0xFFFFFFFF) * precision_2;
1677 const int64_t interpB_i64 =
1678 static_cast<int64_t
>(s_1 * t_1 * val00.
B + s * t_1 * val01.
B + s_1 * t * val10.
B + s * t * val11.
B);
1679 const float interpB = (interpB_i64 >> (nbits * 2)) + (interpB_i64 & 0xFFFFFFFF) * precision_2;
1681 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1682 vpMath::saturate<unsigned char>(interpB), 255);
1684 else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1685 const vpRGBa val00 = src[y_][x_];
1686 const vpRGBa val10 = src[y_ + 1][x_];
1687 const int64_t interpR_i64 =
static_cast<int64_t
>(t_1 * val00.
R + t * val10.
R);
1688 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1690 const int64_t interpG_i64 =
static_cast<int64_t
>(t_1 * val00.
G + t * val10.
G);
1691 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1693 const int64_t interpB_i64 =
static_cast<int64_t
>(t_1 * val00.
B + t * val10.
B);
1694 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1696 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1697 vpMath::saturate<unsigned char>(interpB), 255);
1699 else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1700 const vpRGBa val00 = src[y_][x_];
1701 const vpRGBa val01 = src[y_][x_ + 1];
1702 const int64_t interpR_i64 =
static_cast<int64_t
>(s_1 * val00.
R + s * val01.
R);
1703 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1705 const int64_t interpG_i64 =
static_cast<int64_t
>(s_1 * val00.
G + s * val01.
G);
1706 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1708 const int64_t interpB_i64 =
static_cast<int64_t
>(s_1 * val00.
B + s * val01.
B);
1709 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1711 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1712 vpMath::saturate<unsigned char>(interpB), 255);
1715 dst[i][j] = src[y_][x_];
1728 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1729 int64_t xi = a2_i64;
1730 int64_t yi = a5_i64;
1731 int64_t wi = a8_i64;
1733 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1734 if (yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1735 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1736 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1737 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1738 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1740 const int x_ =
static_cast<int>(xi_);
1741 const int y_ =
static_cast<int>(yi_);
1743 const float t = yi_ - y_;
1744 const float s = xi_ - x_;
1746 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1747 const vpRGBa val00 = src[y_][x_];
1748 const vpRGBa val01 = src[y_][x_ + 1];
1749 const vpRGBa val10 = src[y_ + 1][x_];
1750 const vpRGBa val11 = src[y_ + 1][x_ + 1];
1751 const float colR0 = lerp(val00.
R, val01.
R, s);
1752 const float colR1 = lerp(val10.
R, val11.
R, s);
1753 const float interpR = lerp(colR0, colR1, t);
1755 const float colG0 = lerp(val00.
G, val01.
G, s);
1756 const float colG1 = lerp(val10.
G, val11.
G, s);
1757 const float interpG = lerp(colG0, colG1, t);
1759 const float colB0 = lerp(val00.
B, val01.
B, s);
1760 const float colB1 = lerp(val10.
B, val11.
B, s);
1761 const float interpB = lerp(colB0, colB1, t);
1763 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1764 vpMath::saturate<unsigned char>(interpB), 255);
1766 else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1767 const vpRGBa val00 = src[y_][x_];
1768 const vpRGBa val10 = src[y_ + 1][x_];
1769 const float interpR = lerp(val00.
R, val10.
R, t);
1770 const float interpG = lerp(val00.
G, val10.
G, t);
1771 const float interpB = lerp(val00.
B, val10.
B, t);
1773 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1774 vpMath::saturate<unsigned char>(interpB), 255);
1776 else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1777 const vpRGBa val00 = src[y_][x_];
1778 const vpRGBa val01 = src[y_][x_ + 1];
1779 const float interpR = lerp(val00.
R, val01.
R, s);
1780 const float interpG = lerp(val00.
G, val01.
G, s);
1781 const float interpB = lerp(val00.
B, val01.
B, s);
1783 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1784 vpMath::saturate<unsigned char>(interpB), 255);
1787 dst[i][j] = src[y_][x_];
1803 double a0 = T[0][0];
1804 double a1 = T[0][1];
1805 double a2 = T[0][2];
1806 double a3 = T[1][0];
1807 double a4 = T[1][1];
1808 double a5 = T[1][2];
1809 double a6 = affine ? 0.0 : T[2][0];
1810 double a7 = affine ? 0.0 : T[2][1];
1811 double a8 = affine ? 1.0 : T[2][2];
1813 for (
unsigned int i = 0; i < dst.
getHeight(); ++i) {
1814 for (
unsigned int j = 0; j < dst.
getWidth(); ++j) {
1815 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1816 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1817 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1819 x = x / w - (centerCorner ? 0.5 : 0);
1820 y = y / w - (centerCorner ? 0.5 : 0);
1822 int x_lower =
static_cast<int>(x);
1823 int y_lower =
static_cast<int>(y);
1825 if (y_lower >=
static_cast<int>(src.
getHeight()) || x_lower >=
static_cast<int>(src.
getWidth()) || y < 0 ||
1830 double s = x - x_lower;
1831 double t = y - y_lower;
1833 if (y_lower <
static_cast<int>(src.
getHeight()) - 1 && x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1834 const vpRGBa val00 = src[y_lower][x_lower];
1835 const vpRGBa val01 = src[y_lower][x_lower + 1];
1836 const vpRGBa val10 = src[y_lower + 1][x_lower];
1837 const vpRGBa val11 = src[y_lower + 1][x_lower + 1];
1838 const double colR0 = lerp(val00.
R, val01.
R, s);
1839 const double colR1 = lerp(val10.
R, val11.
R, s);
1840 const double interpR = lerp(colR0, colR1, t);
1842 const double colG0 = lerp(val00.
G, val01.
G, s);
1843 const double colG1 = lerp(val10.
G, val11.
G, s);
1844 const double interpG = lerp(colG0, colG1, t);
1846 const double colB0 = lerp(val00.
B, val01.
B, s);
1847 const double colB1 = lerp(val10.
B, val11.
B, s);
1848 const double interpB = lerp(colB0, colB1, t);
1850 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1851 vpMath::saturate<unsigned char>(interpB), 255);
1853 else if (y_lower <
static_cast<int>(src.
getHeight()) - 1) {
1854 const vpRGBa val00 = src[y_lower][x_lower];
1855 const vpRGBa val10 = src[y_lower + 1][x_lower];
1856 const double interpR = lerp(val00.
R, val10.
R, t);
1857 const double interpG = lerp(val00.
G, val10.
G, t);
1858 const double interpB = lerp(val00.
B, val10.
B, t);
1860 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1861 vpMath::saturate<unsigned char>(interpB), 255);
1863 else if (x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1864 const vpRGBa val00 = src[y_lower][x_lower];
1865 const vpRGBa val01 = src[y_lower][x_lower + 1];
1866 const double interpR = lerp(val00.
R, val01.
R, s);
1867 const double interpG = lerp(val00.
G, val01.
G, s);
1868 const double interpB = lerp(val00.
B, val01.
B, s);
1870 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1871 vpMath::saturate<unsigned char>(interpB), 255);
1874 dst[i][j] = src[y_lower][x_lower];
Implementation of a generic 2D array used as base class for matrices and vectors.
unsigned int getCols() const
unsigned int getRows() const
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
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
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
unsigned int getSize() const
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
Provides simple mathematics computation tools that are not available in the C mathematics library (ma...
static double sqr(double x)
static bool nul(double x, double threshold=0.001)
static int round(double x)
Implementation of a matrix and operations on matrices.
vpMatrix inverseByLU() const
unsigned char B
Blue component.
unsigned char R
Red component.
unsigned char G
Green component.
Defines an oriented rectangle in the plane.
Defines a rectangle in the plane.
Implementation of row vector and the associated operations.