Commit message: .
CVE: CVE-2019-13568
CWE: CWE-787
Vulnerability description: CImg through 2.6.7 has a heap-based buffer overflow in _load_bmp in CImg.h because of erroneous memory allocation for a malformed BMP image.

Project: CImg
File: CImg.h

    **/
    static CImg<T> vector(const T& a0, const T& a1) {
      CImg<T> r(1,2); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1;
      return r;

Project: CImg
File: CImg.h

      static signed char min() { return ~max(); }

Project: CImg
File: CImg.h

    //! Access to pixel value with Neumann boundary conditions \const.
    T atNXYZC(const int pos, const int x, const int y, const int z, const int c) const {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "atNXYZC(): Empty instance.",
                                    cimglist_instance);

      return _atNXYZC(pos,x,y,z,c);

Project: CImg
File: CImg.h


      _cimg_math_parser(const char *const expression, const char *const funcname=0,
                        const CImg<T>& img_input=CImg<T>::const_empty(), CImg<T> *const img_output=0,
                        const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0,
                        const bool _is_fill=false):
        code(_code),p_break((CImg<ulongT>*)(cimg_ulong)-2),
        imgin(img_input),listin(list_inputs?*list_inputs:CImgList<T>::const_empty()),
        imgout(img_output?*img_output:CImg<T>::empty()),listout(list_outputs?*list_outputs:CImgList<T>::empty()),
        img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),user_macro(0),
        mem_img_median(~0U),debug_indent(0),result_dim(0),break_type(0),constcache_size(0),
        is_parallelizable(true),is_fill(_is_fill),need_input_copy(false),
        rng((cimg::_rand(),cimg::rng())),calling_function(funcname?funcname:"cimg_math_parser") {

#if cimg_use_openmp!=0
        rng+=omp_get_thread_num();
#endif
        if (!expression || !*expression)
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: Empty expression.",
                                      pixel_type(),_cimg_mp_calling_function);
        const char *_expression = expression;
        while (*_expression && (cimg::is_blank(*_expression) || *_expression==';')) ++_expression;
        CImg<charT>::string(_expression).move_to(expr);
        char *ps = &expr.back() - 1;
        while (ps>expr._data && (cimg::is_blank(*ps) || *ps==';')) --ps;
        *(++ps) = 0; expr._width = (unsigned int)(ps - expr._data + 1);

        // Ease the retrieval of previous non-space characters afterwards.
        pexpr.assign(expr._width);
        char c, *pe = pexpr._data;
        for (ps = expr._data, c = ' '; *ps; ++ps) {
          if (!cimg::is_blank(*ps)) c = *ps; else *ps = ' ';
          *(pe++) = c;
        }
        *pe = 0;
        level = get_level(expr);

        // Init constant values.
#define _cimg_mp_interpolation (reserved_label[29]!=~0U?reserved_label[29]:0)
#define _cimg_mp_boundary (reserved_label[30]!=~0U?reserved_label[30]:0)
#define _cimg_mp_slot_nan 29
#define _cimg_mp_slot_x 30
#define _cimg_mp_slot_y 31
#define _cimg_mp_slot_z 32
#define _cimg_mp_slot_c 33

        mem.assign(96);
        for (unsigned int i = 0; i<=10; ++i) mem[i] = (double)i; // mem[0-10] = 0...10
        for (unsigned int i = 1; i<=5; ++i) mem[i + 10] = -(double)i; // mem[11-15] = -1...-5
        mem[16] = 0.5;
        mem[17] = 0; // thread_id
        mem[18] = (double)imgin._width; // w
        mem[19] = (double)imgin._height; // h
        mem[20] = (double)imgin._depth; // d
        mem[21] = (double)imgin._spectrum; // s
        mem[22] = (double)imgin._is_shared; // r
        mem[23] = (double)imgin._width*imgin._height; // wh
        mem[24] = (double)imgin._width*imgin._height*imgin._depth; // whd
        mem[25] = (double)imgin._width*imgin._height*imgin._depth*imgin._spectrum; // whds
        mem[26] = (double)listin._width; // l
        mem[27] = std::exp(1.); // e
        mem[28] = cimg::PI; // pi
        mem[_cimg_mp_slot_nan] = cimg::type<double>::nan(); // nan

        // Set value property :
        // { -2 = other | -1 = variable | 0 = computation value |
        //    1 = compile-time constant | N>1 = constant ptr to vector[N-1] }.
        memtype.assign(mem._width,1,1,1,0);
        for (unsigned int i = 0; i<_cimg_mp_slot_x; ++i) memtype[i] = 1;
        memtype[17] = 0;
        memtype[_cimg_mp_slot_x] = memtype[_cimg_mp_slot_y] = memtype[_cimg_mp_slot_z] = memtype[_cimg_mp_slot_c] = -2;
        mempos = _cimg_mp_slot_c + 1;
        variable_pos.assign(8);

        reserved_label.assign(128,1,1,1,~0U);
        // reserved_label[4-28] are used to store these two-char variables:
        // [0] = wh, [1] = whd, [2] = whds, [3] = pi, [4] = im, [5] = iM, [6] = ia, [7] = iv,
        // [8] = is, [9] = ip, [10] = ic, [11] = xm, [12] = ym, [13] = zm, [14] = cm, [15] = xM,
        // [16] = yM, [17] = zM, [18]=cM, [19]=i0...[28]=i9, [29] = interpolation, [30] = boundary

        // Compile expression into a serie of opcodes.
        s_op = ""; ss_op = expr._data;
        const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0,false);
        if (!_cimg_mp_is_constant(ind_result)) {
          if (_cimg_mp_is_vector(ind_result))
            CImg<doubleT>(&mem[ind_result] + 1,_cimg_mp_size(ind_result),1,1,1,true).
              fill(cimg::type<double>::nan());
          else mem[ind_result] = cimg::type<double>::nan();
        }

        // Free resources used for compiling expression and prepare evaluation.
        result_dim = _cimg_mp_size(ind_result);
        if (mem._width>=256 && mem._width - mempos>=mem._width/2) mem.resize(mempos,1,1,1,-1);
        result = mem._data + ind_result;
        memtype.assign();
        constcache_vals.assign();
        constcache_inds.assign();
        level.assign();
        variable_pos.assign();
        reserved_label.assign();
        expr.assign();
        pexpr.assign();
        opcode.assign();
        opcode._is_shared = true;

        // Execute begin() bloc if any specified.
        if (code_begin) {
          mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0;
          p_code_end = code_begin.end();
          for (p_code = code_begin; p_code<p_code_end; ++p_code) {
            opcode._data = p_code->_data;
            const ulongT target = opcode[1];
            mem[target] = _cimg_mp_defunc(*this);
          }
        }
        p_code_end = code.end();

Project: CImg
File: CImg.h


    void _paint(const bool wait_expose=true) {
      if (_is_closed || !_image) return;
      Display *const dpy = cimg::X11_attr().display;
      if (wait_expose) { // Send an expose event sticked to display window to force repaint
        XEvent event;
        event.xexpose.type = Expose;
        event.xexpose.serial = 0;
        event.xexpose.send_event = 1;
        event.xexpose.display = dpy;
        event.xexpose.window = _window;
        event.xexpose.x = 0;
        event.xexpose.y = 0;
        event.xexpose.width = width();
        event.xexpose.height = height();
        event.xexpose.count = 0;
        XSendEvent(dpy,_window,0,0,&event);
      } else { // Repaint directly (may be called from the expose event)
        GC gc = DefaultGC(dpy,DefaultScreen(dpy));

#ifdef cimg_use_xshm
        if (_shminfo) XShmPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height,1);
        else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
#else
        XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
#endif
      }

Project: CImg
File: CImg.h


      static double mp_image_w(_cimg_math_parser& mp) {
        unsigned int ind = (unsigned int)mp.opcode[2];
        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
        return (double)img.width();

Project: CImg
File: CImg.h

    //! Compute n-D Fast Fourier Transform.
    /**
      \param invert Tells if the direct (\c false) or inverse transform (\c true) is computed.
    **/
    CImgList<T>& FFT(const bool invert=false) {
      if (is_empty()) return *this;
      if (_width==1) insert(1);
      if (_width>2)
        cimg::warn(_cimglist_instance
                   "FFT(): Instance has more than 2 images",
                   cimglist_instance);

Project: CImg
File: CImg.h

    **/
    T cubic_atXY_c(const float fx, const float fy, const int z, const int c) const {
      return cimg::type<T>::cut(cubic_atXY(fx,fy,z,c));

Project: CImg
File: CImg.h

    //! Return a 4x4 matrix containing specified coefficients.
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
			  const T& a4, const T& a5, const T& a6, const T& a7,
			  const T& a8, const T& a9, const T& a10, const T& a11,
			  const T& a12, const T& a13, const T& a14, const T& a15) {
      CImg<T> r(4,4); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
      return r;

Project: CImg
File: CImg.h

    template<> struct type<float> {

Project: CImg
File: CImg.h

    */
    static void _cimg_recursive_apply(T *data, const double filter[], const int N, const ulongT off,
				      const unsigned int order, const bool boundary_conditions) {
      double val[4] = { 0 };  // res[n,n - 1,n - 2,n - 3,..] or res[n,n + 1,n + 2,n + 3,..]
      const double
	sumsq = filter[0], sum = sumsq * sumsq,
	a1 = filter[1], a2 = filter[2], a3 = filter[3],
	scaleM = 1. / ( (1. + a1 - a2 + a3) * (1. - a1 - a2 - a3) * (1. + a2 + (a1 - a3) * a3) );
      double M[9]; // Triggs matrix
      M[0] = scaleM * (-a3 * a1 + 1. - a3 * a3 - a2);
      M[1] = scaleM * (a3 + a1) * (a2 + a3 * a1);
      M[2] = scaleM * a3 * (a1 + a3 * a2);
      M[3] = scaleM * (a1 + a3 * a2);
      M[4] = -scaleM * (a2 - 1.) * (a2 + a3 * a1);
      M[5] = -scaleM * a3 * (a3 * a1 + a3 * a3 + a2 - 1.);
      M[6] = scaleM * (a3 * a1 + a2 + a1 * a1 - a2 * a2);
      M[7] = scaleM * (a1 * a2 + a3 * a2 * a2 - a1 * a3 * a3 - a3 * a3 * a3 - a3 * a2 + a3);
      M[8] = scaleM * a3 * (a1 + a3 * a2);
      switch (order) {
      case 0 : {
	const double iplus = (boundary_conditions?data[(N - 1)*off]:(T)0);
	for (int pass = 0; pass<2; ++pass) {
	  if (!pass) {
	    for (int k = 1; k<4; ++k) val[k] = (boundary_conditions?*data/sumsq:0);
	  } else {
	    // apply Triggs boundary conditions
	    const double
	      uplus = iplus/(1. - a1 - a2 - a3), vplus = uplus/(1. - a1 - a2 - a3),
	      unp  = val[1] - uplus, unp1 = val[2] - uplus, unp2 = val[3] - uplus;
	    val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2 + vplus) * sum;
	    val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2 + vplus) * sum;
	    val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2 + vplus) * sum;
	    *data = (T)val[0];
	    data -= off;
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  for (int n = pass; n<N; ++n) {
	    val[0] = (*data);
	    if (pass) val[0] *= sum;
	    for (int k = 1; k<4; ++k) val[0] += val[k] * filter[k];
	    *data = (T)val[0];
	    if (!pass) data += off; else data -= off;
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  if (!pass) data -= off;
	}
      } break;
      case 1 : {
	double x[3]; // [front,center,back]
	for (int pass = 0; pass<2; ++pass) {
	  if (!pass) {
	    for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:(T)0);
	    for (int k = 0; k<4; ++k) val[k] = 0;
	  } else {
	    // apply Triggs boundary conditions
	    const double
	      unp  = val[1], unp1 = val[2], unp2 = val[3];
	    val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum;
	    val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum;
	    val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum;
	    *data = (T)val[0];
	    data -= off;
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  for (int n = pass; n<N - 1; ++n) {
	    if (!pass) {
	      x[0] = *(data + off);
	      val[0] = 0.5f * (x[0] - x[2]);
	    } else val[0] = (*data) * sum;
	    for (int k = 1; k<4; ++k) val[0] += val[k] * filter[k];
	    *data = (T)val[0];
	    if (!pass) {
	      data += off;
	      for (int k = 2; k>0; --k) x[k] = x[k - 1];
	    } else { data-=off;}
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  *data = (T)0;
	}
      } break;
      case 2: {
	double x[3]; // [front,center,back]
	for (int pass = 0; pass<2; ++pass) {
	  if (!pass) {
	    for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:(T)0);
	    for (int k = 0; k<4; ++k) val[k] = 0;
	  } else {
	    // apply Triggs boundary conditions
	    const double
	      unp  = val[1], unp1 = val[2], unp2 = val[3];
	    val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum;
	    val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum;
	    val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum;
	    *data = (T)val[0];
	    data -= off;
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  for (int n = pass; n<N - 1; ++n) {
	    if (!pass) { x[0] = *(data + off); val[0] = (x[1] - x[2]); }
	    else { x[0] = *(data - off); val[0] = (x[2] - x[1]) * sum; }
	    for (int k = 1; k<4; ++k) val[0] += val[k]*filter[k];
	    *data = (T)val[0];
	    if (!pass) data += off; else data -= off;
	    for (int k = 2; k>0; --k) x[k] = x[k - 1];
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  *data = (T)0;
	}
      } break;
      case 3: {
	double x[3]; // [front,center,back]
	for (int pass = 0; pass<2; ++pass) {
	  if (!pass) {
	    for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:(T)0);
	    for (int k = 0; k<4; ++k) val[k] = 0;
	  } else {
	    // apply Triggs boundary conditions
	    const double
	      unp = val[1], unp1 = val[2], unp2 = val[3];
	    val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum;
	    val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum;
	    val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum;
	    *data = (T)val[0];
	    data -= off;
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  for (int n = pass; n<N - 1; ++n) {
	    if (!pass) { x[0] = *(data + off); val[0] = (x[0] - 2*x[1] + x[2]); }
	    else { x[0] = *(data - off); val[0] = 0.5f * (x[2] - x[0]) * sum; }
	    for (int k = 1; k<4; ++k) val[0] += val[k] * filter[k];
	    *data = (T)val[0];
	    if (!pass) data += off; else data -= off;
	    for (int k = 2; k>0; --k) x[k] = x[k - 1];
	    for (int k = 3; k>0; --k) val[k] = val[k - 1];
	  }
	  *data = (T)0;
	}
      } break;
      }

Project: CImg
File: CImg.h


      static double mp_set_Jxyz_s(_cimg_math_parser& mp) {
        CImg<T> &img = mp.imgout;
        const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z];
        const int
          x = (int)(ox + _mp_arg(2)),
          y = (int)(oy + _mp_arg(3)),
          z = (int)(oz + _mp_arg(4));
        const T val = (T)_mp_arg(1);
        if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
          T *ptrd = &img(x,y,z);
          const ulongT whd = (ulongT)img._width*img._height*img._depth;
          cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
        }
        return _mp_arg(1);

Project: CImg
File: CImg.h

      static T min() { return ~max(); }

Project: CImg
File: CImg.h


      static double mp_complex_log(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs);
        *(ptrd++) = 0.5*std::log(r*r + i*i);
        *(ptrd++) = std::atan2(i,r);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    template<typename ti, typename tm>
    CImg<T>& draw_image(const int x0, const int y0, const int z0,
                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
                        const float mask_max_value=1) {
      return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_max_value);

Project: CImg
File: CImg.h

    //! Resize image to become a symmetric tensor \newinstance.
    CImg<T> get_tensor() const {
      CImg<T> res;
      const ulongT siz = size();
      switch (siz) {
      case 1 : break;
      case 3 :
        res.assign(2,2);
        res(0,0) = (*this)(0);
        res(1,0) = res(0,1) = (*this)(1);
        res(1,1) = (*this)(2);
        break;
      case 6 :
        res.assign(3,3);
        res(0,0) = (*this)(0);
        res(1,0) = res(0,1) = (*this)(1);
        res(2,0) = res(0,2) = (*this)(2);
        res(1,1) = (*this)(3);
        res(2,1) = res(1,2) = (*this)(4);
        res(2,2) = (*this)(5);
        break;
      default :
        throw CImgInstanceException(_cimg_instance
                                    "tensor(): Invalid instance size (does not define a 1x1, 2x2 or 3x3 tensor).",
                                    cimg_instance);
      }
      return res;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_mandelbrot(const CImg<tc>& colormap, const float opacity=1,
                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
                             const unsigned int iteration_max=255,
                             const bool is_normalized_iteration=false,
                             const bool is_julia_set=false,
                             const double param_r=0, const double param_i=0) {
      return draw_mandelbrot(0,0,_width - 1,_height - 1,colormap,opacity,
                             z0r,z0i,z1r,z1i,iteration_max,is_normalized_iteration,is_julia_set,param_r,param_i);

Project: CImg
File: CImg.h


      static double mp_acosh(_cimg_math_parser& mp) {
        return cimg::acosh(_mp_arg(2));

Project: CImg
File: CImg.h

    template<typename tp, typename tt, typename tc>
    CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
                         const tc *const color, const float opacity=1,
                         const bool is_closed_set=false, const float precision=4,
                         const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty() || !points || !tangents || points._width<2 || tangents._width<2) return *this;
      bool ninit_hatch = init_hatch;
      switch (points._height) {
      case 0 : case 1 :
        throw CImgArgumentException(_cimg_instance
                                    "draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    points._width,points._height,points._depth,points._spectrum,points._data);

      default : {
        const int x0 = (int)points(0,0), y0 = (int)points(0,1);
        const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);
        int ox = x0, oy = y0;
        float ou = u0, ov = v0;
        for (unsigned int i = 1; i<points._width; ++i) {
          const int x = (int)points(i,0), y = (int)points(i,1);
          const float u = (float)tangents(i,0), v = (float)tangents(i,1);
          draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);
          ninit_hatch = false;
          ox = x; oy = y; ou = u; ov = v;
        }
        if (is_closed_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);
      }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tz,typename tc>
    CImg<T>& draw_line(CImg<tz>& zbuffer,
                       int x0, int y0, const float z0,
                       int x1, int y1, const float z1,
                       const tc *const color, const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty() || z0<=0 || z1<=0 || !opacity || !pattern) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): Specified color is (null).",
                                    cimg_instance);
      if (!is_sameXY(zbuffer))
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have "
                                    "different dimensions.",
                                    cimg_instance,
                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);

      if (std::min(y0,y1)>=height() || std::max(y0,y1)<0 || std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this;

      float iz0 = 1/z0, iz1 = 1/z1;
      int
        w1 = width() - 1, h1 = height() - 1,
        dx01 = x1 - x0, dy01 = y1 - y0;
      float diz01 = iz1 - iz0;

      const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01);
      if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01);
      if (pattern==~0U && y0>y1) {
        cimg::swap(x0,x1,y0,y1,iz0,iz1);
        dx01*=-1; dy01*=-1; diz01*=-1;
      }

      static unsigned int hatch = ~0U - (~0U>>1);
      if (init_hatch) hatch = ~0U - (~0U>>1);
      cimg_init_scanline(opacity);

      const int
        step = y0<=y1?1:-1, hdy01 = dy01*cimg::sign(dx01)/2,
        cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step;
      dy01+=dy01?0:1;

      for (int y = cy0; y!=cy1; y+=step) {
        const int
          yy0 = y - y0,
          x = x0 + (dx01*yy0 + hdy01)/dy01;
        const float iz = iz0 + diz01*yy0/dy01;
        tz *const ptrz = is_horizontal?zbuffer.data(y,x):zbuffer.data(x,y);

        if (x>=0 && x<=w1 && pattern&hatch && iz>=*ptrz) {
          *ptrz = (tz)iz;
          T *const ptrd = is_horizontal?data(y,x):data(x,y);
          cimg_forC(*this,c) {
            const T val = color[c];
            ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity);
          }
        }
        if (!(hatch>>=1)) hatch = ~0U - (~0U>>1);
      }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to HSL color spaces.
    CImg<T>& RGBtoHSL() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoHSL(): Instance is not a RGB image.",
                                    cimg_instance);

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N],
          G = (Tfloat)p2[N],
          B = (Tfloat)p3[N],
          m = cimg::min(R,G,B),
          M = cimg::max(R,G,B),
          C = M - m,
          H = 60*(C==0?0:M==R?cimg::mod((G - B)/C,(Tfloat)6):M==G?(B - R)/C + 2:(R - G)/C + 4),
          L = 0.5f*(m + M)/255,
          S = L==1 || L==0?0:C/(1 - cimg::abs(2*L - 1))/255;
        p1[N] = (T)H;
        p2[N] = (T)S;
        p3[N] = (T)L;
      }
      return *this;

