39 #ifndef vpImageTools_H 40 #define vpImageTools_H 50 #include <visp3/core/vpImage.h> 52 #ifdef VISP_HAVE_PTHREAD 56 #include <visp3/core/vpCameraParameters.h> 57 #include <visp3/core/vpImageException.h> 58 #include <visp3/core/vpMath.h> 59 #include <visp3/core/vpRect.h> 85 static inline void binarise(
vpImage<Type> &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3,
86 const bool useLUT =
true);
91 static void crop(
const vpImage<Type> &I,
double roi_top,
double roi_left,
unsigned int roi_height,
92 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
96 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
99 unsigned int h_scale = 1);
100 template <
class Type>
101 static void crop(
const unsigned char *bitmap,
unsigned int width,
unsigned int height,
const vpRect &roi,
102 vpImage<Type> &crop,
unsigned int v_scale = 1,
unsigned int h_scale = 1);
117 const bool saturate =
false);
122 template <
class Type>
126 template <
class Type>
130 template <
class Type>
133 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS) 138 template <
class Type>
139 vp_deprecated
static void createSubImage(
const vpImage<Type> &I,
unsigned int i_sub,
unsigned int j_sub,
140 unsigned int nrow_sub,
unsigned int ncol_sub,
vpImage<Type> &S);
142 template <
class Type>
149 static float cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t);
151 template <
class Type>
static Type getPixelClamped(
const vpImage<Type> &I,
const float u,
const float v);
154 static float lerp(
const float A,
const float B,
const float t);
156 template <
class Type>
158 const float u,
const float v,
const float xFrac,
const float yFrac);
160 template <
class Type>
162 const float u,
const float v,
const float xFrac,
const float yFrac);
164 template <
class Type>
166 const float u,
const float v);
169 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS) 188 template <
class Type>
190 unsigned int roi_height,
unsigned int roi_width,
vpImage<Type> &crop)
215 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS) 236 template <
class Type>
238 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
240 int i_min = (std::max)((
int)(ceil(roi_top / v_scale)), 0);
241 int j_min = (std::max)((
int)(ceil(roi_left / h_scale)), 0);
242 int i_max = (std::min)((
int)(ceil((roi_top + roi_height)) / v_scale), (
int)(I.
getHeight() / v_scale));
243 int j_max = (std::min)((
int)(ceil((roi_left + roi_width) / h_scale)), (
int)(I.
getWidth() / h_scale));
245 unsigned int i_min_u = (
unsigned int)i_min;
246 unsigned int j_min_u = (
unsigned int)j_min;
248 unsigned int r_width = (
unsigned int)(j_max - j_min);
249 unsigned int r_height = (
unsigned int)(i_max - i_min);
251 crop.
resize(r_height, r_width);
253 if (v_scale == 1 && h_scale == 1) {
254 for (
unsigned int i = 0; i < r_height; i++) {
255 void *src = (
void *)(I[i + i_min_u] + j_min_u);
256 void *dst = (
void *)crop[i];
257 memcpy(dst, src, r_width *
sizeof(Type));
259 }
else if (h_scale == 1) {
260 for (
unsigned int i = 0; i < r_height; i++) {
261 void *src = (
void *)(I[(i + i_min_u) * v_scale] + j_min_u);
262 void *dst = (
void *)crop[i];
263 memcpy(dst, src, r_width *
sizeof(Type));
266 for (
unsigned int i = 0; i < r_height; i++) {
267 for (
unsigned int j = 0; j < r_width; j++) {
268 crop[i][j] = I[(i + i_min_u) * v_scale][(j + j_min_u) * h_scale];
292 template <
class Type>
294 unsigned int roi_width,
vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
316 template <
class Type>
318 unsigned int h_scale)
341 template <
class Type>
343 vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
345 int i_min = (std::max)((
int)(ceil(roi.
getTop() / v_scale)), 0);
346 int j_min = (std::max)((
int)(ceil(roi.
getLeft() / h_scale)), 0);
347 int i_max = (std::min)((
int)(ceil((roi.
getTop() + roi.
getHeight())) / v_scale), (
int)(height / v_scale));
348 int j_max = (std::min)((
int)(ceil((roi.
getLeft() + roi.
getWidth()) / h_scale)), (
int)(width / h_scale));
350 unsigned int i_min_u = (
unsigned int)i_min;
351 unsigned int j_min_u = (
unsigned int)j_min;
353 unsigned int r_width = (
unsigned int)(j_max - j_min);
354 unsigned int r_height = (
unsigned int)(i_max - i_min);
356 crop.
resize(r_height, r_width);
358 if (v_scale == 1 && h_scale == 1) {
359 for (
unsigned int i = 0; i < r_height; i++) {
360 void *src = (
void *)(bitmap + ((i + i_min_u) * width + j_min_u) *
sizeof(Type));
361 void *dst = (
void *)crop[i];
362 memcpy(dst, src, r_width *
sizeof(Type));
364 }
else if (h_scale == 1) {
365 for (
unsigned int i = 0; i < r_height; i++) {
366 void *src = (
void *)(bitmap + ((i + i_min_u) * width * v_scale + j_min_u) *
sizeof(Type));
367 void *dst = (
void *)crop[i];
368 memcpy(dst, src, r_width *
sizeof(Type));
371 for (
unsigned int i = 0; i < r_height; i++) {
372 unsigned int i_src = (i + i_min_u) * width * v_scale + j_min_u * h_scale;
373 for (
unsigned int j = 0; j < r_width; j++) {
374 void *src = (
void *)(bitmap + (i_src + j * h_scale) *
sizeof(Type));
375 void *dst = (
void *)&crop[i][j];
376 memcpy(dst, src,
sizeof(Type));
394 template <
class Type>
396 Type value3,
const bool useLUT)
399 std::cerr <<
"LUT not available for this type ! Will use the iteration method." << std::endl;
405 for (; p < pend; p++) {
409 else if (v > threshold2)
430 unsigned char value1,
unsigned char value2,
unsigned char value3,
const bool useLUT)
434 unsigned char lut[256];
435 for (
unsigned int i = 0; i < 256; i++) {
436 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
441 unsigned char *p = I.
bitmap;
443 for (; p < pend; p++) {
444 unsigned char v = *p;
447 else if (v > threshold2)
455 #ifdef VISP_HAVE_PTHREAD 457 #ifndef DOXYGEN_SHOULD_SKIP_THIS 458 template <
class Type>
class vpUndistortInternalType
466 unsigned int nthreads;
467 unsigned int threadid;
470 vpUndistortInternalType() : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0){};
472 vpUndistortInternalType(
const vpUndistortInternalType<Type> &u) { *
this = u; };
473 vpUndistortInternalType &operator=(
const vpUndistortInternalType<Type> &u)
480 nthreads = u.nthreads;
481 threadid = u.threadid;
486 static void *vpUndistort_threaded(
void *arg);
489 template <
class Type>
void *vpUndistortInternalType<Type>::vpUndistort_threaded(
void *arg)
491 vpUndistortInternalType<Type> *undistortSharedData =
static_cast<vpUndistortInternalType<Type> *
>(arg);
492 int offset = (int)undistortSharedData->threadid;
493 int width = (
int)undistortSharedData->width;
494 int height = (int)undistortSharedData->height;
495 int nthreads = (
int)undistortSharedData->nthreads;
497 double u0 = undistortSharedData->cam.get_u0();
498 double v0 = undistortSharedData->cam.get_v0();
499 double px = undistortSharedData->cam.get_px();
500 double py = undistortSharedData->cam.get_py();
501 double kud = undistortSharedData->cam.get_kud();
503 double invpx = 1.0 / px;
504 double invpy = 1.0 / py;
506 double kud_px2 = kud * invpx * invpx;
507 double kud_py2 = kud * invpy * invpy;
509 Type *dst = undistortSharedData->dst + (height / nthreads * offset) * width;
510 Type *src = undistortSharedData->src;
512 for (
double v = height / nthreads * offset; v < height / nthreads * (offset + 1); v++) {
513 double deltav = v - v0;
515 double fr1 = 1.0 + kud_py2 * deltav * deltav;
517 for (
double u = 0; u < width; u++) {
519 double deltau = u - u0;
521 double fr2 = fr1 + kud_px2 * deltau * deltau;
523 double u_double = deltau * fr2 + u0;
524 double v_double = deltav * fr2 + v0;
529 int u_round = (int)(u_double);
530 int v_round = (int)(v_double);
535 double du_double = (u_double) - (
double)u_round;
536 double dv_double = (v_double) - (
double)v_round;
539 if ((0 <= u_round) && (0 <= v_round) && (u_round < ((width)-1)) && (v_round < ((height)-1))) {
541 const Type *_mp = &src[v_round * width + u_round];
542 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
544 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
545 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
553 pthread_exit((
void *)0);
556 #endif // DOXYGEN_SHOULD_SKIP_THIS 557 #endif // VISP_HAVE_PTHREAD 578 template <
class Type>
581 #ifdef VISP_HAVE_PTHREAD 588 undistI.
resize(height, width);
593 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
599 unsigned int nthreads = 2;
601 pthread_t *callThd =
new pthread_t[nthreads];
602 pthread_attr_init(&attr);
603 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
605 vpUndistortInternalType<Type> *undistortSharedData;
606 undistortSharedData =
new vpUndistortInternalType<Type>[nthreads];
608 for (
unsigned int i = 0; i < nthreads; i++) {
611 undistortSharedData[i].src = I.
bitmap;
612 undistortSharedData[i].dst = undistI.
bitmap;
613 undistortSharedData[i].width = I.
getWidth();
614 undistortSharedData[i].height = I.
getHeight();
615 undistortSharedData[i].cam = cam;
616 undistortSharedData[i].nthreads = nthreads;
617 undistortSharedData[i].threadid = i;
618 pthread_create(&callThd[i], &attr, &vpUndistortInternalType<Type>::vpUndistort_threaded, &undistortSharedData[i]);
620 pthread_attr_destroy(&attr);
623 for (
unsigned int i = 0; i < nthreads; i++) {
625 pthread_join(callThd[i], NULL);
629 delete[] undistortSharedData;
630 #else // VISP_HAVE_PTHREAD 637 undistI.
resize(height, width);
646 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
652 double invpx = 1.0 / px;
653 double invpy = 1.0 / py;
655 double kud_px2 = kud * invpx * invpx;
656 double kud_py2 = kud * invpy * invpy;
658 Type *dst = undistI.
bitmap;
659 for (
double v = 0; v < height; v++) {
660 double deltav = v - v0;
662 double fr1 = 1.0 + kud_py2 * deltav * deltav;
664 for (
double u = 0; u < width; u++) {
666 double deltau = u - u0;
668 double fr2 = fr1 + kud_px2 * deltau * deltau;
670 double u_double = deltau * fr2 + u0;
671 double v_double = deltav * fr2 + v0;
678 int u_round = (int)(u_double);
679 int v_round = (int)(v_double);
684 double du_double = (u_double) - (
double)u_round;
685 double dv_double = (v_double) - (
double)v_round;
688 if ((0 <= u_round) && (0 <= v_round) && (u_round < (((
int)width) - 1)) && (v_round < (((
int)height) - 1))) {
690 const Type *_mp = &I[(
unsigned int)v_round][(
unsigned int)u_round];
691 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
693 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
694 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
702 #endif // VISP_HAVE_PTHREAD 709 undistI.
resize(height,width);
723 for(
int v = 0 ; v < height; v++){
724 for(
int u = 0; u < height; u++){
727 double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
728 double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
729 undistI[v][u] = I.getPixelBI((
float)u_double,(
float)v_double);
744 unsigned int height = 0, width = 0;
748 newI.
resize(height, width);
750 for (
unsigned int i = 0; i < height; i++) {
751 memcpy(newI.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
788 unsigned int height = 0, width = 0;
796 for (i = 0; i < height / 2; i++) {
797 memcpy(Ibuf.
bitmap, I.
bitmap + i * width, width *
sizeof(Type));
799 memcpy(I.
bitmap + i * width, I.
bitmap + (height - 1 - i) * width, width *
sizeof(Type));
800 memcpy(I.
bitmap + (height - 1 - i) * width, Ibuf.
bitmap, width *
sizeof(Type));
804 template <
class Type> Type vpImageTools::getPixelClamped(
const vpImage<Type> &I,
const float u,
const float v)
809 else if (u > (
float)I.
getWidth() - 1.)
826 template <
class Type>
828 const unsigned int j,
const float u,
const float v,
const float xFrac,
832 Type p00 = getPixelClamped(I, u - 1, v - 1);
833 Type p01 = getPixelClamped(I, u + 0, v - 1);
834 Type p02 = getPixelClamped(I, u + 1, v - 1);
835 Type p03 = getPixelClamped(I, u + 2, v - 1);
838 Type p10 = getPixelClamped(I, u - 1, v + 0);
839 Type p11 = getPixelClamped(I, u + 0, v + 0);
840 Type p12 = getPixelClamped(I, u + 1, v + 0);
841 Type p13 = getPixelClamped(I, u + 2, v + 0);
844 Type p20 = getPixelClamped(I, u - 1, v + 1);
845 Type p21 = getPixelClamped(I, u + 0, v + 1);
846 Type p22 = getPixelClamped(I, u + 1, v + 1);
847 Type p23 = getPixelClamped(I, u + 2, v + 1);
850 Type p30 = getPixelClamped(I, u - 1, v + 2);
851 Type p31 = getPixelClamped(I, u + 0, v + 2);
852 Type p32 = getPixelClamped(I, u + 1, v + 2);
853 Type p33 = getPixelClamped(I, u + 2, v + 2);
855 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
856 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
857 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
858 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
859 float value = cubicHermite(col0, col1, col2, col3, yFrac);
860 Ires[i][j] = vpMath::saturate<Type>(value);
865 const unsigned int j,
const float u,
const float v,
const float xFrac,
869 vpRGBa p00 = getPixelClamped(I, u - 1, v - 1);
870 vpRGBa p01 = getPixelClamped(I, u + 0, v - 1);
871 vpRGBa p02 = getPixelClamped(I, u + 1, v - 1);
872 vpRGBa p03 = getPixelClamped(I, u + 2, v - 1);
875 vpRGBa p10 = getPixelClamped(I, u - 1, v + 0);
876 vpRGBa p11 = getPixelClamped(I, u + 0, v + 0);
877 vpRGBa p12 = getPixelClamped(I, u + 1, v + 0);
878 vpRGBa p13 = getPixelClamped(I, u + 2, v + 0);
881 vpRGBa p20 = getPixelClamped(I, u - 1, v + 1);
882 vpRGBa p21 = getPixelClamped(I, u + 0, v + 1);
883 vpRGBa p22 = getPixelClamped(I, u + 1, v + 1);
884 vpRGBa p23 = getPixelClamped(I, u + 2, v + 1);
887 vpRGBa p30 = getPixelClamped(I, u - 1, v + 2);
888 vpRGBa p31 = getPixelClamped(I, u + 0, v + 2);
889 vpRGBa p32 = getPixelClamped(I, u + 1, v + 2);
890 vpRGBa p33 = getPixelClamped(I, u + 2, v + 2);
892 for (
int c = 0; c < 3; c++) {
893 float col0 = cubicHermite(((
unsigned char *)&p00)[c], ((
unsigned char *)&p01)[c], ((
unsigned char *)&p02)[c],
894 ((
unsigned char *)&p03)[c], xFrac);
895 float col1 = cubicHermite(((
unsigned char *)&p10)[c], ((
unsigned char *)&p11)[c], ((
unsigned char *)&p12)[c],
896 ((
unsigned char *)&p13)[c], xFrac);
897 float col2 = cubicHermite(((
unsigned char *)&p20)[c], ((
unsigned char *)&p21)[c], ((
unsigned char *)&p22)[c],
898 ((
unsigned char *)&p23)[c], xFrac);
899 float col3 = cubicHermite(((
unsigned char *)&p30)[c], ((
unsigned char *)&p31)[c], ((
unsigned char *)&p32)[c],
900 ((
unsigned char *)&p33)[c], xFrac);
901 float value = cubicHermite(col0, col1, col2, col3, yFrac);
903 ((
unsigned char *)&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
907 template <
class Type>
909 const unsigned int j,
const float u,
const float v,
const float xFrac,
912 unsigned int u0 = (
unsigned int)u;
913 unsigned int v0 = (
unsigned int)v;
915 unsigned int u1 = (std::min)(I.
getWidth() - 1, (
unsigned int)u + 1);
916 unsigned int v1 = v0;
918 unsigned int u2 = u0;
919 unsigned int v2 = (std::min)(I.
getHeight() - 1, (
unsigned int)v + 1);
921 unsigned int u3 = (std::min)(I.
getWidth() - 1, (
unsigned int)u + 1);
922 unsigned int v3 = (std::min)(I.
getHeight() - 1, (
unsigned int)v + 1);
924 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
925 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
926 float value = lerp(col0, col1, yFrac);
928 Ires[i][j] = vpMath::saturate<Type>(value);
933 const unsigned int j,
const float u,
const float v,
const float xFrac,
936 unsigned int u0 = (
unsigned int)u;
937 unsigned int v0 = (
unsigned int)v;
939 unsigned int u1 = (std::min)(I.
getWidth() - 1, (
unsigned int)u + 1);
940 unsigned int v1 = v0;
942 unsigned int u2 = u0;
943 unsigned int v2 = (std::min)(I.
getHeight() - 1, (
unsigned int)v + 1);
945 unsigned int u3 = (std::min)(I.
getWidth() - 1, (
unsigned int)u + 1);
946 unsigned int v3 = (std::min)(I.
getHeight() - 1, (
unsigned int)v + 1);
948 for (
int c = 0; c < 3; c++) {
949 float col0 = lerp(((
unsigned char *)&I[v0][u0])[c], ((
unsigned char *)&I[v1][u1])[c], xFrac);
950 float col1 = lerp(((
unsigned char *)&I[v2][u2])[c], ((
unsigned char *)&I[v3][u3])[c], xFrac);
951 float value = lerp(col0, col1, yFrac);
953 ((
unsigned char *)&Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
957 template <
class Type>
959 const unsigned int j,
const float u,
const float v)
961 Ires[i][j] = getPixelClamped(I, u, v);
974 template <
class Type>
978 Ires.
resize(height, width);
991 template <
class Type>
995 std::cerr <<
"Input or output image is too small!" << std::endl;
1002 if (method == INTERPOLATION_NEAREST) {
1007 for (
unsigned int i = 0; i < Ires.
getHeight(); i++) {
1008 float v = i * scaleY;
1009 float yFrac = v - (int)v;
1011 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1012 float u = j * scaleX;
1013 float xFrac = u - (int)u;
1015 if (method == INTERPOLATION_NEAREST) {
1016 resizeNearest(I, Ires, i, j, u, v);
1017 }
else if (method == INTERPOLATION_LINEAR) {
1018 resizeBilinear(I, Ires, i, j, u, v, xFrac, yFrac);
1019 }
else if (method == INTERPOLATION_CUBIC) {
1020 resizeBicubic(I, Ires, i, j, u, v, xFrac, yFrac);
Type * bitmap
points toward the bitmap
static double sqr(double x)
Generic class defining intrinsic camera parameters.
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
unsigned int getHeight() const
Defines a rectangle in the plane.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
void performLut(const Type(&lut)[256], const unsigned int nbThreads=1)
unsigned int getWidth() const
Definition of the vpImage class member functions.