39 #ifndef vpImageTools_H
40 #define vpImageTools_H
50 #include <visp3/core/vpImage.h>
52 #ifdef VISP_HAVE_PTHREAD
56 #include <visp3/core/vpImageException.h>
57 #include <visp3/core/vpMath.h>
58 #include <visp3/core/vpRect.h>
59 #include <visp3/core/vpCameraParameters.h>
86 Type threshold1, Type threshold2,
87 Type value1, Type value2, Type value3,
const bool useLUT=
true);
96 double roi_top,
double roi_left,
97 unsigned int roi_height,
unsigned int roi_width,
98 vpImage<Type> &crop,
unsigned int v_scale=1,
unsigned int h_scale=1);
103 unsigned int roi_height,
unsigned int roi_width,
104 vpImage<Type> &crop,
unsigned int v_scale=1,
unsigned int h_scale=1);
108 static void crop(
const unsigned char *bitmap,
unsigned int width,
unsigned int height,
const vpRect &roi,
vpImage<Type> &crop,
109 unsigned int v_scale=1,
unsigned int h_scale=1);
135 const bool saturate=
false);
140 const bool saturate=
false);
145 const unsigned int width,
const unsigned int height,
146 const vpImageInterpolationType &method=INTERPOLATION_NEAREST);
151 const vpImageInterpolationType &method=INTERPOLATION_NEAREST);
158 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
164 vp_deprecated
static void createSubImage(
const vpImage<Type> &I,
165 unsigned int i_sub,
unsigned int j_sub,
166 unsigned int nrow_sub,
unsigned int ncol_sub,
176 static float cubicHermite (
const float A,
const float B,
const float C,
const float D,
const float t);
179 static Type getPixelClamped(
const vpImage<Type> &I,
const float u,
const float v);
182 static float lerp(
const float A,
const float B,
const float t);
186 const float u,
const float v,
const float xFrac,
const float yFrac);
190 const float u,
const float v,
const float xFrac,
const float yFrac);
194 const float u,
const float v);
197 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
216 unsigned int roi_top,
unsigned int roi_left,
217 unsigned int roi_height,
unsigned int roi_width,
246 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
267 double roi_top,
double roi_left,
268 unsigned int roi_height,
unsigned int roi_width,
269 vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
271 int i_min = std::max((
int)(ceil(roi_top/v_scale)), 0);
272 int j_min = std::max((
int)(ceil(roi_left/h_scale)), 0);
273 int i_max = std::min((
int)(ceil((roi_top + roi_height))/v_scale), (
int)(I.
getHeight()/v_scale));
274 int j_max = std::min((
int)(ceil((roi_left + roi_width)/h_scale)), (
int)(I.
getWidth()/h_scale));
276 unsigned int i_min_u = (
unsigned int)i_min;
277 unsigned int j_min_u = (
unsigned int)j_min;
279 unsigned int r_width = (
unsigned int)(j_max-j_min);
280 unsigned int r_height = (
unsigned int)(i_max-i_min);
282 crop.
resize(r_height, r_width) ;
284 if (v_scale == 1 && h_scale == 1) {
285 for (
unsigned int i=0 ; i < r_height ; i++) {
286 void *src = (
void *)(I[i+i_min_u] + j_min_u);
287 void *dst = (
void *)crop[i];
288 memcpy(dst, src, r_width*
sizeof(Type));
291 else if (h_scale == 1) {
292 for (
unsigned int i=0 ; i < r_height ; i++) {
293 void *src = (
void *)(I[(i + i_min_u)*v_scale]+j_min_u);
294 void *dst = (
void *)crop[i];
295 memcpy(dst, src, r_width*
sizeof(Type));
299 for (
unsigned int i=0 ; i < r_height ; i++) {
300 for (
unsigned int j=0 ; j < r_width ; j++) {
301 crop[i][j] = I[(i + i_min_u)*v_scale][(j + j_min_u)*h_scale];
326 unsigned int roi_height,
unsigned int roi_width,
327 vpImage<Type> &crop,
unsigned int v_scale,
unsigned int h_scale)
369 unsigned int v_scale,
unsigned int h_scale)
371 int i_min = std::max((
int)(ceil(roi.
getTop()/v_scale)), 0);
372 int j_min = std::max((
int)(ceil(roi.
getLeft()/h_scale)), 0);
373 int i_max = std::min((
int)(ceil((roi.
getTop() + roi.
getHeight()))/v_scale), (
int)(height/v_scale));
374 int j_max = std::min((
int)(ceil((roi.
getLeft() + roi.
getWidth())/h_scale)), (
int)(width/h_scale));
376 unsigned int i_min_u = (
unsigned int)i_min;
377 unsigned int j_min_u = (
unsigned int)j_min;
379 unsigned int r_width = (
unsigned int)(j_max-j_min);
380 unsigned int r_height = (
unsigned int)(i_max-i_min);
382 crop.
resize(r_height, r_width) ;
384 if (v_scale == 1 && h_scale == 1) {
385 for (
unsigned int i=0 ; i < r_height ; i++) {
386 void *src = (
void *)(bitmap + ( (i+i_min_u)*width + j_min_u ) *
sizeof(Type));
387 void *dst = (
void *)crop[i];
388 memcpy(dst, src, r_width*
sizeof(Type));
391 else if (h_scale == 1) {
392 for (
unsigned int i=0 ; i < r_height ; i++) {
393 void *src = (
void *)(bitmap + ( (i+i_min_u)*width*v_scale + j_min_u ) *
sizeof(Type) );
394 void *dst = (
void *)crop[i];
395 memcpy(dst, src, r_width*
sizeof(Type));
399 for (
unsigned int i=0 ; i < r_height ; i++) {
400 unsigned int i_src = (i+i_min_u)*width*v_scale + j_min_u*h_scale;
401 for (
unsigned int j=0 ; j < r_width ; j++) {
402 void *src = (
void *)(bitmap + (i_src + j*h_scale)*
sizeof(Type));
403 void *dst = (
void *)&crop[i][j];
404 memcpy(dst, src,
sizeof(Type));
424 Type threshold1, Type threshold2,
425 Type value1, Type value2, Type value3,
const bool useLUT)
428 std::cerr <<
"LUT not available for this type ! Will use the iteration method." << std::endl;
434 for (; p < pend; p ++) {
436 if (v < threshold1) *p = value1;
437 else if (v > threshold2) *p = value3;
456 unsigned char threshold1,
unsigned char threshold2,
457 unsigned char value1,
unsigned char value2,
unsigned char value3,
const bool useLUT)
461 unsigned char lut[256];
462 for(
unsigned int i = 0; i < 256; i++) {
463 lut[i] = i < threshold1 ? value1 : (i > threshold2 ? value3 : value2);
469 unsigned char *p = I.
bitmap;
471 for (; p < pend; p ++) {
473 if (v < threshold1) *p = value1;
474 else if (v > threshold2) *p = value3;
480 #ifdef VISP_HAVE_PTHREAD
482 #ifndef DOXYGEN_SHOULD_SKIP_THIS
484 class vpUndistortInternalType
492 unsigned int nthreads;
493 unsigned int threadid;
495 vpUndistortInternalType()
496 : src(NULL), dst(NULL), width(0), height(0), cam(), nthreads(0), threadid(0)
499 vpUndistortInternalType(
const vpUndistortInternalType<Type> &u) {
502 vpUndistortInternalType &operator=(
const vpUndistortInternalType<Type> &u) {
508 nthreads = u.nthreads;
509 threadid = u.threadid;
514 static void *vpUndistort_threaded(
void *arg);
519 void *vpUndistortInternalType<Type>::vpUndistort_threaded(
void *arg)
521 vpUndistortInternalType<Type> *undistortSharedData = (vpUndistortInternalType<Type>*)arg;
522 int offset = (int)undistortSharedData->threadid;
523 int width = (
int)undistortSharedData->width;
524 int height = (int)undistortSharedData->height;
525 int nthreads = (
int)undistortSharedData->nthreads;
527 double u0 = undistortSharedData->cam.get_u0();
528 double v0 = undistortSharedData->cam.get_v0();
529 double px = undistortSharedData->cam.get_px();
530 double py = undistortSharedData->cam.get_py();
531 double kud = undistortSharedData->cam.get_kud();
533 double invpx = 1.0/px;
534 double invpy = 1.0/py;
536 double kud_px2 = kud * invpx * invpx;
537 double kud_py2 = kud * invpy * invpy;
539 Type *dst = undistortSharedData->dst+(height/nthreads*offset)*width;
540 Type *src = undistortSharedData->src;
542 for (
double v = height/nthreads*offset;v < height/nthreads*(offset+1) ; v++) {
543 double deltav = v - v0;
545 double fr1 = 1.0 + kud_py2 * deltav * deltav;
547 for (
double u = 0 ; u < width ; u++) {
549 double deltau = u - u0;
551 double fr2 = fr1 + kud_px2 * deltau * deltau;
553 double u_double = deltau * fr2 + u0;
554 double v_double = deltav * fr2 + v0;
559 int u_round = (int) (u_double);
560 int v_round = (int) (v_double);
561 if (u_round < 0.f) u_round = -1;
562 if (v_round < 0.f) v_round = -1;
563 double du_double = (u_double) - (
double) u_round;
564 double dv_double = (v_double) - (
double) v_round;
567 if ( (0 <= u_round) && (0 <= v_round) &&
568 (u_round < ((width) - 1)) && (v_round < ((height) - 1)) ) {
570 const Type* _mp = &src[v_round*width+u_round];
571 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
573 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
574 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
583 pthread_exit((
void*) 0);
586 #endif // DOXYGEN_SHOULD_SKIP_THIS
587 #endif // VISP_HAVE_PTHREAD
613 #ifdef VISP_HAVE_PTHREAD
620 undistI.
resize(height, width);
625 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
631 unsigned int nthreads = 2;
633 pthread_t *callThd =
new pthread_t [nthreads];
634 pthread_attr_init(&attr);
635 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
637 vpUndistortInternalType<Type> *undistortSharedData;
638 undistortSharedData =
new vpUndistortInternalType<Type> [nthreads];
640 for(
unsigned int i=0;i<nthreads;i++) {
643 undistortSharedData[i].src = I.
bitmap;
644 undistortSharedData[i].dst = undistI.
bitmap;
645 undistortSharedData[i].width = I.
getWidth();
646 undistortSharedData[i].height = I.
getHeight();
647 undistortSharedData[i].cam = cam;
648 undistortSharedData[i].nthreads = nthreads;
649 undistortSharedData[i].threadid = i;
650 pthread_create( &callThd[i], &attr,
651 &vpUndistortInternalType<Type>::vpUndistort_threaded,
652 &undistortSharedData[i]);
654 pthread_attr_destroy(&attr);
657 for(
unsigned int i=0;i<nthreads;i++) {
659 pthread_join( callThd[i], NULL);
663 delete [] undistortSharedData;
664 #else // VISP_HAVE_PTHREAD
671 undistI.
resize(height, width);
680 if (std::fabs(kud) <= std::numeric_limits<double>::epsilon()) {
686 double invpx = 1.0/px;
687 double invpy = 1.0/py;
689 double kud_px2 = kud * invpx * invpx;
690 double kud_py2 = kud * invpy * invpy;
692 Type *dst = undistI.
bitmap;
693 for (
double v = 0;v < height ; v++) {
694 double deltav = v - v0;
696 double fr1 = 1.0 + kud_py2 * deltav * deltav;
698 for (
double u = 0 ; u < width ; u++) {
700 double deltau = u - u0;
702 double fr2 = fr1 + kud_px2 * deltau * deltau;
704 double u_double = deltau * fr2 + u0;
705 double v_double = deltav * fr2 + v0;
712 int u_round = (int) (u_double);
713 int v_round = (int) (v_double);
714 if (u_round < 0.f) u_round = -1;
715 if (v_round < 0.f) v_round = -1;
716 double du_double = (u_double) - (
double) u_round;
717 double dv_double = (v_double) - (
double) v_round;
720 if ( (0 <= u_round) && (0 <= v_round) &&
721 (u_round < (((
int)width) - 1)) && (v_round < (((
int)height) - 1)) ) {
723 const Type* _mp = &I[(
unsigned int)v_round][(
unsigned int)u_round];
724 v01 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
726 v23 = (Type)(_mp[0] + ((_mp[1] - _mp[0]) * du_double));
727 *dst = (Type)(v01 + ((v23 - v01) * dv_double));
736 #endif // VISP_HAVE_PTHREAD
746 undistI.
resize(height,width);
760 for(
int v = 0 ; v < height; v++){
761 for(
int u = 0; u < height; u++){
764 double u_double = ((double)u - u0)*(1.0+kd*r2) + u0;
765 double v_double = ((double)v - v0)*(1.0+kd*r2) + v0;
766 undistI[v][u] = I.getPixelBI((
float)u_double,(
float)v_double);
783 unsigned int height = 0, width = 0;
787 newI.
resize(height, width);
789 for (
unsigned int i = 0; i < height; i++)
791 memcpy(newI.
bitmap+i*width, I.
bitmap+(height-1-i)*width,
830 unsigned int height = 0, width = 0;
838 for ( i = 0; i < height/2; i++)
851 Type vpImageTools::getPixelClamped(
const vpImage<Type> &I,
const float u,
const float v) {
852 unsigned int j = std::min(std::max(0u, (
unsigned int) u), I.
getWidth()-1);
853 unsigned int i = std::min(std::max(0u, (
unsigned int) v), I.
getHeight()-1);
859 template<
class Type>
void
861 const float u,
const float v,
const float xFrac,
const float yFrac) {
863 Type p00 = getPixelClamped(I, u-1, v-1);
864 Type p01 = getPixelClamped(I, u+0, v-1);
865 Type p02 = getPixelClamped(I, u+1, v-1);
866 Type p03 = getPixelClamped(I, u+2, v-1);
869 Type p10 = getPixelClamped(I, u-1, v+0);
870 Type p11 = getPixelClamped(I, u+0, v+0);
871 Type p12 = getPixelClamped(I, u+1, v+0);
872 Type p13 = getPixelClamped(I, u+2, v+0);
875 Type p20 = getPixelClamped(I, u-1, v+1);
876 Type p21 = getPixelClamped(I, u+0, v+1);
877 Type p22 = getPixelClamped(I, u+1, v+1);
878 Type p23 = getPixelClamped(I, u+2, v+1);
881 Type p30 = getPixelClamped(I, u-1, v+2);
882 Type p31 = getPixelClamped(I, u+0, v+2);
883 Type p32 = getPixelClamped(I, u+1, v+2);
884 Type p33 = getPixelClamped(I, u+2, v+2);
886 float col0 = cubicHermite(p00, p01, p02, p03, xFrac);
887 float col1 = cubicHermite(p10, p11, p12, p13, xFrac);
888 float col2 = cubicHermite(p20, p21, p22, p23, xFrac);
889 float col3 = cubicHermite(p30, p31, p32, p33, xFrac);
890 float value = cubicHermite(col0, col1, col2, col3, yFrac);
891 Ires[i][j] = vpMath::saturate<Type>(value);
894 template<>
inline void
896 const float u,
const float v,
const float xFrac,
const float yFrac) {
898 vpRGBa p00 = getPixelClamped(I, u-1, v-1);
899 vpRGBa p01 = getPixelClamped(I, u+0, v-1);
900 vpRGBa p02 = getPixelClamped(I, u+1, v-1);
901 vpRGBa p03 = getPixelClamped(I, u+2, v-1);
904 vpRGBa p10 = getPixelClamped(I, u-1, v+0);
905 vpRGBa p11 = getPixelClamped(I, u+0, v+0);
906 vpRGBa p12 = getPixelClamped(I, u+1, v+0);
907 vpRGBa p13 = getPixelClamped(I, u+2, v+0);
910 vpRGBa p20 = getPixelClamped(I, u-1, v+1);
911 vpRGBa p21 = getPixelClamped(I, u+0, v+1);
912 vpRGBa p22 = getPixelClamped(I, u+1, v+1);
913 vpRGBa p23 = getPixelClamped(I, u+2, v+1);
916 vpRGBa p30 = getPixelClamped(I, u-1, v+2);
917 vpRGBa p31 = getPixelClamped(I, u+0, v+2);
918 vpRGBa p32 = getPixelClamped(I, u+1, v+2);
919 vpRGBa p33 = getPixelClamped(I, u+2, v+2);
921 for (
int c = 0; c < 3; c++) {
922 float col0 = cubicHermite( ((
unsigned char *) &p00)[c], ((
unsigned char *) &p01)[c], ((
unsigned char *) &p02)[c], ((
unsigned char *) &p03)[c], xFrac );
923 float col1 = cubicHermite( ((
unsigned char *) &p10)[c], ((
unsigned char *) &p11)[c], ((
unsigned char *) &p12)[c], ((
unsigned char *) &p13)[c], xFrac );
924 float col2 = cubicHermite( ((
unsigned char *) &p20)[c], ((
unsigned char *) &p21)[c], ((
unsigned char *) &p22)[c], ((
unsigned char *) &p23)[c], xFrac );
925 float col3 = cubicHermite( ((
unsigned char *) &p30)[c], ((
unsigned char *) &p31)[c], ((
unsigned char *) &p32)[c], ((
unsigned char *) &p33)[c], xFrac );
926 float value = cubicHermite(col0, col1, col2, col3, yFrac);
928 ((
unsigned char *) &Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
932 template<
class Type>
void
934 const float u,
const float v,
const float xFrac,
const float yFrac) {
935 unsigned int u0 = (
unsigned int) u;
936 unsigned int v0 = (
unsigned int) v;
938 unsigned int u1 = std::min(I.
getWidth()-1, (
unsigned int) u+1);
939 unsigned int v1 = v0;
941 unsigned int u2 = u0;
942 unsigned int v2 = std::min(I.
getHeight()-1, (
unsigned int) v+1);
944 unsigned int u3 = std::min(I.
getWidth()-1, (
unsigned int) u+1);
945 unsigned int v3 = std::min(I.
getHeight()-1, (
unsigned int) v+1);
947 float col0 = lerp(I[v0][u0], I[v1][u1], xFrac);
948 float col1 = lerp(I[v2][u2], I[v3][u3], xFrac);
949 float value = lerp(col0, col1, yFrac);
951 Ires[i][j] = vpMath::saturate<Type>(value);
954 template<>
inline void
956 const float u,
const float v,
const float xFrac,
const float yFrac) {
957 unsigned int u0 = (
unsigned int) u;
958 unsigned int v0 = (
unsigned int) v;
960 unsigned int u1 = std::min(I.
getWidth()-1, (
unsigned int) u+1);
961 unsigned int v1 = v0;
963 unsigned int u2 = u0;
964 unsigned int v2 = std::min(I.
getHeight()-1, (
unsigned int) v+1);
966 unsigned int u3 = std::min(I.
getWidth()-1, (
unsigned int) u+1);
967 unsigned int v3 = std::min(I.
getHeight()-1, (
unsigned int) v+1);
969 for (
int c = 0; c < 3; c++) {
970 float col0 = lerp( ((
unsigned char *) &I[v0][u0])[c], ((
unsigned char *) &I[v1][u1])[c], xFrac );
971 float col1 = lerp( ((
unsigned char *) &I[v2][u2])[c], ((
unsigned char *) &I[v3][u3])[c], xFrac );
972 float value = lerp(col0, col1, yFrac);
974 ((
unsigned char *) &Ires[i][j])[c] = vpMath::saturate<unsigned char>(value);
978 template<
class Type>
void
980 const float u,
const float v) {
981 Ires[i][j] = getPixelClamped(I, u, v);
993 template<
class Type>
void
995 Ires.
resize(height, width);
1007 template<
class Type>
void
1010 std::cerr <<
"Input or output image is too small!" << std::endl;
1022 for (
unsigned int i = 0; i < Ires.
getHeight(); i++) {
1023 float v = i * scaleY;
1024 float yFrac = v - (int) v;
1026 for (
unsigned int j = 0; j < Ires.
getWidth(); j++) {
1027 float u = j * scaleX;
1028 float xFrac = u - (int) u;
1031 resizeNearest(I, Ires, i, j, u, v);
1033 resizeBilinear(I, Ires, i, j, u, v, xFrac, yFrac);
1035 resizeBicubic(I, Ires, i, j, u, v, xFrac, yFrac);
unsigned int getWidth() const
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)
Definition of the vpImage class member functions.