Project: CImg
File: CImg.h

     **/
    CImg<Tfloat> operator+(const char *const expression) const {
      return CImg<Tfloat>(*this,false)+=expression;

Project: CImg
File: CImg.h

    static CImgList<T> get_load_cimg(std::FILE *const file) {
      return CImgList<T>().load_cimg(file);
    }

    CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename) {
#ifdef cimg_use_zlib
#define _cimgz_load_cimg_case(Tss) { \
   Bytef *const cbuf = new Bytef[csiz]; \
   cimg::fread(cbuf,csiz,nfile); \
   raw.assign(W,H,D,C); \
   uLongf destlen = (ulongT)raw.size()*sizeof(Tss); \
   uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \
   delete[] cbuf; \
   if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \
   raw.move_to(img); \
}
#else
#define _cimgz_load_cimg_case(Tss) \
   throw CImgIOException(_cimglist_instance \
                         "load_cimg(): Unable to load compressed data from file '%s' unless zlib is enabled.", \
                         cimglist_instance, \
                         filename?filename:"(FILE*)");
#endif

#define _cimg_load_cimg_case(Ts,Tss) \
      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
        for (unsigned int l = 0; l<N; ++l) { \
          j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; \
          W = H = D = C = 0; csiz = 0; \
          if ((err = cimg_sscanf(tmp,"%u %u %u %u #%lu",&W,&H,&D,&C,&csiz))<4) \
            throw CImgIOException(_cimglist_instance \
                                  "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'.", \
                                  cimglist_instance, \
                                  W,H,D,C,l,filename?filename:("(FILE*)")); \
          if (W*H*D*C>0) { \
            CImg<Tss> raw; \
            CImg<T> &img = _data[l]; \
            if (err==5) _cimgz_load_cimg_case(Tss) \
            else { \
              img.assign(W,H,D,C); \
              T *ptrd = img._data; \
              for (ulongT to_read = img.size(); to_read; ) { \
                raw.assign((unsigned int)std::min(to_read,cimg_iobuffer)); \
                cimg::fread(raw._data,raw._width,nfile); \
                if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \
                const Tss *ptrs = raw._data; \
                for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \
                to_read-=raw._width; \
              } \
            } \
          } \
        } \
        loaded = true; \
      }

      if (!filename && !file)
        throw CImgArgumentException(_cimglist_instance
                                    "load_cimg(): Specified filename is (null).",
                                    cimglist_instance);

      const ulongT cimg_iobuffer = (ulongT)24*1024*1024;
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      bool loaded = false, endian = cimg::endianness();
      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);
      *tmp = *str_pixeltype = *str_endian = 0;
      unsigned int j, N = 0, W, H, D, C;
      unsigned long csiz;
      int i, err;
      do {
        j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0;
      } while (*tmp=='#' && i>=0);
      err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]",
                        &N,str_pixeltype._data,str_endian._data);
      if (err<2) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimglist_instance
                              "load_cimg(): CImg header not found in file '%s'.",
                              cimglist_instance,
                              filename?filename:"(FILE*)");
      }
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
      assign(N);
      _cimg_load_cimg_case("bool",bool);
      _cimg_load_cimg_case("unsigned_char",unsigned char);
      _cimg_load_cimg_case("uchar",unsigned char);
      _cimg_load_cimg_case("char",char);
      _cimg_load_cimg_case("unsigned_short",unsigned short);
      _cimg_load_cimg_case("ushort",unsigned short);
      _cimg_load_cimg_case("short",short);
      _cimg_load_cimg_case("unsigned_int",unsigned int);
      _cimg_load_cimg_case("uint",unsigned int);
      _cimg_load_cimg_case("int",int);
      _cimg_load_cimg_case("unsigned_long",ulongT);
      _cimg_load_cimg_case("ulong",ulongT);
      _cimg_load_cimg_case("long",longT);
      _cimg_load_cimg_case("unsigned_int64",uint64T);
      _cimg_load_cimg_case("uint64",uint64T);
      _cimg_load_cimg_case("int64",int64T);
      _cimg_load_cimg_case("float",float);
      _cimg_load_cimg_case("double",double);

      if (!loaded) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimglist_instance
                              "load_cimg(): Unsupported pixel type '%s' for file '%s'.",
                              cimglist_instance,
                              str_pixeltype._data,filename?filename:"(FILE*)");

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& draw_image(const int x0, const int y0, const int z0,
                        const CImg<t>& sprite, const float opacity=1) {
      return draw_image(x0,y0,z0,0,sprite,opacity);

Project: CImg
File: CImg.h

    **/
    CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
      CImg<T> res;
      if (res._height!=_spectrum) res.assign(1,_spectrum);
      const ulongT whd = (ulongT)_width*_height*_depth;
      const T *ptrs = data(x,y,z);
      T *ptrd = res._data;
      cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
      return res;

Project: CImg
File: CImg.h

    **/
    CImg<T>& max(const char *const expression) {
      return max((+*this)._fill(expression,true,1,0,0,"max",this));

Project: CImg
File: CImg.h


      static double mp_var(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        CImg<doubleT> vals(i_end - 3);
        double *p = vals.data();
        for (unsigned int i = 3; i<i_end; ++i) *(p++) = _mp_arg(i);
        return vals.variance();

Project: CImg
File: CImg.h

    //! Fill pixel values along the X-axis at a specified pixel position \overloading.
    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const double a0, ...) {
      if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,double);
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from CMYK to CMY color spaces \newinstance.
    CImg<Tfloat> get_CMYKtoCMY() const {
      if (_spectrum!=4)
        throw CImgInstanceException(_cimg_instance
                                    "CMYKtoCMY(): Instance is not a CMYK image.",
                                    cimg_instance);

      CImg<Tfloat> res(_width,_height,_depth,3);
      const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2), *ps4 = data(0,0,0,3);
      Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2);
      const longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,1024))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
	  C = (Tfloat)ps1[N],
	  M = (Tfloat)ps2[N],
	  Y = (Tfloat)ps3[N],
	  K = (Tfloat)ps4[N],
	  K1 = 1 - K/255,
          nC = C*K1 + K,
          nM = M*K1 + K,
          nY = Y*K1 + K;
        pd1[N] = (Tfloat)cimg::cut(nC,0,255),
        pd2[N] = (Tfloat)cimg::cut(nM,0,255),
        pd3[N] = (Tfloat)cimg::cut(nY,0,255);
      }
      return res;

Project: CImg
File: CImg.h

    **/
    int mouse_x() const {
      return _mouse_x;

Project: CImg
File: CImg.h


    const CImg<T>& _save_pnm(std::FILE *const file, const char *const filename,
                             const unsigned int bytes_per_pixel=0) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_pnm(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }

      double stmin, stmax = (double)max_min(stmin);
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_pnm(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename?filename:"(FILE*)");
      if (_spectrum>3)
        cimg::warn(_cimg_instance
                   "save_pnm(): Instance is multispectral, only the three first channels will be saved in file '%s'.",
                   cimg_instance,
                   filename?filename:"(FILE*)");
      if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)
        cimg::warn(_cimg_instance
                   "save_pnm(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.",
                   cimg_instance,
                   stmin,stmax,filename?filename:"(FILE*)");

      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      const T
        *ptr_r = data(0,0,0,0),
        *ptr_g = (_spectrum>=2)?data(0,0,0,1):0,
        *ptr_b = (_spectrum>=3)?data(0,0,0,2):0;
      const ulongT buf_size = std::min((ulongT)(1024*1024),(ulongT)(_width*_height*(_spectrum==1?1UL:3UL)));

      std::fprintf(nfile,"P%c\n%u %u\n%u\n",
                   (_spectrum==1?'5':'6'),_width,_height,stmax<256?255:(stmax<4096?4095:65535));

      switch (_spectrum) {
      case 1 : { // Scalar image
        if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PGM 8 bits
          CImg<ucharT> buf((unsigned int)buf_size);
          for (longT to_write = (longT)width()*height(); to_write>0; ) {
            const ulongT N = std::min((ulongT)to_write,buf_size);
            unsigned char *ptrd = buf._data;
            for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr_r++);
            cimg::fwrite(buf._data,N,nfile);
            to_write-=N;
          }
        } else { // Binary PGM 16 bits
          CImg<ushortT> buf((unsigned int)buf_size);
          for (longT to_write = (longT)width()*height(); to_write>0; ) {
            const ulongT N = std::min((ulongT)to_write,buf_size);
            unsigned short *ptrd = buf._data;
            for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned short)*(ptr_r++);
            if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);
            cimg::fwrite(buf._data,N,nfile);
            to_write-=N;
          }
        }
      } break;
      case 2 : { // RG image
        if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits
          CImg<ucharT> buf((unsigned int)buf_size);
          for (longT to_write = (longT)width()*height(); to_write>0; ) {
            const ulongT N = std::min((ulongT)to_write,buf_size/3);
            unsigned char *ptrd = buf._data;
            for (ulongT i = N; i>0; --i) {
              *(ptrd++) = (unsigned char)*(ptr_r++);
              *(ptrd++) = (unsigned char)*(ptr_g++);
              *(ptrd++) = 0;
            }
            cimg::fwrite(buf._data,3*N,nfile);
            to_write-=N;
          }
        } else {             // Binary PPM 16 bits
          CImg<ushortT> buf((unsigned int)buf_size);
          for (longT to_write = (longT)width()*height(); to_write>0; ) {
            const ulongT N = std::min((ulongT)to_write,buf_size/3);
            unsigned short *ptrd = buf._data;
            for (ulongT i = N; i>0; --i) {
              *(ptrd++) = (unsigned short)*(ptr_r++);
              *(ptrd++) = (unsigned short)*(ptr_g++);
              *(ptrd++) = 0;
            }
            if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);
            cimg::fwrite(buf._data,3*N,nfile);
            to_write-=N;
          }
        }
      } break;
      default : { // RGB image
        if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits
          CImg<ucharT> buf((unsigned int)buf_size);
          for (longT to_write = (longT)width()*height(); to_write>0; ) {
            const ulongT N = std::min((ulongT)to_write,buf_size/3);
            unsigned char *ptrd = buf._data;
            for (ulongT i = N; i>0; --i) {
              *(ptrd++) = (unsigned char)*(ptr_r++);
              *(ptrd++) = (unsigned char)*(ptr_g++);
              *(ptrd++) = (unsigned char)*(ptr_b++);
            }
            cimg::fwrite(buf._data,3*N,nfile);
            to_write-=N;
          }
        } else { // Binary PPM 16 bits
          CImg<ushortT> buf((unsigned int)buf_size);
          for (longT to_write = (longT)width()*height(); to_write>0; ) {
            const ulongT N = std::min((ulongT)to_write,buf_size/3);
            unsigned short *ptrd = buf._data;
            for (ulongT i = N; i>0; --i) {
              *(ptrd++) = (unsigned short)*(ptr_r++);
              *(ptrd++) = (unsigned short)*(ptr_g++);
              *(ptrd++) = (unsigned short)*(ptr_b++);
            }
            if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size);
            cimg::fwrite(buf._data,3*N,nfile);
            to_write-=N;
          }
        }
      }
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h


      static double mp_modulo(_cimg_math_parser& mp) {
        return cimg::mod(_mp_arg(2),_mp_arg(3));

Project: CImg
File: CImg.h


    CImg<T>& _load_bmp(std::FILE *const file, const char *const filename) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_bmp(): Specified filename is (null).",
                                    cimg_instance);

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      CImg<ucharT> header(54);
      cimg::fread(header._data,54,nfile);
      if (*header!='B' || header[1]!='M') {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_bmp(): Invalid BMP file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }

      // Read header and pixel buffer
      int
        file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
        offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
        header_size = header[0x0E] + (header[0x0F]<<8) + (header[0x10]<<16) + (header[0x11]<<24),
        dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
        dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
        compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
        nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
        bpp = header[0x1C] + (header[0x1D]<<8);

      if (!file_size || file_size==offset) {
        cimg::fseek(nfile,0,SEEK_END);
        file_size = (int)cimg::ftell(nfile);
        cimg::fseek(nfile,54,SEEK_SET);
      }
      if (header_size>40) cimg::fseek(nfile,header_size - 40,SEEK_CUR);

      const int
        dx_bytes = (bpp==1)?(dx/8 + (dx%8?1:0)):((bpp==4)?(dx/2 + (dx%2)):(int)((longT)dx*bpp/8)),
        align_bytes = (4 - dx_bytes%4)%4;
      const ulongT
        cimg_iobuffer = (ulongT)24*1024*1024,
        buf_size = std::min((ulongT)cimg::abs(dy)*(dx_bytes + align_bytes),(ulongT)file_size - offset);

      CImg<intT> colormap;
      if (bpp<16) { if (!nb_colors) nb_colors = 1<<bpp; } else nb_colors = 0;
      if (nb_colors) { colormap.assign(nb_colors); cimg::fread(colormap._data,nb_colors,nfile); }
      const int xoffset = offset - 14 - header_size - 4*nb_colors;
      if (xoffset>0) cimg::fseek(nfile,xoffset,SEEK_CUR);

      CImg<ucharT> buffer;
      if (buf_size<cimg_iobuffer) {
//        buffer.assign(cimg::abs(dy)*(dx_bytes + align_bytes),1,1,1,0);
        buffer.assign(buf_size,1,1,1,0);
        cimg::fread(buffer._data,buf_size,nfile);
      } else buffer.assign(dx_bytes + align_bytes);
      unsigned char *ptrs = buffer;

      // Decompress buffer (if necessary)
      if (compression) {
        if (file)
          throw CImgIOException(_cimg_instance
                                "load_bmp(): Unable to load compressed data from '(*FILE)' inputs.",
                                cimg_instance);
        else {
          if (!file) cimg::fclose(nfile);
          return load_other(filename);
        }
      }

      // Read pixel data
      assign(dx,cimg::abs(dy),1,3,0);
      switch (bpp) {
      case 1 : { // Monochrome
        if (colormap._width>=2) for (int y = height() - 1; y>=0; --y) {
          if (buf_size>=cimg_iobuffer) {
            if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break;
            cimg::fseek(nfile,align_bytes,SEEK_CUR);
          }
          unsigned char mask = 0x80, val = 0;
          cimg_forX(*this,x) {
            if (mask==0x80) val = *(ptrs++);
            const unsigned char *col = (unsigned char*)(colormap._data + (val&mask?1:0));
            (*this)(x,y,2) = (T)*(col++);
            (*this)(x,y,1) = (T)*(col++);
            (*this)(x,y,0) = (T)*(col++);
            mask = cimg::ror(mask);
          }
          ptrs+=align_bytes;
        }
      } break;
      case 4 : { // 16 colors
        if (colormap._width>=16) for (int y = height() - 1; y>=0; --y) {
          if (buf_size>=cimg_iobuffer) {
            if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break;
            cimg::fseek(nfile,align_bytes,SEEK_CUR);
          }
          unsigned char mask = 0xF0, val = 0;
          cimg_forX(*this,x) {
            if (mask==0xF0) val = *(ptrs++);
            const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));
            const unsigned char *col = (unsigned char*)(colormap._data + color);
            (*this)(x,y,2) = (T)*(col++);
            (*this)(x,y,1) = (T)*(col++);
            (*this)(x,y,0) = (T)*(col++);
            mask = cimg::ror(mask,4);
          }
          ptrs+=align_bytes;
        }
      } break;
      case 8 : { // 256 colors
        if (colormap._width>=256) for (int y = height() - 1; y>=0; --y) {
          if (buf_size>=cimg_iobuffer) {
            if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break;
            cimg::fseek(nfile,align_bytes,SEEK_CUR);
          }
          cimg_forX(*this,x) {
            const unsigned char *col = (unsigned char*)(colormap._data + *(ptrs++));
            (*this)(x,y,2) = (T)*(col++);
            (*this)(x,y,1) = (T)*(col++);
            (*this)(x,y,0) = (T)*(col++);
          }
          ptrs+=align_bytes;
        }
      } break;
      case 16 : { // 16 bits colors
        for (int y = height() - 1; y>=0; --y) {
          if (buf_size>=cimg_iobuffer) {
            if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break;
            cimg::fseek(nfile,align_bytes,SEEK_CUR);
          }
          cimg_forX(*this,x) {
            const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
            const unsigned short col = (unsigned short)(c1|(c2<<8));
            (*this)(x,y,2) = (T)(col&0x1F);
            (*this)(x,y,1) = (T)((col>>5)&0x1F);
            (*this)(x,y,0) = (T)((col>>10)&0x1F);
          }
          ptrs+=align_bytes;
        }
      } break;
      case 24 : { // 24 bits colors
        for (int y = height() - 1; y>=0; --y) {
          if (buf_size>=cimg_iobuffer) {
            if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break;
            cimg::fseek(nfile,align_bytes,SEEK_CUR);
          }
          cimg_forX(*this,x) {
            (*this)(x,y,2) = (T)*(ptrs++);
            (*this)(x,y,1) = (T)*(ptrs++);
            (*this)(x,y,0) = (T)*(ptrs++);
          }
          ptrs+=align_bytes;
        }
      } break;
      case 32 : { // 32 bits colors
        for (int y = height() - 1; y>=0; --y) {
          if (buf_size>=cimg_iobuffer) {
            if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break;
            cimg::fseek(nfile,align_bytes,SEEK_CUR);
          }
          cimg_forX(*this,x) {
            (*this)(x,y,2) = (T)*(ptrs++);
            (*this)(x,y,1) = (T)*(ptrs++);
            (*this)(x,y,0) = (T)*(ptrs++);
            ++ptrs;
          }
          ptrs+=align_bytes;
        }
      } break;
      }
      if (dy<0) mirror('y');
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

      static cimg_int64 min() { return ~max(); }

