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);
150 template <
class Type>
152 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
154 template <
class Type>
156 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
160 bool useOptimized =
true);
162 template <
class Type>
164 unsigned int nThreads = 2);
166 template <
class Type>
170 template <
class Type>
172 const vpImageInterpolationType &interpolation = INTERPOLATION_NEAREST,
173 bool fixedPointArithmetic =
true,
bool pixelCenter =
false);
175 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
180 template <
class Type>
182 unsigned int nrow_sub,
unsigned int ncol_sub,
vpImage<Type> &S);
184 template <
class Type>
191 static float cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t);
193 template <
class Type>
static Type getPixelClamped(
const vpImage<Type> &I,
float u,
float v);
195 static int coordCast(
double x);
198 static double lerp(
double A,
double B,
double t);
199 static float lerp(
float A,
float B,
float t);
200 static int64_t lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1);
206 template <
class Type>
208 float v,
float xFrac,
float yFrac);
210 template <
class Type>
212 float v,
float xFrac,
float yFrac);
214 template <
class Type>
218 static void resizeSimdlib(
const vpImage<vpRGBa> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
220 static void resizeSimdlib(
const vpImage<unsigned char> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
223 template <
class Type>
227 template <
class Type>
229 bool centerCorner,
bool fixedPoint);
231 static bool checkFixedPoint(
unsigned int x,
unsigned int y,
const vpMatrix &T,
bool affine);
234 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
254 template <
class Type>
256 unsigned int roi_height,
unsigned int roi_width,
vpImage<Type> &crop)
305 template <
class Type>
307 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
309 int i_min = (std::max)((
int)(ceil(roi_top / v_scale)), 0);
310 int j_min = (std::max)((
int)(ceil(roi_left / h_scale)), 0);
311 int i_max = (std::min)((
int)(ceil((roi_top + roi_height)) / v_scale), (
int)(I.
getHeight() / v_scale));
312 int j_max = (std::min)((
int)(ceil((roi_left + roi_width) / h_scale)), (
int)(I.
getWidth() / h_scale));
314 unsigned int i_min_u = (
unsigned int)i_min;
315 unsigned int j_min_u = (
unsigned int)j_min;
317 unsigned int r_width = (
unsigned int)(j_max - j_min);
318 unsigned int r_height = (
unsigned int)(i_max - i_min);
320 crop.resize(r_height, r_width);
322 if (v_scale == 1 && h_scale == 1) {
323 for (
unsigned int i = 0; i < r_height; i++) {
324 void *src = (
void *)(I[i + i_min_u] + j_min_u);
325 void *dst = (
void *)
crop[i];
326 memcpy(dst, src, r_width *
sizeof(Type));
328 }
else if (h_scale == 1) {
329 for (
unsigned int i = 0; i < r_height; i++) {
330 void *src = (
void *)(I[(i + i_min_u) * v_scale] + j_min_u);
331 void *dst = (
void *)
crop[i];
332 memcpy(dst, src, r_width *
sizeof(Type));
335 for (
unsigned int i = 0; i < r_height; i++) {
336 for (
unsigned int j = 0; j < r_width; j++) {
337 crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
360 template <
class Type>
362 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
383 template <
class Type>
385 unsigned int h_scale)
408 template <
class Type>
410 vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
412 int i_min = (std::max)((
int)(ceil(roi.
getTop() / v_scale)), 0);
413 int j_min = (std::max)((
int)(ceil(roi.
getLeft() / h_scale)), 0);
414 int i_max = (std::min)((
int)(ceil((roi.
getTop() + roi.
getHeight()) / v_scale)), (
int)(height / v_scale));
415 int j_max = (std::min)((
int)(ceil((roi.
getLeft() + roi.
getWidth()) / h_scale)), (
int)(width / h_scale));
417 unsigned int i_min_u = (
unsigned int)i_min;
418 unsigned int j_min_u = (
unsigned int)j_min;
420 unsigned int r_width = (
unsigned int)(j_max - j_min);
421 unsigned int r_height = (
unsigned int)(i_max - i_min);
423 crop.resize(r_height, r_width);
425 if (v_scale == 1 && h_scale == 1) {
426 for (
unsigned int i = 0; i < r_height; i++) {
427 void *src = (
void *)(bitmap + ((i + i_min_u) * width + j_min_u) *
sizeof(Type));
428 void *dst = (
void *)
crop[i];
429 memcpy(dst, src, r_width *
sizeof(Type));
431 }
else if (h_scale == 1) {
432 for (
unsigned int i = 0; i < r_height; i++) {
433 void *src = (
void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) *
sizeof(Type));
434 void *dst = (
void *)
crop[i];
435 memcpy(dst, src, r_width *
sizeof(Type));
438 for (
unsigned int i = 0; i < r_height; i++) {
439 unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
440 for (
unsigned int j = 0; j < r_width; j++) {
441 void *src = (
void *)(bitmap + (i_src + j * h_scale) *
sizeof(Type));
442 void *dst = (
void *)&
crop[i][j];
443 memcpy(dst, src,
sizeof(Type));
459 template <
class Type>
461 Type value3,
bool useLUT)
464 std::cerr <<
"LUT not available for this type ! Will use the iteration method." << std::endl;
470 for (; p < pend; p++) {
474 else if (v > threshold2)
493 unsigned char value1,
unsigned char value2,
unsigned char value3,
bool useLUT)
497 unsigned char lut[256];
498 for (
unsigned int i = 0; i < 256; i++) {
499 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
504 unsigned char *p = I.
bitmap;
506 for (; p < pend; p++) {
507 unsigned char v = *p;
510 else if (v > threshold2)
518 #ifdef VISP_HAVE_PTHREAD
520 #ifndef DOXYGEN_SHOULD_SKIP_THIS
521 template <
class Type>
class vpUndistortInternalType
529 unsigned int nthreads;
530 unsigned int threadid;
533 vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0) {}
535 vpUndistortInternalType(
const vpUndistortInternalType<Type> &u) { *
this = u; }
536 vpUndistortInternalType &operator=(
const vpUndistortInternalType<Type> &u)
543 nthreads = u.nthreads;
544 threadid = u.threadid;
549 static void *vpUndistort_threaded(
void *arg);
552 template <
class Type>
void *vpUndistortInternalType<Type>::vpUndistort_threaded(
void *arg)
554 vpUndistortInternalType<Type> *undistortSharedData =
static_cast<vpUndistortInternalType<Type> *
>(arg);
555 int offset = (int)undistortSharedData->threadid;
556 int width = (
int)undistortSharedData->width;
557 int height = (int)undistortSharedData->height;
558 int nthreads = (
int)undistortSharedData->nthreads;
560 double u0 = undistortSharedData->cam.get_u0();
561 double v0 = undistortSharedData->cam.get_v0();
562 double px = undistortSharedData->cam.get_px();
563 double py = undistortSharedData->cam.get_py();
564 double kud = undistortSharedData->cam.get_kud();
566 double invpx = 1.0 / px;
567 double invpy = 1.0 / py;
569 double kud_px2 = kud * invpx * invpx;
570 double kud_py2 = kud * invpy * invpy;
572 Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
573 Type *src = undistortSharedData->src;
575 for (
double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
576 double deltav = v - v0;
578 double fr1 = 1.0 + kud_py2 * deltav * deltav;
580 for (
double u = 0; u < width; u++) {
582 double deltau = u - u0;
584 double fr2 = fr1 + kud_px2 * deltau * deltau;
586 double u_double = deltau * fr2 + u0;
587 double v_double = deltav * fr2 + v0;
592 int u_round = (int)(u_double);
593 int v_round = (int)(v_double);
598 double du_double = (u_double) - (
double)u_round;
599 double dv_double = (v_double) - (
double)v_round;
602 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
604 const Type *_mp = &src[v_round * width + u_round];
605 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
607 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
608 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
616 pthread_exit((
void *)0);
645 template <
class Type>
647 unsigned int nThreads)
649 #ifdef VISP_HAVE_PTHREAD
656 undistI.
resize(height, width);
661 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
667 unsigned int nthreads = nThreads;
669 pthread_t *callThd =
new pthread_t[nthreads];
670 pthread_attr_init(&attr);
671 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
673 vpUndistortInternalType<Type> *undistortSharedData;
674 undistortSharedData =
new vpUndistortInternalType<Type>[nthreads];
676 for (
unsigned int i = 0; i < nthreads; i++) {
679 undistortSharedData[i].src = I.
bitmap;
680 undistortSharedData[i].dst = undistI.
bitmap;
681 undistortSharedData[i].width = I.
getWidth();
682 undistortSharedData[i].height = I.
getHeight();
683 undistortSharedData[i].cam = cam;
684 undistortSharedData[i].nthreads = nthreads;
685 undistortSharedData[i].threadid = i;
686 pthread_create(&callThd[i], &attr, &vpUndistortInternalType<Type>::vpUndistort_threaded, &undistortSharedData[i]);
688 pthread_attr_destroy(&attr);
691 for (
unsigned int i = 0; i < nthreads; i++) {
693 pthread_join(callThd[i], NULL);
697 delete[] undistortSharedData;
706 undistI.
resize(height, width);
715 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
721 double invpx = 1.0 / px;
722 double invpy = 1.0 / py;
724 double kud_px2 = kud * invpx * invpx;
725 double kud_py2 = kud * invpy * invpy;
727 Type *dst = undistI.
bitmap;
728 for (
double v = 0; v < height; v++) {
729 double deltav = v - v0;
731 double fr1 = 1.0 + kud_py2 * deltav * deltav;
733 for (
double u = 0; u < width; u++) {
735 double deltau = u - u0;
737 double fr2 = fr1 + kud_px2 * deltau * deltau;
739 double u_double = deltau * fr2 + u0;
740 double v_double = deltav * fr2 + v0;
747 int u_round = (int)(u_double);
748 int v_round = (int)(v_double);
753 double du_double = (u_double) - (
double)u_round;
754 double dv_double = (v_double) - (
double)v_round;
757 if ((0 <= u_round) && (0 <= v_round) && (u_round < (((
int)width) - 1)) && (v_round < (((
int)height) - 1))) {
759 const Type *_mp = &I[(
unsigned int)v_round][(
unsigned int)u_round];
760 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
762 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
763 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
778 undistI.
resize(height,width);
792 for(
int v = 0 ; v < height; v++){
793 for(
int u = 0; u < height; u++){
796 double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
797 double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
798 undistI[v][u] = I.getPixelBI((
float)u_double,(float)v_double);
818 template <
class Type>
822 remap(I, mapU, mapV, mapDu, mapDv, newI);
834 newI.
resize(height, width);
836 for (
unsigned int i = 0; i < height; i++) {
837 memcpy(newI.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
878 for (
unsigned int i = 0; i < height / 2; i++) {
879 memcpy(Ibuf.
bitmap, I.
bitmap + i * width, width *
sizeof(Type));
881 memcpy(I.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
882 memcpy(I.
bitmap + (height - 1 - i) * width, Ibuf.
bitmap, width *
sizeof(Type));
886 template <
class Type> Type vpImageTools::getPixelClamped(
const vpImage<Type> &I,
float u,
float v)
890 x = (std::max)(0, (std::min)(x,
static_cast<int>(I.
getWidth()) - 1));
891 y = (std::max)(0, (std::min)(y,
static_cast<int>(I.
getHeight()) - 1));
898 template <
class Type>
900 float v,
float xFrac,
float yFrac)
903 Type p00 = getPixelClamped(I, u - 1, v - 1);
904 Type p01 = getPixelClamped(I, u + 0, v - 1);
905 Type p02 = getPixelClamped(I, u + 1, v - 1);
906 Type p03 = getPixelClamped(I, u + 2, v - 1);
909 Type p10 = getPixelClamped(I, u - 1, v + 0);
910 Type p11 = getPixelClamped(I, u + 0, v + 0);
911 Type p12 = getPixelClamped(I, u + 1, v + 0);
912 Type p13 = getPixelClamped(I, u + 2, v + 0);
915 Type p20 = getPixelClamped(I, u - 1, v + 1);
916 Type p21 = getPixelClamped(I, u + 0, v + 1);
917 Type p22 = getPixelClamped(I, u + 1, v + 1);
918 Type p23 = getPixelClamped(I, u + 2, v + 1);
921 Type p30 = getPixelClamped(I, u - 1, v + 2);
922 Type p31 = getPixelClamped(I, u + 0, v + 2);
923 Type p32 = getPixelClamped(I, u + 1, v + 2);
924 Type p33 = getPixelClamped(I, u + 2, v + 2);
926 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
927 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
928 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
929 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
930 float value = cubicHermite(col0, col1, col2, col3, yFrac);
931 Ires[i][j] = vpMath::saturate<Type>(value);
936 float u,
float v,
float xFrac,
float yFrac)
939 vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
940 vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
941 vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
942 vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
945 vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
946 vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
947 vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
948 vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
951 vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
952 vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
953 vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
954 vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
957 vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
958 vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
959 vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
960 vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
962 for (
int c = 0; c < 3; c++) {
963 float col0 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p00)[c]),
964 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p01)[c]),
965 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p02)[c]),
966 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p03)[c]), xFrac);
967 float col1 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p10)[c]),
968 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p11)[c]),
969 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p12)[c]),
970 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p13)[c]), xFrac);
971 float col2 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p20)[c]),
972 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p21)[c]),
973 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p22)[c]),
974 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p23)[c]), xFrac);
975 float col3 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p30)[c]),
976 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p31)[c]),
977 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p32)[c]),
978 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p33)[c]), xFrac);
979 float value = cubicHermite(col0, col1, col2, col3, yFrac);
981 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
985 template <
class Type>
987 float v,
float xFrac,
float yFrac)
989 int u0 =
static_cast<int>(u);
990 int v0 =
static_cast<int>(v);
992 int u1 = (std::min)(
static_cast<int>(I.
getWidth()) - 1, u0 + 1);
996 int v2 = (std::min)(
static_cast<int>(I.
getHeight()) - 1, v0 + 1);
1001 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
1002 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
1003 float value = lerp(col0, col1, yFrac);
1005 Ires[i][j] = vpMath::saturate<Type>(value);
1010 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
1012 int u0 =
static_cast<int>(u);
1013 int v0 =
static_cast<int>(v);
1015 int u1 = (std::min)(
static_cast<int>(I.
getWidth()) - 1, u0 + 1);
1019 int v2 = (std::min)(
static_cast<int>(I.
getHeight()) - 1, v0 + 1);
1024 for (
int c = 0; c < 3; c++) {
1025 float col0 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v0][u0])[c]),
1026 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v1][u1])[c]), xFrac);
1027 float col1 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v2][u2])[c]),
1028 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v3][u3])[c]), xFrac);
1029 float value = lerp(col0, col1, yFrac);
1031 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1035 template <
class Type>
1039 Ires[i][j] = getPixelClamped(I, u, v);
1060 template <
class Type>
1064 Ires.
resize(height, width);
1086 template <
class Type>
1095 std::cerr <<
"Input or output image is too small!" << std::endl;
1100 std::cerr <<
"INTERPOLATION_AREA is not implemented for this type." << std::endl;
1106 const float half = 0.5f;
1110 omp_set_num_threads(
static_cast<int>(nThreads));
1112 #pragma omp parallel for schedule(dynamic)
1114 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1115 const float v = (i + half) * scaleY - half;
1116 const int v0 =
static_cast<int>(v);
1117 const float yFrac = v - v0;
1119 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1120 const float u = (j + half) * scaleX - half;
1121 const int u0 =
static_cast<int>(u);
1122 const float xFrac = u - u0;
1125 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1127 resizeBilinear(I, Ires,
static_cast<unsigned int>(i), j, u0, v0, xFrac, yFrac);
1129 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1145 std::cerr <<
"Input or output image is too small!" << std::endl;
1156 const float half = 0.5f;
1160 omp_set_num_threads(
static_cast<int>(nThreads));
1162 #pragma omp parallel for schedule(dynamic)
1164 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1165 float v = (i + half) * scaleY - half;
1166 float yFrac = v -
static_cast<int>(v);
1168 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1169 float u = (j + half) * scaleX - half;
1170 float xFrac = u -
static_cast<int>(u);
1173 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1175 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1192 std::cerr <<
"Input or output image is too small!" << std::endl;
1203 const float half = 0.5f;
1207 omp_set_num_threads(
static_cast<int>(nThreads));
1209 #pragma omp parallel for schedule(dynamic)
1211 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1212 float v = (i + half) * scaleY - half;
1213 float yFrac = v -
static_cast<int>(v);
1215 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1216 float u = (j + half) * scaleX - half;
1217 float xFrac = u -
static_cast<int>(u);
1220 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1222 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1243 template <
class Type>
1248 std::cerr <<
"Input transformation must be a (2x3) or (3x3) matrix." << std::endl;
1256 const bool affine = (T.
getRows() == 2);
1265 double D = M[0][0] * M[1][1] - M[0][1] * M[1][0];
1266 D = !
vpMath::nul(D, std::numeric_limits<double>::epsilon()) ? 1.0 / D : 0;
1267 double A11 = M[1][1] * D, A22 = M[0][0] * D;
1272 double b1 = -M[0][0] * M[0][2] - M[0][1] * M[1][2];
1273 double b2 = -M[1][0] * M[0][2] - M[1][1] * M[1][2];
1280 if (fixedPointArithmetic && !pixelCenter) {
1281 fixedPointArithmetic = checkFixedPoint(0, 0, M, affine) && checkFixedPoint(dst.
getWidth() - 1, 0, M, affine) &&
1282 checkFixedPoint(0, dst.
getHeight() - 1, M, affine) &&
1288 warpNN(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1291 warpLinear(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1295 template <
class Type>
1297 bool centerCorner,
bool fixedPoint)
1299 if (fixedPoint && !centerCorner) {
1300 const int nbits = 16;
1301 const int32_t precision = 1 << nbits;
1302 const float precision_1 = 1 /
static_cast<float>(precision);
1304 int32_t a0_i32 =
static_cast<int32_t
>(T[0][0] * precision);
1305 int32_t a1_i32 =
static_cast<int32_t
>(T[0][1] * precision);
1306 int32_t a2_i32 =
static_cast<int32_t
>(T[0][2] * precision);
1307 int32_t a3_i32 =
static_cast<int32_t
>(T[1][0] * precision);
1308 int32_t a4_i32 =
static_cast<int32_t
>(T[1][1] * precision);
1309 int32_t a5_i32 =
static_cast<int32_t
>(T[1][2] * precision);
1310 int32_t a6_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][0] * precision) : 0;
1311 int32_t a7_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][1] * precision) : 0;
1312 int32_t a8_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][2] * precision) : 1;
1314 int32_t height_1_i32 =
static_cast<int32_t
>((src.
getHeight() - 1) * precision) + 0x8000;
1315 int32_t width_1_i32 =
static_cast<int32_t
>((src.
getWidth() - 1) * precision) + 0x8000;
1318 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1319 int32_t xi = a2_i32;
1320 int32_t yi = a5_i32;
1322 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1323 if (yi >= 0 && yi < height_1_i32 && xi >= 0 && xi < width_1_i32) {
1324 float x_ = (xi >> nbits) + (xi & 0xFFFF) * precision_1;
1325 float y_ = (yi >> nbits) + (yi & 0xFFFF) * precision_1;
1329 dst[i][j] = src[y][x];
1340 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1341 int64_t xi = a2_i32;
1342 int64_t yi = a5_i32;
1343 int64_t wi = a8_i32;
1345 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1346 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1347 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1348 float w_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1349 float x_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / w_;
1350 float y_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / w_;
1355 dst[i][j] = src[y][x];
1369 double a0 = T[0][0];
1370 double a1 = T[0][1];
1371 double a2 = T[0][2];
1372 double a3 = T[1][0];
1373 double a4 = T[1][1];
1374 double a5 = T[1][2];
1375 double a6 = affine ? 0.0 : T[2][0];
1376 double a7 = affine ? 0.0 : T[2][1];
1377 double a8 = affine ? 1.0 : T[2][2];
1379 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1380 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1381 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1382 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1383 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1385 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1389 int x_ = centerCorner ? coordCast(x / w) :
vpMath::round(x / w);
1390 int y_ = centerCorner ? coordCast(y / w) :
vpMath::round(y / w);
1392 if (x_ >= 0 && x_ <
static_cast<int>(src.
getWidth()) && y_ >= 0 && y_ <
static_cast<int>(src.
getHeight())) {
1393 dst[i][j] = src[y_][x_];
1400 template <
class Type>
1402 bool centerCorner,
bool fixedPoint)
1404 if (fixedPoint && !centerCorner) {
1405 const int nbits = 16;
1406 const int64_t precision = 1 << nbits;
1407 const float precision_1 = 1 /
static_cast<float>(precision);
1408 const int64_t precision2 = 1ULL << (2 * nbits);
1409 const float precision_2 = 1 /
static_cast<float>(precision2);
1411 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1412 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1413 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1414 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1415 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1416 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1417 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1418 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1419 int64_t a8_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][2] * precision) : 1;
1421 int64_t height_i64 =
static_cast<int64_t
>(src.
getHeight() * precision);
1422 int64_t width_i64 =
static_cast<int64_t
>(src.
getWidth() * precision);
1425 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1426 int64_t xi_ = a2_i64;
1427 int64_t yi_ = a5_i64;
1429 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1430 if (yi_ >= 0 && yi_ < height_i64 && xi_ >= 0 && xi_ < width_i64) {
1431 const int64_t xi_lower = xi_ & (~0xFFFF);
1432 const int64_t yi_lower = yi_ & (~0xFFFF);
1434 const int64_t t = yi_ - yi_lower;
1435 const int64_t t_1 = precision - t;
1436 const int64_t s = xi_ - xi_lower;
1437 const int64_t s_1 = precision - s;
1439 const int x_ =
static_cast<int>(xi_ >> nbits);
1440 const int y_ =
static_cast<int>(yi_ >> nbits);
1442 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1443 const Type val00 = src[y_][x_];
1444 const Type val01 = src[y_][x_ + 1];
1445 const Type val10 = src[y_ + 1][x_];
1446 const Type val11 = src[y_ + 1][x_ + 1];
1447 const int64_t interp_i64 =
1448 static_cast<int64_t
>(s_1 * t_1 * val00 + s * t_1 * val01 + s_1 * t * val10 + s * t * val11);
1449 const float interp = (interp_i64 >> (nbits * 2)) + (interp_i64 & 0xFFFFFFFF) * precision_2;
1450 dst[i][j] = vpMath::saturate<Type>(interp);
1451 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1452 const Type val00 = src[y_][x_];
1453 const Type val10 = src[y_ + 1][x_];
1454 const int64_t interp_i64 =
static_cast<int64_t
>(t_1 * val00 + t * val10);
1455 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1456 dst[i][j] = vpMath::saturate<Type>(interp);
1457 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1458 const Type val00 = src[y_][x_];
1459 const Type val01 = src[y_][x_ + 1];
1460 const int64_t interp_i64 =
static_cast<int64_t
>(s_1 * val00 + s * val01);
1461 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1462 dst[i][j] = vpMath::saturate<Type>(interp);
1464 dst[i][j] = src[y_][x_];
1476 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1477 int64_t xi = a2_i64;
1478 int64_t yi = a5_i64;
1479 int64_t wi = a8_i64;
1481 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1482 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1483 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1484 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1485 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1486 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1488 const int x_ =
static_cast<int>(xi_);
1489 const int y_ =
static_cast<int>(yi_);
1491 const float t = yi_ - y_;
1492 const float s = xi_ - x_;
1494 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1495 const Type val00 = src[y_][x_];
1496 const Type val01 = src[y_][x_ + 1];
1497 const Type val10 = src[y_ + 1][x_];
1498 const Type val11 = src[y_ + 1][x_ + 1];
1499 const float col0 = lerp(val00, val01, s);
1500 const float col1 = lerp(val10, val11, s);
1501 const float interp = lerp(col0, col1, t);
1502 dst[i][j] = vpMath::saturate<Type>(interp);
1503 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1504 const Type val00 = src[y_][x_];
1505 const Type val10 = src[y_ + 1][x_];
1506 const float interp = lerp(val00, val10, t);
1507 dst[i][j] = vpMath::saturate<Type>(interp);
1508 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1509 const Type val00 = src[y_][x_];
1510 const Type val01 = src[y_][x_ + 1];
1511 const float interp = lerp(val00, val01, s);
1512 dst[i][j] = vpMath::saturate<Type>(interp);
1514 dst[i][j] = src[y_][x_];
1529 double a0 = T[0][0];
1530 double a1 = T[0][1];
1531 double a2 = T[0][2];
1532 double a3 = T[1][0];
1533 double a4 = T[1][1];
1534 double a5 = T[1][2];
1535 double a6 = affine ? 0.0 : T[2][0];
1536 double a7 = affine ? 0.0 : T[2][1];
1537 double a8 = affine ? 1.0 : T[2][2];
1539 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1540 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1541 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1542 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1543 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1544 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1548 x = x / w - (centerCorner ? 0.5 : 0);
1549 y = y / w - (centerCorner ? 0.5 : 0);
1551 int x_lower =
static_cast<int>(x);
1552 int y_lower =
static_cast<int>(y);
1554 if (y_lower >=
static_cast<int>(src.
getHeight()) || x_lower >=
static_cast<int>(src.
getWidth()) || y < 0 ||
1559 double s = x - x_lower;
1560 double t = y - y_lower;
1562 if (y_lower <
static_cast<int>(src.
getHeight()) - 1 && x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1563 const Type val00 = src[y_lower][x_lower];
1564 const Type val01 = src[y_lower][x_lower + 1];
1565 const Type val10 = src[y_lower + 1][x_lower];
1566 const Type val11 = src[y_lower + 1][x_lower + 1];
1567 const double col0 = lerp(val00, val01, s);
1568 const double col1 = lerp(val10, val11, s);
1569 const double interp = lerp(col0, col1, t);
1570 dst[i][j] = vpMath::saturate<Type>(interp);
1571 }
else if (y_lower <
static_cast<int>(src.
getHeight()) - 1) {
1572 const Type val00 = src[y_lower][x_lower];
1573 const Type val10 = src[y_lower + 1][x_lower];
1574 const double interp = lerp(val00, val10, t);
1575 dst[i][j] = vpMath::saturate<Type>(interp);
1576 }
else if (x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1577 const Type val00 = src[y_lower][x_lower];
1578 const Type val01 = src[y_lower][x_lower + 1];
1579 const double interp = lerp(val00, val01, s);
1580 dst[i][j] = vpMath::saturate<Type>(interp);
1582 dst[i][j] = src[y_lower][x_lower];
1591 bool centerCorner,
bool fixedPoint)
1593 if (fixedPoint && !centerCorner) {
1594 const int nbits = 16;
1595 const int64_t precision = 1 << nbits;
1596 const float precision_1 = 1 /
static_cast<float>(precision);
1597 const int64_t precision2 = 1ULL << (2 * nbits);
1598 const float precision_2 = 1 /
static_cast<float>(precision2);
1600 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1601 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1602 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1603 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1604 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1605 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1606 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1607 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1608 int64_t a8_i64 = precision;
1610 int64_t height_i64 =
static_cast<int64_t
>(src.
getHeight() * precision);
1611 int64_t width_i64 =
static_cast<int64_t
>(src.
getWidth() * precision);
1614 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1615 int64_t xi = a2_i64;
1616 int64_t yi = a5_i64;
1618 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1619 if (yi >= 0 && yi < height_i64 && xi >= 0 && xi < width_i64) {
1620 const int64_t xi_lower = xi & (~0xFFFF);
1621 const int64_t yi_lower = yi & (~0xFFFF);
1623 const int64_t t = yi - yi_lower;
1624 const int64_t t_1 = precision - t;
1625 const int64_t s = xi - xi_lower;
1626 const int64_t s_1 = precision - s;
1628 const int x_ =
static_cast<int>(xi >> nbits);
1629 const int y_ =
static_cast<int>(yi >> nbits);
1631 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1632 const vpRGBa val00 = src[y_][x_];
1633 const vpRGBa val01 = src[y_][x_ + 1];
1634 const vpRGBa val10 = src[y_ + 1][x_];
1635 const vpRGBa val11 = src[y_ + 1][x_ + 1];
1636 const int64_t interpR_i64 =
1637 static_cast<int64_t
>(s_1 * t_1 * val00.
R + s * t_1 * val01.
R + s_1 * t * val10.
R + s * t * val11.
R);
1638 const float interpR = (interpR_i64 >> (nbits * 2)) + (interpR_i64 & 0xFFFFFFFF) * precision_2;
1640 const int64_t interpG_i64 =
1641 static_cast<int64_t
>(s_1 * t_1 * val00.
G + s * t_1 * val01.
G + s_1 * t * val10.
G + s * t * val11.
G);
1642 const float interpG = (interpG_i64 >> (nbits * 2)) + (interpG_i64 & 0xFFFFFFFF) * precision_2;
1644 const int64_t interpB_i64 =
1645 static_cast<int64_t
>(s_1 * t_1 * val00.
B + s * t_1 * val01.
B + s_1 * t * val10.
B + s * t * val11.
B);
1646 const float interpB = (interpB_i64 >> (nbits * 2)) + (interpB_i64 & 0xFFFFFFFF) * precision_2;
1648 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1649 vpMath::saturate<unsigned char>(interpB), 255);
1650 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1651 const vpRGBa val00 = src[y_][x_];
1652 const vpRGBa val10 = src[y_ + 1][x_];
1653 const int64_t interpR_i64 =
static_cast<int64_t
>(t_1 * val00.
R + t * val10.
R);
1654 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1656 const int64_t interpG_i64 =
static_cast<int64_t
>(t_1 * val00.
G + t * val10.
G);
1657 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1659 const int64_t interpB_i64 =
static_cast<int64_t
>(t_1 * val00.
B + t * val10.
B);
1660 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1662 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1663 vpMath::saturate<unsigned char>(interpB), 255);
1664 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1665 const vpRGBa val00 = src[y_][x_];
1666 const vpRGBa val01 = src[y_][x_ + 1];
1667 const int64_t interpR_i64 =
static_cast<int64_t
>(s_1 * val00.
R + s * val01.
R);
1668 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1670 const int64_t interpG_i64 =
static_cast<int64_t
>(s_1 * val00.
G + s * val01.
G);
1671 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1673 const int64_t interpB_i64 =
static_cast<int64_t
>(s_1 * val00.
B + s * val01.
B);
1674 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1676 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1677 vpMath::saturate<unsigned char>(interpB), 255);
1679 dst[i][j] = src[y_][x_];
1691 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1692 int64_t xi = a2_i64;
1693 int64_t yi = a5_i64;
1694 int64_t wi = a8_i64;
1696 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1697 if (yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1698 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1699 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1700 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1701 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1703 const int x_ =
static_cast<int>(xi_);
1704 const int y_ =
static_cast<int>(yi_);
1706 const float t = yi_ - y_;
1707 const float s = xi_ - x_;
1709 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1710 const vpRGBa val00 = src[y_][x_];
1711 const vpRGBa val01 = src[y_][x_ + 1];
1712 const vpRGBa val10 = src[y_ + 1][x_];
1713 const vpRGBa val11 = src[y_ + 1][x_ + 1];
1714 const float colR0 = lerp(val00.
R, val01.
R, s);
1715 const float colR1 = lerp(val10.
R, val11.
R, s);
1716 const float interpR = lerp(colR0, colR1, t);
1718 const float colG0 = lerp(val00.
G, val01.
G, s);
1719 const float colG1 = lerp(val10.
G, val11.
G, s);
1720 const float interpG = lerp(colG0, colG1, t);
1722 const float colB0 = lerp(val00.
B, val01.
B, s);
1723 const float colB1 = lerp(val10.
B, val11.
B, s);
1724 const float interpB = lerp(colB0, colB1, t);
1726 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1727 vpMath::saturate<unsigned char>(interpB), 255);
1728 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1729 const vpRGBa val00 = src[y_][x_];
1730 const vpRGBa val10 = src[y_ + 1][x_];
1731 const float interpR = lerp(val00.
R, val10.
R, t);
1732 const float interpG = lerp(val00.
G, val10.
G, t);
1733 const float interpB = lerp(val00.
B, val10.
B, t);
1735 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1736 vpMath::saturate<unsigned char>(interpB), 255);
1737 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1738 const vpRGBa val00 = src[y_][x_];
1739 const vpRGBa val01 = src[y_][x_ + 1];
1740 const float interpR = lerp(val00.
R, val01.
R, s);
1741 const float interpG = lerp(val00.
G, val01.
G, s);
1742 const float interpB = lerp(val00.
B, val01.
B, s);
1744 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1745 vpMath::saturate<unsigned char>(interpB), 255);
1747 dst[i][j] = src[y_][x_];
1762 double a0 = T[0][0];
1763 double a1 = T[0][1];
1764 double a2 = T[0][2];
1765 double a3 = T[1][0];
1766 double a4 = T[1][1];
1767 double a5 = T[1][2];
1768 double a6 = affine ? 0.0 : T[2][0];
1769 double a7 = affine ? 0.0 : T[2][1];
1770 double a8 = affine ? 1.0 : T[2][2];
1772 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1773 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1774 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1775 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1776 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1778 x = x / w - (centerCorner ? 0.5 : 0);
1779 y = y / w - (centerCorner ? 0.5 : 0);
1781 int x_lower =
static_cast<int>(x);
1782 int y_lower =
static_cast<int>(y);
1784 if (y_lower >=
static_cast<int>(src.
getHeight()) || x_lower >=
static_cast<int>(src.
getWidth()) || y < 0 ||
1789 double s = x - x_lower;
1790 double t = y - y_lower;
1792 if (y_lower <
static_cast<int>(src.
getHeight()) - 1 && x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1793 const vpRGBa val00 = src[y_lower][x_lower];
1794 const vpRGBa val01 = src[y_lower][x_lower + 1];
1795 const vpRGBa val10 = src[y_lower + 1][x_lower];
1796 const vpRGBa val11 = src[y_lower + 1][x_lower + 1];
1797 const double colR0 = lerp(val00.
R, val01.
R, s);
1798 const double colR1 = lerp(val10.
R, val11.
R, s);
1799 const double interpR = lerp(colR0, colR1, t);
1801 const double colG0 = lerp(val00.
G, val01.
G, s);
1802 const double colG1 = lerp(val10.
G, val11.
G, s);
1803 const double interpG = lerp(colG0, colG1, t);
1805 const double colB0 = lerp(val00.
B, val01.
B, s);
1806 const double colB1 = lerp(val10.
B, val11.
B, s);
1807 const double interpB = lerp(colB0, colB1, t);
1809 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1810 vpMath::saturate<unsigned char>(interpB), 255);
1811 }
else if (y_lower <
static_cast<int>(src.
getHeight()) - 1) {
1812 const vpRGBa val00 = src[y_lower][x_lower];
1813 const vpRGBa val10 = src[y_lower + 1][x_lower];
1814 const double interpR = lerp(val00.
R, val10.
R, t);
1815 const double interpG = lerp(val00.
G, val10.
G, t);
1816 const double interpB = lerp(val00.
B, val10.
B, t);
1818 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1819 vpMath::saturate<unsigned char>(interpB), 255);
1820 }
else if (x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1821 const vpRGBa val00 = src[y_lower][x_lower];
1822 const vpRGBa val01 = src[y_lower][x_lower + 1];
1823 const double interpR = lerp(val00.
R, val01.
R, s);
1824 const double interpG = lerp(val00.
G, val01.
G, s);
1825 const double interpB = lerp(val00.
B, val01.
B, s);
1827 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1828 vpMath::saturate<unsigned char>(interpB), 255);
1830 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.
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 s=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.