34#include <visp3/core/vpCPUFeatures.h>
35#include <visp3/core/vpImageConvert.h>
36#include <visp3/core/vpImageTools.h>
37#include <visp3/core/vpImageException.h>
39#if defined(VISP_HAVE_SIMDLIB)
40#include <Simd/SimdLib.hpp>
104 unsigned char B_star)
112 double factor =
static_cast<double>((B_star - A_star) /
static_cast<double>((B - A)));
114 unsigned int i_height = I.getHeight();
115 unsigned int i_width = I.getWidth();
116 for (
unsigned int i = 0; i < i_height; ++i) {
117 for (
unsigned int j = 0; j < i_width; ++j) {
127 I[i][j] =
static_cast<unsigned char>(A_star + (factor * (v - A)));
156#if defined(VISP_HAVE_SIMDLIB)
159 const int val_255 = 255;
160 unsigned int i1_size = I1.
getSize();
161 for (
unsigned int i = 0; i < i1_size; ++i) {
163 Idiff.
bitmap[i] =
static_cast<unsigned char>(std::max<unsigned char>(std::min<unsigned char>(diff, val_255), 0));
185 "Cannot compute image difference. The two images "
186 "(%ux%u) and (%ux%u) have not the same size",
194#if defined(VISP_HAVE_SIMDLIB)
195 SimdImageDifference(
reinterpret_cast<unsigned char *
>(I1.
bitmap),
reinterpret_cast<unsigned char *
>(I2.
bitmap),
196 I1.
getSize() * 4,
reinterpret_cast<unsigned char *
>(Idiff.
bitmap));
198 const unsigned int val_4 = 4;
199 const int val_255 = 255;
200 unsigned int i1_size = I1.
getSize();
201 for (
unsigned int i = 0; i < (i1_size * val_4); ++i) {
236 for (
unsigned int b = 0; b < n; ++b) {
260 for (
unsigned int b = 0; b < n; ++b) {
289 for (
unsigned int b = 0; b < n; ++b) {
326#if defined(VISP_HAVE_SIMDLIB)
327 typedef Simd::View<Simd::Allocator> View;
332 Simd::OperationBinary8u(img1, img2, imgAdd,
333 saturate ? SimdOperationBinary8uSaturatedAddition : SimdOperationBinary8uAddition);
335 unsigned char *ptr_I1 = I1.
bitmap;
336 unsigned char *ptr_I2 = I2.
bitmap;
337 unsigned char *ptr_Ires = Ires.
bitmap;
338 unsigned int ires_size = Ires.
getSize();
339 for (
unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
369#if defined(VISP_HAVE_SIMDLIB)
370 typedef Simd::View<Simd::Allocator> View;
375 Simd::OperationBinary8u(img1, img2, imgAdd,
376 saturate ? SimdOperationBinary8uSaturatedSubtraction : SimdOperationBinary8uSubtraction);
378 unsigned char *ptr_I1 = I1.
bitmap;
379 unsigned char *ptr_I2 = I2.
bitmap;
380 unsigned char *ptr_Ires = Ires.
bitmap;
381 unsigned int ires_size = Ires.
getSize();
382 for (
unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
383 *ptr_Ires = saturate ?
385 ((*ptr_I1) - (*ptr_I2));
405 mapU.
resize(height, width,
false,
false);
406 mapV.
resize(height, width,
false,
false);
407 mapDu.
resize(height, width,
false,
false);
408 mapDv.
resize(height, width,
false,
false);
411 bool is_KannalaBrandt =
414 float u0 =
static_cast<float>(cam.get_u0());
415 float v0 =
static_cast<float>(cam.get_v0());
416 float px =
static_cast<float>(cam.get_px());
417 float py =
static_cast<float>(cam.get_py());
419 std::vector<double> dist_coefs;
421 if (!is_KannalaBrandt) {
422 kud =
static_cast<float>(cam.get_kud());
425 dist_coefs = cam.getKannalaBrandtDistortionCoefficients();
428 if ((!is_KannalaBrandt) && (std::fabs(
static_cast<double>(kud)) <= std::numeric_limits<double>::epsilon())) {
430 for (
unsigned int i = 0; i < height; ++i) {
431 for (
unsigned int j = 0; j < width; ++j) {
432 mapU[i][j] =
static_cast<int>(j);
433 mapV[i][j] =
static_cast<int>(i);
443 float kud_px2 = 0., kud_py2 = 0., deltau_px, deltav_py = 0;
445 float deltav, deltau;
446 float u_float, v_float;
447 int u_round, v_round;
449 double theta, theta_d;
450 double theta2, theta4, theta6, theta8;
451 const unsigned int index_0 = 0;
452 const unsigned int index_1 = 1;
453 const unsigned int index_2 = 2;
454 const unsigned int index_3 = 3;
459 if (!is_KannalaBrandt) {
460 kud_px2 = kud * invpx * invpx;
461 kud_py2 = kud * invpy * invpy;
464 for (
unsigned int v = 0; v < height; ++v) {
467 if (!is_KannalaBrandt) {
468 fr1 = 1.0f + (kud_py2 * deltav * deltav);
471 deltav_py = deltav * invpy;
474 for (
unsigned int u = 0; u < width; ++u) {
477 if (!is_KannalaBrandt) {
478 fr2 = fr1 + (kud_px2 * deltau * deltau);
480 u_float = (deltau * fr2) + u0;
481 v_float = (deltav * fr2) + v0;
485 deltau_px = deltau * invpx;
491 theta6 = theta2 * theta4;
494 theta_d = theta * (1 + (dist_coefs[index_0] * theta2) + (dist_coefs[index_1] * theta4) + (dist_coefs[index_2] * theta6) +
495 (dist_coefs[index_3] * theta8));
498 scale = (std::fabs(r) < std::numeric_limits<double>::epsilon()) ? 1.0 : (theta_d / r);
499 u_float =
static_cast<float>((deltau * scale) + u0);
500 v_float =
static_cast<float>((deltav * scale) + v0);
503 u_round =
static_cast<int>(u_float);
504 v_round =
static_cast<int>(v_float);
506 mapU[v][u] = u_round;
507 mapV[v][u] = v_round;
509 mapDu[v][u] = u_float - u_round;
510 mapDv[v][u] = v_float - v_round;
528 if (I.getSize() == 0) {
529 std::cerr <<
"Error, input image is empty." << std::endl;
533 II.
resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
534 IIsq.
resize(I.getHeight() + 1, I.getWidth() + 1, 0.0);
537 unsigned int ii_width = II.
getWidth();
538 for (
unsigned int i = 1; i < ii_height; ++i) {
539 for (
unsigned int j = 1; j < ii_width; ++j) {
540 II[i][j] = (I[i - 1][j - 1] + II[i - 1][j] + II[i][j - 1]) - II[i - 1][j - 1];
541 IIsq[i][j] = (
vpMath::sqr(I[i - 1][j - 1]) + IIsq[i - 1][j] + IIsq[i][j - 1]) - IIsq[i - 1][j - 1];
557 "Error: in vpImageTools::normalizedCorrelation(): "
558 "image dimension mismatch between I1=%ux%u and I2=%ux%u",
569#if defined(VISP_HAVE_SIMDLIB)
570 SimdNormalizedCorrelation(I1.
bitmap, a, I2.
bitmap, b, I1.
getSize(), a2, b2, ab, useOptimized);
572 unsigned int i1_size = I1.
getSize();
573 for (
unsigned int cpt = 0; cpt < i1_size; ++cpt) {
581 return ab / sqrt(a2 * b2);
592 unsigned int height = I.getHeight(), width = I.getWidth();
595 for (
unsigned int i = 0; i < height; ++i) {
596 for (
unsigned int j = 0; j < width; ++j) {
600 for (
unsigned int j = 0; j < width; ++j) {
611 double s = I.getSum();
612 unsigned int i_height = I.getHeight();
613 unsigned int i_width = I.getWidth();
614 for (
unsigned int i = 0; i < i_height; ++i) {
615 for (
unsigned int j = 0; j < i_width; ++j) {
616 I(i, j, I(i, j) / s);
630 int x1 =
static_cast<int>(floor(point.
get_i()));
631 int x2 =
static_cast<int>(ceil(point.
get_i()));
632 int y1 =
static_cast<int>(floor(point.
get_j()));
633 int y2 =
static_cast<int>(ceil(point.
get_j()));
640 v1 = ((x2 - point.
get_i()) * I(x1, y1)) + ((point.
get_i() - x1) * I(x2, y1));
641 v2 = ((x2 - point.
get_i()) * I(x1, y2)) + ((point.
get_i() - x1) * I(x2, y2));
646 return ((y2 - point.
get_j()) * v1) + ((point.
get_j() - y1) * v2);
664 return interpolationNearest(I, point);
668 "vpImageTools::interpolate(): bi-cubic interpolation is not implemented.");
686 double x1 = r.getTopLeft().get_i();
687 double y1 = r.getTopLeft().get_j();
688 double t = r.getOrientation();
689 double cos_t = cos(t);
690 double sin_t = sin(t);
692 for (
unsigned int x = 0; x < x_d; ++x) {
693 double x_cos_t = x * cos_t;
694 double x_sin_t = x * sin_t;
695 for (
unsigned int y = 0; y < y_d; ++y) {
697 static_cast<unsigned char>(
interpolate(src,
vpImagePoint(x1 + x_cos_t + (y * sin_t), (y1 - x_sin_t) + (y * cos_t)),
713 double x1 = r.getTopLeft().get_i();
714 double y1 = r.getTopLeft().get_j();
715 double t = r.getOrientation();
716 double cos_t = cos(t);
717 double sin_t = sin(t);
719 for (
unsigned int x = 0; x < x_d; ++x) {
720 double x_cos_t = x * cos_t;
721 double x_sin_t = x * sin_t;
722 for (
unsigned int y = 0; y < y_d; ++y) {
748 if (I.getSize() == 0) {
749 std::cerr <<
"Error, input image is empty." << std::endl;
754 std::cerr <<
"Error, template image is empty." << std::endl;
759 std::cerr <<
"Error, template image is bigger than input image." << std::endl;
768 I_score.
resize(I.getHeight() - height_tpl, I.getWidth() - width_tpl, 0.0);
778 const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
779 const double mean2 = sum2 / I_tpl.
getSize();
780 unsigned int i_tpl_double_size = I_tpl_double.
getSize();
781 for (
unsigned int cpt = 0; cpt < i_tpl_double_size; ++cpt) {
782 I_tpl_double.
bitmap[cpt] -= mean2;
785#if defined(_OPENMP) && (_OPENMP >= 200711)
786#pragma omp parallel for schedule(dynamic)
787 for (
unsigned int i = 0; i < I.getHeight() - height_tpl; i += step_v) {
788 for (
unsigned int j = 0; j < I.getWidth() - width_tpl; j += step_u) {
794 int end =
static_cast<int>((I.getHeight() - height_tpl) / step_v) + 1;
795 std::vector<unsigned int> vec_step_v(
static_cast<size_t>(end));
796 unsigned int i_height = I.getHeight();
797 for (
unsigned int cpt = 0, idx = 0; cpt < (i_height - height_tpl); cpt += step_v, ++idx) {
798 vec_step_v[
static_cast<size_t>(idx)] = cpt;
801#pragma omp parallel for schedule(dynamic)
803 for (
int cpt = 0; cpt < end; ++cpt) {
804 unsigned int i_width = I.getWidth();
805 for (
unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
806 I_score[vec_step_v[cpt]][j] =
816 unsigned int i_width = I.getWidth();
817 for (
unsigned int i = 0; i < (i_height - height_tpl); i += step_v) {
818 for (
unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
835float vpImageTools::cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t)
837 float a = (((-A + (3.0f * B)) - (3.0f * C)) + D) / 2.0f;
838 float b = (A + (2.0f * C)) - (((5.0f * B) + D) / 2.0f);
839 float c = (-A + C) / 2.0f;
842 return (a * t * t * t) + (b * t * t) + (c * t) + d;
845int vpImageTools::coordCast(
double x) {
return x < 0 ? -1 :
static_cast<int>(
x); }
847double vpImageTools::lerp(
double A,
double B,
double t) {
return (A * (1.0 - t)) + (B *
t); }
849float vpImageTools::lerp(
float A,
float B,
float t) {
return (A * (1.0f - t)) + (B *
t); }
851int64_t vpImageTools::lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1) {
return (A * t_1) + (B *
t); }
856 unsigned int i0,
unsigned int j0)
860#if defined(VISP_HAVE_SIMDLIB)
864 unsigned int i2_width = I2.
getWidth();
865 for (
unsigned int i = 0;
i < i2_height; ++
i) {
866 for (
unsigned int j = 0;
j < i2_width; ++
j) {
867 ab += (I1[i0 +
i][j0 +
j]) * I2[i][j];
874 (((II[i0 + height_tpl][j0 + width_tpl] + II[i0][j0]) - II[i0][j0 + width_tpl]) - II[i0 + height_tpl][j0]);
875 const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
884 return ab / sqrt(a2 * b2);
900 Iundist.
resize(I.getHeight(), I.getWidth());
901 const int I_height =
static_cast<int>(I.getHeight());
904#pragma omp parallel for schedule(dynamic)
906 for (
int i_ = 0; i_ < I_height; ++i_) {
907 const unsigned int i =
static_cast<unsigned int>(i_);
908 unsigned int i_width = I.getWidth();
909 for (
unsigned int j = 0; j < i_width; ++j) {
911 int u_round = mapU[i][j];
912 int v_round = mapV[i][j];
914 float du = mapDu[i][j];
915 float dv = mapDv[i][j];
917 if ((0 <= u_round) && (0 <= v_round) && (u_round < (
static_cast<int>(I.getWidth()) - 1)) &&
918 (v_round < (I_height - 1))) {
920 float col0 = lerp(I[v_round][u_round], I[v_round][u_round + 1], du);
921 float col1 = lerp(I[v_round + 1][u_round], I[v_round + 1][u_round + 1], du);
922 float value = lerp(col0, col1, dv);
924 Iundist[i][j] =
static_cast<unsigned char>(value);
946 Iundist.
resize(I.getHeight(), I.getWidth());
947 const int I_height =
static_cast<int>(I.getHeight());
949#pragma omp parallel for schedule(dynamic)
951 for (
int i = 0; i < I_height; ++i) {
952#if defined(VISP_HAVE_SIMDLIB)
953 SimdRemap(
reinterpret_cast<unsigned char *
>(I.bitmap), 4, I.getWidth(), I.getHeight(), i * I.getWidth(), mapU.
data,
954 mapV.
data, mapDu.
data, mapDv.
data,
reinterpret_cast<unsigned char *
>(Iundist.
bitmap));
956 const unsigned int i_ =
static_cast<unsigned int>(i);
957 unsigned int i_width = I.getWidth();
958 for (
unsigned int j = 0; j < i_width; ++j) {
960 int u_round = mapU[i_][j];
961 int v_round = mapV[i_][j];
963 float du = mapDu[i_][j];
964 float dv = mapDv[i_][j];
966 if ((0 <= u_round) && (0 <= v_round) && (u_round < (
static_cast<int>(I.getWidth()) - 1))
967 && (v_round < (I_height - 1))) {
969 float col0 = lerp(I[v_round][u_round].R, I[v_round][u_round + 1].R, du);
970 float col1 = lerp(I[v_round + 1][u_round].R, I[v_round + 1][u_round + 1].R, du);
971 float value = lerp(col0, col1, dv);
973 Iundist[i][j].R =
static_cast<unsigned char>(value);
975 col0 = lerp(I[v_round][u_round].G, I[v_round][u_round + 1].G, du);
976 col1 = lerp(I[v_round + 1][u_round].G, I[v_round + 1][u_round + 1].G, du);
977 value = lerp(col0, col1, dv);
979 Iundist[i][j].G =
static_cast<unsigned char>(value);
981 col0 = lerp(I[v_round][u_round].B, I[v_round][u_round + 1].B, du);
982 col1 = lerp(I[v_round + 1][u_round].B, I[v_round + 1][u_round + 1].B, du);
983 value = lerp(col0, col1, dv);
985 Iundist[i][j].B =
static_cast<unsigned char>(value);
987 col0 = lerp(I[v_round][u_round].A, I[v_round][u_round + 1].A, du);
988 col1 = lerp(I[v_round + 1][u_round].A, I[v_round + 1][u_round + 1].A, du);
989 value = lerp(col0, col1, dv);
991 Iundist[i][j].A =
static_cast<unsigned char>(value);
1001#if defined(VISP_HAVE_SIMDLIB)
1002void vpImageTools::resizeSimdlib(
const vpImage<vpRGBa> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
1005 Idst.
resize(resizeHeight, resizeWidth);
1007 typedef Simd::View<Simd::Allocator> View;
1011 Simd::Resize(src, dst, method ==
INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1017 Idst.
resize(resizeHeight, resizeWidth);
1019 typedef Simd::View<Simd::Allocator> View;
1023 Simd::Resize(src, dst, method ==
INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1027bool vpImageTools::checkFixedPoint(
unsigned int x,
unsigned int y,
const vpMatrix &T,
bool affine)
1029 const unsigned int index_0 = 0;
1030 const unsigned int index_1 = 1;
1031 const unsigned int index_2 = 2;
1032 double a0 = T[index_0][index_0];
1033 double a1 = T[index_0][index_1];
1034 double a2 = T[index_0][index_2];
1035 double a3 = T[index_1][index_0];
1036 double a4 = T[index_1][index_1];
1037 double a5 = T[index_1][index_2];
1038 double a6 = affine ? 0.0 : T[index_2][index_0];
1039 double a7 = affine ? 0.0 : T[index_2][index_1];
1040 double a8 = affine ? 1.0 : T[index_2][index_2];
1042 double w = (a6 *
x) + (a7 * y) + a8;
1043 double x2 = ((a0 *
x) + (a1 *
y) + a2) / w;
1044 double y2 = ((a3 *
x) + (a4 *
y) + a5) / w;
1046 const double limit = 1 << 15;
1069 const vpColVector &hsv_range,
unsigned char *mask,
unsigned int size)
1071 const std::size_t val_6 = 6;
1072 if ((hue ==
nullptr) || (saturation ==
nullptr) || (value ==
nullptr)) {
1074 "Error in vpImageTools::inRange(): hsv pointer are empty"));
1076 else if (hsv_range.
size() != val_6) {
1078 "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.
size()));
1080 const unsigned int index_0 = 0;
1081 const unsigned int index_1 = 1;
1082 const unsigned int index_2 = 2;
1083 const unsigned int index_3 = 3;
1084 const unsigned int index_4 = 4;
1085 const unsigned int index_5 = 5;
1086 const unsigned char val_uchar_255 = 255;
1087 unsigned char h_low =
static_cast<unsigned char>(hsv_range[index_0]);
1088 unsigned char h_high =
static_cast<unsigned char>(hsv_range[index_1]);
1089 unsigned char s_low =
static_cast<unsigned char>(hsv_range[index_2]);
1090 unsigned char s_high =
static_cast<unsigned char>(hsv_range[index_3]);
1091 unsigned char v_low =
static_cast<unsigned char>(hsv_range[index_4]);
1092 unsigned char v_high =
static_cast<unsigned char>(hsv_range[index_5]);
1093 int size_ =
static_cast<int>(size);
1094 int cpt_in_range = 0;
1096#pragma omp parallel for reduction(+:cpt_in_range)
1098 for (
int i = 0; i < size_; ++i) {
1099 bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1100 bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1101 bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1102 if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1103 mask[i] = val_uchar_255;
1110 return cpt_in_range;
1133 const std::vector<int> &hsv_range,
unsigned char *mask,
unsigned int size)
1135 const std::size_t val_6 = 6;
1136 if ((hue ==
nullptr) || (saturation ==
nullptr) || (value ==
nullptr)) {
1138 "Error in vpImageTools::inRange(): hsv pointer are empty"));
1140 else if (hsv_range.size() != val_6) {
1142 "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.size()));
1144 const unsigned int index_0 = 0;
1145 const unsigned int index_1 = 1;
1146 const unsigned int index_2 = 2;
1147 const unsigned int index_3 = 3;
1148 const unsigned int index_4 = 4;
1149 const unsigned int index_5 = 5;
1150 unsigned char h_low =
static_cast<unsigned char>(hsv_range[index_0]);
1151 unsigned char h_high =
static_cast<unsigned char>(hsv_range[index_1]);
1152 unsigned char s_low =
static_cast<unsigned char>(hsv_range[index_2]);
1153 unsigned char s_high =
static_cast<unsigned char>(hsv_range[index_3]);
1154 unsigned char v_low =
static_cast<unsigned char>(hsv_range[index_4]);
1155 unsigned char v_high =
static_cast<unsigned char>(hsv_range[index_5]);
1156 int size_ =
static_cast<int>(size);
1157 int cpt_in_range = 0;
1159 const unsigned char val_uc_255 = 255;
1161#pragma omp parallel for reduction(+:cpt_in_range)
1163 for (
int i = 0; i < size_; ++i) {
1164 bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1165 bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1166 bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1167 if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1168 mask[i] = val_uc_255;
1175 return cpt_in_range;
Implementation of a generic 2D array used as base class for matrices and vectors.
Type * data
Address of the first element of the data array.
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
unsigned int size() const
Return the number of elements of the 2D array.
Generic class defining intrinsic camera parameters.
vpCameraParametersProjType
@ ProjWithKannalaBrandtDistortion
Projection with Kannala-Brandt distortion model.
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
@ dimensionError
Bad dimension.
@ notImplementedError
Not implemented.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Error that can be emitted by the vpImage class and its derivatives.
@ notInitializedError
Image not initialized.
@ incorrectInitializationError
Wrong image initialization.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition of the vpImage class member functions.
unsigned int getWidth() const
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
unsigned int getSize() const
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
double getMeanValue(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Return the mean value of the bitmap.
static Tp saturate(unsigned char v)
static Type maximum(const Type &a, const Type &b)
static double sqr(double x)
static Type abs(const Type &x)
static int round(double x)
static Type minimum(const Type &a, const Type &b)
Implementation of a matrix and operations on matrices.
Defines an oriented rectangle in the plane.
Defines a rectangle in the plane.
Implementation of row vector and the associated operations.
void resize(unsigned int i, bool flagNullify=true)