Project: CImg
File: CImg.h

    // [internal] Perform 3D rotation with arbitrary axis and angle.
    void _rotate(CImg<T>& res, const CImg<Tfloat>& R,
                 const unsigned int interpolation, const unsigned int boundary_conditions,
                 const float w2, const float h2, const float d2,
                 const float rw2, const float rh2, const float rd2) const {
      switch (boundary_conditions) {
      case 3 : // Mirror
        switch (interpolation) {
        case 2 : { // Cubic interpolation
          const float ww = 2.f*width(), hh = 2.f*height(), dd = 2.f*depth();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = cimg::mod((float)(w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc),ww),
              Y = cimg::mod((float)(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),hh),
              Z = cimg::mod((float)(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc),dd);
            cimg_forC(res,c) res(x,y,z,c) = _cubic_atXYZ_c(X<width()?X:ww - X - 1,
                                                           Y<height()?Y:hh - Y - 1,
                                                           Z<depth()?Z:dd - Z - z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          const float ww = 2.f*width(), hh = 2.f*height(), dd = 2.f*depth();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = cimg::mod((float)(w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc),ww),
              Y = cimg::mod((float)(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),hh),
              Z = cimg::mod((float)(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc),dd);
            cimg_forC(res,c) res(x,y,z,c) = (T)_linear_atXYZ(X<width()?X:ww - X - 1,
                                                             Y<height()?Y:hh - Y - 1,
                                                             Z<depth()?Z:dd - Z - 1,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          const int ww = 2*width(), hh = 2*height(), dd = 2*depth();
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float xc = x - rw2, yc = y - rh2, zc = z - rd2;
            const int
              X = cimg::mod((int)cimg::round(w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc),ww),
              Y = cimg::mod((int)cimg::round(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),hh),
              Z = cimg::mod((int)cimg::round(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc),dd);
            cimg_forC(res,c) res(x,y,z,c) = (*this)(X<width()?X:ww - X - 1,
                                                    Y<height()?Y:hh - Y - 1,
                                                    Z<depth()?Z:dd - Z -  1,c);
          }
        }
        } break;

      case 2 : // Periodic
        switch (interpolation) {
        case 2 : { // Cubic interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc,
              Y = h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc,
              Z = d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc;
            cimg_forC(res,c) res(x,y,z,c) = _cubic_atXYZ_pc(X,Y,Z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc,
              Y = h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc,
              Z = d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc;
            cimg_forC(res,c) res(x,y,z,c) = (T)_linear_atXYZ_p(X,Y,Z,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float xc = x - rw2, yc = y - rh2, zc = z - rd2;
            const int
              X = cimg::mod((int)cimg::round(w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc),width()),
              Y = cimg::mod((int)cimg::round(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),height()),
              Z = cimg::mod((int)cimg::round(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc),depth());
            cimg_forC(res,c) res(x,y,z,c) = (*this)(X,Y,Z,c);
          }
        }
        } break;

      case 1 : // Neumann
        switch (interpolation) {
        case 2 : { // Cubic interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc,
              Y = h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc,
              Z = d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc;
            cimg_forC(res,c) res(x,y,z,c) = _cubic_atXYZ_c(X,Y,Z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc,
              Y = h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc,
              Z = d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc;
            cimg_forC(res,c) res(x,y,z,c) = _linear_atXYZ(X,Y,Z,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float xc = x - rw2, yc = y - rh2, zc = z - rd2;
            const int
              X = (int)cimg::round(w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc),
              Y = (int)cimg::round(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),
              Z = (int)cimg::round(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc);
            cimg_forC(res,c) res(x,y,z,c) = _atXYZ(X,Y,Z,c);
          }
        }
        } break;

      default : // Dirichlet
        switch (interpolation) {
        case 2 : { // Cubic interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc,
              Y = h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc,
              Z = d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc;
            cimg_forC(res,c) res(x,y,z,c) = cubic_atXYZ_c(X,Y,Z,c,(T)0);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float
              xc = x - rw2, yc = y - rh2, zc = z - rd2,
              X = w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc,
              Y = h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc,
              Z = d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc;
            cimg_forC(res,c) res(x,y,z,c) = linear_atXYZ(X,Y,Z,c,(T)0);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048))
          cimg_forXYZ(res,x,y,z) {
            const float xc = x - rw2, yc = y - rh2, zc = z - rd2;
            const int
              X = (int)cimg::round(w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc),
              Y = (int)cimg::round(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),
              Z = (int)cimg::round(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc);
            cimg_forC(res,c) res(x,y,z,c) = atXYZ(X,Y,Z,c,(T)0);
          }
        }
        } break;
      }

Project: CImg
File: CImg.h

    template<typename t>
    bool contains(const T& pixel, t& x, t& y) const {
      const ulongT wh = (ulongT)_width*_height, siz = wh*_depth*_spectrum;
      const T *const ppixel = &pixel;
      if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;
      ulongT off = ((unsigned int)(ppixel - _data))%wh;
      const ulongT ny = off/_width, nx = off%_width;
      x = (t)nx; y = (t)ny;
      return true;

Project: CImg
File: CImg.h


      static double mp_image_whds(_cimg_math_parser& mp) {
        unsigned int ind = (unsigned int)mp.opcode[2];
        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
        return (double)img.width()*img.height()*img.depth()*img.spectrum();

Project: CImg
File: CImg.h

    //! Remove image pointed by iterator.
    /**
      \param iter Iterator pointing to the image to remove.

Project: CImg
File: CImg.h

      static bool is_nan(const short) { return false; }

Project: CImg
File: CImg.h

    **/
    static void save_empty_cimg(const char *const filename,
                                const unsigned int dx, const unsigned int dy=1,
                                const unsigned int dz=1, const unsigned int dc=1) {
      return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dc);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_rol(const CImg<t>& img) const {
      return (+*this).rol(img);

Project: CImg
File: CImg.h

  struct CImgInstanceException : public CImgException {

Project: CImg
File: CImg.h

    //! Rotate volumetric image with arbitrary angle and axis, around a center point \newinstance.
    CImg<T> get_rotate(const float u, const float v, const float w, const float angle,
                       const float cx, const float cy, const float cz,
                       const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const {
      if (is_empty()) return *this;
      CImg<T> res(_width,_height,_depth,_spectrum);
      CImg<floatT> R = CImg<floatT>::rotation_matrix(u,v,w,-angle);
      _rotate(res,R,interpolation,boundary_conditions,cx,cy,cz,cx,cy,cz);
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z,
         std::initializer_list<t> values,
	 const bool repeat_values=true):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(size_x,size_y,size_z);
      _cimg_constructor_cpp11(repeat_values);

Project: CImg
File: CImg.h

    //! Return a reference to the last image of the list \const.
    CImg<T>& back() {
      return *(_data + _width - 1);

Project: CImg
File: CImg.h

        \param step_frame Step applied between each frame.
        \param[out] voxel_size Voxel size, as stored in the filename.
        \param[out] description Description, as stored in the filename.
    **/
    CImgList<T>& load_tiff(const char *const filename,
			   const unsigned int first_frame=0, const unsigned int last_frame=~0U,
			   const unsigned int step_frame=1,
                           float *const voxel_size=0,
                           CImg<charT> *const description=0) {
      const unsigned int
	nfirst_frame = first_frame<last_frame?first_frame:last_frame,
	nstep_frame = step_frame?step_frame:1;
      unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
#ifndef cimg_use_tiff
      cimg::unused(voxel_size,description);
      if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
        throw CImgArgumentException(_cimglist_instance
                                    "load_tiff(): Unable to load sub-images from file '%s' unless libtiff is enabled.",
                                    cimglist_instance,
                                    filename);

      return assign(CImg<T>::get_load_tiff(filename));
#else
#if cimg_verbosity<3
        TIFFSetWarningHandler(0);
        TIFFSetErrorHandler(0);
#endif
      TIFF *tif = TIFFOpen(filename,"r");
      if (tif) {
        unsigned int nb_images = 0;
        do ++nb_images; while (TIFFReadDirectory(tif));
        if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
          cimg::warn(_cimglist_instance
                     "load_tiff(): Invalid specified frame range is [%u,%u] (step %u) since "
                     "file '%s' contains %u image(s).",
                     cimglist_instance,
                     nfirst_frame,nlast_frame,nstep_frame,filename,nb_images);

        if (nfirst_frame>=nb_images) return assign();
        if (nlast_frame>=nb_images) nlast_frame = nb_images - 1;
        assign(1 + (nlast_frame - nfirst_frame)/nstep_frame);
        TIFFSetDirectory(tif,0);
        cimglist_for(*this,l) _data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame,voxel_size,description);
        TIFFClose(tif);
      } else throw CImgIOException(_cimglist_instance
                                   "load_tiff(): Failed to open file '%s'.",
                                   cimglist_instance,

Project: CImg
File: CImg.h

    template<typename t>
    bool is_sameYC(const CImg<t>& img) const {
      return is_sameYC(img._height,img._spectrum);

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
      return _load_rgba(0,filename,dimw,dimh);

Project: CImg
File: CImg.h


      static double mp_list_Ixyz(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
          interpolation = (unsigned int)_mp_arg(6),
          boundary_conditions = (unsigned int)_mp_arg(7),
          vsiz = (unsigned int)mp.opcode[8];
        const CImg<T> &img = mp.listin[ind];
        const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5);
        const ulongT whd = (ulongT)img._width*img._height*img._depth;
        const T *ptrs;
        switch (interpolation) {
        case 2 : // Cubic interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ(cx,cy,cz,c);
          } break;
          case 2 : // Periodic
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ_p((float)x,(float)y,(float)z,c);
            break;
          case 1 : // Neumann
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._cubic_atXYZ((float)x,(float)y,(float)z,c);
            break;
          default : // Dirichlet
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.cubic_atXYZ((float)x,(float)y,(float)z,c,(T)0);
          } break;
        case 1 : // Linear interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const float
              w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
          } break;
          case 2 : // Periodic
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ_p((float)x,(float)y,(float)z,c);
            break;
          case 1 : // Neumann
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ((float)x,(float)y,(float)z,c);
            break;
          default : // Dirichlet
            cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,(T)0);
          } break;
        default : // Nearest neighbor interpolation
          switch (boundary_conditions) {
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(),
              mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), mz = cimg::mod((int)z,d2),
              cx = mx<img.width()?mx:w2 - mx - 1,
              cy = my<img.height()?my:h2 - my - 1,
              cz = mz<img.depth()?mz:d2 - mz - 1;
            ptrs = &img(cx,cy,cz);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          case 2 : { // Periodic
            const int
              cx = (int)cimg::mod(x,(double)img._width),
              cy = (int)cimg::mod(y,(double)img._height),
              cz = (int)cimg::mod(z,(double)img._depth);
            ptrs = &img(cx,cy,cz);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          case 1 : { // Neumann
            ptrs = &img._atXYZ((int)x,(int)y,(int)z);
            cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
          } break;
          default : // Dirichlet
            if (img.containsXYZC((int)x,(int)y,(int)z)) {
              ptrs = &img((int)x,(int)y,(int)z);
              cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
            } else std::memset(ptrd,0,vsiz*sizeof(double));
          }
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h


    inline double grand() {
      cimg::mutex(4);
      const double res = cimg::grand(&cimg::rng());
      cimg::mutex(4,0);
      return res;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_pnk(const char *const filename) const {
      return _save_pnk(0,filename);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T& value) {
      return assign(img,dimensions).fill(value);

Project: CImg
File: CImg.h

      void lock(const unsigned int) {}

Project: CImg
File: CImg.h

    //! Compute L2-norm of each multi-valued pixel of the image instance \newinstance.
    CImg<Tfloat> get_norm(const int norm_type=2) const {
      if (is_empty()) return *this;
      if (_spectrum==1 && norm_type) return get_abs();
      const ulongT whd = (ulongT)_width*_height*_depth;
      CImg<Tfloat> res(_width,_height,_depth);
      switch (norm_type) {
      case -1 : { // Linf-norm
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 &&
                                                                   _height*_depth>=16))
        cimg_forYZ(*this,y,z) {
          const ulongT off = (ulongT)offset(0,y,z);
          const T *ptrs = _data + off;
          Tfloat *ptrd = res._data + off;
          cimg_forX(*this,x) {
            Tfloat n = 0;
            const T *_ptrs = ptrs++;
            cimg_forC(*this,c) { const Tfloat val = (Tfloat)cimg::abs(*_ptrs); if (val>n) n = val; _ptrs+=whd; }
            *(ptrd++) = n;
          }
        }
      } break;
      case 0 : { // L0-norm
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 &&
                                                                   _height*_depth>=16))
        cimg_forYZ(*this,y,z) {
          const ulongT off = (ulongT)offset(0,y,z);
          const T *ptrs = _data + off;
          Tfloat *ptrd = res._data + off;
          cimg_forX(*this,x) {
            unsigned int n = 0;
            const T *_ptrs = ptrs++;
            cimg_forC(*this,c) { n+=*_ptrs==0?0:1; _ptrs+=whd; }
            *(ptrd++) = (Tfloat)n;
          }
        }
      } break;
      case 1 : { // L1-norm
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 &&
                                                                   _height*_depth>=16))
        cimg_forYZ(*this,y,z) {
          const ulongT off = (ulongT)offset(0,y,z);
          const T *ptrs = _data + off;
          Tfloat *ptrd = res._data + off;
          cimg_forX(*this,x) {
            Tfloat n = 0;
            const T *_ptrs = ptrs++;
            cimg_forC(*this,c) { n+=cimg::abs(*_ptrs); _ptrs+=whd; }
            *(ptrd++) = n;
          }
        }
      } break;
      case 2 : { // L2-norm
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 &&
                                                                   _height*_depth>=16))
        cimg_forYZ(*this,y,z) {
          const ulongT off = (ulongT)offset(0,y,z);
          const T *ptrs = _data + off;
          Tfloat *ptrd = res._data + off;
          cimg_forX(*this,x) {
            Tfloat n = 0;
            const T *_ptrs = ptrs++;
            cimg_forC(*this,c) { n+=cimg::sqr((Tfloat)*_ptrs); _ptrs+=whd; }
            *(ptrd++) = (Tfloat)std::sqrt((Tfloat)n);
          }
        }
      } break;
      default : { // Linf-norm
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 &&
                                                                   _height*_depth>=16))
        cimg_forYZ(*this,y,z) {
          const ulongT off = (ulongT)offset(0,y,z);
          const T *ptrs = _data + off;
          Tfloat *ptrd = res._data + off;
          cimg_forX(*this,x) {
            Tfloat n = 0;
            const T *_ptrs = ptrs++;
            cimg_forC(*this,c) { n+=std::pow(cimg::abs((Tfloat)*_ptrs),(Tfloat)norm_type); _ptrs+=whd; }
            *(ptrd++) = (Tfloat)std::pow((Tfloat)n,1/(Tfloat)norm_type);
          }
        }
      }
      }
      return res;

