39 #ifndef vpImageTools_H
40 #define vpImageTools_H
49 #include <visp3/core/vpImage.h>
51 #ifdef VISP_HAVE_PTHREAD
55 #include <visp3/core/vpCameraParameters.h>
56 #include <visp3/core/vpImageException.h>
57 #include <visp3/core/vpMath.h>
58 #include <visp3/core/vpRect.h>
59 #include <visp3/core/vpRectOriented.h>
89 static inline void binarise(
vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
95 static void crop(
const vpImage<Type> &I,
double roi_top,
double roi_left,
unsigned int roi_height,
96 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
100 template <
class Type>
102 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
103 template <
class Type>
105 unsigned int h_scale = 1);
106 template <
class Type>
107 static void crop(
const unsigned char *bitmap,
unsigned int width,
unsigned int height,
const vpRect &roi,
108 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
127 bool saturate =
false);
132 static void initUndistortMap(
const vpCameraParameters &cam,
unsigned int width,
unsigned int height,
137 const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
142 bool useOptimized =
true);
151 template <
class Type>
153 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads=0);
155 template <
class Type>
157 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads=0);
161 bool useOptimized =
true);
163 template <
class Type>
165 unsigned int nThreads=2);
167 template <
class Type>
169 const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST,
170 bool fixedPointArithmetic=
true,
bool pixelCenter=
false);
172 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
177 template <
class Type>
178 vp_deprecated
static void createSubImage(
const vpImage<Type> &I,
unsigned int i_sub,
unsigned int j_sub,
179 unsigned int nrow_sub,
unsigned int ncol_sub,
vpImage<Type> &S);
181 template <
class Type>
188 static float cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t);
190 template <
class Type>
static Type getPixelClamped(
const vpImage<Type> &I,
float u,
float v);
192 static int coordCast(
double x);
195 static double lerp(
double A,
double B,
double t);
196 static float lerp(
float A,
float B,
float t);
197 static int64_t lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1);
203 template <
class Type>
205 float u,
float v,
float xFrac,
float yFrac);
207 template <
class Type>
209 float u,
float v,
float xFrac,
float yFrac);
211 template <
class Type>
215 template <
class Type>
218 template <
class Type>
221 static bool checkFixedPoint(
unsigned int x,
unsigned int y,
const vpMatrix &T,
bool affine);
224 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
244 template <
class Type>
246 unsigned int roi_height,
unsigned int roi_width,
vpImage<Type> &crop)
271 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
295 template <
class Type>
297 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
299 int i_min = (std::max)((
int)(ceil(roi_top / v_scale)), 0);
300 int j_min = (std::max)((
int)(ceil(roi_left / h_scale)), 0);
301 int i_max = (std::min)((
int)(ceil((roi_top + roi_height)) / v_scale), (
int)(I.
getHeight() / v_scale));
302 int j_max = (std::min)((
int)(ceil((roi_left + roi_width) / h_scale)), (
int)(I.
getWidth() / h_scale));
304 unsigned int i_min_u = (
unsigned int)i_min;
305 unsigned int j_min_u = (
unsigned int)j_min;
307 unsigned int r_width = (
unsigned int)(j_max - j_min);
308 unsigned int r_height = (
unsigned int)(i_max - i_min);
310 crop.resize(r_height, r_width);
312 if (v_scale == 1 && h_scale == 1) {
313 for (
unsigned int i = 0; i < r_height; i++) {
314 void *src = (
void *)(I[i + i_min_u] + j_min_u);
315 void *dst = (
void *)
crop[i];
316 memcpy(dst, src, r_width *
sizeof(Type));
318 }
else if (h_scale == 1) {
319 for (
unsigned int i = 0; i < r_height; i++) {
320 void *src = (
void *)(I[(i + i_min_u) * v_scale] + j_min_u);
321 void *dst = (
void *)
crop[i];
322 memcpy(dst, src, r_width *
sizeof(Type));
325 for (
unsigned int i = 0; i < r_height; i++) {
326 for (
unsigned int j = 0; j < r_width; j++) {
327 crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
351 template <
class Type>
353 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
375 template <
class Type>
377 unsigned int h_scale)
400 template <
class Type>
402 vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
404 int i_min = (std::max)((
int)(ceil(roi.
getTop() / v_scale)), 0);
405 int j_min = (std::max)((
int)(ceil(roi.
getLeft() / h_scale)), 0);
406 int i_max = (std::min)((
int)(ceil((roi.
getTop() + roi.
getHeight()) / v_scale)), (
int)(height / v_scale));
407 int j_max = (std::min)((
int)(ceil((roi.
getLeft() + roi.
getWidth()) / h_scale)), (
int)(width / h_scale));
409 unsigned int i_min_u = (
unsigned int)i_min;
410 unsigned int j_min_u = (
unsigned int)j_min;
412 unsigned int r_width = (
unsigned int)(j_max - j_min);
413 unsigned int r_height = (
unsigned int)(i_max - i_min);
415 crop.resize(r_height, r_width);
417 if (v_scale == 1 && h_scale == 1) {
418 for (
unsigned int i = 0; i < r_height; i++) {
419 void *src = (
void *)(bitmap + ((i + i_min_u) * width + j_min_u) *
sizeof(Type));
420 void *dst = (
void *)
crop[i];
421 memcpy(dst, src, r_width *
sizeof(Type));
423 }
else if (h_scale == 1) {
424 for (
unsigned int i = 0; i < r_height; i++) {
425 void *src = (
void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) *
sizeof(Type));
426 void *dst = (
void *)
crop[i];
427 memcpy(dst, src, r_width *
sizeof(Type));
430 for (
unsigned int i = 0; i < r_height; i++) {
431 unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
432 for (
unsigned int j = 0; j < r_width; j++) {
433 void *src = (
void *)(bitmap + (i_src + j * h_scale) *
sizeof(Type));
434 void *dst = (
void *)&
crop[i][j];
435 memcpy(dst, src,
sizeof(Type));
451 template <
class Type>
453 Type value3,
bool useLUT)
456 std::cerr <<
"LUT not available for this type ! Will use the iteration method." << std::endl;
462 for (; p < pend; p++) {
466 else if (v > threshold2)
485 unsigned char value1,
unsigned char value2,
unsigned char value3,
bool useLUT)
489 unsigned char lut[256];
490 for (
unsigned int i = 0; i < 256; i++) {
491 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
496 unsigned char *p = I.
bitmap;
498 for (; p < pend; p++) {
499 unsigned char v = *p;
502 else if (v > threshold2)
510 #ifdef VISP_HAVE_PTHREAD
512 #ifndef DOXYGEN_SHOULD_SKIP_THIS
513 template <
class Type>
class vpUndistortInternalType
521 unsigned int nthreads;
522 unsigned int threadid;
525 vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0) {}
527 vpUndistortInternalType(
const vpUndistortInternalType<Type> &u) { *
this = u; }
528 vpUndistortInternalType &operator=(
const vpUndistortInternalType<Type> &u)
535 nthreads = u.nthreads;
536 threadid = u.threadid;
541 static void *vpUndistort_threaded(
void *arg);
544 template <
class Type>
void *vpUndistortInternalType<Type>::vpUndistort_threaded(
void *arg)
546 vpUndistortInternalType<Type> *undistortSharedData =
static_cast<vpUndistortInternalType<Type> *
>(arg);
547 int offset = (int)undistortSharedData->threadid;
548 int width = (
int)undistortSharedData->width;
549 int height = (int)undistortSharedData->height;
550 int nthreads = (
int)undistortSharedData->nthreads;
552 double u0 = undistortSharedData->cam.get_u0();
553 double v0 = undistortSharedData->cam.get_v0();
554 double px = undistortSharedData->cam.get_px();
555 double py = undistortSharedData->cam.get_py();
556 double kud = undistortSharedData->cam.get_kud();
558 double invpx = 1.0 / px;
559 double invpy = 1.0 / py;
561 double kud_px2 = kud * invpx * invpx;
562 double kud_py2 = kud * invpy * invpy;
564 Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
565 Type *src = undistortSharedData->src;
567 for (
double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
568 double deltav = v - v0;
570 double fr1 = 1.0 + kud_py2 * deltav * deltav;
572 for (
double u = 0; u < width; u++) {
574 double deltau = u - u0;
576 double fr2 = fr1 + kud_px2 * deltau * deltau;
578 double u_double = deltau * fr2 + u0;
579 double v_double = deltav * fr2 + v0;
584 int u_round = (int)(u_double);
585 int v_round = (int)(v_double);
590 double du_double = (u_double) - (
double)u_round;
591 double dv_double = (v_double) - (
double)v_round;
594 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
596 const Type *_mp = &src[v_round * width + u_round];
597 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
599 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
600 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
608 pthread_exit((
void *)0);
611 #endif // DOXYGEN_SHOULD_SKIP_THIS
612 #endif // VISP_HAVE_PTHREAD
640 template <
class Type>
642 unsigned int nThreads)
644 #ifdef VISP_HAVE_PTHREAD
651 undistI.
resize(height, width);
656 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
662 unsigned int nthreads = nThreads;
664 pthread_t *callThd =
new pthread_t[nthreads];
665 pthread_attr_init(&attr);
666 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
668 vpUndistortInternalType<Type> *undistortSharedData;
669 undistortSharedData =
new vpUndistortInternalType<Type>[nthreads];
671 for (
unsigned int i = 0; i < nthreads; i++) {
674 undistortSharedData[i].src = I.
bitmap;
675 undistortSharedData[i].dst = undistI.
bitmap;
676 undistortSharedData[i].width = I.
getWidth();
677 undistortSharedData[i].height = I.
getHeight();
678 undistortSharedData[i].cam = cam;
679 undistortSharedData[i].nthreads = nthreads;
680 undistortSharedData[i].threadid = i;
681 pthread_create(&callThd[i], &attr, &vpUndistortInternalType<Type>::vpUndistort_threaded, &undistortSharedData[i]);
683 pthread_attr_destroy(&attr);
686 for (
unsigned int i = 0; i < nthreads; i++) {
688 pthread_join(callThd[i], NULL);
692 delete[] undistortSharedData;
693 #else // VISP_HAVE_PTHREAD
701 undistI.
resize(height, width);
710 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
716 double invpx = 1.0 / px;
717 double invpy = 1.0 / py;
719 double kud_px2 = kud * invpx * invpx;
720 double kud_py2 = kud * invpy * invpy;
722 Type *dst = undistI.
bitmap;
723 for (
double v = 0; v < height; v++) {
724 double deltav = v - v0;
726 double fr1 = 1.0 + kud_py2 * deltav * deltav;
728 for (
double u = 0; u < width; u++) {
730 double deltau = u - u0;
732 double fr2 = fr1 + kud_px2 * deltau * deltau;
734 double u_double = deltau * fr2 + u0;
735 double v_double = deltav * fr2 + v0;
742 int u_round = (int)(u_double);
743 int v_round = (int)(v_double);
748 double du_double = (u_double) - (
double)u_round;
749 double dv_double = (v_double) - (
double)v_round;
752 if ((0 <= u_round) && (0 <= v_round) && (u_round < (((
int)width) - 1)) && (v_round < (((
int)height) - 1))) {
754 const Type *_mp = &I[(
unsigned int)v_round][(
unsigned int)u_round];
755 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
757 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
758 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
766 #endif // VISP_HAVE_PTHREAD
773 undistI.
resize(height,width);
787 for(
int v = 0 ; v < height; v++){
788 for(
int u = 0; u < height; u++){
791 double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
792 double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
793 undistI[v][u] = I.getPixelBI((
float)u_double,(float)v_double);
808 unsigned int height = 0, width = 0;
812 newI.
resize(height, width);
814 for (
unsigned int i = 0; i < height; i++) {
815 memcpy(newI.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
852 unsigned int height = 0, width = 0;
860 for (i = 0; i < height / 2; i++) {
861 memcpy(Ibuf.
bitmap, I.
bitmap + i * width, width *
sizeof(Type));
863 memcpy(I.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
864 memcpy(I.
bitmap + (height - 1 - i) * width, Ibuf.
bitmap, width *
sizeof(Type));
868 template <
class Type> Type vpImageTools::getPixelClamped(
const vpImage<Type> &I,
float u,
float v)
873 else if (u >
static_cast<float>(I.
getWidth()) - 1.f)
876 j =
static_cast<unsigned int>(u);
880 else if (v >
static_cast<float>(I.
getHeight()) - 1.f)
883 i =
static_cast<unsigned int>(v);
890 template <
class Type>
892 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
895 Type p00 = getPixelClamped(I, u - 1, v - 1);
896 Type p01 = getPixelClamped(I, u + 0, v - 1);
897 Type p02 = getPixelClamped(I, u + 1, v - 1);
898 Type p03 = getPixelClamped(I, u + 2, v - 1);
901 Type p10 = getPixelClamped(I, u - 1, v + 0);
902 Type p11 = getPixelClamped(I, u + 0, v + 0);
903 Type p12 = getPixelClamped(I, u + 1, v + 0);
904 Type p13 = getPixelClamped(I, u + 2, v + 0);
907 Type p20 = getPixelClamped(I, u - 1, v + 1);
908 Type p21 = getPixelClamped(I, u + 0, v + 1);
909 Type p22 = getPixelClamped(I, u + 1, v + 1);
910 Type p23 = getPixelClamped(I, u + 2, v + 1);
913 Type p30 = getPixelClamped(I, u - 1, v + 2);
914 Type p31 = getPixelClamped(I, u + 0, v + 2);
915 Type p32 = getPixelClamped(I, u + 1, v + 2);
916 Type p33 = getPixelClamped(I, u + 2, v + 2);
918 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
919 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
920 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
921 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
922 float value = cubicHermite(col0, col1, col2, col3, yFrac);
923 Ires[i][j] = vpMath::saturate<Type>(value);
928 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
931 vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
932 vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
933 vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
934 vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
937 vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
938 vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
939 vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
940 vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
943 vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
944 vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
945 vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
946 vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
949 vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
950 vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
951 vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
952 vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
954 for (
int c = 0; c < 3; c++) {
955 float col0 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p00)[c]),
956 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p01)[c]),
957 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p02)[c]),
958 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p03)[c]), xFrac);
959 float col1 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p10)[c]),
960 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p11)[c]),
961 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p12)[c]),
962 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p13)[c]), xFrac);
963 float col2 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p20)[c]),
964 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p21)[c]),
965 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p22)[c]),
966 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p23)[c]), xFrac);
967 float col3 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p30)[c]),
968 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p31)[c]),
969 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p32)[c]),
970 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p33)[c]), xFrac);
971 float value = cubicHermite(col0, col1, col2, col3, yFrac);
973 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
977 template <
class Type>
979 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
981 unsigned int u0 =
static_cast<unsigned int>(u);
982 unsigned int v0 =
static_cast<unsigned int>(v);
984 unsigned int u1 = (std::min)(I.
getWidth() - 1,
static_cast<unsigned int>(u) + 1);
985 unsigned int v1 = v0;
987 unsigned int u2 = u0;
988 unsigned int v2 = (std::min)(I.
getHeight() - 1,
static_cast<unsigned int>(v) + 1);
990 unsigned int u3 = u1;
991 unsigned int v3 = v2;
993 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
994 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
995 float value = lerp(col0, col1, yFrac);
997 Ires[i][j] = vpMath::saturate<Type>(value);
1002 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
1004 unsigned int u0 =
static_cast<unsigned int>(u);
1005 unsigned int v0 =
static_cast<unsigned int>(v);
1007 unsigned int u1 = (std::min)(I.
getWidth() - 1,
static_cast<unsigned int>(u) + 1);
1008 unsigned int v1 = v0;
1010 unsigned int u2 = u0;
1011 unsigned int v2 = (std::min)(I.
getHeight() - 1,
static_cast<unsigned int>(v) + 1);
1013 unsigned int u3 = (std::min)(I.
getWidth() - 1,
static_cast<unsigned int>(u) + 1);
1014 unsigned int v3 = (std::min)(I.
getHeight() - 1,
static_cast<unsigned int>(v) + 1);
1016 for (
int c = 0; c < 3; c++) {
1017 float col0 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v0][u0])[c]),
1018 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v1][u1])[c]), xFrac);
1019 float col1 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v2][u2])[c]),
1020 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v3][u3])[c]), xFrac);
1021 float value = lerp(col0, col1, yFrac);
1023 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1027 template <
class Type>
1029 unsigned int j,
float u,
float v)
1031 Ires[i][j] = getPixelClamped(I, u, v);
1047 template <
class Type>
1050 unsigned int nThreads)
1052 Ires.
resize(height, width);
1069 template <
class Type>
1078 std::cerr <<
"Input or output image is too small!" << std::endl;
1083 float scaleX = (I.
getWidth() - 1) /
static_cast<float>(Ires.
getWidth() - 1);
1092 omp_set_num_threads(
static_cast<int>(nThreads));
1094 #pragma omp parallel for schedule(dynamic)
1096 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1097 float v = i * scaleY;
1098 float yFrac = v -
static_cast<int>(v);
1100 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1101 float u = j * scaleX;
1102 float xFrac = u -
static_cast<int>(u);
1105 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1107 resizeBilinear(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1109 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1124 std::cerr <<
"Input or output image is too small!" << std::endl;
1130 float scaleX = (I.
getWidth() - 1) /
static_cast<float>(Ires.
getWidth() - 1);
1139 omp_set_num_threads(
static_cast<int>(nThreads));
1141 #pragma omp parallel for schedule(dynamic)
1143 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1144 float v = i * scaleY;
1145 float yFrac = v -
static_cast<int>(v);
1147 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1148 float u = j * scaleX;
1149 float xFrac = u -
static_cast<int>(u);
1152 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1154 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1159 const int precision = 1 << 16;
1160 int64_t scaleY =
static_cast<int64_t
>((I.
getHeight() - 1) /
static_cast<float>(Ires.
getHeight() - 1) * precision);
1161 int64_t scaleX =
static_cast<int64_t
>((I.
getWidth() - 1) /
static_cast<float>(Ires.
getWidth() - 1) * precision);
1165 omp_set_num_threads(
static_cast<int>(nThreads));
1167 #pragma omp parallel for schedule(dynamic)
1169 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1170 int64_t v = i * scaleY;
1171 int64_t vround = v & (~0xFFFF);
1172 int64_t rratio = v - vround;
1173 int64_t y_ = v >> 16;
1174 int64_t rfrac = precision - rratio;
1176 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1177 int64_t u = j * scaleX;
1178 int64_t uround = u & (~0xFFFF);
1179 int64_t cratio = u - uround;
1180 int64_t x_ = u >> 16;
1181 int64_t cfrac = precision - cratio;
1183 if (y_ + 1 <
static_cast<int64_t
>(I.
getHeight()) && x_ + 1 <
static_cast<int64_t
>(I.
getWidth())) {
1184 int64_t up = *
reinterpret_cast<uint16_t *
>(I.
bitmap + y_ * I.
getWidth() + x_);
1185 int64_t down = *
reinterpret_cast<uint16_t *
>(I.
bitmap + (y_ + 1) * I.
getWidth() + x_);
1187 Ires[i][j] =
static_cast<unsigned char>((((up & 0x00FF) * rfrac + (down & 0x00FF) * rratio) * cfrac +
1188 ((up >> 8) * rfrac + (down >> 8) * rratio) * cratio) >> 32);
1189 }
else if (y_ + 1 <
static_cast<int64_t
>(I.
getHeight())) {
1190 Ires[i][j] =
static_cast<unsigned char>(((*(I.
bitmap + y_ * I.
getWidth() + x_)
1191 * rfrac + *(I.
bitmap + (y_ + 1) * I.
getWidth() + x_) * rratio)) >> 16);
1192 }
else if (x_ + 1 <
static_cast<int64_t
>(I.
getWidth())) {
1193 uint16_t up = *
reinterpret_cast<uint16_t *
>(I.
bitmap + y_ * I.
getWidth() + x_);
1194 Ires[i][j] =
static_cast<unsigned char>(((up & 0x00FF) * cfrac + (up >> 8) * cratio) >> 16);
1212 std::cerr <<
"Input or output image is too small!" << std::endl;
1218 float scaleX = (I.
getWidth() - 1) /
static_cast<float>(Ires.
getWidth() - 1);
1227 omp_set_num_threads(
static_cast<int>(nThreads));
1229 #pragma omp parallel for schedule(dynamic)
1231 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1232 float v = i * scaleY;
1233 float yFrac = v -
static_cast<int>(v);
1235 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1236 float u = j * scaleX;
1237 float xFrac = u -
static_cast<int>(u);
1240 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1242 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1247 const int precision = 1 << 16;
1248 int64_t scaleY =
static_cast<int64_t
>((I.
getHeight() - 1) /
static_cast<float>(Ires.
getHeight() - 1) * precision);
1249 int64_t scaleX =
static_cast<int64_t
>((I.
getWidth() - 1) /
static_cast<float>(Ires.
getWidth() - 1) * precision);
1253 omp_set_num_threads(
static_cast<int>(nThreads));
1255 #pragma omp parallel for schedule(dynamic)
1257 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1258 int64_t v = i * scaleY;
1259 int64_t vround = v & (~0xFFFF);
1260 int64_t rratio = v - vround;
1261 int64_t y_ = v >> 16;
1262 int64_t rfrac = precision - rratio;
1264 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1265 int64_t u = j * scaleX;
1266 int64_t uround = u & (~0xFFFF);
1267 int64_t cratio = u - uround;
1268 int64_t x_ = u >> 16;
1269 int64_t cfrac = precision - cratio;
1271 if (y_ + 1 <
static_cast<int64_t
>(I.
getHeight()) && x_ + 1 <
static_cast<int64_t
>(I.
getWidth())) {
1274 int64_t valueR = lerp2(col0, col1, cratio, cfrac);
1278 int64_t valueG = lerp2(col0, col1, cratio, cfrac);
1282 int64_t valueB = lerp2(col0, col1, cratio, cfrac);
1284 Ires[i][j] =
vpRGBa(
static_cast<unsigned char>(valueR >> 32),
1285 static_cast<unsigned char>(valueG >> 32),
1286 static_cast<unsigned char>(valueB >> 32));
1287 }
else if (y_ + 1 <
static_cast<int64_t
>(I.
getHeight())) {
1292 Ires[i][j] =
vpRGBa(
static_cast<unsigned char>(valueR >> 16),
1293 static_cast<unsigned char>(valueG >> 16),
1294 static_cast<unsigned char>(valueB >> 16));
1295 }
else if (x_ + 1 <
static_cast<int64_t
>(I.
getWidth())) {
1296 int64_t valueR = lerp2((I.
bitmap + x_)->R, (I.
bitmap + x_ + 1)->R, cratio, cfrac);
1297 int64_t valueG = lerp2((I.
bitmap + x_)->G, (I.
bitmap + x_ + 1)->G, cratio, cfrac);
1298 int64_t valueB = lerp2((I.
bitmap + x_)->B, (I.
bitmap + x_ + 1)->B, cratio, cfrac);
1300 Ires[i][j] =
vpRGBa(
static_cast<unsigned char>(valueR >> 16),
1301 static_cast<unsigned char>(valueG >> 16),
1302 static_cast<unsigned char>(valueB >> 16));
1325 template <
class Type>
1328 bool fixedPointArithmetic,
bool pixelCenter)
1331 std::cerr <<
"Input transformation must be a (2x3) or (3x3) matrix." << std::endl;
1335 if (src.getSize() == 0) {
1339 const bool affine = (T.
getRows() == 2);
1342 if (dst.getSize() == 0) {
1343 dst.resize(src.getHeight(), src.getWidth(), Type(0));
1348 double D = M[0][0] * M[1][1] - M[0][1] * M[1][0];
1349 D = !
vpMath::nul(D, std::numeric_limits<double>::epsilon()) ? 1.0 / D : 0;
1350 double A11 = M[1][1] * D, A22 = M[0][0] * D;
1351 M[0][0] = A11; M[0][1] *= -D;
1352 M[1][0] *= -D; M[1][1] = A22;
1353 double b1 = -M[0][0] * M[0][2] - M[0][1] * M[1][2];
1354 double b2 = -M[1][0] * M[0][2] - M[1][1] * M[1][2];
1355 M[0][2] = b1; M[1][2] = b2;
1360 if (fixedPointArithmetic && !pixelCenter) {
1361 fixedPointArithmetic = checkFixedPoint(0, 0, M, affine) &&
1362 checkFixedPoint(dst.getWidth()-1, 0, M, affine) &&
1363 checkFixedPoint(0, dst.getHeight()-1, M, affine) &&
1364 checkFixedPoint(dst.getWidth() - 1, dst.getHeight() - 1, M, affine);
1369 warpNN(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1372 warpLinear(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1376 template <
class Type>
1378 bool centerCorner,
bool fixedPoint)
1380 if (fixedPoint && !centerCorner) {
1381 const int nbits = 16;
1382 const int32_t precision = 1 << nbits;
1383 const float precision_1 = 1 /
static_cast<float>(precision);
1385 int32_t a0_i32 =
static_cast<int32_t
>(T[0][0] * precision);
1386 int32_t a1_i32 =
static_cast<int32_t
>(T[0][1] * precision);
1387 int32_t a2_i32 =
static_cast<int32_t
>(T[0][2] * precision);
1388 int32_t a3_i32 =
static_cast<int32_t
>(T[1][0] * precision);
1389 int32_t a4_i32 =
static_cast<int32_t
>(T[1][1] * precision);
1390 int32_t a5_i32 =
static_cast<int32_t
>(T[1][2] * precision);
1391 int32_t a6_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][0] * precision) : 0;
1392 int32_t a7_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][1] * precision) : 0;
1393 int32_t a8_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][2] * precision) : 1;
1395 int32_t height_1_i32 =
static_cast<int32_t
>((src.getHeight() - 1) * precision) + 0x8000;
1396 int32_t width_1_i32 =
static_cast<int32_t
>((src.getWidth() - 1) * precision) + 0x8000;
1399 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1400 int32_t xi = a2_i32;
1401 int32_t yi = a5_i32;
1403 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1404 if (yi >= 0 && yi < height_1_i32 && xi >= 0 && xi < width_1_i32) {
1405 float x_ = (xi >> nbits) + (xi & 0xFFFF) * precision_1;
1406 float y_ = (yi >> nbits) + (yi & 0xFFFF) * precision_1;
1410 dst[i][j] = src[y][x];
1421 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1422 int64_t xi = a2_i32;
1423 int64_t yi = a5_i32;
1424 int64_t wi = a8_i32;
1426 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1427 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.getHeight()) - 1)*wi &&
1428 xi >= 0 && xi <= (
static_cast<int>(src.getWidth()) - 1)*wi) {
1429 float w_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1430 float x_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / w_;
1431 float y_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / w_;
1436 dst[i][j] = src[y][x];
1450 double a0 = T[0][0];
double a1 = T[0][1];
double a2 = T[0][2];
1451 double a3 = T[1][0];
double a4 = T[1][1];
double a5 = T[1][2];
1452 double a6 = affine ? 0.0 : T[2][0];
1453 double a7 = affine ? 0.0 : T[2][1];
1454 double a8 = affine ? 1.0 : T[2][2];
1456 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1457 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1458 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1459 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1460 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1462 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1466 int x_ = centerCorner ? coordCast(x / w) :
vpMath::round(x / w);
1467 int y_ = centerCorner ? coordCast(y / w) :
vpMath::round(y / w);
1469 if (x_ >= 0 && x_ <
static_cast<int>(src.getWidth()) &&
1470 y_ >= 0 && y_ <
static_cast<int>(src.getHeight())) {
1471 dst[i][j] = src[y_][x_];
1478 template <
class Type>
1480 bool centerCorner,
bool fixedPoint)
1482 if (fixedPoint && !centerCorner) {
1483 const int nbits = 16;
1484 const int64_t precision = 1 << nbits;
1485 const float precision_1 = 1 /
static_cast<float>(precision);
1486 const int64_t precision2 = 1ULL << (2 * nbits);
1487 const float precision_2 = 1 /
static_cast<float>(precision2);
1489 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1490 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1491 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1492 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1493 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1494 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1495 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1496 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1497 int64_t a8_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][2] * precision) : 1;
1499 int64_t height_i64 =
static_cast<int64_t
>(src.getHeight() * precision);
1500 int64_t width_i64 =
static_cast<int64_t
>(src.getWidth() * precision);
1503 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1504 int64_t xi_ = a2_i64;
1505 int64_t yi_ = a5_i64;
1507 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1508 if (yi_ >= 0 && yi_ < height_i64 && xi_ >= 0 && xi_ < width_i64) {
1509 const int64_t xi_lower = xi_ & (~0xFFFF);
1510 const int64_t yi_lower = yi_ & (~0xFFFF);
1512 const int64_t t = yi_ - yi_lower;
1513 const int64_t t_1 = precision - t;
1514 const int64_t s = xi_ - xi_lower;
1515 const int64_t s_1 = precision - s;
1517 const int x_ =
static_cast<int>(xi_ >> nbits);
1518 const int y_ =
static_cast<int>(yi_ >> nbits);
1520 if (y_ <
static_cast<int>(src.getHeight())-1 && x_ <
static_cast<int>(src.getWidth())-1) {
1521 const Type val00 = src[y_][x_];
1522 const Type val01 = src[y_][x_+1];
1523 const Type val10 = src[y_+1][x_];
1524 const Type val11 = src[y_+1][x_+1];
1525 const int64_t interp_i64 =
static_cast<int64_t
>(s_1*t_1*val00 + s*t_1*val01 + s_1*t*val10 + s*t*val11);
1526 const float interp = (interp_i64 >> (nbits*2)) + (interp_i64 & 0xFFFFFFFF) * precision_2;
1527 dst[i][j] = vpMath::saturate<Type>(interp);
1528 }
else if (y_ <
static_cast<int>(src.getHeight())-1) {
1529 const Type val00 = src[y_][x_];
1530 const Type val10 = src[y_+1][x_];
1531 const int64_t interp_i64 =
static_cast<int64_t
>(t_1*val00 + t*val10);
1532 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1533 dst[i][j] = vpMath::saturate<Type>(interp);
1534 }
else if (x_ <
static_cast<int>(src.getWidth())-1) {
1535 const Type val00 = src[y_][x_];
1536 const Type val01 = src[y_][x_+1];
1537 const int64_t interp_i64 =
static_cast<int64_t
>(s_1*val00 + s*val01);
1538 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1539 dst[i][j] = vpMath::saturate<Type>(interp);
1541 dst[i][j] = src[y_][x_];
1553 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1554 int64_t xi = a2_i64;
1555 int64_t yi = a5_i64;
1556 int64_t wi = a8_i64;
1558 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1559 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.getHeight()) - 1)*wi &&
1560 xi >= 0 && xi <= (
static_cast<int>(src.getWidth()) - 1)*wi) {
1561 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1562 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1563 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1565 const int x_ =
static_cast<int>(xi_);
1566 const int y_ =
static_cast<int>(yi_);
1568 const float t = yi_ - y_;
1569 const float s = xi_ - x_;
1571 if (y_ <
static_cast<int>(src.getHeight()) - 1 && x_ <
static_cast<int>(src.getWidth()) - 1) {
1572 const Type val00 = src[y_][x_];
1573 const Type val01 = src[y_][x_ + 1];
1574 const Type val10 = src[y_ + 1][x_];
1575 const Type val11 = src[y_ + 1][x_ + 1];
1576 const float col0 = lerp(val00, val01, s);
1577 const float col1 = lerp(val10, val11, s);
1578 const float interp = lerp(col0, col1, t);
1579 dst[i][j] = vpMath::saturate<Type>(interp);
1580 }
else if (y_ <
static_cast<int>(src.getHeight()) - 1) {
1581 const Type val00 = src[y_][x_];
1582 const Type val10 = src[y_ + 1][x_];
1583 const float interp = lerp(val00, val10, t);
1584 dst[i][j] = vpMath::saturate<Type>(interp);
1585 }
else if (x_ <
static_cast<int>(src.getWidth()) - 1) {
1586 const Type val00 = src[y_][x_];
1587 const Type val01 = src[y_][x_ + 1];
1588 const float interp = lerp(val00, val01, s);
1589 dst[i][j] = vpMath::saturate<Type>(interp);
1591 dst[i][j] = src[y_][x_];
1606 double a0 = T[0][0];
double a1 = T[0][1];
double a2 = T[0][2];
1607 double a3 = T[1][0];
double a4 = T[1][1];
double a5 = T[1][2];
1608 double a6 = affine ? 0.0 : T[2][0];
1609 double a7 = affine ? 0.0 : T[2][1];
1610 double a8 = affine ? 1.0 : T[2][2];
1612 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1613 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1614 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1615 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1616 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1617 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1621 x = x / w - (centerCorner ? 0.5 : 0);
1622 y = y / w - (centerCorner ? 0.5 : 0);
1624 int x_lower =
static_cast<int>(x);
1625 int y_lower =
static_cast<int>(y);
1627 if (y_lower >=
static_cast<int>(src.getHeight()) || x_lower >=
static_cast<int>(src.getWidth()) ||
1632 double s = x - x_lower;
1633 double t = y - y_lower;
1635 if (y_lower <
static_cast<int>(src.getHeight())-1 && x_lower <
static_cast<int>(src.getWidth())-1) {
1636 const Type val00 = src[y_lower][x_lower];
1637 const Type val01 = src[y_lower][x_lower + 1];
1638 const Type val10 = src[y_lower + 1][x_lower];
1639 const Type val11 = src[y_lower + 1][x_lower + 1];
1640 const double col0 = lerp(val00, val01, s);
1641 const double col1 = lerp(val10, val11, s);
1642 const double interp = lerp(col0, col1, t);
1643 dst[i][j] = vpMath::saturate<Type>(interp);
1644 }
else if (y_lower <
static_cast<int>(src.getHeight())-1) {
1645 const Type val00 = src[y_lower][x_lower];
1646 const Type val10 = src[y_lower + 1][x_lower];
1647 const double interp = lerp(val00, val10, t);
1648 dst[i][j] = vpMath::saturate<Type>(interp);
1649 }
else if (x_lower <
static_cast<int>(src.getWidth())-1) {
1650 const Type val00 = src[y_lower][x_lower];
1651 const Type val01 = src[y_lower][x_lower + 1];
1652 const double interp = lerp(val00, val01, s);
1653 dst[i][j] = vpMath::saturate<Type>(interp);
1655 dst[i][j] = src[y_lower][x_lower];
1664 bool centerCorner,
bool fixedPoint)
1666 if (fixedPoint && !centerCorner) {
1667 const int nbits = 16;
1668 const int64_t precision = 1 << nbits;
1669 const float precision_1 = 1 /
static_cast<float>(precision);
1670 const int64_t precision2 = 1ULL << (2 * nbits);
1671 const float precision_2 = 1 /
static_cast<float>(precision2);
1673 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1674 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1675 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1676 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1677 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1678 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1679 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1680 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1681 int64_t a8_i64 = precision;
1683 int64_t height_i64 =
static_cast<int64_t
>(src.getHeight() * precision);
1684 int64_t width_i64 =
static_cast<int64_t
>(src.getWidth() * precision);
1687 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1688 int64_t xi = a2_i64;
1689 int64_t yi = a5_i64;
1691 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1692 if (yi >= 0 && yi < height_i64 && xi >= 0 && xi < width_i64) {
1693 const int64_t xi_lower = xi & (~0xFFFF);
1694 const int64_t yi_lower = yi & (~0xFFFF);
1696 const int64_t t = yi - yi_lower;
1697 const int64_t t_1 = precision - t;
1698 const int64_t s = xi - xi_lower;
1699 const int64_t s_1 = precision - s;
1701 const int x_ =
static_cast<int>(xi >> nbits);
1702 const int y_ =
static_cast<int>(yi >> nbits);
1704 if (y_ <
static_cast<int>(src.getHeight())-1 && x_ <
static_cast<int>(src.getWidth())-1) {
1705 const vpRGBa val00 = src[y_][x_];
1706 const vpRGBa val01 = src[y_][x_+1];
1707 const vpRGBa val10 = src[y_+1][x_];
1708 const vpRGBa val11 = src[y_+1][x_+1];
1709 const int64_t interpR_i64 =
static_cast<int64_t
>(s_1*t_1*val00.
R + s * t_1*val01.
R + s_1 * t*val10.
R + s * t*val11.
R);
1710 const float interpR = (interpR_i64 >> (nbits*2)) + (interpR_i64 & 0xFFFFFFFF) * precision_2;
1712 const int64_t interpG_i64 =
static_cast<int64_t
>(s_1*t_1*val00.
G + s * t_1*val01.
G + s_1 * t*val10.
G + s * t*val11.
G);
1713 const float interpG = (interpG_i64 >> (nbits * 2)) + (interpG_i64 & 0xFFFFFFFF) * precision_2;
1715 const int64_t interpB_i64 =
static_cast<int64_t
>(s_1*t_1*val00.
B + s * t_1*val01.
B + s_1 * t*val10.
B + s * t*val11.
B);
1716 const float interpB = (interpB_i64 >> (nbits * 2)) + (interpB_i64 & 0xFFFFFFFF) * precision_2;
1718 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1719 vpMath::saturate<unsigned char>(interpG),
1720 vpMath::saturate<unsigned char>(interpB),
1722 }
else if (y_ <
static_cast<int>(src.getHeight())-1) {
1723 const vpRGBa val00 = src[y_][x_];
1724 const vpRGBa val10 = src[y_+1][x_];
1725 const int64_t interpR_i64 =
static_cast<int64_t
>(t_1*val00.
R + t*val10.
R);
1726 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1728 const int64_t interpG_i64 =
static_cast<int64_t
>(t_1*val00.
G + t * val10.
G);
1729 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1731 const int64_t interpB_i64 =
static_cast<int64_t
>(t_1*val00.
B + t * val10.
B);
1732 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1734 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1735 vpMath::saturate<unsigned char>(interpG),
1736 vpMath::saturate<unsigned char>(interpB),
1738 }
else if (x_ <
static_cast<int>(src.getWidth())-1) {
1739 const vpRGBa val00 = src[y_][x_];
1740 const vpRGBa val01 = src[y_][x_+1];
1741 const int64_t interpR_i64 =
static_cast<int64_t
>(s_1*val00.
R + s*val01.
R);
1742 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1744 const int64_t interpG_i64 =
static_cast<int64_t
>(s_1*val00.
G + s * val01.
G);
1745 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1747 const int64_t interpB_i64 =
static_cast<int64_t
>(s_1*val00.
B + s * val01.
B);
1748 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1750 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1751 vpMath::saturate<unsigned char>(interpG),
1752 vpMath::saturate<unsigned char>(interpB),
1755 dst[i][j] = src[y_][x_];
1767 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1768 int64_t xi = a2_i64;
1769 int64_t yi = a5_i64;
1770 int64_t wi = a8_i64;
1772 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1773 if (yi >= 0 && yi <= (
static_cast<int>(src.getHeight()) - 1)*wi &&
1774 xi >= 0 && xi <= (
static_cast<int>(src.getWidth()) - 1)*wi) {
1775 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1776 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1777 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1779 const int x_ =
static_cast<int>(xi_);
1780 const int y_ =
static_cast<int>(yi_);
1782 const float t = yi_ - y_;
1783 const float s = xi_ - x_;
1785 if (y_ <
static_cast<int>(src.getHeight()) - 1 && x_ <
static_cast<int>(src.getWidth()) - 1) {
1786 const vpRGBa val00 = src[y_][x_];
1787 const vpRGBa val01 = src[y_][x_ + 1];
1788 const vpRGBa val10 = src[y_ + 1][x_];
1789 const vpRGBa val11 = src[y_ + 1][x_ + 1];
1790 const float colR0 = lerp(val00.
R, val01.
R, s);
1791 const float colR1 = lerp(val10.
R, val11.
R, s);
1792 const float interpR = lerp(colR0, colR1, t);
1794 const float colG0 = lerp(val00.
G, val01.
G, s);
1795 const float colG1 = lerp(val10.
G, val11.
G, s);
1796 const float interpG = lerp(colG0, colG1, t);
1798 const float colB0 = lerp(val00.
B, val01.
B, s);
1799 const float colB1 = lerp(val10.
B, val11.
B, s);
1800 const float interpB = lerp(colB0, colB1, t);
1802 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1803 vpMath::saturate<unsigned char>(interpG),
1804 vpMath::saturate<unsigned char>(interpB),
1806 }
else if (y_ <
static_cast<int>(src.getHeight()) - 1) {
1807 const vpRGBa val00 = src[y_][x_];
1808 const vpRGBa val10 = src[y_ + 1][x_];
1809 const float interpR = lerp(val00.
R, val10.
R, t);
1810 const float interpG = lerp(val00.
G, val10.
G, t);
1811 const float interpB = lerp(val00.
B, val10.
B, t);
1813 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1814 vpMath::saturate<unsigned char>(interpG),
1815 vpMath::saturate<unsigned char>(interpB),
1817 }
else if (x_ <
static_cast<int>(src.getWidth()) - 1) {
1818 const vpRGBa val00 = src[y_][x_];
1819 const vpRGBa val01 = src[y_][x_ + 1];
1820 const float interpR = lerp(val00.
R, val01.
R, s);
1821 const float interpG = lerp(val00.
G, val01.
G, s);
1822 const float interpB = lerp(val00.
B, val01.
B, s);
1824 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1825 vpMath::saturate<unsigned char>(interpG),
1826 vpMath::saturate<unsigned char>(interpB),
1829 dst[i][j] = src[y_][x_];
1844 double a0 = T[0][0];
double a1 = T[0][1];
double a2 = T[0][2];
1845 double a3 = T[1][0];
double a4 = T[1][1];
double a5 = T[1][2];
1846 double a6 = affine ? 0.0 : T[2][0];
1847 double a7 = affine ? 0.0 : T[2][1];
1848 double a8 = affine ? 1.0 : T[2][2];
1850 for (
unsigned int i = 0; i < dst.getHeight(); i++) {
1851 for (
unsigned int j = 0; j < dst.getWidth(); j++) {
1852 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1853 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1854 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1856 x = x / w - (centerCorner ? 0.5 : 0);
1857 y = y / w - (centerCorner ? 0.5 : 0);
1859 int x_lower =
static_cast<int>(x);
1860 int y_lower =
static_cast<int>(y);
1862 if (y_lower >=
static_cast<int>(src.getHeight()) || x_lower >=
static_cast<int>(src.getWidth()) ||
1867 double s = x - x_lower;
1868 double t = y - y_lower;
1870 if (y_lower <
static_cast<int>(src.getHeight())-1 && x_lower <
static_cast<int>(src.getWidth())-1) {
1871 const vpRGBa val00 = src[y_lower][x_lower];
1872 const vpRGBa val01 = src[y_lower][x_lower +1];
1873 const vpRGBa val10 = src[y_lower +1][x_lower];
1874 const vpRGBa val11 = src[y_lower +1][x_lower +1];
1875 const double colR0 = lerp(val00.
R, val01.
R, s);
1876 const double colR1 = lerp(val10.
R, val11.
R, s);
1877 const double interpR = lerp(colR0, colR1, t);
1879 const double colG0 = lerp(val00.
G, val01.
G, s);
1880 const double colG1 = lerp(val10.
G, val11.
G, s);
1881 const double interpG = lerp(colG0, colG1, t);
1883 const double colB0 = lerp(val00.
B, val01.
B, s);
1884 const double colB1 = lerp(val10.
B, val11.
B, s);
1885 const double interpB = lerp(colB0, colB1, t);
1887 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1888 vpMath::saturate<unsigned char>(interpG),
1889 vpMath::saturate<unsigned char>(interpB),
1891 }
else if (y_lower <
static_cast<int>(src.getHeight())-1) {
1892 const vpRGBa val00 = src[y_lower][x_lower];
1893 const vpRGBa val10 = src[y_lower +1][x_lower];
1894 const double interpR = lerp(val00.
R, val10.
R, t);
1895 const double interpG = lerp(val00.
G, val10.
G, t);
1896 const double interpB = lerp(val00.
B, val10.
B, t);
1898 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1899 vpMath::saturate<unsigned char>(interpG),
1900 vpMath::saturate<unsigned char>(interpB),
1902 }
else if (x_lower <
static_cast<int>(src.getWidth())-1) {
1903 const vpRGBa val00 = src[y_lower][x_lower];
1904 const vpRGBa val01 = src[y_lower][x_lower +1];
1905 const double interpR = lerp(val00.
R, val01.
R, s);
1906 const double interpG = lerp(val00.
G, val01.
G, s);
1907 const double interpB = lerp(val00.
B, val01.
B, s);
1909 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR),
1910 vpMath::saturate<unsigned char>(interpG),
1911 vpMath::saturate<unsigned char>(interpB),
1914 dst[i][j] = src[y_lower][x_lower];