34 #ifndef vpImageTools_H
35 #define vpImageTools_H
44 #include <visp3/core/vpImage.h>
46 #ifdef VISP_HAVE_PTHREAD
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>
84 static inline void binarise(
vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
90 static void crop(
const vpImage<Type> &I,
double roi_top,
double roi_left,
unsigned int roi_height,
91 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
97 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
100 unsigned int h_scale = 1);
101 template <
class Type>
102 static void crop(
const unsigned char *bitmap,
unsigned int width,
unsigned int height,
const vpRect &roi,
103 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
122 bool saturate =
false);
127 static void initUndistortMap(
const vpCameraParameters &cam,
unsigned int width,
unsigned int height,
132 const vpImageInterpolationType &method = INTERPOLATION_NEAREST);
145 template <
class Type>
147 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
149 template <
class Type>
151 const vpImageInterpolationType &method = INTERPOLATION_NEAREST,
unsigned int nThreads = 0);
155 bool useOptimized =
true);
157 template <
class Type>
159 unsigned int nThreads = 2);
161 template <
class Type>
165 template <
class Type>
167 const vpImageInterpolationType &interpolation = INTERPOLATION_NEAREST,
168 bool fixedPointArithmetic =
true,
bool pixelCenter =
false);
170 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
175 template <
class Type>
177 unsigned int nrow_sub,
unsigned int ncol_sub,
vpImage<Type> &S);
179 template <
class Type>
186 static float cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t);
188 template <
class Type>
static Type getPixelClamped(
const vpImage<Type> &I,
float u,
float v);
190 static int coordCast(
double x);
193 static double lerp(
double A,
double B,
double t);
194 static float lerp(
float A,
float B,
float t);
195 static int64_t lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1);
201 template <
class Type>
203 float v,
float xFrac,
float yFrac);
205 template <
class Type>
207 float v,
float xFrac,
float yFrac);
209 template <
class Type>
213 static void resizeSimdlib(
const vpImage<vpRGBa> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
215 static void resizeSimdlib(
const vpImage<unsigned char> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
218 template <
class Type>
222 template <
class Type>
224 bool centerCorner,
bool fixedPoint);
226 static bool checkFixedPoint(
unsigned int x,
unsigned int y,
const vpMatrix &T,
bool affine);
229 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
249 template <
class Type>
251 unsigned int roi_height,
unsigned int roi_width,
vpImage<Type> &crop)
300 template <
class Type>
302 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
304 int i_min = (std::max)((
int)(ceil(roi_top / v_scale)), 0);
305 int j_min = (std::max)((
int)(ceil(roi_left / h_scale)), 0);
306 int i_max = (std::min)((
int)(ceil((roi_top + roi_height)) / v_scale), (
int)(I.
getHeight() / v_scale));
307 int j_max = (std::min)((
int)(ceil((roi_left + roi_width) / h_scale)), (
int)(I.
getWidth() / h_scale));
309 unsigned int i_min_u = (
unsigned int)i_min;
310 unsigned int j_min_u = (
unsigned int)j_min;
312 unsigned int r_width = (
unsigned int)(j_max - j_min);
313 unsigned int r_height = (
unsigned int)(i_max - i_min);
315 crop.resize(r_height, r_width);
317 if (v_scale == 1 && h_scale == 1) {
318 for (
unsigned int i = 0; i < r_height; i++) {
319 void *src = (
void *)(I[i + i_min_u] + j_min_u);
320 void *dst = (
void *)
crop[i];
321 memcpy(dst, src, r_width *
sizeof(Type));
323 }
else if (h_scale == 1) {
324 for (
unsigned int i = 0; i < r_height; i++) {
325 void *src = (
void *)(I[(i + i_min_u) * v_scale] + j_min_u);
326 void *dst = (
void *)
crop[i];
327 memcpy(dst, src, r_width *
sizeof(Type));
330 for (
unsigned int i = 0; i < r_height; i++) {
331 for (
unsigned int j = 0; j < r_width; j++) {
332 crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
355 template <
class Type>
357 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
378 template <
class Type>
380 unsigned int h_scale)
403 template <
class Type>
405 vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
407 int i_min = (std::max)((
int)(ceil(roi.
getTop() / v_scale)), 0);
408 int j_min = (std::max)((
int)(ceil(roi.
getLeft() / h_scale)), 0);
409 int i_max = (std::min)((
int)(ceil((roi.
getTop() + roi.
getHeight()) / v_scale)), (
int)(height / v_scale));
410 int j_max = (std::min)((
int)(ceil((roi.
getLeft() + roi.
getWidth()) / h_scale)), (
int)(width / h_scale));
412 unsigned int i_min_u = (
unsigned int)i_min;
413 unsigned int j_min_u = (
unsigned int)j_min;
415 unsigned int r_width = (
unsigned int)(j_max - j_min);
416 unsigned int r_height = (
unsigned int)(i_max - i_min);
418 crop.resize(r_height, r_width);
420 if (v_scale == 1 && h_scale == 1) {
421 for (
unsigned int i = 0; i < r_height; i++) {
422 void *src = (
void *)(bitmap + ((i + i_min_u) * width + j_min_u) *
sizeof(Type));
423 void *dst = (
void *)
crop[i];
424 memcpy(dst, src, r_width *
sizeof(Type));
426 }
else if (h_scale == 1) {
427 for (
unsigned int i = 0; i < r_height; i++) {
428 void *src = (
void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) *
sizeof(Type));
429 void *dst = (
void *)
crop[i];
430 memcpy(dst, src, r_width *
sizeof(Type));
433 for (
unsigned int i = 0; i < r_height; i++) {
434 unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
435 for (
unsigned int j = 0; j < r_width; j++) {
436 void *src = (
void *)(bitmap + (i_src + j * h_scale) *
sizeof(Type));
437 void *dst = (
void *)&
crop[i][j];
438 memcpy(dst, src,
sizeof(Type));
454 template <
class Type>
456 Type value3,
bool useLUT)
459 std::cerr <<
"LUT not available for this type ! Will use the iteration method." << std::endl;
465 for (; p < pend; p++) {
469 else if (v > threshold2)
488 unsigned char value1,
unsigned char value2,
unsigned char value3,
bool useLUT)
492 unsigned char lut[256];
493 for (
unsigned int i = 0; i < 256; i++) {
494 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
499 unsigned char *p = I.
bitmap;
501 for (; p < pend; p++) {
502 unsigned char v = *p;
505 else if (v > threshold2)
513 #ifdef VISP_HAVE_PTHREAD
515 #ifndef DOXYGEN_SHOULD_SKIP_THIS
516 template <
class Type>
class vpUndistortInternalType
524 unsigned int nthreads;
525 unsigned int threadid;
528 vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0) {}
530 vpUndistortInternalType(
const vpUndistortInternalType<Type> &u) { *
this = u; }
531 vpUndistortInternalType &operator=(
const vpUndistortInternalType<Type> &u)
538 nthreads = u.nthreads;
539 threadid = u.threadid;
544 static void *vpUndistort_threaded(
void *arg);
547 template <
class Type>
void *vpUndistortInternalType<Type>::vpUndistort_threaded(
void *arg)
549 vpUndistortInternalType<Type> *undistortSharedData =
static_cast<vpUndistortInternalType<Type> *
>(arg);
550 int offset = (int)undistortSharedData->threadid;
551 int width = (
int)undistortSharedData->width;
552 int height = (int)undistortSharedData->height;
553 int nthreads = (
int)undistortSharedData->nthreads;
555 double u0 = undistortSharedData->cam.get_u0();
556 double v0 = undistortSharedData->cam.get_v0();
557 double px = undistortSharedData->cam.get_px();
558 double py = undistortSharedData->cam.get_py();
559 double kud = undistortSharedData->cam.get_kud();
561 double invpx = 1.0 / px;
562 double invpy = 1.0 / py;
564 double kud_px2 = kud * invpx * invpx;
565 double kud_py2 = kud * invpy * invpy;
567 Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
568 Type *src = undistortSharedData->src;
570 for (
double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
571 double deltav = v - v0;
573 double fr1 = 1.0 + kud_py2 * deltav * deltav;
575 for (
double u = 0; u < width; u++) {
577 double deltau = u - u0;
579 double fr2 = fr1 + kud_px2 * deltau * deltau;
581 double u_double = deltau * fr2 + u0;
582 double v_double = deltav * fr2 + v0;
587 int u_round = (int)(u_double);
588 int v_round = (int)(v_double);
593 double du_double = (u_double) - (
double)u_round;
594 double dv_double = (v_double) - (
double)v_round;
597 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
599 const Type *_mp = &src[v_round * width + u_round];
600 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
602 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
603 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
611 pthread_exit((
void *)0);
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;
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));
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);
813 template <
class Type>
817 remap(I, mapU, mapV, mapDu, mapDv, newI);
829 newI.
resize(height, width);
831 for (
unsigned int i = 0; i < height; i++) {
832 memcpy(newI.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
873 for (
unsigned int i = 0; i < height / 2; i++) {
874 memcpy(Ibuf.
bitmap, I.
bitmap + i * width, width *
sizeof(Type));
876 memcpy(I.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
877 memcpy(I.
bitmap + (height - 1 - i) * width, Ibuf.
bitmap, width *
sizeof(Type));
881 template <
class Type> Type vpImageTools::getPixelClamped(
const vpImage<Type> &I,
float u,
float v)
885 x = (std::max)(0, (std::min)(x,
static_cast<int>(I.
getWidth()) - 1));
886 y = (std::max)(0, (std::min)(y,
static_cast<int>(I.
getHeight()) - 1));
893 template <
class Type>
895 float v,
float xFrac,
float yFrac)
898 Type p00 = getPixelClamped(I, u - 1, v - 1);
899 Type p01 = getPixelClamped(I, u + 0, v - 1);
900 Type p02 = getPixelClamped(I, u + 1, v - 1);
901 Type p03 = getPixelClamped(I, u + 2, v - 1);
904 Type p10 = getPixelClamped(I, u - 1, v + 0);
905 Type p11 = getPixelClamped(I, u + 0, v + 0);
906 Type p12 = getPixelClamped(I, u + 1, v + 0);
907 Type p13 = getPixelClamped(I, u + 2, v + 0);
910 Type p20 = getPixelClamped(I, u - 1, v + 1);
911 Type p21 = getPixelClamped(I, u + 0, v + 1);
912 Type p22 = getPixelClamped(I, u + 1, v + 1);
913 Type p23 = getPixelClamped(I, u + 2, v + 1);
916 Type p30 = getPixelClamped(I, u - 1, v + 2);
917 Type p31 = getPixelClamped(I, u + 0, v + 2);
918 Type p32 = getPixelClamped(I, u + 1, v + 2);
919 Type p33 = getPixelClamped(I, u + 2, v + 2);
921 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
922 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
923 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
924 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
925 float value = cubicHermite(col0, col1, col2, col3, yFrac);
926 Ires[i][j] = vpMath::saturate<Type>(value);
931 float u,
float v,
float xFrac,
float yFrac)
934 vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
935 vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
936 vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
937 vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
940 vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
941 vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
942 vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
943 vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
946 vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
947 vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
948 vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
949 vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
952 vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
953 vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
954 vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
955 vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
957 for (
int c = 0; c < 3; c++) {
958 float col0 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p00)[c]),
959 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p01)[c]),
960 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p02)[c]),
961 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p03)[c]), xFrac);
962 float col1 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p10)[c]),
963 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p11)[c]),
964 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p12)[c]),
965 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p13)[c]), xFrac);
966 float col2 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p20)[c]),
967 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p21)[c]),
968 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p22)[c]),
969 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p23)[c]), xFrac);
970 float col3 = cubicHermite(
static_cast<float>(
reinterpret_cast<unsigned char *
>(&p30)[c]),
971 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p31)[c]),
972 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p32)[c]),
973 static_cast<float>(
reinterpret_cast<unsigned char *
>(&p33)[c]), xFrac);
974 float value = cubicHermite(col0, col1, col2, col3, yFrac);
976 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
980 template <
class Type>
982 float v,
float xFrac,
float yFrac)
984 int u0 =
static_cast<int>(u);
985 int v0 =
static_cast<int>(v);
987 int u1 = (std::min)(
static_cast<int>(I.
getWidth()) - 1, u0 + 1);
991 int v2 = (std::min)(
static_cast<int>(I.
getHeight()) - 1, v0 + 1);
996 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
997 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
998 float value = lerp(col0, col1, yFrac);
1000 Ires[i][j] = vpMath::saturate<Type>(value);
1005 unsigned int j,
float u,
float v,
float xFrac,
float yFrac)
1007 int u0 =
static_cast<int>(u);
1008 int v0 =
static_cast<int>(v);
1010 int u1 = (std::min)(
static_cast<int>(I.
getWidth()) - 1, u0 + 1);
1014 int v2 = (std::min)(
static_cast<int>(I.
getHeight()) - 1, v0 + 1);
1019 for (
int c = 0; c < 3; c++) {
1020 float col0 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v0][u0])[c]),
1021 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v1][u1])[c]), xFrac);
1022 float col1 = lerp(
static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v2][u2])[c]),
1023 static_cast<float>(
reinterpret_cast<const unsigned char *
>(&I[v3][u3])[c]), xFrac);
1024 float value = lerp(col0, col1, yFrac);
1026 reinterpret_cast<unsigned char *
>(&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
1030 template <
class Type>
1034 Ires[i][j] = getPixelClamped(I, u, v);
1055 template <
class Type>
1059 Ires.
resize(height, width);
1081 template <
class Type>
1090 std::cerr <<
"Input or output image is too small!" << std::endl;
1095 std::cerr <<
"INTERPOLATION_AREA is not implemented for this type." << std::endl;
1101 const float half = 0.5f;
1105 omp_set_num_threads(
static_cast<int>(nThreads));
1107 #pragma omp parallel for schedule(dynamic)
1109 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1110 const float v = (i + half) * scaleY - half;
1111 const int v0 =
static_cast<int>(v);
1112 const float yFrac = v - v0;
1114 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1115 const float u = (j + half) * scaleX - half;
1116 const int u0 =
static_cast<int>(u);
1117 const float xFrac = u - u0;
1120 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1122 resizeBilinear(I, Ires,
static_cast<unsigned int>(i), j, u0, v0, xFrac, yFrac);
1124 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1140 std::cerr <<
"Input or output image is too small!" << std::endl;
1151 const float half = 0.5f;
1155 omp_set_num_threads(
static_cast<int>(nThreads));
1157 #pragma omp parallel for schedule(dynamic)
1159 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1160 float v = (i + half) * scaleY - half;
1161 float yFrac = v -
static_cast<int>(v);
1163 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1164 float u = (j + half) * scaleX - half;
1165 float xFrac = u -
static_cast<int>(u);
1168 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1170 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1187 std::cerr <<
"Input or output image is too small!" << std::endl;
1198 const float half = 0.5f;
1202 omp_set_num_threads(
static_cast<int>(nThreads));
1204 #pragma omp parallel for schedule(dynamic)
1206 for (
int i = 0; i < static_cast<int>(Ires.
getHeight()); i++) {
1207 float v = (i + half) * scaleY - half;
1208 float yFrac = v -
static_cast<int>(v);
1210 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1211 float u = (j + half) * scaleX - half;
1212 float xFrac = u -
static_cast<int>(u);
1215 resizeNearest(I, Ires,
static_cast<unsigned int>(i), j, u, v);
1217 resizeBicubic(I, Ires,
static_cast<unsigned int>(i), j, u, v, xFrac, yFrac);
1238 template <
class Type>
1243 std::cerr <<
"Input transformation must be a (2x3) or (3x3) matrix." << std::endl;
1251 const bool affine = (T.
getRows() == 2);
1260 double D = M[0][0] * M[1][1] - M[0][1] * M[1][0];
1261 D = !
vpMath::nul(D, std::numeric_limits<double>::epsilon()) ? 1.0 / D : 0;
1262 double A11 = M[1][1] * D, A22 = M[0][0] * D;
1267 double b1 = -M[0][0] * M[0][2] - M[0][1] * M[1][2];
1268 double b2 = -M[1][0] * M[0][2] - M[1][1] * M[1][2];
1275 if (fixedPointArithmetic && !pixelCenter) {
1276 fixedPointArithmetic = checkFixedPoint(0, 0, M, affine) && checkFixedPoint(dst.
getWidth() - 1, 0, M, affine) &&
1277 checkFixedPoint(0, dst.
getHeight() - 1, M, affine) &&
1283 warpNN(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1286 warpLinear(src, M, dst, affine, pixelCenter, fixedPointArithmetic);
1290 template <
class Type>
1292 bool centerCorner,
bool fixedPoint)
1294 if (fixedPoint && !centerCorner) {
1295 const int nbits = 16;
1296 const int32_t precision = 1 << nbits;
1297 const float precision_1 = 1 /
static_cast<float>(precision);
1299 int32_t a0_i32 =
static_cast<int32_t
>(T[0][0] * precision);
1300 int32_t a1_i32 =
static_cast<int32_t
>(T[0][1] * precision);
1301 int32_t a2_i32 =
static_cast<int32_t
>(T[0][2] * precision);
1302 int32_t a3_i32 =
static_cast<int32_t
>(T[1][0] * precision);
1303 int32_t a4_i32 =
static_cast<int32_t
>(T[1][1] * precision);
1304 int32_t a5_i32 =
static_cast<int32_t
>(T[1][2] * precision);
1305 int32_t a6_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][0] * precision) : 0;
1306 int32_t a7_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][1] * precision) : 0;
1307 int32_t a8_i32 = T.
getRows() == 3 ?
static_cast<int32_t
>(T[2][2] * precision) : 1;
1309 int32_t height_1_i32 =
static_cast<int32_t
>((src.
getHeight() - 1) * precision) + 0x8000;
1310 int32_t width_1_i32 =
static_cast<int32_t
>((src.
getWidth() - 1) * precision) + 0x8000;
1313 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1314 int32_t xi = a2_i32;
1315 int32_t yi = a5_i32;
1317 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1318 if (yi >= 0 && yi < height_1_i32 && xi >= 0 && xi < width_1_i32) {
1319 float x_ = (xi >> nbits) + (xi & 0xFFFF) * precision_1;
1320 float y_ = (yi >> nbits) + (yi & 0xFFFF) * precision_1;
1324 dst[i][j] = src[y][x];
1335 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1336 int64_t xi = a2_i32;
1337 int64_t yi = a5_i32;
1338 int64_t wi = a8_i32;
1340 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1341 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1342 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1343 float w_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1344 float x_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / w_;
1345 float y_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / w_;
1350 dst[i][j] = src[y][x];
1364 double a0 = T[0][0];
1365 double a1 = T[0][1];
1366 double a2 = T[0][2];
1367 double a3 = T[1][0];
1368 double a4 = T[1][1];
1369 double a5 = T[1][2];
1370 double a6 = affine ? 0.0 : T[2][0];
1371 double a7 = affine ? 0.0 : T[2][1];
1372 double a8 = affine ? 1.0 : T[2][2];
1374 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1375 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1376 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1377 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1378 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1380 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1384 int x_ = centerCorner ? coordCast(x / w) :
vpMath::round(x / w);
1385 int y_ = centerCorner ? coordCast(y / w) :
vpMath::round(y / w);
1387 if (x_ >= 0 && x_ <
static_cast<int>(src.
getWidth()) && y_ >= 0 && y_ <
static_cast<int>(src.
getHeight())) {
1388 dst[i][j] = src[y_][x_];
1395 template <
class Type>
1397 bool centerCorner,
bool fixedPoint)
1399 if (fixedPoint && !centerCorner) {
1400 const int nbits = 16;
1401 const int64_t precision = 1 << nbits;
1402 const float precision_1 = 1 /
static_cast<float>(precision);
1403 const int64_t precision2 = 1ULL << (2 * nbits);
1404 const float precision_2 = 1 /
static_cast<float>(precision2);
1406 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1407 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1408 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1409 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1410 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1411 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1412 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1413 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1414 int64_t a8_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][2] * precision) : 1;
1416 int64_t height_i64 =
static_cast<int64_t
>(src.
getHeight() * precision);
1417 int64_t width_i64 =
static_cast<int64_t
>(src.
getWidth() * precision);
1420 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1421 int64_t xi_ = a2_i64;
1422 int64_t yi_ = a5_i64;
1424 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1425 if (yi_ >= 0 && yi_ < height_i64 && xi_ >= 0 && xi_ < width_i64) {
1426 const int64_t xi_lower = xi_ & (~0xFFFF);
1427 const int64_t yi_lower = yi_ & (~0xFFFF);
1429 const int64_t t = yi_ - yi_lower;
1430 const int64_t t_1 = precision - t;
1431 const int64_t s = xi_ - xi_lower;
1432 const int64_t s_1 = precision - s;
1434 const int x_ =
static_cast<int>(xi_ >> nbits);
1435 const int y_ =
static_cast<int>(yi_ >> nbits);
1437 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1438 const Type val00 = src[y_][x_];
1439 const Type val01 = src[y_][x_ + 1];
1440 const Type val10 = src[y_ + 1][x_];
1441 const Type val11 = src[y_ + 1][x_ + 1];
1442 const int64_t interp_i64 =
1443 static_cast<int64_t
>(s_1 * t_1 * val00 + s * t_1 * val01 + s_1 * t * val10 + s * t * val11);
1444 const float interp = (interp_i64 >> (nbits * 2)) + (interp_i64 & 0xFFFFFFFF) * precision_2;
1445 dst[i][j] = vpMath::saturate<Type>(interp);
1446 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1447 const Type val00 = src[y_][x_];
1448 const Type val10 = src[y_ + 1][x_];
1449 const int64_t interp_i64 =
static_cast<int64_t
>(t_1 * val00 + t * val10);
1450 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1451 dst[i][j] = vpMath::saturate<Type>(interp);
1452 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1453 const Type val00 = src[y_][x_];
1454 const Type val01 = src[y_][x_ + 1];
1455 const int64_t interp_i64 =
static_cast<int64_t
>(s_1 * val00 + s * val01);
1456 const float interp = (interp_i64 >> nbits) + (interp_i64 & 0xFFFF) * precision_1;
1457 dst[i][j] = vpMath::saturate<Type>(interp);
1459 dst[i][j] = src[y_][x_];
1471 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1472 int64_t xi = a2_i64;
1473 int64_t yi = a5_i64;
1474 int64_t wi = a8_i64;
1476 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1477 if (wi != 0 && yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1478 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1479 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1480 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1481 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1483 const int x_ =
static_cast<int>(xi_);
1484 const int y_ =
static_cast<int>(yi_);
1486 const float t = yi_ - y_;
1487 const float s = xi_ - x_;
1489 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1490 const Type val00 = src[y_][x_];
1491 const Type val01 = src[y_][x_ + 1];
1492 const Type val10 = src[y_ + 1][x_];
1493 const Type val11 = src[y_ + 1][x_ + 1];
1494 const float col0 = lerp(val00, val01, s);
1495 const float col1 = lerp(val10, val11, s);
1496 const float interp = lerp(col0, col1, t);
1497 dst[i][j] = vpMath::saturate<Type>(interp);
1498 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1499 const Type val00 = src[y_][x_];
1500 const Type val10 = src[y_ + 1][x_];
1501 const float interp = lerp(val00, val10, t);
1502 dst[i][j] = vpMath::saturate<Type>(interp);
1503 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1504 const Type val00 = src[y_][x_];
1505 const Type val01 = src[y_][x_ + 1];
1506 const float interp = lerp(val00, val01, s);
1507 dst[i][j] = vpMath::saturate<Type>(interp);
1509 dst[i][j] = src[y_][x_];
1524 double a0 = T[0][0];
1525 double a1 = T[0][1];
1526 double a2 = T[0][2];
1527 double a3 = T[1][0];
1528 double a4 = T[1][1];
1529 double a5 = T[1][2];
1530 double a6 = affine ? 0.0 : T[2][0];
1531 double a7 = affine ? 0.0 : T[2][1];
1532 double a8 = affine ? 1.0 : T[2][2];
1534 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1535 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1536 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1537 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1538 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1539 if (
vpMath::nul(w, std::numeric_limits<double>::epsilon())) {
1543 x = x / w - (centerCorner ? 0.5 : 0);
1544 y = y / w - (centerCorner ? 0.5 : 0);
1546 int x_lower =
static_cast<int>(x);
1547 int y_lower =
static_cast<int>(y);
1549 if (y_lower >=
static_cast<int>(src.
getHeight()) || x_lower >=
static_cast<int>(src.
getWidth()) || y < 0 ||
1554 double s = x - x_lower;
1555 double t = y - y_lower;
1557 if (y_lower <
static_cast<int>(src.
getHeight()) - 1 && x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1558 const Type val00 = src[y_lower][x_lower];
1559 const Type val01 = src[y_lower][x_lower + 1];
1560 const Type val10 = src[y_lower + 1][x_lower];
1561 const Type val11 = src[y_lower + 1][x_lower + 1];
1562 const double col0 = lerp(val00, val01, s);
1563 const double col1 = lerp(val10, val11, s);
1564 const double interp = lerp(col0, col1, t);
1565 dst[i][j] = vpMath::saturate<Type>(interp);
1566 }
else if (y_lower <
static_cast<int>(src.
getHeight()) - 1) {
1567 const Type val00 = src[y_lower][x_lower];
1568 const Type val10 = src[y_lower + 1][x_lower];
1569 const double interp = lerp(val00, val10, t);
1570 dst[i][j] = vpMath::saturate<Type>(interp);
1571 }
else if (x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1572 const Type val00 = src[y_lower][x_lower];
1573 const Type val01 = src[y_lower][x_lower + 1];
1574 const double interp = lerp(val00, val01, s);
1575 dst[i][j] = vpMath::saturate<Type>(interp);
1577 dst[i][j] = src[y_lower][x_lower];
1586 bool centerCorner,
bool fixedPoint)
1588 if (fixedPoint && !centerCorner) {
1589 const int nbits = 16;
1590 const int64_t precision = 1 << nbits;
1591 const float precision_1 = 1 /
static_cast<float>(precision);
1592 const int64_t precision2 = 1ULL << (2 * nbits);
1593 const float precision_2 = 1 /
static_cast<float>(precision2);
1595 int64_t a0_i64 =
static_cast<int64_t
>(T[0][0] * precision);
1596 int64_t a1_i64 =
static_cast<int64_t
>(T[0][1] * precision);
1597 int64_t a2_i64 =
static_cast<int64_t
>(T[0][2] * precision);
1598 int64_t a3_i64 =
static_cast<int64_t
>(T[1][0] * precision);
1599 int64_t a4_i64 =
static_cast<int64_t
>(T[1][1] * precision);
1600 int64_t a5_i64 =
static_cast<int64_t
>(T[1][2] * precision);
1601 int64_t a6_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][0] * precision) : 0;
1602 int64_t a7_i64 = T.
getRows() == 3 ?
static_cast<int64_t
>(T[2][1] * precision) : 0;
1603 int64_t a8_i64 = precision;
1605 int64_t height_i64 =
static_cast<int64_t
>(src.
getHeight() * precision);
1606 int64_t width_i64 =
static_cast<int64_t
>(src.
getWidth() * precision);
1609 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1610 int64_t xi = a2_i64;
1611 int64_t yi = a5_i64;
1613 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1614 if (yi >= 0 && yi < height_i64 && xi >= 0 && xi < width_i64) {
1615 const int64_t xi_lower = xi & (~0xFFFF);
1616 const int64_t yi_lower = yi & (~0xFFFF);
1618 const int64_t t = yi - yi_lower;
1619 const int64_t t_1 = precision - t;
1620 const int64_t s = xi - xi_lower;
1621 const int64_t s_1 = precision - s;
1623 const int x_ =
static_cast<int>(xi >> nbits);
1624 const int y_ =
static_cast<int>(yi >> nbits);
1626 if (y_ <
static_cast<int>(src.
getHeight()) - 1 && x_ <
static_cast<int>(src.
getWidth()) - 1) {
1627 const vpRGBa val00 = src[y_][x_];
1628 const vpRGBa val01 = src[y_][x_ + 1];
1629 const vpRGBa val10 = src[y_ + 1][x_];
1630 const vpRGBa val11 = src[y_ + 1][x_ + 1];
1631 const int64_t interpR_i64 =
1632 static_cast<int64_t
>(s_1 * t_1 * val00.
R + s * t_1 * val01.
R + s_1 * t * val10.
R + s * t * val11.
R);
1633 const float interpR = (interpR_i64 >> (nbits * 2)) + (interpR_i64 & 0xFFFFFFFF) * precision_2;
1635 const int64_t interpG_i64 =
1636 static_cast<int64_t
>(s_1 * t_1 * val00.
G + s * t_1 * val01.
G + s_1 * t * val10.
G + s * t * val11.
G);
1637 const float interpG = (interpG_i64 >> (nbits * 2)) + (interpG_i64 & 0xFFFFFFFF) * precision_2;
1639 const int64_t interpB_i64 =
1640 static_cast<int64_t
>(s_1 * t_1 * val00.
B + s * t_1 * val01.
B + s_1 * t * val10.
B + s * t * val11.
B);
1641 const float interpB = (interpB_i64 >> (nbits * 2)) + (interpB_i64 & 0xFFFFFFFF) * precision_2;
1643 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1644 vpMath::saturate<unsigned char>(interpB), 255);
1645 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1646 const vpRGBa val00 = src[y_][x_];
1647 const vpRGBa val10 = src[y_ + 1][x_];
1648 const int64_t interpR_i64 =
static_cast<int64_t
>(t_1 * val00.
R + t * val10.
R);
1649 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1651 const int64_t interpG_i64 =
static_cast<int64_t
>(t_1 * val00.
G + t * val10.
G);
1652 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1654 const int64_t interpB_i64 =
static_cast<int64_t
>(t_1 * val00.
B + t * val10.
B);
1655 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1657 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1658 vpMath::saturate<unsigned char>(interpB), 255);
1659 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1660 const vpRGBa val00 = src[y_][x_];
1661 const vpRGBa val01 = src[y_][x_ + 1];
1662 const int64_t interpR_i64 =
static_cast<int64_t
>(s_1 * val00.
R + s * val01.
R);
1663 const float interpR = (interpR_i64 >> nbits) + (interpR_i64 & 0xFFFF) * precision_1;
1665 const int64_t interpG_i64 =
static_cast<int64_t
>(s_1 * val00.
G + s * val01.
G);
1666 const float interpG = (interpG_i64 >> nbits) + (interpG_i64 & 0xFFFF) * precision_1;
1668 const int64_t interpB_i64 =
static_cast<int64_t
>(s_1 * val00.
B + s * val01.
B);
1669 const float interpB = (interpB_i64 >> nbits) + (interpB_i64 & 0xFFFF) * precision_1;
1671 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1672 vpMath::saturate<unsigned char>(interpB), 255);
1674 dst[i][j] = src[y_][x_];
1686 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1687 int64_t xi = a2_i64;
1688 int64_t yi = a5_i64;
1689 int64_t wi = a8_i64;
1691 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1692 if (yi >= 0 && yi <= (
static_cast<int>(src.
getHeight()) - 1) * wi && xi >= 0 &&
1693 xi <= (
static_cast<int>(src.
getWidth()) - 1) * wi) {
1694 const float wi_ = (wi >> nbits) + (wi & 0xFFFF) * precision_1;
1695 const float xi_ = ((xi >> nbits) + (xi & 0xFFFF) * precision_1) / wi_;
1696 const float yi_ = ((yi >> nbits) + (yi & 0xFFFF) * precision_1) / wi_;
1698 const int x_ =
static_cast<int>(xi_);
1699 const int y_ =
static_cast<int>(yi_);
1701 const float t = yi_ - y_;
1702 const float s = xi_ - x_;
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 float colR0 = lerp(val00.
R, val01.
R, s);
1710 const float colR1 = lerp(val10.
R, val11.
R, s);
1711 const float interpR = lerp(colR0, colR1, t);
1713 const float colG0 = lerp(val00.
G, val01.
G, s);
1714 const float colG1 = lerp(val10.
G, val11.
G, s);
1715 const float interpG = lerp(colG0, colG1, t);
1717 const float colB0 = lerp(val00.
B, val01.
B, s);
1718 const float colB1 = lerp(val10.
B, val11.
B, s);
1719 const float interpB = lerp(colB0, colB1, t);
1721 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1722 vpMath::saturate<unsigned char>(interpB), 255);
1723 }
else if (y_ <
static_cast<int>(src.
getHeight()) - 1) {
1724 const vpRGBa val00 = src[y_][x_];
1725 const vpRGBa val10 = src[y_ + 1][x_];
1726 const float interpR = lerp(val00.
R, val10.
R, t);
1727 const float interpG = lerp(val00.
G, val10.
G, t);
1728 const float interpB = lerp(val00.
B, val10.
B, t);
1730 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1731 vpMath::saturate<unsigned char>(interpB), 255);
1732 }
else if (x_ <
static_cast<int>(src.
getWidth()) - 1) {
1733 const vpRGBa val00 = src[y_][x_];
1734 const vpRGBa val01 = src[y_][x_ + 1];
1735 const float interpR = lerp(val00.
R, val01.
R, s);
1736 const float interpG = lerp(val00.
G, val01.
G, s);
1737 const float interpB = lerp(val00.
B, val01.
B, s);
1739 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1740 vpMath::saturate<unsigned char>(interpB), 255);
1742 dst[i][j] = src[y_][x_];
1757 double a0 = T[0][0];
1758 double a1 = T[0][1];
1759 double a2 = T[0][2];
1760 double a3 = T[1][0];
1761 double a4 = T[1][1];
1762 double a5 = T[1][2];
1763 double a6 = affine ? 0.0 : T[2][0];
1764 double a7 = affine ? 0.0 : T[2][1];
1765 double a8 = affine ? 1.0 : T[2][2];
1767 for (
unsigned int i = 0; i < dst.
getHeight(); i++) {
1768 for (
unsigned int j = 0; j < dst.
getWidth(); j++) {
1769 double x = a0 * (centerCorner ? j + 0.5 : j) + a1 * (centerCorner ? i + 0.5 : i) + a2;
1770 double y = a3 * (centerCorner ? j + 0.5 : j) + a4 * (centerCorner ? i + 0.5 : i) + a5;
1771 double w = a6 * (centerCorner ? j + 0.5 : j) + a7 * (centerCorner ? i + 0.5 : i) + a8;
1773 x = x / w - (centerCorner ? 0.5 : 0);
1774 y = y / w - (centerCorner ? 0.5 : 0);
1776 int x_lower =
static_cast<int>(x);
1777 int y_lower =
static_cast<int>(y);
1779 if (y_lower >=
static_cast<int>(src.
getHeight()) || x_lower >=
static_cast<int>(src.
getWidth()) || y < 0 ||
1784 double s = x - x_lower;
1785 double t = y - y_lower;
1787 if (y_lower <
static_cast<int>(src.
getHeight()) - 1 && x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1788 const vpRGBa val00 = src[y_lower][x_lower];
1789 const vpRGBa val01 = src[y_lower][x_lower + 1];
1790 const vpRGBa val10 = src[y_lower + 1][x_lower];
1791 const vpRGBa val11 = src[y_lower + 1][x_lower + 1];
1792 const double colR0 = lerp(val00.
R, val01.
R, s);
1793 const double colR1 = lerp(val10.
R, val11.
R, s);
1794 const double interpR = lerp(colR0, colR1, t);
1796 const double colG0 = lerp(val00.
G, val01.
G, s);
1797 const double colG1 = lerp(val10.
G, val11.
G, s);
1798 const double interpG = lerp(colG0, colG1, t);
1800 const double colB0 = lerp(val00.
B, val01.
B, s);
1801 const double colB1 = lerp(val10.
B, val11.
B, s);
1802 const double interpB = lerp(colB0, colB1, t);
1804 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1805 vpMath::saturate<unsigned char>(interpB), 255);
1806 }
else if (y_lower <
static_cast<int>(src.
getHeight()) - 1) {
1807 const vpRGBa val00 = src[y_lower][x_lower];
1808 const vpRGBa val10 = src[y_lower + 1][x_lower];
1809 const double interpR = lerp(val00.
R, val10.
R, t);
1810 const double interpG = lerp(val00.
G, val10.
G, t);
1811 const double interpB = lerp(val00.
B, val10.
B, t);
1813 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1814 vpMath::saturate<unsigned char>(interpB), 255);
1815 }
else if (x_lower <
static_cast<int>(src.
getWidth()) - 1) {
1816 const vpRGBa val00 = src[y_lower][x_lower];
1817 const vpRGBa val01 = src[y_lower][x_lower + 1];
1818 const double interpR = lerp(val00.
R, val01.
R, s);
1819 const double interpG = lerp(val00.
G, val01.
G, s);
1820 const double interpB = lerp(val00.
B, val01.
B, s);
1822 dst[i][j] =
vpRGBa(vpMath::saturate<unsigned char>(interpR), vpMath::saturate<unsigned char>(interpG),
1823 vpMath::saturate<unsigned char>(interpB), 255);
1825 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 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.