Project: CImg
File: CImg.h

    //! Convert pixel values from sRGB to RGB color spaces \newinstance.
    CImg<Tfloat> get_sRGBtoRGB() const {
      return CImg<Tfloat>(*this,false).sRGBtoRGB();

Project: CImg
File: CImg.h


    double _eval(CImg<T> *const img_output, const char *const expression,
                 const double x, const double y, const double z, const double c,
                 const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {
      if (!expression || !*expression) return 0;
      if (!expression[1]) switch (*expression) { // Single-char optimization
        case 'w' : return (double)_width;
        case 'h' : return (double)_height;
        case 'd' : return (double)_depth;
        case 's' : return (double)_spectrum;
        case 'r' : return (double)_is_shared;
        }
      _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
                                         *expression=='*' || *expression==':'),"eval",
                           *this,img_output,list_inputs,list_outputs,false);
      const double val = mp(x,y,z,c);
      mp.end();
      return val;

Project: CImg
File: CImg.h

    //! Return hyperbolic arcsine of a value.
    inline double asinh(const double x) {
#if cimg_use_cpp11==1 && !defined(_MSC_VER)
      return std::asinh(x);
#else
      return std::log(x + std::sqrt(x*x + 1));
#endif

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& assign(const CImg<t>& img, const bool is_shared) {
      return assign(img._data,img._width,img._height,img._depth,img._spectrum,is_shared);

Project: CImg
File: CImg.h


    static longT _distance_sep_mdt(const longT i, const longT u, const longT *const g) {
      return (u - i<=g[u] - g[i]?999999999:(g[u] - g[i] + u + i)/2);

Project: CImg
File: CImg.h

    **/
    CImg<charT> value_string(const char separator=',', const unsigned int max_size=0,
                             const char *const format=0) const {
      if (is_empty() || max_size==1) return CImg<charT>(1,1,1,1,0);
      CImgList<charT> items;
      CImg<charT> s_item(256); *s_item = 0;
      const T *ptrs = _data;
      unsigned int string_size = 0;
      const char *const _format = format?format:cimg::type<T>::format();
      for (ulongT off = 0, siz = size(); off<siz && (!max_size || string_size<max_size); ++off) {
        const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width,_format,
                                                             cimg::type<T>::format(*(ptrs++)));
        CImg<charT> item(s_item._data,printed_size);
        item[printed_size - 1] = separator;
        item.move_to(items);
        if (max_size) string_size+=printed_size;
      }
      CImg<charT> res;
      (items>'x').move_to(res);
      if (max_size && res._width>=max_size) res.crop(0,max_size - 1);
      res.back() = 0;
      return res;

Project: CImg
File: CImg.h

    **/
    CImgList<Tfloat> get_symmetric_eigen() const {
      CImgList<Tfloat> res(2);
      symmetric_eigen(res[0],res[1]);
      return res;

Project: CImg
File: CImg.h


      static double mp_prod(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        double val = _mp_arg(3);
        for (unsigned int i = 4; i<i_end; ++i) val*=_mp_arg(i);
        return val;

Project: CImg
File: CImg.h

    }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_ror(const CImg<t>& img) const {
      return (+*this).ror(img);

Project: CImg
File: CImg.h

    //! Load image from an ANALYZE7.5/NIFTI file \overloading.
    CImg<T>& load_analyze(std::FILE *const file, float *const voxel_size=0) {
      return _load_analyze(file,0,voxel_size);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> operator+(const t value) const {
      return CImg<_cimg_Tt>(*this,false)+=value;

Project: CImg
File: CImg.h


    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int,
                  const ulongT wh) {
      return _data[x + y*_width + z*wh];

Project: CImg
File: CImg.h

    //! Compute the bitwise left rotation of each pixel value \newinstance.
    CImg<T> get_rol(const unsigned int n=1) const {
      return (+*this).rol(n);

Project: CImg
File: CImg.h

    //! Blur image using Van Vliet recursive Gaussian filter. \newinstance.
    CImg<Tfloat> get_vanvliet(const float sigma, const unsigned int order, const char axis='x',
                              const bool boundary_conditions=true) const {
      return CImg<Tfloat>(*this,false).vanvliet(sigma,order,axis,boundary_conditions);

Project: CImg
File: CImg.h

    **/
    unsigned int key(const unsigned int pos=0) const {
      return pos<128?_keys[pos]:0;

Project: CImg
File: CImg.h

     **/
    static CImg<T>& empty() {
      static CImg<T> _empty;
      return _empty.assign();

Project: CImg
File: CImg.h

    //! Return a \c 1x14 image containing specified values.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11,
			  const T& a12, const T& a13) {
      CImg<T> r(1,14); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12; *(ptr++) = a13;
      return r;

Project: CImg
File: CImg.h


    inline double uppercase(const double x) {
      return (double)((x<'a'||x>'z')?x:x - 'a' + 'A');

Project: CImg
File: CImg.h

      \param y1 Ending Y-coordinates of image regions to read (~0U for max).
      \param z1 Ending Z-coordinates of image regions to read (~0U for max).
      \param c1 Ending C-coordinates of image regions to read (~0U for max).
    **/
    CImgList<T>& load_cimg(const char *const filename,
                           const unsigned int n0, const unsigned int n1,
                           const unsigned int x0, const unsigned int y0,
                           const unsigned int z0, const unsigned int c0,

Project: CImg
File: CImg.h

    //! Return a \c 1x16 image containing specified values.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11,
			  const T& a12, const T& a13, const T& a14, const T& a15) {
      CImg<T> r(1,16); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
      return r;

Project: CImg
File: CImg.h


      static double mp_vector_map_v(_cimg_math_parser& mp) { // Operator(vector)
        unsigned int
          siz = (unsigned int)mp.opcode[2],
          ptrs = (unsigned int)mp.opcode[4] + 1;
        double *ptrd = &_mp_arg(1) + 1;
        mp_func op = (mp_func)mp.opcode[3];
        CImg<ulongT> l_opcode(1,3);
        l_opcode.swap(mp.opcode);
        ulongT &argument = mp.opcode[2];
        while (siz-->0) { argument = ptrs++; *(ptrd++) = (*op)(mp); }
        l_opcode.swap(mp.opcode);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    **/
    inline cimg_int64 fsize(const char *const filename) {
      std::FILE *const file = cimg::std_fopen(filename,"rb");
      if (!file) return (cimg_int64)-1;
      std::fseek(file,0,SEEK_END);
      const cimg_int64 siz = (cimg_int64)std::ftell(file);
      cimg::fclose(file);
      return siz;

Project: CImg
File: CImg.h

    **/
    static void save_empty_cimg(std::FILE *const file,
                                const unsigned int dx, const unsigned int dy=1,
                                const unsigned int dz=1, const unsigned int dc=1) {
      return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dc);

Project: CImg
File: CImg.h

    //! Access to pixel value with Dirichlet boundary conditions for the coordinate (\c pos) \const.
    T atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {
      return (pos<0 || pos>=width())?out_value:(*this)(pos,x,y,z,c);

Project: CImg
File: CImg.h


      static double mp_find(_cimg_math_parser& mp) {
        const bool is_forward = (bool)_mp_arg(5);
        const ulongT siz = (ulongT)mp.opcode[3];
        longT ind = (longT)(mp.opcode[6]!=_cimg_mp_slot_nan?_mp_arg(6):is_forward?0:siz - 1);
        if (ind<0 || ind>=(longT)siz) return -1.;
        const double
          *const ptrb = &_mp_arg(2) + 1,
          *const ptre = ptrb + siz,
          val = _mp_arg(4),
          *ptr = ptrb + ind;

        // Forward search
        if (is_forward) {
          while (ptr<ptre && *ptr!=val) ++ptr;
          return ptr==ptre?-1.:(double)(ptr - ptrb);
        }

        // Backward search.
        while (ptr>=ptrb && *ptr!=val) --ptr;
        return ptr<ptrb?-1.:(double)(ptr - ptrb);

Project: CImg
File: CImg.h

    //! Save image as a DLM file \overloading.
    const CImg<T>& save_dlm(std::FILE *const file) const {
      return _save_dlm(file,0);

Project: CImg
File: CImg.h

    }
    inline double abs(const double a) {
      return std::fabs(a);

Project: CImg
File: CImg.h

    }
    inline int mod(const unsigned short x, const unsigned short m) {
      return x%m;

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_pfm(const char *const filename) {
      return _load_pfm(0,filename);

Project: CImg
File: CImg.h

#ifdef cimg_use_half
    inline half rol(const half a, const unsigned int n=1) {
      return (half)rol((int)a,n);

Project: CImg
File: CImg.h


      static double mp_list_width(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        return (double)mp.listin[ind]._width;

Project: CImg
File: CImg.h


      static double mp_isint(_cimg_math_parser& mp) {
        return (double)(cimg::mod(_mp_arg(2),1.)==0);

Project: CImg
File: CImg.h

    **/
    T& at(const int offset, const T& out_value) {
      return (offset<0 || offset>=(int)size())?(cimg::temporary(out_value)=out_value):(*this)[offset];

Project: CImg
File: CImg.h

    //! Blur image using patch-based space \newinstance.
    CImg<Tfloat> get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3,
                                const unsigned int lookup_size=4, const float smoothness=0,
                                const bool is_fast_approx=true) const {

#define _cimg_blur_patch3d_fast(N) \
      cimg_for##N##XYZ(res,x,y,z) { \
        T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \
        const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \
          x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
        float sum_weights = 0; \
        cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) \
          if (cimg::abs((Tfloat)img(x,y,z,0) - (Tfloat)img(p,q,r,0))<sigma_p3) { \
            T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,p,q,r,c,pQ,T); pQ+=N3; } \
            float distance2 = 0; \
            pQ = Q._data; cimg_for(P,_pP,T) { const float dI = (float)*_pP - (float)*(pQ++); distance2+=dI*dI; } \
            distance2/=Pnorm; \
            const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
              alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = alldist>3?0.f:1.f; \
            sum_weights+=weight; \
            cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \
          } \
        if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \
        else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \
    }

#define _cimg_blur_patch3d(N) \
      cimg_for##N##XYZ(res,x,y,z) { \
        T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \
        const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \
          x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
        float sum_weights = 0, weight_max = 0; \
        cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { \
          T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,p,q,r,c,pQ,T); pQ+=N3; } \
          float distance2 = 0; \
          pQ = Q._data; cimg_for(P,_pP,T) { const float dI = (float)*_pP - (float)*(pQ++); distance2+=dI*dI; } \
          distance2/=Pnorm; \
          const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
            alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)std::exp(-alldist); \
          if (weight>weight_max) weight_max = weight; \
          sum_weights+=weight; \
          cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \
        } \
        sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c); \
        if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \
        else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \
      }

#define _cimg_blur_patch2d_fast(N) \
        cimg_for##N##XY(res,x,y) { \
          T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \
          const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \
          float sum_weights = 0; \
          cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) \
            if (cimg::abs((Tfloat)img(x,y,0,0) - (Tfloat)img(p,q,0,0))<sigma_p3) { \
              T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N(img,p,q,0,c,pQ,T); pQ+=N2; } \
              float distance2 = 0; \
              pQ = Q._data; cimg_for(P,_pP,T) { const float dI = (float)*_pP - (float)*(pQ++); distance2+=dI*dI; } \
              distance2/=Pnorm; \
              const float dx = (float)p - x, dy = (float)q - y, \
                alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = alldist>3?0.f:1.f; \
              sum_weights+=weight; \
              cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \
            } \
          if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \
          else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \
        }

#define _cimg_blur_patch2d(N) \
        cimg_for##N##XY(res,x,y) { \
          T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \
          const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \
          float sum_weights = 0, weight_max = 0; \
          cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { \
            T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N(img,p,q,0,c,pQ,T); pQ+=N2; } \
            float distance2 = 0; \
            pQ = Q._data; cimg_for(P,_pP,T) { const float dI = (float)*_pP - (float)*(pQ++); distance2+=dI*dI; } \
            distance2/=Pnorm; \
            const float dx = (float)p - x, dy = (float)q - y, \
              alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)std::exp(-alldist); \
            if (weight>weight_max) weight_max = weight; \
            sum_weights+=weight; \
            cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \
          } \
          sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c); \
          if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \
          else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \
    }

      if (is_empty() || !patch_size || !lookup_size) return +*this;
      CImg<Tfloat> res(_width,_height,_depth,_spectrum,0);
      const CImg<T> _img = smoothness>0?get_blur(smoothness):CImg<Tfloat>(),&img = smoothness>0?_img:*this;
      CImg<T> P(patch_size*patch_size*_spectrum), Q(P);
      const float
        nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100,
        sigma_s2 = nsigma_s*nsigma_s, sigma_p2 = sigma_p*sigma_p, sigma_p3 = 3*sigma_p,
        Pnorm = P.size()*sigma_p2;
      const int rsize2 = (int)lookup_size/2, rsize1 = (int)lookup_size - rsize2 - 1;
      const unsigned int N2 = patch_size*patch_size, N3 = N2*patch_size;
      cimg::unused(N2,N3);
      if (_depth>1) switch (patch_size) { // 3D
        case 2 : if (is_fast_approx) _cimg_blur_patch3d_fast(2) else _cimg_blur_patch3d(2) break;
        case 3 : if (is_fast_approx) _cimg_blur_patch3d_fast(3) else _cimg_blur_patch3d(3) break;
        default : {
          const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1;
          if (is_fast_approx)
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                               cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height*res._depth>=4)
                               private(P,Q))
            cimg_forXYZ(res,x,y,z) { // Fast
              P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true);
              const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1,
                x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
              float sum_weights = 0;
              cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r)
                if (cimg::abs((Tfloat)img(x,y,z,0) - (Tfloat)img(p,q,r,0))<sigma_p3) {
                  (Q = img.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P;
                  const float
                    dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
                    distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
                    weight = distance2>3?0.f:1.f;
                  sum_weights+=weight;
                  cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c);
                }
              if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights;
              else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c));
            } else
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                               if (res._width>=32 && res._height*res._depth>=4) firstprivate(P,Q))
            cimg_forXYZ(res,x,y,z) { // Exact
              P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true);
              const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1,
                x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
              float sum_weights = 0, weight_max = 0;
              cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) {
                (Q = img.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P;
                const float
                  dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
                  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
                  weight = (float)std::exp(-distance2);
                if (weight>weight_max) weight_max = weight;
                sum_weights+=weight;
                cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c);
              }
              sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c);
              if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights;
              else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c));
            }
        }
        } else switch (patch_size) { // 2D
        case 2 : if (is_fast_approx) _cimg_blur_patch2d_fast(2) else _cimg_blur_patch2d(2) break;
        case 3 : if (is_fast_approx) _cimg_blur_patch2d_fast(3) else _cimg_blur_patch2d(3) break;
        case 4 : if (is_fast_approx) _cimg_blur_patch2d_fast(4) else _cimg_blur_patch2d(4) break;
        case 5 : if (is_fast_approx) _cimg_blur_patch2d_fast(5) else _cimg_blur_patch2d(5) break;
        case 6 : if (is_fast_approx) _cimg_blur_patch2d_fast(6) else _cimg_blur_patch2d(6) break;
        case 7 : if (is_fast_approx) _cimg_blur_patch2d_fast(7) else _cimg_blur_patch2d(7) break;
        case 8 : if (is_fast_approx) _cimg_blur_patch2d_fast(8) else _cimg_blur_patch2d(8) break;
        case 9 : if (is_fast_approx) _cimg_blur_patch2d_fast(9) else _cimg_blur_patch2d(9) break;
        default : { // Fast
          const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1;
          if (is_fast_approx)
            cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height>=4)
                               firstprivate(P,Q))
            cimg_forXY(res,x,y) { // Fast
              P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);
              const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
              float sum_weights = 0;
              cimg_for_inXY(res,x0,y0,x1,y1,p,q)
                if ((Tfloat)cimg::abs(img(x,y,0) - (Tfloat)img(p,q,0))<sigma_p3) {
                  (Q = img.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P;
                  const float
                    dx = (float)x - p, dy = (float)y - q,
                    distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
                    weight = distance2>3?0.f:1.f;
                  sum_weights+=weight;
                  cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c);
                }
              if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights;
              else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c));
            } else
            cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height>=4)
                               firstprivate(P,Q))
            cimg_forXY(res,x,y) { // Exact
              P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);
              const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
              float sum_weights = 0, weight_max = 0;
              cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) {
                (Q = img.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P;
                const float
                  dx = (float)x - p, dy = (float)y - q,
                  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
                  weight = (float)std::exp(-distance2);
                if (weight>weight_max) weight_max = weight;
                sum_weights+=weight;
                cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c);
              }
              sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c);
              if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights;
              else cimg_forC(res,c) res(x,y,0,c) = (Tfloat)((*this)(x,y,c));
            }
        }
        }
      return res;

Project: CImg
File: CImg.h

    //! Return specified range of image channels \inplace.
    CImg<T>& channels(const int c0, const int c1) {
      return get_channels(c0,c1).move_to(*this);

Project: CImg
File: CImg.h


    const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {
      return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth;

Project: CImg
File: CImg.h

    inline unsigned int& exception_mode(const unsigned int mode) {
      return exception_mode(mode,true);
    }

Project: CImg
File: CImg.h

     **/
    ~CImgList() {
      delete[] _data;

Project: CImg
File: CImg.h

    template<typename t>
    const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
      if (is_empty()) { val.assign(); vec.assign(); }
      else {
        if (_width!=_height || _depth>1 || _spectrum>1)
          throw CImgInstanceException(_cimg_instance
                                      "eigen(): Instance is not a square matrix.",
                                      cimg_instance);

        if (val.size()<(ulongT)_width) val.assign(1,_width);
        if (vec.size()<(ulongT)_width*_width) vec.assign(_width,_width);
        switch (_width) {
        case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break;
        case 2 : {
          const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d;
          double f = e*e - 4*(a*d - b*c);
          if (f<0) cimg::warn(_cimg_instance
                              "eigen(): Complex eigenvalues found.",
                              cimg_instance);
          f = std::sqrt(f);
          const double
            l1 = 0.5*(e - f),
            l2 = 0.5*(e + f),
            b2 = b*b,
            norm1 = std::sqrt(cimg::sqr(l2 - a) + b2),
            norm2 = std::sqrt(cimg::sqr(l1 - a) + b2);
          val[0] = (t)l2;
          val[1] = (t)l1;
          if (norm1>0) { vec(0,0) = (t)(b/norm1); vec(0,1) = (t)((l2 - a)/norm1); } else { vec(0,0) = 1; vec(0,1) = 0; }
          if (norm2>0) { vec(1,0) = (t)(b/norm2); vec(1,1) = (t)((l1 - a)/norm2); } else { vec(1,0) = 1; vec(1,1) = 0; }
        } break;
        default :
          throw CImgInstanceException(_cimg_instance
                                      "eigen(): Eigenvalues computation of general matrices is limited "
                                      "to 2x2 matrices.",
                                      cimg_instance);
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Return a C-string containing the error message associated to the thrown exception.

Project: CImg
File: CImg.h

      return *this;
    }

    //! Insert a copy of the image \c img into the current image list, at position \c pos \specialization.
    CImgList<T>& insert(const CImg<T>& img, const unsigned int pos=~0U, const bool is_shared=false) {
      const unsigned int npos = pos==~0U?_width:pos;
      if (npos>_width)
        throw CImgArgumentException(_cimglist_instance
                                    "insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) "
                                    "at position %u.",
                                    cimglist_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data,npos);
      CImg<T> *const new_data = (++_width>_allocated_width)?new CImg<T>[_allocated_width?(_allocated_width<<=1):
                                                                        (_allocated_width=16)]:0;
      if (!_data) { // Insert new element into empty list
        _data = new_data;
        if (is_shared && img) {
          _data->_width = img._width;
          _data->_height = img._height;
          _data->_depth = img._depth;
          _data->_spectrum = img._spectrum;
          _data->_is_shared = true;
          _data->_data = img._data;
        } else *_data = img;
      }
      else {
        if (new_data) { // Insert with re-allocation
          if (npos) std::memcpy((void*)new_data,(void*)_data,sizeof(CImg<T>)*npos);
          if (npos!=_width - 1)
            std::memcpy((void*)(new_data + npos + 1),(void*)(_data + npos),sizeof(CImg<T>)*(_width - 1 - npos));
          if (is_shared && img) {
            new_data[npos]._width = img._width;
            new_data[npos]._height = img._height;
            new_data[npos]._depth = img._depth;
            new_data[npos]._spectrum = img._spectrum;
            new_data[npos]._is_shared = true;
            new_data[npos]._data = img._data;
          } else {
            new_data[npos]._width = new_data[npos]._height = new_data[npos]._depth = new_data[npos]._spectrum = 0;
            new_data[npos]._data = 0;
            new_data[npos] = img;
          }
          std::memset((void*)_data,0,sizeof(CImg<T>)*(_width - 1));
          delete[] _data;
          _data = new_data;
        } else { // Insert without re-allocation
          if (npos!=_width - 1)
            std::memmove((void*)(_data + npos + 1),(void*)(_data + npos),sizeof(CImg<T>)*(_width - 1 - npos));
          if (is_shared && img) {
            _data[npos]._width = img._width;
            _data[npos]._height = img._height;
            _data[npos]._depth = img._depth;
            _data[npos]._spectrum = img._spectrum;
            _data[npos]._is_shared = true;
            _data[npos]._data = img._data;
          } else {
            _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0;
            _data[npos]._data = 0;
            _data[npos] = img;
          }

Project: CImg
File: CImg.h

    **/
    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
                        const unsigned int depth, const unsigned int spectrum, const T& val) {
      assign(n);
      cimglist_apply(*this,assign)(width,height,depth,spectrum,val);
      return *this;

Project: CImg
File: CImg.h

    //! Blur image anisotropically, in an edge-preserving way \newinstance.
    CImg<Tfloat> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f,
                                      const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
                                      const float da=30, const float gauss_prec=2,
                                      const unsigned int interpolation_type=0,
                                      const bool is_fast_approx=true) const {
      return CImg<Tfloat>(*this,false).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,
                                                        interpolation_type,is_fast_approx);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> get_discard(const CImg<t>& values, const char axis=0) const {
      CImg<T> res;
      if (!values) return +*this;
      if (is_empty()) return res;
      const ulongT vsiz = values.size();
      const char _axis = cimg::lowercase(axis);
      ulongT j = 0;
      unsigned int k = 0;
      int i0 = 0;
      res.assign(width(),height(),depth(),spectrum());
      switch (_axis) {
      case 'x' : {
        cimg_forX(*this,i) {
          if ((*this)(i)!=(T)values[j]) {
            if (j) --i;
            res.draw_image(k,get_columns(i0,i));
            k+=i - i0 + 1; i0 = i + 1; j = 0;
          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }
        }
        if (i0<width()) { res.draw_image(k,get_columns(i0,width() - 1)); k+=width() - i0; }
        res.resize(k,-100,-100,-100,0);
      } break;
      case 'y' : {
        cimg_forY(*this,i) {
          if ((*this)(0,i)!=(T)values[j]) {
            if (j) --i;
            res.draw_image(0,k,get_rows(i0,i));
            k+=i - i0 + 1; i0 = i + 1; j = 0;
          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }
        }
        if (i0<height()) { res.draw_image(0,k,get_rows(i0,height() - 1)); k+=height() - i0; }
        res.resize(-100,k,-100,-100,0);
      } break;
      case 'z' : {
        cimg_forZ(*this,i) {
          if ((*this)(0,0,i)!=(T)values[j]) {
            if (j) --i;
            res.draw_image(0,0,k,get_slices(i0,i));
            k+=i - i0 + 1; i0 = i + 1; j = 0;
          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }
        }
        if (i0<depth()) { res.draw_image(0,0,k,get_slices(i0,height() - 1)); k+=depth() - i0; }
        res.resize(-100,-100,k,-100,0);
      } break;
      case 'c' : {
        cimg_forC(*this,i) {
          if ((*this)(0,0,0,i)!=(T)values[j]) {
            if (j) --i;
            res.draw_image(0,0,0,k,get_channels(i0,i));
            k+=i - i0 + 1; i0 = i + 1; j = 0;
          } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } }
        }
        if (i0<spectrum()) { res.draw_image(0,0,k,get_channels(i0,height() - 1)); k+=spectrum() - i0; }
        res.resize(-100,-100,-100,k,0);
      } break;
      default : {
        res.unroll('y');
        cimg_foroff(*this,i) {
          if ((*this)[i]!=(T)values[j]) {
            if (j) --i;
            std::memcpy(res._data + k,_data + i0,(i - i0 + 1)*sizeof(T));
            k+=i - i0 + 1; i0 = (int)i + 1; j = 0;
          } else { ++j; if (j>=vsiz) { j = 0; i0 = (int)i + 1; }}
        }
        const ulongT siz = size();
        if ((ulongT)i0<siz) { std::memcpy(res._data + k,_data + i0,(siz - i0)*sizeof(T)); k+=siz - i0; }
        res.resize(1,k,1,1,0);
      }
      }
      return res;

Project: CImg
File: CImg.h

    inline unsigned int& exception_mode(const unsigned int value, const bool is_set) {
      static unsigned int mode = cimg_verbosity;
      if (is_set) { cimg::mutex(0); mode = value<4?value:4; cimg::mutex(0,0); }
      return mode;
    }

Project: CImg
File: CImg.h

      _functor4d_streamline3d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,2,3); }

Project: CImg
File: CImg.h

    /**
       \param n Number of empty images to insert.
       \param pos Index of the insertion.
    **/
    CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
      CImg<T> empty;
      if (!n) return *this;

Project: CImg
File: CImg.h

    template<typename T>
    explicit CImgDisplay(const CImgList<T>& list,
                         const char *const title=0, const unsigned int normalization=3,
                         const bool is_fullscreen=false, const bool is_closed=false):
      _width(0),_height(0),_normalization(0),
      _min(0),_max(0),
      _is_fullscreen(false),
      _title(0),
      _window_width(0),_window_height(0),_button(0),
      _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
      _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
      _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
      assign(list,title,normalization,is_fullscreen,is_closed);

Project: CImg
File: CImg.h

     **/
    CImg<T>& operator++() {
      if (is_empty()) return *this;
      cimg_openmp_for(*this,*ptr + 1,524288);
      return *this;

Project: CImg
File: CImg.h


    static bool _is_CImg3d(const T val, const char c) {
      return val>=(T)c && val<(T)(c + 1);

Project: CImg
File: CImg.h

    //! Return pointer to the first image of the list \const.
    const CImg<T> *data() const {
      return _data;

Project: CImg
File: CImg.h

    template<typename T>
    inline T _hypot(const T x, const T y) { // Slower but more precise version
      T nx = cimg::abs(x), ny = cimg::abs(y), t;
      if (nx<ny) { t = nx; nx = ny; } else t = ny;
      if (nx>0) { t/=nx; return nx*std::sqrt(1 + t*t); }
      return 0;

Project: CImg
File: CImg.h


    inline float option(const char *const name, const int argc, const char *const *const argv,
                        const float defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const float res = s?(float)cimg::atof(s):defaut;
      char *const tmp = new char[256];
      cimg_snprintf(tmp,256,"%g",res);
      cimg::option(name,0,0,tmp,usage);
      delete[] tmp;
      return res;

Project: CImg
File: CImg.h

      static short max() { return (short)((unsigned short)-1>>1); }

Project: CImg
File: CImg.h


      static double mp_list_spectrum(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        return (double)mp.listin[ind]._spectrum;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
                            const tc *const color, const float opacity,
                            const float brightness,
                            const float nopacity, const float copacity, const ulongT whd, const T _sc_maxval) {
      const int nx0 = x0>0?x0:0, nx1 = x1<width()?x1:width() - 1, dx = nx1 - nx0;
      if (dx>=0) {
        const tc *col = color;
        const ulongT off = whd - dx - 1;
        T *ptrd = data(nx0,y);
        if (opacity>=1) { // ** Opaque drawing **
          if (brightness==1) { // Brightness==1
            if (sizeof(T)!=1) cimg_forC(*this,c) {
                const T val = (T)*(col++);
                for (int x = dx; x>=0; --x) *(ptrd++) = val;
                ptrd+=off;
              } else cimg_forC(*this,c) {
                const T val = (T)*(col++);
                std::memset(ptrd,(int)val,dx + 1);
                ptrd+=whd;
              }
          } else if (brightness<1) { // Brightness<1
            if (sizeof(T)!=1) cimg_forC(*this,c) {
                const T val = (T)(*(col++)*brightness);
                for (int x = dx; x>=0; --x) *(ptrd++) = val;
                ptrd+=off;
              } else cimg_forC(*this,c) {
                const T val = (T)(*(col++)*brightness);
                std::memset(ptrd,(int)val,dx + 1);
                ptrd+=whd;
              }
          } else { // Brightness>1
            if (sizeof(T)!=1) cimg_forC(*this,c) {
                const T val = (T)((2-brightness)**(col++) + (brightness - 1)*_sc_maxval);
                for (int x = dx; x>=0; --x) *(ptrd++) = val;
                ptrd+=off;
              } else cimg_forC(*this,c) {
                const T val = (T)((2-brightness)**(col++) + (brightness - 1)*_sc_maxval);
                std::memset(ptrd,(int)val,dx + 1);
                ptrd+=whd;
              }
          }
        } else { // ** Transparent drawing **
          if (brightness==1) { // Brightness==1
            cimg_forC(*this,c) {
              const Tfloat val = *(col++)*nopacity;
              for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; }
              ptrd+=off;
            }
          } else if (brightness<=1) { // Brightness<1
            cimg_forC(*this,c) {
              const Tfloat val = *(col++)*brightness*nopacity;
              for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; }
              ptrd+=off;
            }
          } else { // Brightness>1
            cimg_forC(*this,c) {
              const Tfloat val = ((2-brightness)**(col++) + (brightness - 1)*_sc_maxval)*nopacity;
              for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; }
              ptrd+=off;
            }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t, typename to>
    static float __draw_object3d(const CImgList<t>& opacities, const unsigned int n_primitive, CImg<to>& opacity) {
      if (n_primitive>=opacities._width || opacities[n_primitive].is_empty()) { opacity.assign(); return 1; }
      if (opacities[n_primitive].size()==1) { opacity.assign(); return opacities(n_primitive,0); }
      opacity.assign(opacities[n_primitive],true);
      return 1.f;

Project: CImg
File: CImg.h

    **/
    double variance(const unsigned int variance_method=1) const {
      double foo;
      return variance_mean(variance_method,foo);

Project: CImg
File: CImg.h

    template<typename t>
    bool operator==(const t value) const {
      if (is_empty()) return false;
      typedef _cimg_Tt Tt;
      bool is_equal = true;
      for (T *ptrd = _data + size(); is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)value)) {}
      return is_equal;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& operator()(const unsigned int pos) const {
      return const_cast<CImgList<T>*>(this)->operator()(pos);

Project: CImg
File: CImg.h

     **/
    double trace() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "trace(): Empty instance.",
                                    cimg_instance);
      double res = 0;
      cimg_forX(*this,k) res+=(double)(*this)(k,k);
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    void _eik_priority_queue_insert(CImg<charT>& state, unsigned int& siz, const t value,
                                    const unsigned int x, const unsigned int y, const unsigned int z) {
      if (state(x,y,z)>0) return;
      state(x,y,z) = 0;
      if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); }
      (*this)(siz - 1,0) = (T)value; (*this)(siz - 1,1) = (T)x; (*this)(siz - 1,2) = (T)y; (*this)(siz - 1,3) = (T)z;
      for (unsigned int pos = siz - 1, par = 0; pos && value>(t)(*this)(par=(pos + 1)/2 - 1,0); pos = par) {
        cimg::swap((*this)(pos,0),(*this)(par,0)); cimg::swap((*this)(pos,1),(*this)(par,1));
        cimg::swap((*this)(pos,2),(*this)(par,2)); cimg::swap((*this)(pos,3),(*this)(par,3));
      }

Project: CImg
File: CImg.h

    **/
    static CImgList<T>& empty() {
      static CImgList<T> _empty;
      return _empty.assign();

Project: CImg
File: CImg.h

    //! Return options specified on the command line.
    inline const char* option(const char *const name, const int argc, const char *const *const argv,
                              const char *const defaut, const char *const usage, const bool reset_static) {
      static bool first = true, visu = false;
      if (reset_static) { first = true; return 0; }
      const char *res = 0;
      if (first) {
        first = false;
        visu = cimg::option("-h",argc,argv,(char*)0,(char*)0,false)!=0;
        visu |= cimg::option("-help",argc,argv,(char*)0,(char*)0,false)!=0;
        visu |= cimg::option("--help",argc,argv,(char*)0,(char*)0,false)!=0;
      }
      if (!name && visu) {
        if (usage) {
          std::fprintf(cimg::output(),"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
          std::fprintf(cimg::output(),": %s",usage);
          std::fprintf(cimg::output()," (%s, %s)\n\n",cimg_date,cimg_time);
        }
        if (defaut) std::fprintf(cimg::output(),"%s\n",defaut);
      }
      if (name) {
        if (argc>0) {
          int k = 0;
          while (k<argc && std::strcmp(argv[k],name)) ++k;
          res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
        } else res = defaut;
        if (visu && usage) std::fprintf(cimg::output(),"    %s%-16s%s %-24s %s%s%s\n",
                                        cimg::t_bold,name,cimg::t_normal,res?res:"0",
                                        cimg::t_green,usage,cimg::t_normal);
      }
      return res;

Project: CImg
File: CImg.h

    **/
    CImg<T>& mirror(const char axis) {
      if (is_empty()) return *this;
      T *pf, *pb, *buf = 0;
      switch (cimg::lowercase(axis)) {
      case 'x' : {
        pf = _data; pb = data(_width - 1);
        const unsigned int width2 = _width/2;
        for (unsigned int yzv = 0; yzv<_height*_depth*_spectrum; ++yzv) {
          for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
          pf+=_width - width2;
          pb+=_width + width2;
        }
      } break;
      case 'y' : {
        buf = new T[_width];
        pf = _data; pb = data(0,_height - 1);
        const unsigned int height2 = _height/2;
        for (unsigned int zv = 0; zv<_depth*_spectrum; ++zv) {
          for (unsigned int y = 0; y<height2; ++y) {
            std::memcpy(buf,pf,_width*sizeof(T));
            std::memcpy(pf,pb,_width*sizeof(T));
            std::memcpy(pb,buf,_width*sizeof(T));
            pf+=_width;
            pb-=_width;
          }
          pf+=(ulongT)_width*(_height - height2);
          pb+=(ulongT)_width*(_height + height2);
        }
      } break;
      case 'z' : {
        buf = new T[(ulongT)_width*_height];
        pf = _data; pb = data(0,0,_depth - 1);
        const unsigned int depth2 = _depth/2;
        cimg_forC(*this,c) {
          for (unsigned int z = 0; z<depth2; ++z) {
            std::memcpy(buf,pf,_width*_height*sizeof(T));
            std::memcpy(pf,pb,_width*_height*sizeof(T));
            std::memcpy(pb,buf,_width*_height*sizeof(T));
            pf+=(ulongT)_width*_height;
            pb-=(ulongT)_width*_height;
          }
          pf+=(ulongT)_width*_height*(_depth - depth2);
          pb+=(ulongT)_width*_height*(_depth + depth2);
        }
      } break;
      case 'c' : {
        buf = new T[(ulongT)_width*_height*_depth];
        pf = _data; pb = data(0,0,0,_spectrum - 1);
        const unsigned int _spectrum2 = _spectrum/2;
        for (unsigned int v = 0; v<_spectrum2; ++v) {
          std::memcpy(buf,pf,_width*_height*_depth*sizeof(T));
          std::memcpy(pf,pb,_width*_height*_depth*sizeof(T));
          std::memcpy(pb,buf,_width*_height*_depth*sizeof(T));
          pf+=(ulongT)_width*_height*_depth;
          pb-=(ulongT)_width*_height*_depth;
        }
      } break;
      default :
        throw CImgArgumentException(_cimg_instance
                                    "mirror(): Invalid specified axis '%c'.",
                                    cimg_instance,
                                    axis);
      }
      delete[] buf;
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& shift_object3d() {
      if (_height!=3 || _depth>1 || _spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "shift_object3d(): Instance is not a set of 3D vertices.",
                                    cimg_instance);

      CImg<T> xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2);
      float
        xm, xM = (float)xcoords.max_min(xm),
        ym, yM = (float)ycoords.max_min(ym),
        zm, zM = (float)zcoords.max_min(zm);
      xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
      return *this;

Project: CImg
File: CImg.h

    //! Estimate displacement field between two images \newinstance.
    CImg<floatT> get_displacement(const CImg<T>& source,
                                  const float smoothness=0.1f, const float precision=5.f,
                                  const unsigned int nb_scales=0, const unsigned int iteration_max=10000,
                                  const bool is_backward=false,
                                  const CImg<floatT>& guide=CImg<floatT>::const_empty()) const {
      if (is_empty() || !source) return +*this;
      if (!is_sameXYZC(source))
        throw CImgArgumentException(_cimg_instance
                                    "displacement(): Instance and source image (%u,%u,%u,%u,%p) have "
                                    "different dimensions.",
                                    cimg_instance,
                                    source._width,source._height,source._depth,source._spectrum,source._data);
      if (precision<0)
        throw CImgArgumentException(_cimg_instance
                                    "displacement(): Invalid specified precision %g "
                                    "(should be >=0)",
                                    cimg_instance,
                                    precision);

      const bool is_3d = source._depth>1;
      const unsigned int constraint = is_3d?3:2;

      if (guide &&
          (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<constraint))
        throw CImgArgumentException(_cimg_instance
                                    "displacement(): Specified guide (%u,%u,%u,%u,%p) "
                                    "has invalid dimensions.",
                                    cimg_instance,
                                    guide._width,guide._height,guide._depth,guide._spectrum,guide._data);

      const unsigned int
        mins = is_3d?cimg::min(_width,_height,_depth):std::min(_width,_height),
        _nb_scales = nb_scales>0?nb_scales:
        (unsigned int)cimg::round(std::log(mins/8.)/std::log(1.5),1,1);

      const float _precision = (float)std::pow(10.,-(double)precision);
      float sm, sM = source.max_min(sm), tm, tM = max_min(tm);
      const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm);

      CImg<floatT> U, V;
      floatT bound = 0;
      for (int scale = (int)_nb_scales - 1; scale>=0; --scale) {
        const float factor = (float)std::pow(1.5,(double)scale);
        const unsigned int
          _sw = (unsigned int)(_width/factor), sw = _sw?_sw:1,
          _sh = (unsigned int)(_height/factor), sh = _sh?_sh:1,
          _sd = (unsigned int)(_depth/factor), sd = _sd?_sd:1;
        if (sw<5 && sh<5 && (!is_3d || sd<5)) continue;  // Skip too small scales
        const CImg<Tfloat>
          I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta,
          I2 = (get_resize(I1,2)-=tm)/=tdelta;
        if (guide._spectrum>constraint) guide.get_resize(I2._width,I2._height,I2._depth,-100,1).move_to(V);
        if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3);
        else {
          if (guide)
            guide.get_shared_channels(0,is_3d?2:1).get_resize(I2._width,I2._height,I2._depth,-100,2).move_to(U);
          else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0);
        }

        float dt = 2, energy = cimg::type<float>::max();
        const CImgList<Tfloat> dI = is_backward?I1.get_gradient():I2.get_gradient();
        cimg_abort_init;

        for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) {
          cimg_abort_test;
          float _energy = 0;

          if (is_3d) { // 3D version
            if (smoothness>=0) // Isotropic regularization
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                                 cimg_openmp_if(_height*_depth>=(cimg_openmp_sizefactor)*8 &&
                                                _width>=(cimg_openmp_sizefactor)*16)
                                 reduction(+:_energy))
              cimg_forYZ(U,y,z) {
                const int
                  _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y,
                  _p1z = z?z - 1:0, _n1z = z<U.depth() - 1?z + 1:z;
                cimg_for3X(U,x) {
                  const float
                    X = is_backward?x - U(x,y,z,0):x + U(x,y,z,0),
                    Y = is_backward?y - U(x,y,z,1):y + U(x,y,z,1),
                    Z = is_backward?z - U(x,y,z,2):z + U(x,y,z,2);
                  float delta_I = 0, _energy_regul = 0;
                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1._linear_atXYZ(X,Y,Z,c) - I2(x,y,z,c));
                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,z,c) - I2._linear_atXYZ(X,Y,Z,c));
                  cimg_forC(U,c) {
                    const float
                      Ux = 0.5f*(U(_n1x,y,z,c) - U(_p1x,y,z,c)),
                      Uy = 0.5f*(U(x,_n1y,z,c) - U(x,_p1y,z,c)),
                      Uz = 0.5f*(U(x,y,_n1z,c) - U(x,y,_p1z,c)),
                      Uxx = U(_n1x,y,z,c) + U(_p1x,y,z,c),
                      Uyy = U(x,_n1y,z,c) + U(x,_p1y,z,c),
                      Uzz = U(x,y,_n1z,c) + U(x,y,_p1z,c);
                    U(x,y,z,c) = (float)(U(x,y,z,c) + dt*(delta_I*dI[c]._linear_atXYZ(X,Y,Z) +
                                                          smoothness* ( Uxx + Uyy + Uzz)))/(1 + 6*smoothness*dt);
                    _energy_regul+=Ux*Ux + Uy*Uy + Uz*Uz;
                  }
                  if (is_backward) { // Constraint displacement vectors to stay in image
                    if (U(x,y,z,0)>x) U(x,y,z,0) = (float)x;
                    if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y;
                    if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z;
                    bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound;
                    bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound;
                    bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound;
                  } else {
                    if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x;
                    if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y;
                    if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z;
                    bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound;
                    bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound;
                    bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound;
                  }
                  _energy+=delta_I*delta_I + smoothness*_energy_regul;
                }
                if (V) cimg_forXYZ(V,_x,_y,_z) if (V(_x,_y,_z,3)) { // Apply constraints
                    U(_x,_y,_z,0) = V(_x,_y,_z,0)/factor;
                    U(_x,_y,_z,1) = V(_x,_y,_z,1)/factor;
                    U(_x,_y,_z,2) = V(_x,_y,_z,2)/factor;
                  }
              } else { // Anisotropic regularization
              const float nsmoothness = -smoothness;
              cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                                 cimg_openmp_if(_height*_depth>=(cimg_openmp_sizefactor)*8 &&
                                                _width>=(cimg_openmp_sizefactor)*16)
                                 reduction(+:_energy))
              cimg_forYZ(U,y,z) {
                const int
                  _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y,
                  _p1z = z?z - 1:0, _n1z = z<U.depth() - 1?z + 1:z;
                cimg_for3X(U,x) {
                  const float
                    X = is_backward?x - U(x,y,z,0):x + U(x,y,z,0),
                    Y = is_backward?y - U(x,y,z,1):y + U(x,y,z,1),
                    Z = is_backward?z - U(x,y,z,2):z + U(x,y,z,2);
                  float delta_I = 0, _energy_regul = 0;
                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1._linear_atXYZ(X,Y,Z,c) - I2(x,y,z,c));
                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,z,c) - I2._linear_atXYZ(X,Y,Z,c));
                  cimg_forC(U,c) {
                    const float
                      Ux = 0.5f*(U(_n1x,y,z,c) - U(_p1x,y,z,c)),
                      Uy = 0.5f*(U(x,_n1y,z,c) - U(x,_p1y,z,c)),
                      Uz = 0.5f*(U(x,y,_n1z,c) - U(x,y,_p1z,c)),
                      N2 = Ux*Ux + Uy*Uy + Uz*Uz,
                      N = std::sqrt(N2),
                      N3 = 1e-5f + N2*N,
                      coef_a = (1 - Ux*Ux/N2)/N,
                      coef_b = -2*Ux*Uy/N3,
                      coef_c = -2*Ux*Uz/N3,
                      coef_d = (1 - Uy*Uy/N2)/N,
                      coef_e = -2*Uy*Uz/N3,
                      coef_f = (1 - Uz*Uz/N2)/N,
                      Uxx = U(_n1x,y,z,c) + U(_p1x,y,z,c),
                      Uyy = U(x,_n1y,z,c) + U(x,_p1y,z,c),
                      Uzz = U(x,y,_n1z,c) + U(x,y,_p1z,c),
                      Uxy = 0.25f*(U(_n1x,_n1y,z,c) + U(_p1x,_p1y,z,c) - U(_n1x,_p1y,z,c) - U(_n1x,_p1y,z,c)),
                      Uxz = 0.25f*(U(_n1x,y,_n1z,c) + U(_p1x,y,_p1z,c) - U(_n1x,y,_p1z,c) - U(_n1x,y,_p1z,c)),
                      Uyz = 0.25f*(U(x,_n1y,_n1z,c) + U(x,_p1y,_p1z,c) - U(x,_n1y,_p1z,c) - U(x,_n1y,_p1z,c));
                    U(x,y,z,c) = (float)(U(x,y,z,c) + dt*(delta_I*dI[c]._linear_atXYZ(X,Y,Z) +
                                                          nsmoothness* ( coef_a*Uxx + coef_b*Uxy +
                                                                         coef_c*Uxz + coef_d*Uyy +
                                                                         coef_e*Uyz + coef_f*Uzz ))
                                         )/(1 + 2*(coef_a + coef_d + coef_f)*nsmoothness*dt);
                    _energy_regul+=N;
                  }
                  if (is_backward) { // Constraint displacement vectors to stay in image
                    if (U(x,y,z,0)>x) U(x,y,z,0) = (float)x;
                    if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y;
                    if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z;
                    bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound;
                    bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound;
                    bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound;
                  } else {
                    if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x;
                    if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y;
                    if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z;
                    bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound;
                    bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound;
                    bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound;
                  }
                  _energy+=delta_I*delta_I + nsmoothness*_energy_regul;
                }
                if (V) cimg_forXYZ(V,_x,_y,_z) if (V(_x,_y,_z,3)) { // Apply constraints
                    U(_x,_y,_z,0) = V(_x,_y,_z,0)/factor;
                    U(_x,_y,_z,1) = V(_x,_y,_z,1)/factor;
                    U(_x,_y,_z,2) = V(_x,_y,_z,2)/factor;
                  }
              }
            }
          } else { // 2D version
            if (smoothness>=0) // Isotropic regularization
              cimg_pragma_openmp(parallel for cimg_openmp_if(_height>=(cimg_openmp_sizefactor)*8 &&
                                                             _width>=(cimg_openmp_sizefactor)*16) reduction(+:_energy))
              cimg_forY(U,y) {
                const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y;
                cimg_for3X(U,x) {
                  const float
                    X = is_backward?x - U(x,y,0):x + U(x,y,0),
                    Y = is_backward?y - U(x,y,1):y + U(x,y,1);
                  float delta_I = 0, _energy_regul = 0;
                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1._linear_atXY(X,Y,c) - I2(x,y,c));
                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,c) - I2._linear_atXY(X,Y,c));
                  cimg_forC(U,c) {
                    const float
                      Ux = 0.5f*(U(_n1x,y,c) - U(_p1x,y,c)),
                      Uy = 0.5f*(U(x,_n1y,c) - U(x,_p1y,c)),
                      Uxx = U(_n1x,y,c) + U(_p1x,y,c),
                      Uyy = U(x,_n1y,c) + U(x,_p1y,c);
                    U(x,y,c) = (float)(U(x,y,c) + dt*(delta_I*dI[c]._linear_atXY(X,Y) +
                                                      smoothness*( Uxx + Uyy )))/(1 + 4*smoothness*dt);
                    _energy_regul+=Ux*Ux + Uy*Uy;
                  }
                  if (is_backward) { // Constraint displacement vectors to stay in image
                    if (U(x,y,0)>x) U(x,y,0) = (float)x;
                    if (U(x,y,1)>y) U(x,y,1) = (float)y;
                    bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound;
                    bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound;
                  } else {
                    if (U(x,y,0)<-x) U(x,y,0) = -(float)x;
                    if (U(x,y,1)<-y) U(x,y,1) = -(float)y;
                    bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound;
                    bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound;
                  }
                  _energy+=delta_I*delta_I + smoothness*_energy_regul;
                }
                if (V) cimg_forXY(V,_x,_y) if (V(_x,_y,2)) { // Apply constraints
                    U(_x,_y,0) = V(_x,_y,0)/factor;
                    U(_x,_y,1) = V(_x,_y,1)/factor;
                  }
              } else { // Anisotropic regularization
              const float nsmoothness = -smoothness;
              cimg_pragma_openmp(parallel for cimg_openmp_if(_height>=(cimg_openmp_sizefactor)*8 &&
                                                             _width>=(cimg_openmp_sizefactor)*16) reduction(+:_energy))
              cimg_forY(U,y) {
                const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y;
                cimg_for3X(U,x) {
                  const float
                    X = is_backward?x - U(x,y,0):x + U(x,y,0),
                    Y = is_backward?y - U(x,y,1):y + U(x,y,1);
                  float delta_I = 0, _energy_regul = 0;
                  if (is_backward) cimg_forC(I2,c) delta_I+=(float)(I1._linear_atXY(X,Y,c) - I2(x,y,c));
                  else cimg_forC(I2,c) delta_I+=(float)(I1(x,y,c) - I2._linear_atXY(X,Y,c));
                  cimg_forC(U,c) {
                    const float
                      Ux = 0.5f*(U(_n1x,y,c) - U(_p1x,y,c)),
                      Uy = 0.5f*(U(x,_n1y,c) - U(x,_p1y,c)),
                      N2 = Ux*Ux + Uy*Uy,
                      N = std::sqrt(N2),
                      N3 = 1e-5f + N2*N,
                      coef_a = Uy*Uy/N3,
                      coef_b = -2*Ux*Uy/N3,
                      coef_c = Ux*Ux/N3,
                      Uxx = U(_n1x,y,c) + U(_p1x,y,c),
                      Uyy = U(x,_n1y,c) + U(x,_p1y,c),
                      Uxy = 0.25f*(U(_n1x,_n1y,c) + U(_p1x,_p1y,c) - U(_n1x,_p1y,c) - U(_n1x,_p1y,c));
                    U(x,y,c) = (float)(U(x,y,c) + dt*(delta_I*dI[c]._linear_atXY(X,Y) +
                                                      nsmoothness*( coef_a*Uxx + coef_b*Uxy + coef_c*Uyy )))/
                      (1 + 2*(coef_a + coef_c)*nsmoothness*dt);
                    _energy_regul+=N;
                  }
                  if (is_backward) { // Constraint displacement vectors to stay in image
                    if (U(x,y,0)>x) U(x,y,0) = (float)x;
                    if (U(x,y,1)>y) U(x,y,1) = (float)y;
                    bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound;
                    bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound;
                  } else {
                    if (U(x,y,0)<-x) U(x,y,0) = -(float)x;
                    if (U(x,y,1)<-y) U(x,y,1) = -(float)y;
                    bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound;
                    bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound;
                  }
                  _energy+=delta_I*delta_I + nsmoothness*_energy_regul;
                }
                if (V) cimg_forXY(V,_x,_y) if (V(_x,_y,2)) { // Apply constraints
                    U(_x,_y,0) = V(_x,_y,0)/factor;
                    U(_x,_y,1) = V(_x,_y,1)/factor;
                  }
              }
            }
          }
          const float d_energy = (_energy - energy)/(sw*sh*sd);
          if (d_energy<=0 && -d_energy<_precision) break;
          if (d_energy>0) dt*=0.5f;
          energy = _energy;
        }
      }
      return U;

Project: CImg
File: CImg.h


      static double mp_list_depth(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        return (double)mp.listin[ind]._depth;

Project: CImg
File: CImg.h

    **/
    CImg<T>& at(const int pos) {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "at(): Empty instance.",
                                    cimglist_instance);

      return _data[cimg::cut(pos,0,width() - 1)];

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& display(const CImg<T>& img) {
      return assign(img);

Project: CImg
File: CImg.h

    **/
    CImgDisplay& flush() {
      set_key().set_button().set_wheel();
      _is_resized = _is_moved = _is_event = false;
      _fps_timer = _fps_frames = _timer = 0;
      _fps_fps = 0;
      return *this;

Project: CImg
File: CImg.h

    //! Return a 4x4 diagonal matrix containing specified coefficients.
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
      return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);

Project: CImg
File: CImg.h

    template<typename t>
    void _load_tiff_contig(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) {
      t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif));
      if (buf) {
        uint32 row, rowsperstrip = (uint32)-1;
        TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
        for (row = 0; row<ny; row+= rowsperstrip) {
          uint32 nrow = (row + rowsperstrip>ny?ny - row:rowsperstrip);
          tstrip_t strip = TIFFComputeStrip(tif, row, 0);
          if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
            _TIFFfree(buf); TIFFClose(tif);
            throw CImgIOException(_cimg_instance
                                  "load_tiff(): Invalid strip in file '%s'.",
                                  cimg_instance,
                                  TIFFFileName(tif));
          }
          const t *ptr = buf;
          for (unsigned int rr = 0; rr<nrow; ++rr)
            for (unsigned int cc = 0; cc<nx; ++cc)
              for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row + rr,vv) = (T)*(ptr++);
        }
        _TIFFfree(buf);
      }

Project: CImg
File: CImg.h

    template<typename T>
    inline int fdate(const char *const path, T *attr, const unsigned int nb_attr) {
#define _cimg_fdate_err() for (unsigned int i = 0; i<nb_attr; ++i) attr[i] = (T)-1
      int res = -1;
      if (!path || !*path) { _cimg_fdate_err(); return -1; }
      cimg::mutex(6);
#if cimg_OS==2
      HANDLE file = CreateFileA(path,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
      if (file!=INVALID_HANDLE_VALUE) {
        FILETIME _ft;
        SYSTEMTIME ft;
        if (GetFileTime(file,0,0,&_ft) && FileTimeToSystemTime(&_ft,&ft)) {
          for (unsigned int i = 0; i<nb_attr; ++i) {
            res = (int)(attr[i]==0?ft.wYear:attr[i]==1?ft.wMonth:attr[i]==2?ft.wDay:
                        attr[i]==3?ft.wDayOfWeek:attr[i]==4?ft.wHour:attr[i]==5?ft.wMinute:
                        attr[i]==6?ft.wSecond:-1);
            attr[i] = (T)res;
          }
        } else _cimg_fdate_err();
        CloseHandle(file);
      } else _cimg_fdate_err();
#elif cimg_OS==1
      struct stat st_buf;
      if (!stat(path,&st_buf)) {
        const time_t _ft = st_buf.st_mtime;
        const struct tm& ft = *std::localtime(&_ft);
        for (unsigned int i = 0; i<nb_attr; ++i) {
          res = (int)(attr[i]==0?ft.tm_year + 1900:attr[i]==1?ft.tm_mon + 1:attr[i]==2?ft.tm_mday:
                      attr[i]==3?ft.tm_wday:attr[i]==4?ft.tm_hour:attr[i]==5?ft.tm_min:
                      attr[i]==6?ft.tm_sec:-1);
          attr[i] = (T)res;
        }
      } else _cimg_fdate_err();
#endif
      cimg::mutex(6,0);
      return res;

Project: CImg
File: CImg.h

    //! Load image sequence from a YUV file \newinstance.
    static CImg<T> get_load_yuv(std::FILE *const file,
                                const unsigned int size_x, const unsigned int size_y=1,
                                const unsigned int chroma_subsampling=444,
                                const unsigned int first_frame=0, const unsigned int last_frame=~0U,
				const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') {
      return CImgList<T>().load_yuv(file,size_x,size_y,chroma_subsampling,
                                    first_frame,last_frame,step_frame,yuv2rgb).get_append(axis);

Project: CImg
File: CImg.h

    **/
    Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1,
        z = (int)fz - (fz>=0?0:1), nz = z + 1;
      const float
        dx = fx - x,
        dy = fy - y,
        dz = fz - z;
      const Tfloat
        Iccc = (Tfloat)atXYZ(x,y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value),
        Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value),
        Iccn = (Tfloat)atXYZ(x,y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value),
        Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value);
      return Iccc +
        dx*(Incc - Iccc +
            dy*(Iccc + Innc - Icnc - Incc +
                dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) +
            dz*(Iccc + Incn - Iccn - Incc)) +
        dy*(Icnc - Iccc +
            dz*(Iccc + Icnn - Iccn - Icnc)) +
        dz*(Iccn - Iccc);

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \newinstance.
    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,
                     const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,
                     const T& val12) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,
                                                           val11,val12);

Project: CImg
File: CImg.h

    //! Load image from an INRIMAGE-4 file \newinstance.
    static CImg<T> get_load_inr(const char *const filename, float *const voxel_size=0) {
      return CImg<T>().load_inr(filename,voxel_size);

Project: CImg
File: CImg.h


    inline unsigned int prand(const double z, cimg_ulong *const p_rng) {
      if (z<=1.e-10) return 0;
      if (z>100) return (unsigned int)((std::sqrt(z) * cimg::grand(p_rng)) + z);
      unsigned int k = 0;
      const double y = std::exp(-z);
      for (double s = 1.; s>=y; ++k) s*=cimg::rand(1,p_rng);
      return k - 1;

Project: CImg
File: CImg.h

      static bool is_nan(const T) { return false; }

Project: CImg
File: CImg.h

     **/
    double product() const {
      if (is_empty()) return 0;
      double res = 1;
      cimg_for(*this,ptrs,T) res*=(double)*ptrs;
      return res;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to HSL color spaces \newinstance.
    CImg<Tfloat> get_RGBtoHSL() const {
      return CImg<Tfloat>(*this,false).RGBtoHSL();

Project: CImg
File: CImg.h

  struct CImgWarningException : public CImgException {

Project: CImg
File: CImg.h

    //! Return a CImg<T>::iterator pointing next to the last pixel value \const.
    const_iterator end() const {
      return _data + size();

Project: CImg
File: CImg.h


      _cimg_math_parser():
        code(_code),p_code_end(0),p_break((CImg<ulongT>*)(cimg_ulong)-2),
        imgin(CImg<T>::const_empty()),listin(CImgList<T>::const_empty()),
        imgout(CImg<T>::empty()),listout(CImgList<T>::empty()),
        img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0),
        result_dim(0),break_type(0),constcache_size(0),is_parallelizable(true),is_fill(false),need_input_copy(false),
        rng(0),calling_function(0) {
        mem.assign(1 + _cimg_mp_slot_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()()
        result = mem._data;

Project: CImg
File: CImg.h

    template<typename tz, typename tc>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           int x0, int y0, const float z0,
                           int x1, int y1, const float z1,
                           int x2, int y2, const float z2,
                           const tc *const color,
                           float bs0,
                           float bs1,
                           float bs2,
                           float opacity=1) {
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Specified color is (null).",
                                    cimg_instance);
      if (!is_sameXY(zbuffer))
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have "
                                    "different dimensions.",
                                    cimg_instance,
                                    zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data);

      float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2;
      if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,bs0,bs1);
      if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,bs0,bs2);
      if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,bs1,bs2);
      if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this;

      const int
        w1 = width() - 1, h1 = height() - 1,
        dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1,
        dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1),
        cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1),
        hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2;
      const float
        diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1,
        dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1;

      cimg_init_scanline(opacity);

      for (int y = cy0; y<=cy2; ++y) {
        const int yy0 = y - y0, yy1 = y - y1;
        int
          xm = y<y1?x0 + (dx01*yy0 + hdy01)/dy01:x1 + (dx12*yy1 + hdy12)/dy12,
          xM = x0 + (dx02*yy0 + hdy02)/dy02;
        float
          izm = y<y1?(iz0 + diz01*yy0/dy01):(iz1 + diz12*yy1/dy12),
          izM = iz0 + diz02*yy0/dy02,
          bsm = y<y1?(bs0 + dbs01*yy0/dy01):(bs1 + dbs12*yy1/dy12),
          bsM = bs0 + dbs02*yy0/dy02;
        if (xm>xM) cimg::swap(xm,xM,izm,izM,bsm,bsM);
        if (xM>=0 || xm<=w1) {
          const int
            cxm = cimg::cut(xm,0,w1),
            cxM = cimg::cut(xM,0,w1);
          T *ptrd = data(cxm,y);
          tz *ptrz = zbuffer.data(cxm,y);
          const int dxmM = std::max(1,xM - xm);
          const float dizmM = izM - izm, dbsmM = bsM - bsm;

          for (int x = cxm; x<=cxM; ++x) {
            const int xxm = x - xm;
            const float iz = izm + dizmM*xxm/dxmM;
            if (iz>=*ptrz) {
              *ptrz = (tz)iz;
              const float cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2);
              cimg_forC(*this,c) {
                const Tfloat val = cbs<=1?color[c]*cbs:(2 - cbs)*color[c] + (cbs - 1)*_sc_maxval;
                ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity);
              }
            }
            ++ptrd; ++ptrz;
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Load a list from a PAR/REC (Philips) file.
    /**
      \param filename Filename to read data from.
    **/
    CImgList<T>& load_parrec(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimglist_instance
                                    "load_parrec(): Specified filename is (null).",
                                    cimglist_instance);

      CImg<charT> body(1024), filenamepar(1024), filenamerec(1024);
      *body = *filenamepar = *filenamerec = 0;
      const char *const ext = cimg::split_filename(filename,body);
      if (!std::strcmp(ext,"par")) {
        std::strncpy(filenamepar,filename,filenamepar._width - 1);
        cimg_snprintf(filenamerec,filenamerec._width,"%s.rec",body._data);
      }
      if (!std::strcmp(ext,"PAR")) {
        std::strncpy(filenamepar,filename,filenamepar._width - 1);
        cimg_snprintf(filenamerec,filenamerec._width,"%s.REC",body._data);
      }
      if (!std::strcmp(ext,"rec")) {
        std::strncpy(filenamerec,filename,filenamerec._width - 1);
        cimg_snprintf(filenamepar,filenamepar._width,"%s.par",body._data);
      }
      if (!std::strcmp(ext,"REC")) {
        std::strncpy(filenamerec,filename,filenamerec._width - 1);
        cimg_snprintf(filenamepar,filenamepar._width,"%s.PAR",body._data);
      }
      std::FILE *file = cimg::fopen(filenamepar,"r");

      // Parse header file
      CImgList<floatT> st_slices;
      CImgList<uintT> st_global;
      CImg<charT> line(256); *line = 0;
      int err;
      do { err = std::fscanf(file,"%255[^\n]%*c",line._data); } while (err!=EOF && (*line=='#' || *line=='.'));
      do {
        unsigned int sn,size_x,size_y,pixsize;
        float rs,ri,ss;
        err = std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&size_x,&size_y,&ri,&rs,&ss);
        if (err==7) {
          CImg<floatT>::vector((float)sn,(float)pixsize,(float)size_x,(float)size_y,ri,rs,ss,0).move_to(st_slices);
          unsigned int i; for (i = 0; i<st_global._width && sn<=st_global[i][2]; ++i) {}
          if (i==st_global._width) CImg<uintT>::vector(size_x,size_y,sn).move_to(st_global);
          else {
            CImg<uintT> &vec = st_global[i];
            if (size_x>vec[0]) vec[0] = size_x;
            if (size_y>vec[1]) vec[1] = size_y;
            vec[2] = sn;
          }
          st_slices[st_slices._width - 1][7] = (float)i;
        }
      } while (err==7);

      // Read data
      std::FILE *file2 = cimg::fopen(filenamerec,"rb");
      cimglist_for(st_global,l) {
        const CImg<uintT>& vec = st_global[l];
        CImg<T>(vec[0],vec[1],vec[2]).move_to(*this);
      }

      cimglist_for(st_slices,l) {
        const CImg<floatT>& vec = st_slices[l];
        const unsigned int
          sn = (unsigned int)vec[0] - 1,
          pixsize = (unsigned int)vec[1],
          size_x = (unsigned int)vec[2],
          size_y = (unsigned int)vec[3],
          imn = (unsigned int)vec[7];
        const float ri = vec[4], rs = vec[5], ss = vec[6];
        switch (pixsize) {
        case 8 : {
          CImg<ucharT> buf(size_x,size_y);
          cimg::fread(buf._data,size_x*size_y,file2);
          if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y);
          CImg<T>& img = (*this)[imn];
          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
        } break;
        case 16 : {
          CImg<ushortT> buf(size_x,size_y);
          cimg::fread(buf._data,size_x*size_y,file2);
          if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y);
          CImg<T>& img = (*this)[imn];
          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
        } break;
        case 32 : {
          CImg<uintT> buf(size_x,size_y);
          cimg::fread(buf._data,size_x*size_y,file2);
          if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y);
          CImg<T>& img = (*this)[imn];
          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
        } break;
        default :
          cimg::fclose(file);
          cimg::fclose(file2);
          throw CImgIOException(_cimglist_instance
                                "load_parrec(): Unsupported %d-bits pixel type for file '%s'.",
                                cimglist_instance,
                                pixsize,filename);
        }
      }
      cimg::fclose(file);
      cimg::fclose(file2);
      if (!_width)
        throw CImgIOException(_cimglist_instance
                              "load_parrec(): Failed to recognize valid PAR-REC data in file '%s'.",

Project: CImg
File: CImg.h

#else

Project: CImg
File: CImg.h

    **/
    CImg<T>& erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) {
      if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this;
      if (sx>1 && _width>1) { // Along X-axis
        const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;
        CImg<T> buf(L);
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288))
        cimg_forYZC(*this,y,z,c) {
          T *const ptrdb = buf._data, *ptrd = buf._data, *const ptrde = buf._data + L - 1;
          const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;
          T cur = *ptrs; ptrs+=off; bool is_first = true;
          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {
            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }}
          *(ptrd++) = cur;
          if (ptrs>=ptrse) {
            T *pd = data(0,y,z,c); cur = std::min(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; }
          } else {
            for (int p = s1; p>0 && ptrd<=ptrde; --p) {
              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
              *(ptrd++) = cur;
            }
            for (int p = L - s - 1; p>0; --p) {
              const T val = *ptrs; ptrs+=off;
              if (is_first) {
                const T *nptrs = ptrs - off; cur = val;
                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }
                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;
              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }
              *(ptrd++) = cur;
            }
            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;
            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {
              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;
            }
            *(ptrd--) = cur;
            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {
              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;
            }
            T *pd = data(0,y,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }
          }
        }
      }

      if (sy>1 && _height>1) { // Along Y-axis
        const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
          s2 = _s2>L?L:_s2;
        CImg<T> buf(L);
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288))
        cimg_forXZC(*this,x,z,c) {
          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;
          const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;
          T cur = *ptrs; ptrs+=off; bool is_first = true;
          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {
            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
          }
          *(ptrd++) = cur;
          if (ptrs>=ptrse) {
            T *pd = data(x,0,z,c); cur = std::min(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; }
          } else {
            for (int p = s1; p>0 && ptrd<=ptrde; --p) {
              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
              *(ptrd++) = cur;
            }
            for (int p = L - s - 1; p>0; --p) {
              const T val = *ptrs; ptrs+=off;
              if (is_first) {
                const T *nptrs = ptrs - off; cur = val;
                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }
                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;
              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }
              *(ptrd++) = cur;
            }
            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;
            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {
              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;
            }
            *(ptrd--) = cur;
            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {
              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;
            }
            T *pd = data(x,0,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }
          }
        }
      }

      if (sz>1 && _depth>1) { // Along Z-axis
        const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
          s2 = _s2>L?L:_s2;
        CImg<T> buf(L);
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288))
        cimg_forXYC(*this,x,y,c) {
          T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1;
          const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off;
          T cur = *ptrs; ptrs+=off; bool is_first = true;
          for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) {
            const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
          }
          *(ptrd++) = cur;
          if (ptrs>=ptrse) {
            T *pd = data(x,y,0,c); cur = std::min(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; }
          } else {
            for (int p = s1; p>0 && ptrd<=ptrde; --p) {
              const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; }
              *(ptrd++) = cur;
            }
            for (int p = L - s - 1; p>0; --p) {
              const T val = *ptrs; ptrs+=off;
              if (is_first) {
                const T *nptrs = ptrs - off; cur = val;
                for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; }
                nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false;
              } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; }
              *(ptrd++) = cur;
            }
            ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off;
            for (int p = s1; p>0 && ptrs>=ptrsb; --p) {
              const T val = *ptrs; ptrs-=off; if (val<cur) cur = val;
            }
            *(ptrd--) = cur;
            for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) {
              const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur;
            }
            T *pd = data(x,y,0,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; }
          }
        }
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_print(_cimg_math_parser& mp) {
          const double val = _mp_arg(1);
          const bool print_char = (bool)mp.opcode[3];
          cimg_pragma_openmp(critical(mp_print))
          {
            CImg<charT> _expr(mp.opcode[2] - 4);
            const ulongT *ptrs = mp.opcode._data + 4;
            cimg_for(_expr,ptrd,char) *ptrd = (char)*(ptrs++);
            cimg::strellipsize(_expr);
            cimg::mutex(6);
            if (print_char)
              std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %g = '%c'",_expr._data,val,(int)val);
            else
              std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %g",_expr._data,val);
            std::fflush(cimg::output());
            cimg::mutex(6,0);
          }
          return val;

Project: CImg
File: CImg.h

      pthread_mutex_t mutex[32];

Project: CImg
File: CImg.h

    **/
    int window_y() const {
      return _window_y;

Project: CImg
File: CImg.h

    **/
    CImgDisplay& set_normalization(const unsigned int normalization) {
      _normalization = normalization;
      _min = _max = 0;
      return *this;

Project: CImg
File: CImg.h


      unsigned int vector_copy(const unsigned int arg) { // Insert new copy of specified vector in memory
        const unsigned int
          siz = _cimg_mp_size(arg),
          pos = vector(siz);
        CImg<ulongT>::vector((ulongT)mp_vector_copy,pos,arg,siz).move_to(code);
        return pos;

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \newinstance.
    CImg<T> get_fill(const T& val0, const T& val1, const T& val2) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2);

Project: CImg
File: CImg.h

    template<typename tp, typename tc, typename to>
    CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives,
                              const CImgList<tc>& colors,
                              const to& opacities,
                              const bool full_check=true) {
      return get_object3dtoCImg3d(primitives,colors,opacities,full_check).move_to(*this);

Project: CImg
File: CImg.h

    template<typename t1, typename t2>
    CImg<intT> _matchpatch(const CImg<T>& patch_image,
                           const unsigned int patch_width,
                           const unsigned int patch_height,
                           const unsigned int patch_depth,
                           const unsigned int nb_iterations,
                           const unsigned int nb_randoms,
                           const float occ_penalization,
                           const CImg<t1> &guide,
                           const bool is_matching_score,
                           CImg<t2> &matching_score) const {
      if (is_empty()) return CImg<intT>::const_empty();
      if (patch_image._spectrum!=_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "matchpatch(): Instance image and specified patch image (%u,%u,%u,%u,%p) "
                                    "have different spectrums.",
                                    cimg_instance,
                                    patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,
                                    patch_image._data);
      if (patch_width>_width || patch_height>_height || patch_depth>_depth)
        throw CImgArgumentException(_cimg_instance
                                    "matchpatch(): Specified patch size %ux%ux%u is bigger than the dimensions "
                                    "of the instance image.",
                                    cimg_instance,patch_width,patch_height,patch_depth);
      if (patch_width>patch_image._width || patch_height>patch_image._height || patch_depth>patch_image._depth)
        throw CImgArgumentException(_cimg_instance
                                    "matchpatch(): Specified patch size %ux%ux%u is bigger than the dimensions "
                                    "of the patch image image (%u,%u,%u,%u,%p).",
                                    cimg_instance,patch_width,patch_height,patch_depth,
                                    patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,
                                    patch_image._data);
      const unsigned int
        _constraint = patch_image._depth>1?3:2,
        constraint = guide._spectrum>_constraint?_constraint:0;

      if (guide &&
          (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<_constraint))
        throw CImgArgumentException(_cimg_instance
                                    "matchpatch(): Specified guide (%u,%u,%u,%u,%p) has invalid dimensions "
                                    "considering instance and patch image (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    guide._width,guide._height,guide._depth,guide._spectrum,guide._data,
                                    patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,
                                    patch_image._data);

      CImg<intT> a_map(_width,_height,_depth,patch_image._depth>1?3:2);
      CImg<ucharT> is_updated(_width,_height,_depth,1,3);
      CImg<floatT> score(_width,_height,_depth);
      CImg<uintT> occ, loop_order;
      ulongT rng = (cimg::_rand(),cimg::rng());
      if (occ_penalization!=0) {
        occ.assign(patch_image._width,patch_image._height,patch_image._depth,1,0);
        loop_order.assign(_width,_height,_depth,_depth>1?3:2);
        cimg_forXYZ(loop_order,x,y,z) {
          loop_order(x,y,z,0) = x;
          loop_order(x,y,z,1) = y;
          if (loop_order._spectrum>2) loop_order(x,y,z,2) = z;
        }
        cimg_forXYZ(loop_order,x,y,z) { // Randomize loop order in case of constraints on patch occurrence
          const unsigned int
            X = (unsigned int)cimg::round(cimg::rand(loop_order._width - 1.,&rng)),
            Y = (unsigned int)cimg::round(cimg::rand(loop_order._height - 1.,&rng)),
            Z = loop_order._depth>1?(unsigned int)cimg::round(cimg::rand(loop_order._depth  - 1.,&rng)):0U;
          cimg::swap(loop_order(x,y,z,0),loop_order(X,Y,Z,0));
          cimg::swap(loop_order(x,y,z,1),loop_order(X,Y,Z,1));
          if (loop_order._spectrum>2) cimg::swap(loop_order(x,y,z,2),loop_order(X,Y,Z,2));
        }
      }
      const int
        psizew = (int)patch_width,  psizew1 = psizew/2, psizew2 = psizew - psizew1 - 1,
        psizeh = (int)patch_height, psizeh1 = psizeh/2, psizeh2 = psizeh - psizeh1 - 1,
        psized = (int)patch_depth,  psized1 = psized/2, psized2 = psized - psized1 - 1;

      // Interleave image buffers to speed up patch comparison (cache-friendly).
      CImg<T> in_this = get_permute_axes("cxyz");
      in_this._width = _width*_spectrum;
      in_this._height = _height;
      in_this._depth = _depth;
      in_this._spectrum = 1;
      CImg<T> in_patch = patch_image.get_permute_axes("cxyz");
      in_patch._width = patch_image._width*patch_image._spectrum;
      in_patch._height = patch_image._height;
      in_patch._depth = patch_image._depth;
      in_patch._spectrum = 1;

      if (_depth>1 || patch_image._depth>1) { // 3D version

        // Initialize correspondence map.
        if (guide)
          cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(_width,64))
            cimg_forXYZ(*this,x,y,z) { // User-defined initialization
            const int
              cx1 = x<=psizew1?x:(x<width()  - psizew2?psizew1:psizew + x - width()),  cx2 = psizew - cx1 - 1,
              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
              cz1 = z<=psized1?z:(z<depth()  - psized2?psized1:psized + z - depth()),  cz2 = psized - cz1 - 1,
              u = cimg::cut((int)guide(x,y,z,0),cx1,patch_image.width() - 1 - cx2),
              v = cimg::cut((int)guide(x,y,z,1),cy1,patch_image.height() - 1 - cy2),
              w = cimg::cut((int)guide(x,y,z,2),cz1,patch_image.depth() - 1 - cz2);
            a_map(x,y,z,0) = u;
            a_map(x,y,z,1) = v;
            a_map(x,y,z,2) = w;
            score(x,y,z) = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                       x - cx1,y - cy1,z - cz1,
                                       u - cx1,v - cy1,w - cz1,
                                       u,v,w,0,cimg::type<float>::inf());
          } else cimg_pragma_openmp(parallel cimg_openmp_if_size(_width,64)) {
            ulongT _rng = (cimg::_rand(),cimg::rng());

#if cimg_use_openmp!=0
            _rng+=omp_get_thread_num();
#endif
            cimg_pragma_openmp(for cimg_openmp_collapse(2))
              cimg_forXYZ(*this,x,y,z) { // Random initialization
              const int
                cx1 = x<=psizew1?x:(x<width()  - psizew2?psizew1:psizew + x - width()),  cx2 = psizew - cx1 - 1,
                cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
                cz1 = z<=psized1?z:(z<depth()  - psized2?psized1:psized + z - depth()),  cz2 = psized - cz1 - 1,
                u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2,&_rng)),
                v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2,&_rng)),
                w = (int)cimg::round(cimg::rand(cz1,patch_image.depth() - 1 - cz2,&_rng));
              a_map(x,y,z,0) = u;
              a_map(x,y,z,1) = v;
              a_map(x,y,z,2) = w;
              score(x,y,z) = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                         x - cx1,y - cy1,z - cz1,
                                         u - cx1,v - cy1,w - cz1,
                                         u,v,w,0,cimg::type<float>::inf());
            }
            cimg::srand(_rng);
          }

        // Start iteration loop.
        cimg_abort_init;
        for (unsigned int iter = 0; iter<nb_iterations; ++iter) {
          cimg_abort_test;
          const bool is_odd = iter%2;
          const unsigned int cmask = is_odd?1:2, nmask = 3 - cmask;
          if (iter) occ.fill(0);

          cimg_pragma_openmp(parallel cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*64 &&
                                                     iter<nb_iterations-2)) {
            ulongT _rng = (cimg::_rand(),cimg::rng());

#if cimg_use_openmp!=0
            _rng+=omp_get_thread_num();
#endif
            cimg_pragma_openmp(for cimg_openmp_collapse(2))
              cimg_forXYZ(*this,X,Y,Z) {
              const int
                _x = is_odd?width() - 1 - X:X,
                _y = is_odd?height() - 1 - Y:Y,
                _z = is_odd?depth() - 1 - Z:Z;
              int x, y, z;
              if (occ_penalization) {
                x = loop_order(_x,_y,_z,0);
                y = loop_order(_x,_y,_z,1);
                if (loop_order._spectrum>2) z = loop_order(_x,_y,_z,2); else z = _z;
              } else { x = _x; y = _y; z = _z; }

              if (score(x,y,z)<=1e-5 || (constraint && guide(x,y,z,constraint)!=0)) continue;
              const int
                cx1 = x<=psizew1?x:(x<width()  - psizew2?psizew1:psizew + x - width()),  cx2 = psizew - cx1 - 1,
                cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
                cz1 = z<=psized1?z:(z<depth()  - psized2?psized1:psized + z - depth()),  cz2 = psized - cz1 - 1,
                xp = x - cx1,
                yp = y - cy1,
                zp = z - cz1;

              int best_u = a_map(x,y,z,0), best_v = a_map(x,y,z,1), best_w = a_map(x,y,z,2), u, v, w;
              const float best_score0 = score(x,y,z);
              float best_score = best_score0, s;

              // Propagation.
              if (x>0 && (is_updated(x - 1,y,z)&cmask)) { // Compare with left neighbor
                u = a_map(x - 1,y,z,0);
                v = a_map(x - 1,y,z,1);
                w = a_map(x - 1,y,z,2);
                if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2 &&
                    w>=cz1 && w<patch_image.depth() - cz2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                  xp,yp,zp,u + 1 - cx1,v - cy1,w - cz1,
                                  u,v,w,occ_penalization,best_score);
                  if (s<best_score) { best_u = u + 1; best_v = v; best_w = w; best_score = s; }
                }
              }
              if (y>0 && (is_updated(x,y - 1,z)&cmask)) { // Compare with up neighbor
                u = a_map(x,y - 1,z,0);
                v = a_map(x,y - 1,z,1);
                w = a_map(x,y - 1,z,2);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 - 1 && v<patch_image.height() - 1 - cy2 &&
                    w>=cz1 && w<patch_image.depth() - cz2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                  xp,yp,zp,u - cx1,v + 1 - cy1,w - cz1,
                                  u,v,w,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v + 1; best_w = w; best_score = s; }
                }
              }
              if (z>0 && (is_updated(x,y,z - 1)&cmask)) { // Compare with backward neighbor
                u = a_map(x,y,z - 1,0);
                v = a_map(x,y,z - 1,1);
                w = a_map(x,y,z - 1,2);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2 &&
                    w>=cz1 - 1 && w<patch_image.depth() - 1 - cz2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                  xp,yp,zp,u - cx1,v - cy1,w + 1 - cz1,
                                  u,v,w,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v; best_w = w + 1; best_score = s; }
                }
              }
              if (x<width() - 1 && (is_updated(x + 1,y,z)&cmask)) { // Compare with right neighbor
                u = a_map(x + 1,y,z,0);
                v = a_map(x + 1,y,z,1);
                w = a_map(x + 1,y,z,2);
                if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2 &&
                    w>=cz1 && w<patch_image.depth() - cz2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                  xp,yp,zp,u - 1 - cx1,v - cy1,w - cz1,
                                  u,v,w,occ_penalization,best_score);
                  if (s<best_score) { best_u = u - 1; best_v = v; best_w = w; best_score = s; }
                }
              }
              if (y<height() - 1 && (is_updated(x,y + 1,z)&cmask)) { // Compare with bottom neighbor
                u = a_map(x,y + 1,z,0);
                v = a_map(x,y + 1,z,1);
                w = a_map(x,y + 1,z,2);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 + 1 && v<patch_image.height() + 1 - cy2 &&
                    w>=cz1 && w<patch_image.depth() - cz2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                  xp,yp,zp,u - cx1,v - 1 - cy1,w - cz1,
                                  u,v,w,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v - 1; best_w = w; best_score = s; }
                }
              }
              if (z<depth() - 1 && (is_updated(x,y,z + 1)&cmask)) { // Compare with forward neighbor
                u = a_map(x,y,z + 1,0);
                v = a_map(x,y,z + 1,1);
                w = a_map(x,y,z + 1,2);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2 &&
                    w>=cz1 + 1 && w<patch_image.depth() + 1 - cz2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                  xp,yp,zp,u - cx1,v - cy1,w - 1 - cz1,
                                  u,v,w,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v; best_w = w - 1; best_score = s; }
                }
              }

              // Randomization.
              float
                dw = (float)patch_image.width(),
                dh = (float)patch_image.height(),
                dd = (float)patch_image.depth();
              for (unsigned int i = 0; i<nb_randoms; ++i) {
                u = (int)cimg::round(cimg::rand(std::max((float)cx1,best_u - dw),
                                                std::min(patch_image.width() - 1.f - cx2,best_u + dw),&_rng));
                v = (int)cimg::round(cimg::rand(std::max((float)cy1,best_v - dh),
                                                std::min(patch_image.height() - 1.f - cy2,best_v + dh),&_rng));
                w = (int)cimg::round(cimg::rand(std::max((float)cz1,best_w - dd),
                                                std::min(patch_image.depth() - 1.f - cz2,best_w + dd),&_rng));
                if (u!=best_u || v!=best_v || w!=best_w) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,patch_depth,_spectrum,
                                  xp,yp,zp,u - cx1,v - cy1,w - cz1,
                                  u,v,w,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v; best_w = w; best_score = s; }
                  dw = std::max(5.f,dw*0.5f); dh = std::max(5.f,dh*0.5f); dd = std::max(5.f,dd*0.5f);
                }
              }

              if (best_score<best_score0) {
                a_map(x,y,z,0) = best_u;
                a_map(x,y,z,1) = best_v;
                a_map(x,y,z,2) = best_w;
                score(x,y,z) = best_score;
                is_updated(x,y,z) = 3;
              } else is_updated(x,y,z)&=~nmask;
              if (occ_penalization!=0) cimg_pragma_openmp(atomic) ++occ(best_u,best_v,best_w);
            }
            cimg::srand(_rng);
          }
        }

      } else { // 2D version

        // Initialize correspondence map.
        if (guide)
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width,64))
            cimg_forXY(*this,x,y) { // User-defined initialization
            const int
              cx1 = x<=psizew1?x:(x<width()  - psizew2?psizew1:psizew + x - width()),  cx2 = psizew - cx1 - 1,
              cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
              u = cimg::cut((int)guide(x,y,0),cx1,patch_image.width() - 1 - cx2),
              v = cimg::cut((int)guide(x,y,1),cy1,patch_image.height() - 1 - cy2);
            a_map(x,y,0) = u;
            a_map(x,y,1) = v;
            score(x,y) = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,_spectrum,
                                     x - cx1,y - cy1,u - cx1,v - cy1,
                                     u,v,0,cimg::type<float>::inf());
          } else cimg_pragma_openmp(parallel cimg_openmp_if_size(_width,64)) {
            ulongT _rng = (cimg::_rand(),cimg::rng());

#if cimg_use_openmp!=0
            _rng+=omp_get_thread_num();
#endif
            cimg_pragma_openmp(for)
              cimg_forXY(*this,x,y) { // Random initialization
              const int
                cx1 = x<=psizew1?x:(x<width()  - psizew2?psizew1:psizew + x - width()),  cx2 = psizew - cx1 - 1,
                cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
                u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2,&_rng)),
                v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2,&_rng));
              a_map(x,y,0) = u;
              a_map(x,y,1) = v;
              score(x,y) = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,_spectrum,
                                       x - cx1,y - cy1,u - cx1,v - cy1,
                                       u,v,0,cimg::type<float>::inf());
            }
            cimg::srand(_rng);
          }

        // Start iteration loop.
        cimg_abort_init;
        for (unsigned int iter = 0; iter<nb_iterations; ++iter) {
          cimg_abort_test;
          const bool is_odd = iter%2;
          const unsigned int cmask = is_odd?1:2, nmask = 3 - cmask;
          if (iter) occ.fill(0);

          cimg_pragma_openmp(parallel cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*64 &&
                                                     iter<nb_iterations-2)) {
            ulongT _rng = (cimg::_rand(),cimg::rng());

#if cimg_use_openmp!=0
            _rng+=omp_get_thread_num();
#endif
            cimg_pragma_openmp(for)
              cimg_forXY(*this,X,Y) {
              const int
                _x = is_odd?width() - 1 - X:X,
                _y = is_odd?height() - 1 - Y:Y;
              int x, y;
              if (occ_penalization) {
                x = loop_order(_x,_y,0);
                y = loop_order(_x,_y,1);
              } else { x = _x; y = _y; }

              if (score(x,y)<=1e-5 || (constraint && guide(x,y,constraint)!=0)) continue;
              const int
                cx1 = x<=psizew1?x:(x<width()  - psizew2?psizew1:psizew + x - width()),  cx2 = psizew - cx1 - 1,
                cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
                xp = x - cx1,
                yp = y - cy1;

              int best_u = a_map(x,y,0), best_v = a_map(x,y,1), u, v;
              const float best_score0 = score(x,y);
              float best_score = best_score0, s;

              // Propagation.
              if (x>0 && (is_updated(x - 1,y)&cmask)) { // Compare with left neighbor
                u = a_map(x - 1,y,0);
                v = a_map(x - 1,y,1);
                if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,_spectrum,
                                  xp,yp,u + 1 - cx1,v - cy1,
                                  u,v,occ_penalization,best_score);
                  if (s<best_score) { best_u = u + 1; best_v = v; best_score = s; }
                }
              }
              if (y>0 && (is_updated(x,y - 1)&cmask)) { // Compare with up neighbor
                u = a_map(x,y - 1,0);
                v = a_map(x,y - 1,1);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 - 1 && v<patch_image.height() - 1 - cy2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,_spectrum,
                                  xp,yp,u - cx1,v + 1 - cy1,
                                  u,v,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v + 1; best_score = s; }
                }
              }
              if (x<width() - 1 && (is_updated(x + 1,y)&cmask)) { // Compare with right neighbor
                u = a_map(x + 1,y,0);
                v = a_map(x + 1,y,1);
                if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,_spectrum,
                                  xp,yp,u - 1 - cx1,v - cy1,
                                  u,v,occ_penalization,best_score);
                  if (s<best_score) { best_u = u - 1; best_v = v; best_score = s; }
                }
              }
              if (y<height() - 1 && (is_updated(x,y + 1)&cmask)) { // Compare with bottom neighbor
                u = a_map(x,y + 1,0);
                v = a_map(x,y + 1,1);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 + 1 && v<patch_image.height() + 1 - cy2) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,_spectrum,
                                  xp,yp,u - cx1,v - 1 - cy1,
                                  u,v,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v - 1; best_score = s; }
                }
              }

              // Randomization.
              float
                dw = (float)patch_image.width(),
                dh = (float)patch_image.height();
              for (unsigned int i = 0; i<nb_randoms; ++i) {
                u = (int)cimg::round(cimg::rand(std::max((float)cx1,best_u - dw),
                                                std::min(patch_image.width() - 1.f - cx2,best_u + dw),&_rng));
                v = (int)cimg::round(cimg::rand(std::max((float)cy1,best_v - dh),
                                                std::min(patch_image.height() - 1.f - cy2,best_v + dh),&_rng));
                if (u!=best_u || v!=best_v) {
                  s = _matchpatch(in_this,in_patch,occ,patch_width,patch_height,_spectrum,
                                  xp,yp,u - cx1,v - cy1,
                                  u,v,occ_penalization,best_score);
                  if (s<best_score) { best_u = u; best_v = v; best_score = s; }
                  dw = std::max(5.f,dw*0.5f); dh = std::max(5.f,dh*0.5f);
                }
              }

              if (best_score<best_score0) {
                a_map(x,y,0) = best_u;
                a_map(x,y,1) = best_v;
                score(x,y) = best_score;
                is_updated(x,y) = 3;
              } else is_updated(x,y)&=~nmask;
              if (occ_penalization!=0) cimg_pragma_openmp(atomic) ++occ(best_u,best_v);
            }
          }
          cimg::srand(rng);
        }
      }
      if (is_matching_score) score.move_to(matching_score);
      return a_map;

Project: CImg
File: CImg.h

    **/
    CImg<Tfloat> operator%(const char *const expression) const {
      return CImg<Tfloat>(*this,false)%=expression;

Project: CImg
File: CImg.h

      return *this;
    }

    // [internal] Return string to describe display title.
    CImg<charT> __display() const {
      CImg<charT> res, str;
      cimglist_for(*this,l) {
        CImg<charT>::string((char*)_data[l]).move_to(str);
        if (l!=width() - 1) {
          str.resize(str._width + 1,1,1,1,0);
          str[str._width - 2] = ',';
          str[str._width - 1] = ' ';
        }
        res.append(str,'x');
      }
      if (!res) return CImg<charT>(1,1,1,1,0).move_to(res);
      cimg::strellipsize(res,128,false);
      if (_width>1) {
        const unsigned int l = (unsigned int)std::strlen(res);
        if (res._width<=l + 16) res.resize(l + 16,1,1,1,0);

Project: CImg
File: CImg.h


      static double mp_linear_add(_cimg_math_parser& mp) {
        return _mp_arg(2)*_mp_arg(3) + _mp_arg(4);

Project: CImg
File: CImg.h

    //! Load image from a PNG file \newinstance.
    static CImg<T> get_load_png(std::FILE *const file, unsigned int *const bits_per_pixel=0) {
      return CImg<T>().load_png(file,bits_per_pixel);

Project: CImg
File: CImg.h

    //! Construct image copy \specialization.
    CImg(const CImg<T>& img) {
      const size_t siz = (size_t)img.size();
      if (img._data && siz) {
        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
        _is_shared = img._is_shared;
        if (_is_shared) _data = const_cast<T*>(img._data);
        else {
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),
                                        img._width,img._height,img._depth,img._spectrum);

          }
          std::memcpy(_data,img._data,siz*sizeof(T));
        }
      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }

Project: CImg
File: CImg.h

      static char inf() { return max(); }

Project: CImg
File: CImg.h

    //! Fill image with random values in specified range \newinstance.
    CImg<T> get_rand(const T& val_min, const T& val_max) const {
      return (+*this).rand(val_min,val_max);

Project: CImg
File: CImg.h


      static double mp_exp(_cimg_math_parser& mp) {
        return std::exp(_mp_arg(2));

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to YCbCr color spaces.
    CImg<T>& RGBtoYCbCr() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoYCbCr(): Instance is not a RGB image.",
                                    cimg_instance);

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,512))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N],
          G = (Tfloat)p2[N],
          B = (Tfloat)p3[N],
          Y = (66*R + 129*G + 25*B + 128)/256 + 16,
          Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
          Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
        p1[N] = (T)cimg::cut(Y,0,255),
        p2[N] = (T)cimg::cut(Cb,0,255),
        p3[N] = (T)cimg::cut(Cr,0,255);
      }
      return *this;

Project: CImg
File: CImg.h

    //! Return the sinc of a given value.
    inline double sinc(const double x) {
      return x?std::sin(x)/x:1;

Project: CImg
File: CImg.h

    **/
    Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "linear_atXY(): Empty instance.",
                                    cimg_instance);

      return _linear_atXY(fx,fy,z,c);

Project: CImg
File: CImg.h


    static int screen_width() {
      Display *const dpy = cimg::X11_attr().display;
      int res = 0;
      if (!dpy) {
        Display *const _dpy = XOpenDisplay(0);
        if (!_dpy)
          throw CImgDisplayException("CImgDisplay::screen_width(): Failed to open X11 display.");
        res = DisplayWidth(_dpy,DefaultScreen(_dpy));
        XCloseDisplay(_dpy);
      } else {

#ifdef cimg_use_xrandr
        if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution)
          res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width;
        else res = DisplayWidth(dpy,DefaultScreen(dpy));
#else
        res = DisplayWidth(dpy,DefaultScreen(dpy));
#endif
      }
      return res;

Project: CImg
File: CImg.h

    **/
    CImg<T>& normalize() {
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 &&
                                                                 _height*_depth>=16))
      cimg_forYZ(*this,y,z) {
        T *ptrd = data(0,y,z,0);
        cimg_forX(*this,x) {
          const T *ptrs = ptrd;
          float n = 0;
          cimg_forC(*this,c) { n+=cimg::sqr((float)*ptrs); ptrs+=whd; }
          n = (float)std::sqrt(n);
          T *_ptrd = ptrd++;
          if (n>0) cimg_forC(*this,c) { *_ptrd = (T)(*_ptrd/n); _ptrd+=whd; }
          else cimg_forC(*this,c) { *_ptrd = (T)0; _ptrd+=whd; }
        }
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_image_resize(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listout.width());
        cimg::mutex(6);
        CImg<T> &img = mp.listout[ind];
        const double
          _w = mp.opcode[3]==~0U?-100:_mp_arg(3),
          _h = mp.opcode[4]==~0U?-100:_mp_arg(4),
          _d = mp.opcode[5]==~0U?-100:_mp_arg(5),
          _s = mp.opcode[6]==~0U?-100:_mp_arg(6);
        const unsigned int
          w = (unsigned int)(_w>=0?_w:-_w*img.width()/100),
          h = (unsigned int)(_h>=0?_h:-_h*img.height()/100),
          d = (unsigned int)(_d>=0?_d:-_d*img.depth()/100),
          s = (unsigned int)(_s>=0?_s:-_s*img.spectrum()/100),
          interp = (int)_mp_arg(7);
        if (mp.is_fill && img._data==mp.imgout._data) {
          cimg::mutex(6,0);
          throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'resize()': "
                                      "Cannot both fill and resize image (%u,%u,%u,%u) "
                                      "to new dimensions (%u,%u,%u,%u).",
                                      img.pixel_type(),img._width,img._height,img._depth,img._spectrum,w,h,d,s);
        }
        const unsigned int
          boundary = (int)_mp_arg(8);
        const float
          cx = (float)_mp_arg(9),
          cy = (float)_mp_arg(10),
          cz = (float)_mp_arg(11),
          cc = (float)_mp_arg(12);
        img.resize(w,h,d,s,interp,boundary,cx,cy,cz,cc);
        cimg::mutex(6,0);
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    }

    //! Insert n copies of the list \c list at position \c pos of the current list \newinstance.
    template<typename t>

Project: CImg
File: CImg.h

    //! Convert pixel values from HSL to RGB color spaces \newinstance.
    CImg<Tuchar> get_HSLtoRGB() const {
      return CImg<Tuchar>(*this,false).HSLtoRGB();

Project: CImg
File: CImg.h

    CImgException() { _message = new char[1]; *_message = 0; }

Project: CImg
File: CImg.h

      static unsigned char min() { return 0; }

Project: CImg
File: CImg.h

      static bool is_inf(const cimg_int64) { return false; }

Project: CImg
File: CImg.h


      static double mp_eq(_cimg_math_parser& mp) {
        return (double)(_mp_arg(2)==_mp_arg(3));

Project: CImg
File: CImg.h

    **/
    int depth() const {
      return (int)_depth;

Project: CImg
File: CImg.h

    **/
    CImg<T> operator&(const char *const expression) const {
      return (+*this)&=expression;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
      return set_vector_at(mat,x,y,z);

Project: CImg
File: CImg.h

    //! Convert pixel values from HSL to RGB color spaces.
    CImg<T>& HSLtoRGB() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "HSLtoRGB(): Instance is not a HSL image.",
                                    cimg_instance);

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          H = cimg::mod((Tfloat)p1[N]/60,(Tfloat)6),
          S = (Tfloat)p2[N],
          L = (Tfloat)p3[N],
          C = (1 - cimg::abs(2*L - 1))*S,
          X = C*(1 - cimg::abs(cimg::mod(H,(Tfloat)2) - 1)),
          m = L - C/2;
        Tfloat R, G, B;
        switch ((int)H) {
        case 0 : R = C; G = X; B = 0; break;
        case 1 : R = X; G = C; B = 0; break;
        case 2 : R = 0; G = C; B = X; break;
        case 3 : R = 0; G = X; B = C; break;
        case 4 : R = X; G = 0; B = C; break;
        default : R = C; G = 0; B = X;
        }
        p1[N] = (T)((R + m)*255);
        p2[N] = (T)((G + m)*255);
        p3[N] = (T)((B + m)*255);
      }
      return *this;

Project: CImg
File: CImg.h

    //! Invert endianness of all pixel values \newinstance.
    CImg<T> get_invert_endianness() const {
      return (+*this).invert_endianness();

Project: CImg
File: CImg.h

                                 const unsigned int z0, const unsigned int c0) const {
      return _save_cimg(file,0,n0,x0,y0,z0,c0);
    }

    static void _save_empty_cimg(std::FILE *const file, const char *const filename,
                                const unsigned int nb,
                                const unsigned int dx, const unsigned int dy,
                                const unsigned int dz, const unsigned int dc) {
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      const ulongT siz = (ulongT)dx*dy*dz*dc*sizeof(T);
      std::fprintf(nfile,"%u %s\n",nb,pixel_type());
      for (unsigned int i=nb; i; --i) {
        std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dc);

Project: CImg
File: CImg.h

    **/
    CImg<T> operator--(int) {
      const CImg<T> copy(*this,false);
      --*this;
      return copy;

Project: CImg
File: CImg.h

    CImg<typename cimg::superset<t,long>::type>
    get_distance_dijkstra(const T& value, const CImg<t>& metric, const bool is_high_connectivity,
                          CImg<to>& return_path) const {
      if (is_empty()) return return_path.assign();
      if (!is_sameXYZ(metric))
        throw CImgArgumentException(_cimg_instance
                                    "distance_dijkstra(): image instance and metric map (%u,%u,%u,%u) "
                                    "have incompatible dimensions.",
                                    cimg_instance,
                                    metric._width,metric._height,metric._depth,metric._spectrum);
      typedef typename cimg::superset<t,long>::type td;  // Type used for computing cumulative distances
      CImg<td> result(_width,_height,_depth,_spectrum), Q;
      CImg<boolT> is_queued(_width,_height,_depth,1);
      if (return_path) return_path.assign(_width,_height,_depth,_spectrum);

      cimg_forC(*this,c) {
        const CImg<T> img = get_shared_channel(c);
        const CImg<t> met = metric.get_shared_channel(c%metric._spectrum);
        CImg<td> res = result.get_shared_channel(c);
        CImg<to> path = return_path?return_path.get_shared_channel(c):CImg<to>();
        unsigned int sizeQ = 0;

        // Detect initial seeds.
        is_queued.fill(0);
        cimg_forXYZ(img,x,y,z) if (img(x,y,z)==value) {
          Q._priority_queue_insert(is_queued,sizeQ,0,x,y,z);
          res(x,y,z) = 0;
          if (path) path(x,y,z) = (to)0;
        }

        // Start distance propagation.
        while (sizeQ) {

          // Get and remove point with minimal potential from the queue.
          const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3);
          const td P = (td)-Q(0,0);
          Q._priority_queue_remove(sizeQ);

          // Update neighbors.
          td npot = 0;
          if (x - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x - 1,y,z) + P),x - 1,y,z)) {
            res(x - 1,y,z) = npot; if (path) path(x - 1,y,z) = (to)2;
          }
          if (x + 1<width() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x + 1,y,z) + P),x + 1,y,z)) {
            res(x + 1,y,z) = npot; if (path) path(x + 1,y,z) = (to)1;
          }
          if (y - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y - 1,z) + P),x,y - 1,z)) {
            res(x,y - 1,z) = npot; if (path) path(x,y - 1,z) = (to)8;
          }
          if (y + 1<height() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y + 1,z) + P),x,y + 1,z)) {
            res(x,y + 1,z) = npot; if (path) path(x,y + 1,z) = (to)4;
          }
          if (z - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z - 1) + P),x,y,z - 1)) {
            res(x,y,z - 1) = npot; if (path) path(x,y,z - 1) = (to)32;
          }
          if (z + 1<depth() && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z + 1) + P),x,y,z + 1)) {
            res(x,y,z + 1) = npot; if (path) path(x,y,z + 1) = (to)16;
          }

          if (is_high_connectivity) {
            const float sqrt2 = std::sqrt(2.f), sqrt3 = std::sqrt(3.f);

            // Diagonal neighbors on slice z.
            if (x - 1>=0 && y - 1>=0 &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y - 1,z) + P)),x - 1,y - 1,z)) {
              res(x - 1,y - 1,z) = npot; if (path) path(x - 1,y - 1,z) = (to)10;
            }
            if (x + 1<width() && y - 1>=0 &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y - 1,z) + P)),x + 1,y - 1,z)) {
              res(x + 1,y - 1,z) = npot; if (path) path(x + 1,y - 1,z) = (to)9;
            }
            if (x - 1>=0 && y + 1<height() &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y + 1,z) + P)),x - 1,y + 1,z)) {
              res(x - 1,y + 1,z) = npot; if (path) path(x - 1,y + 1,z) = (to)6;
            }
            if (x + 1<width() && y + 1<height() &&
                Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y + 1,z) + P)),x + 1,y + 1,z)) {
              res(x + 1,y + 1,z) = npot; if (path) path(x + 1,y + 1,z) = (to)5;
            }

            if (z - 1>=0) { // Diagonal neighbors on slice z - 1
              if (x - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z - 1) + P)),x - 1,y,z - 1)) {
                res(x - 1,y,z - 1) = npot; if (path) path(x - 1,y,z - 1) = (to)34;
              }
              if (x + 1<width() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y,z - 1) + P)),x + 1,y,z - 1)) {
                res(x + 1,y,z - 1) = npot; if (path) path(x + 1,y,z - 1) = (to)33;
              }
              if (y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z - 1) + P)),x,y - 1,z - 1)) {
                res(x,y - 1,z - 1) = npot; if (path) path(x,y - 1,z - 1) = (to)40;
              }
              if (y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y + 1,z - 1) + P)),x,y + 1,z - 1)) {
                res(x,y + 1,z - 1) = npot; if (path) path(x,y + 1,z - 1) = (to)36;
              }
              if (x - 1>=0 && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z - 1) + P)),
                                           x - 1,y - 1,z - 1)) {
                res(x - 1,y - 1,z - 1) = npot; if (path) path(x - 1,y - 1,z - 1) = (to)42;
              }
              if (x + 1<width() && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z - 1) + P)),
                                           x + 1,y - 1,z - 1)) {
                res(x + 1,y - 1,z - 1) = npot; if (path) path(x + 1,y - 1,z - 1) = (to)41;
              }
              if (x - 1>=0 && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y + 1,z - 1) + P)),
                                           x - 1,y + 1,z - 1)) {
                res(x - 1,y + 1,z - 1) = npot; if (path) path(x - 1,y + 1,z - 1) = (to)38;
              }
              if (x + 1<width() && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y + 1,z - 1) + P)),
                                           x + 1,y + 1,z - 1)) {
                res(x + 1,y + 1,z - 1) = npot; if (path) path(x + 1,y + 1,z - 1) = (to)37;
              }
            }

            if (z + 1<depth()) { // Diagonal neighbors on slice z + 1
              if (x - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z + 1) + P)),x - 1,y,z + 1)) {
                res(x - 1,y,z + 1) = npot; if (path) path(x - 1,y,z + 1) = (to)18;
              }
              if (x + 1<width() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y,z + 1) + P)),x + 1,y,z + 1)) {
                res(x + 1,y,z + 1) = npot; if (path) path(x + 1,y,z + 1) = (to)17;
              }
              if (y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z + 1) + P)),x,y - 1,z + 1)) {
                res(x,y - 1,z + 1) = npot; if (path) path(x,y - 1,z + 1) = (to)24;
              }
              if (y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y + 1,z + 1) + P)),x,y + 1,z + 1)) {
                res(x,y + 1,z + 1) = npot; if (path) path(x,y + 1,z + 1) = (to)20;
              }
              if (x - 1>=0 && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z + 1) + P)),
                                           x - 1,y - 1,z + 1)) {
                res(x - 1,y - 1,z + 1) = npot; if (path) path(x - 1,y - 1,z + 1) = (to)26;
              }
              if (x + 1<width() && y - 1>=0 &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z + 1) + P)),
                                           x + 1,y - 1,z + 1)) {
                res(x + 1,y - 1,z + 1) = npot; if (path) path(x + 1,y - 1,z + 1) = (to)25;
              }
              if (x - 1>=0 && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y + 1,z + 1) + P)),
                                           x - 1,y + 1,z + 1)) {
                res(x - 1,y + 1,z + 1) = npot; if (path) path(x - 1,y + 1,z + 1) = (to)22;
              }
              if (x + 1<width() && y + 1<height() &&
                  Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y + 1,z + 1) + P)),
                                           x + 1,y + 1,z + 1)) {
                res(x + 1,y + 1,z + 1) = npot; if (path) path(x + 1,y + 1,z + 1) = (to)21;
              }
            }
          }
        }
      }
      return result;

Project: CImg
File: CImg.h

    template<typename T>
    inline T median(T val0, T val1, T val2, T val3, T val4) {
      T tmp = std::min(val0,val1);
      val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4);
      val3 = std::max(val0,tmp);  val1 = std::min(val1,val4); tmp = std::min(val1,val2); val2 = std::max(val1,val2);
      val1 = tmp; tmp = std::min(val2,val3);
      return std::max(val1,tmp);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {
      return draw_image(0,sprite,opacity);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> operator+(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false)+=img;