Commit message: Fix other issues in 'CImg<T>::load_bmp()'.
CVE: CVE-2018-7641
CWE: CWE-125
Vulnerability description: An issue was discovered in CImg v.220. A heap-based buffer over-read in load_bmp in CImg.h occurs when loading a crafted bmp image, a different vulnerability than CVE-2018-7588. This is in a "32 bits colors" case, aka case 32.

Project: CImg
File: CImg.h


      static double mp_whiledo(_cimg_math_parser& mp) {
        const ulongT
          mem_body = mp.opcode[1],
          mem_cond = mp.opcode[2];
        const CImg<ulongT>
          *const p_cond = ++mp.p_code,
          *const p_body = p_cond + mp.opcode[3],
          *const p_end = p_body + mp.opcode[4];
        const unsigned int vsiz = (unsigned int)mp.opcode[5];
        bool is_cond = false;
        if (mp.opcode[6]) { // Set default value for result and condition if necessary
          if (vsiz) CImg<doubleT>(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type<double>::nan());
          else mp.mem[mem_body] = cimg::type<double>::nan();
        }
        if (mp.opcode[7]) mp.mem[mem_cond] = 0;
        const unsigned int _break_type = mp.break_type;
        mp.break_type = 0;
        do {
          for (mp.p_code = p_cond; mp.p_code<p_body; ++mp.p_code) { // Evaluate condition
            mp.opcode._data = mp.p_code->_data;
            const ulongT target = mp.opcode[1];
            mp.mem[target] = _cimg_mp_defunc(mp);
          }
          if (mp.break_type==1) break;
          is_cond = (bool)mp.mem[mem_cond];
          if (is_cond && !mp.break_type) // Evaluate body
            for (mp.p_code = p_body; mp.p_code<p_end; ++mp.p_code) {
              mp.opcode._data = mp.p_code->_data;
              const ulongT target = mp.opcode[1];
              mp.mem[target] = _cimg_mp_defunc(mp);
            }
          if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;
        } while (is_cond);

        mp.break_type = _break_type;
        mp.p_code = p_end - 1;
        return mp.mem[mem_body];

Project: CImg
File: CImg.h

    template<typename tz, typename tc>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           const int x0, const int y0, const float z0,
                           const int x1, const int y1, const float z1,
                           const int x2, const int y2, const float z2,
                           const CImg<tc>& texture,
                           const int tx0, const int ty0,
                           const int tx1, const int ty1,
                           const int tx2, const int ty2,
                           const float opacity=1,
                           const float brightness=1) {
      typedef typename cimg::superset<tz,float>::type tzfloat;
      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
      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);

      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture))
        return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
      static const T maxval = (T)std::min(cimg::type<T>::max(),(T)cimg::type<tc>::max());
      const float
        nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f),
        nbrightness = cimg::cut(brightness,0,2);
      const ulongT
        whd = (ulongT)_width*_height*_depth,
        twh = (ulongT)texture._width*texture._height,
        offx = _spectrum*whd;
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
      float
        ntx0 = tx0/z0, nty0 = ty0/z0,
        ntx1 = tx1/z1, nty1 = ty1/z1,
        ntx2 = tx2/z2, nty2 = ty2/z2;
      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
      if (ny0>=height() || ny2<0) return *this;
      float
        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
        ptyl = (nty1 - nty0)/(ny1 - ny0),
        ptyr = (nty2 - nty0)/(ny2 - ny0),
        ptyn = (nty2 - nty1)/(ny2 - ny1),
        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):
          (ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):
          (ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
      tzfloat
        pzl = (nz1 - nz0)/(ny1 - ny0),
        pzr = (nz2 - nz0)/(ny2 - ny0),
        pzn = (nz2 - nz1)/(ny2 - ny1),
        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
      _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
        int xleft = xleft0, xright = xright0;
        float txleft = txl, txright = txr, tyleft = tyl, tyright = tyr;
        tzfloat zleft = zl, zright = zr;
        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
        const int dx = xright - xleft;
        const float pentetx = (txright - txleft)/dx, pentety = (tyright - tyleft)/dx;
        const tzfloat pentez = (zright - zleft)/dx;
        if (xleft<0 && dx) {
          zleft-=xleft*(zright - zleft)/dx;
          txleft-=xleft*(txright - txleft)/dx;
          tyleft-=xleft*(tyright - tyleft)/dx;
        }
        if (xleft<0) xleft = 0;
        if (xright>=width() - 1) xright = width() - 1;
        T *ptrd = data(xleft,y,0,0);
        tz *ptrz = zbuffer.data(xleft,y);
        if (opacity>=1) {
          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
              if (zleft>=(tzfloat)*ptrz) {
                *ptrz = (tz)zleft;
                const tzfloat invz = 1/zleft;
                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
                cimg_forC(*this,c) {
                  *ptrd = (T)*col;
                  ptrd+=whd; col+=twh;
                }
                ptrd-=offx;
              }
              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
              if (zleft>=(tzfloat)*ptrz) {
                *ptrz = (tz)zleft;
                const tzfloat invz = 1/zleft;
                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
                cimg_forC(*this,c) {
                  *ptrd = (T)(nbrightness**col);
                  ptrd+=whd; col+=twh;
                }
                ptrd-=offx;
              }
              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
              if (zleft>=(tzfloat)*ptrz) {
                *ptrz = (tz)zleft;
                const tzfloat invz = 1/zleft;
                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
                cimg_forC(*this,c) {
                  *ptrd = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval);
                  ptrd+=whd; col+=twh;
                }
                ptrd-=offx;
              }
              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            }
        } else {
          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
              if (zleft>=(tzfloat)*ptrz) {
                *ptrz = (tz)zleft;
                const tzfloat invz = 1/zleft;
                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
                cimg_forC(*this,c) {
                  *ptrd = (T)(nopacity**col + *ptrd*copacity);
                  ptrd+=whd; col+=twh;
                }
                ptrd-=offx;
              }
              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
              if (zleft>=(tzfloat)*ptrz) {
                *ptrz = (tz)zleft;
                const tzfloat invz = 1/zleft;
                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
                cimg_forC(*this,c) {
                  *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
                  ptrd+=whd; col+=twh;
                }
                ptrd-=offx;
              }
              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
              if (zleft>=(tzfloat)*ptrz) {
                *ptrz = (tz)zleft;
                const tzfloat invz = 1/zleft;
                const tc *col = &texture._atXY((int)(txleft*invz),(int)(tyleft*invz));
                cimg_forC(*this,c) {
                  const T val = (T)((2 - nbrightness)**col + (nbrightness - 1)*maxval);
                  *ptrd = (T)(nopacity*val + *ptrd*copacity);
                  ptrd+=whd; col+=twh;
                }
                ptrd-=offx;
              }
              zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
            }
        }
        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

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

      get_shared_row(0)+=tx; get_shared_row(1)+=ty; get_shared_row(2)+=tz;
      return *this;

Project: CImg
File: CImg.h

    //! Blur image with the median filter \newinstance.
    CImg<T> get_blur_median(const unsigned int n, const float threshold=0) const {
      if (is_empty() || n<=1) return +*this;
      CImg<T> res(_width,_height,_depth,_spectrum);
      T *ptrd = res._data;
      cimg::unused(ptrd);
      const int hr = (int)n/2, hl = n - hr - 1;
      if (res._depth!=1) { // 3d
        if (threshold>0)
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=16 && _height*_depth*_spectrum>=4))
          cimg_forXYZC(*this,x,y,z,c) { // With threshold.
            const int
              x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr,
              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
              nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1;
            const Tfloat val0 = (Tfloat)(*this)(x,y,z,c);
            CImg<T> values(n*n*n);
            unsigned int nb_values = 0;
            T *ptrd = values.data();
            cimg_for_inXYZ(*this,nx0,ny0,nz0,nx1,ny1,nz1,p,q,r)
              if (cimg::abs((*this)(p,q,r,c) - val0)<=threshold) { *(ptrd++) = (*this)(p,q,r,c); ++nb_values; }
            res(x,y,z,c) = nb_values?values.get_shared_points(0,nb_values - 1).median():(*this)(x,y,z,c);
          }
        else
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=16 && _height*_depth*_spectrum>=4))
          cimg_forXYZC(*this,x,y,z,c) { // Without threshold.
            const int
              x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr,
              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
              nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1;
            res(x,y,z,c) = get_crop(nx0,ny0,nz0,c,nx1,ny1,nz1,c).median();
          }
      } else {
        if (threshold>0)
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width>=16 && _height*_spectrum>=4))
          cimg_forXYC(*this,x,y,c) { // With threshold.
            const int
              x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
                                        nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1;
            const Tfloat val0 = (Tfloat)(*this)(x,y,c);
            CImg<T> values(n*n);
            unsigned int nb_values = 0;
            T *ptrd = values.data();
            cimg_for_inXY(*this,nx0,ny0,nx1,ny1,p,q)
              if (cimg::abs((*this)(p,q,c) - val0)<=threshold) { *(ptrd++) = (*this)(p,q,c); ++nb_values; }
            res(x,y,c) = nb_values?values.get_shared_points(0,nb_values - 1).median():(*this)(x,y,c);
          }
        else {
          const int
            w1 = width() - 1, h1 = height() - 1,
            w2 = width() - 2, h2 = height() - 2,
            w3 = width() - 3, h3 = height() - 3,
            w4 = width() - 4, h4 = height() - 4;
          switch (n) { // Without threshold.
          case 3 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
            cimg_forC(*this,c) {
              CImg<T> I(9);
              cimg_for_in3x3(*this,1,1,w2,h2,x,y,0,c,I,T)
                res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],I[5],I[6],I[7],I[8]);
              cimg_for_borderXY(*this,x,y,1)
                res(x,y,c) = get_crop(std::max(0,x - 1),std::max(0,y - 1),0,c,
                                      std::min(w1,x + 1),std::min(h1,y + 1),0,c).median();
            }
          } break;
          case 5 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
            cimg_forC(*this,c) {
              CImg<T> I(25);
              cimg_for_in5x5(*this,2,2,w3,h3,x,y,0,c,I,T)
                res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],
                                          I[5],I[6],I[7],I[8],I[9],
                                          I[10],I[11],I[12],I[13],I[14],
                                          I[15],I[16],I[17],I[18],I[19],
                                          I[20],I[21],I[22],I[23],I[24]);
              cimg_for_borderXY(*this,x,y,2)
                res(x,y,c) = get_crop(std::max(0,x - 2),std::max(0,y - 2),0,c,
                                      std::min(w1,x + 2),std::min(h1,y + 2),0,c).median();
            }
          } break;
          case 7 : {
            cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2))
            cimg_forC(*this,c) {
              CImg<T> I(49);
              cimg_for_in7x7(*this,3,3,w4,h4,x,y,0,c,I,T)
                res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],I[5],I[6],
                                          I[7],I[8],I[9],I[10],I[11],I[12],I[13],
                                          I[14],I[15],I[16],I[17],I[18],I[19],I[20],
                                          I[21],I[22],I[23],I[24],I[25],I[26],I[27],
                                          I[28],I[29],I[30],I[31],I[32],I[33],I[34],
                                          I[35],I[36],I[37],I[38],I[39],I[40],I[41],
                                          I[42],I[43],I[44],I[45],I[46],I[47],I[48]);
              cimg_for_borderXY(*this,x,y,3)
                res(x,y,c) = get_crop(std::max(0,x - 3),std::max(0,y - 3),0,c,
                                      std::min(w1,x + 3),std::min(h1,y + 3),0,c).median();
            }
          } break;
          default : {
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width>=16 && _height*_spectrum>=4))
            cimg_forXYC(*this,x,y,c) {
              const int
                x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
                nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
                                          nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1;
              res(x,y,c) = get_crop(nx0,ny0,0,c,nx1,ny1,0,c).median();
            }
          }
          }
        }
      }
      return res;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h


      static double mp_vector_print(_cimg_math_parser& mp) {
        const bool print_string = (bool)mp.opcode[4];
        cimg_pragma_openmp(critical(mp_vector_print))
        {
          CImg<charT> expr(mp.opcode[2] - 5);
          const ulongT *ptrs = mp.opcode._data + 5;
          cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
          cimg::strellipsize(expr);
          unsigned int
            ptr = (unsigned int)mp.opcode[1] + 1,
            siz0 = (unsigned int)mp.opcode[3],
            siz = siz0;
          cimg::mutex(6);
          std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = [ ",expr._data);
          unsigned int count = 0;
          while (siz-->0) {
            if (count>=64 && siz>=64) {
              std::fprintf(cimg::output(),"...,");
              ptr = (unsigned int)mp.opcode[1] + 1 + siz0 - 64;
              siz = 64;
            } else std::fprintf(cimg::output(),"%g%s",mp.mem[ptr++],siz?",":"");
            ++count;
          }
          if (print_string) {
            CImg<charT> str(siz0 + 1);
            ptr = (unsigned int)mp.opcode[1] + 1;
            for (unsigned int k = 0; k<siz0; ++k) str[k] = (char)mp.mem[ptr++];
            str[siz0] = 0;
            cimg::strellipsize(str,1024,false);
            std::fprintf(cimg::output()," ] = '%s' (size: %u)",str._data,siz0);
          } else std::fprintf(cimg::output()," ] (size: %u)",siz0);
          std::fflush(cimg::output());
          cimg::mutex(6,0);
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Label connected components \newinstance.
    CImg<ulongT> get_label(const bool is_high_connectivity=false,
                           const Tfloat tolerance=0) const {
      if (is_empty()) return CImg<ulongT>();

      // Create neighborhood tables.
      int dx[13], dy[13], dz[13], nb = 0;
      dx[nb] = 1; dy[nb] = 0; dz[nb++] = 0;
      dx[nb] = 0; dy[nb] = 1; dz[nb++] = 0;
      if (is_high_connectivity) {
        dx[nb] = 1; dy[nb] = 1; dz[nb++] = 0;
        dx[nb] = 1; dy[nb] = -1; dz[nb++] = 0;
      }
      if (_depth>1) { // 3d version.
        dx[nb] = 0; dy[nb] = 0; dz[nb++]=1;
        if (is_high_connectivity) {
          dx[nb] = 1; dy[nb] = 1; dz[nb++] = -1;
          dx[nb] = 1; dy[nb] = 0; dz[nb++] = -1;
          dx[nb] = 1; dy[nb] = -1; dz[nb++] = -1;
          dx[nb] = 0; dy[nb] = 1; dz[nb++] = -1;

          dx[nb] = 0; dy[nb] = 1; dz[nb++] = 1;
          dx[nb] = 1; dy[nb] = -1; dz[nb++] = 1;
          dx[nb] = 1; dy[nb] = 0; dz[nb++] = 1;
          dx[nb] = 1; dy[nb] = 1; dz[nb++] = 1;
        }
      }
      return _label(nb,dx,dy,dz,tolerance);

Project: CImg
File: CImg.h


    //! Reverse primitives orientations of a 3d object.
    /**
    **/
    CImgList<T>& reverse_object3d() {
      cimglist_for(*this,l) {
        CImg<T>& p = _data[l];
        switch (p.size()) {
        case 2 : case 3: cimg::swap(p[0],p[1]); break;
        case 6 : cimg::swap(p[0],p[1],p[2],p[4],p[3],p[5]); break;
        case 9 : cimg::swap(p[0],p[1],p[3],p[5],p[4],p[6]); break;
        case 4 : cimg::swap(p[0],p[1],p[2],p[3]); break;
        case 12 : cimg::swap(p[0],p[1],p[2],p[3],p[4],p[6],p[5],p[7],p[8],p[10],p[9],p[11]); break;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator&=(const t value) {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
      cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd & (ulongT)value);
      return *this;

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<_cimg_Tfloat> log2(const CImg<T>& instance) {
    return instance.get_log2();

Project: CImg
File: CImg.h

    // Return a random filename.
    inline const char* filenamerand() {
      cimg::mutex(6);
      static char randomid[9];
      cimg::srand();
      for (unsigned int k = 0; k<8; ++k) {
        const int v = (int)cimg::rand(65535)%3;
        randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)):
                             (v==1?('a' + ((int)cimg::rand(65535)%26)):
                              ('A' + ((int)cimg::rand(65535)%26))));
      }
      cimg::mutex(6,0);
      return randomid;

Project: CImg
File: CImg.h

    **/
    CImg<T>& cos() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h


      static double mp_mean(_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/(i_end - 3);

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


    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

    //! Estimate displacement field between two images \newinstance.
    CImg<floatT> get_displacement(const CImg<T>& source,
                                  const float smoothness=0.1f, const float precision=5.0f,
                                  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.0)/std::log(1.5),1,1);

      const float _precision = (float)std::pow(10.0,-(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 collapse(2) cimg_openmp_if(_height*_depth>=8 && _width>=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 collapse(2) cimg_openmp_if(_height*_depth>=8 && _width>=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>=8 && _width>=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_forX(V,x) 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>=8 && _width>=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_forX(V,x) 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

    template<typename t>
    CImg<_cimg_Tt> get_erode(const CImg<t>& kernel, const bool boundary_conditions=true,
                             const bool is_real=false) const {
      if (is_empty() || !kernel) return *this;
      if (!is_real && kernel==0) return CImg<T>(width(),height(),depth(),spectrum(),0);
      typedef _cimg_Tt Tt;
      CImg<Tt> res(_width,_height,_depth,std::max(_spectrum,kernel._spectrum));
      const int
        mx2 = kernel.width()/2, my2 = kernel.height()/2, mz2 = kernel.depth()/2,
        mx1 = kernel.width() - mx2 - 1, my1 = kernel.height() - my2 - 1, mz1 = kernel.depth() - mz2 - 1,
        mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
      const bool
        is_inner_parallel = _width*_height*_depth>=32768,
        is_outer_parallel = res.size()>=32768;
      cimg::unused(is_inner_parallel,is_outer_parallel);
      _cimg_abort_init_omp;
      cimg_abort_init;
      cimg_pragma_openmp(parallel for cimg_openmp_if(!is_inner_parallel && is_outer_parallel))
      cimg_forC(res,c) _cimg_abort_try_omp {
        cimg_abort_test;
        const CImg<T> img = get_shared_channel(c%_spectrum);
        const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
        if (is_real) { // Real erosion
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(is_inner_parallel))
          for (int z = mz1; z<mze; ++z)
            for (int y = my1; y<mye; ++y)
              for (int x = mx1; x<mxe; ++x) _cimg_abort_try_omp2 {
                cimg_abort_test2;
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                      const Tt cval = (Tt)(img(x + xm,y + ym,z + zm) - mval);
                      if (cval<min_val) min_val = cval;
                    }
                res(x,y,z,c) = min_val;
              } _cimg_abort_catch_omp2
          if (boundary_conditions)
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                      const Tt cval = (Tt)(img._atXYZ(x + xm,y + ym,z + zm) - mval);
                      if (cval<min_val) min_val = cval;
                    }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2
          else
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm) {
                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                      const Tt cval = (Tt)(img.atXYZ(x + xm,y + ym,z + zm,0,(T)0) - mval);
                      if (cval<min_val) min_val = cval;
                    }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2

        } else { // Binary erosion
          cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(is_inner_parallel))
          for (int z = mz1; z<mze; ++z)
            for (int y = my1; y<mye; ++y)
              for (int x = mx1; x<mxe; ++x) _cimg_abort_try_omp2 {
                cimg_abort_test2;
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                        const Tt cval = (Tt)img(x + xm,y + ym,z + zm);
                        if (cval<min_val) min_val = cval;
                      }
                res(x,y,z,c) = min_val;
              } _cimg_abort_catch_omp2
          if (boundary_conditions)
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                        const T cval = (Tt)img._atXYZ(x + xm,y + ym,z + zm);
                        if (cval<min_val) min_val = cval;
                      }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2
          else
            cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(is_inner_parallel))
            cimg_forYZ(res,y,z) _cimg_abort_try_omp2 {
              cimg_abort_test2;
              for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1 - 1 || x>=mxe)?++x:(x=mxe))) {
                Tt min_val = cimg::type<Tt>::max();
                for (int zm = -mz1; zm<=mz2; ++zm)
                  for (int ym = -my1; ym<=my2; ++ym)
                    for (int xm = -mx1; xm<=mx2; ++xm)
                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                        const T cval = (Tt)img.atXYZ(x + xm,y + ym,z + zm,0,(T)0);
                        if (cval<min_val) min_val = cval;
                      }
                res(x,y,z,c) = min_val;
              }
            } _cimg_abort_catch_omp2
        }
      } _cimg_abort_catch_omp
      cimg_abort_test;
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0,
                        const CImg<t>& sprite, const float opacity=1) {
      if (is_empty() || !sprite) return *this;
      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity);
      if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared())
        return assign(sprite,false);
      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0);
      const int
        lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0),
        lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0),
        lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),
        lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);
      const t
        *ptrs = sprite._data +
        (bx?-x0:0) +
        (by?-y0*(ulongT)sprite.width():0) +
        (bz?-z0*(ulongT)sprite.width()*sprite.height():0) +
        (bc?-c0*(ulongT)sprite.width()*sprite.height()*sprite.depth():0);
      const ulongT
        offX = (ulongT)_width - lX,
        soffX = (ulongT)sprite._width - lX,
        offY = (ulongT)_width*(_height - lY),
        soffY = (ulongT)sprite._width*(sprite._height - lY),
        offZ = (ulongT)_width*_height*(_depth - lZ),
        soffZ = (ulongT)sprite._width*sprite._height*(sprite._depth - lZ);
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      if (lX>0 && lY>0 && lZ>0 && lC>0) {
        T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0);
        for (int v = 0; v<lC; ++v) {
          for (int z = 0; z<lZ; ++z) {
            for (int y = 0; y<lY; ++y) {
              if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
              else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
              ptrd+=offX; ptrs+=soffX;
            }
            ptrd+=offY; ptrs+=soffY;
          }
          ptrd+=offZ; ptrs+=soffZ;
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to HSI color spaces.
    CImg<T>& RGBtoHSI() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoHSI(): 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 ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=256))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N],
          G = (Tfloat)p2[N],
          B = (Tfloat)p3[N],
          theta = (Tfloat)(std::acos(0.5f*((R - G) + (R - B))/
                                     std::sqrt(cimg::sqr(R - G) + (R - B)*(G - B)))*180/cimg::PI),
          m = cimg::min(R,G,B),
          sum = R + G + B;
        Tfloat H = 0, S = 0, I = 0;
        if (theta>0) H = B<=G?theta:360 - theta;
        if (sum>0) S = 1 - 3*m/sum;
        I = sum/(3*255);
        p1[N] = (T)cimg::cut(H,0,360);
        p2[N] = (T)cimg::cut(S,0,1);
        p3[N] = (T)cimg::cut(I,0,1);
      }
      return *this;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    **/
    static void FFT(CImg<T>& real, CImg<T>& imag, const char axis, const bool is_invert=false) {
      if (!real)
        throw CImgInstanceException("CImg<%s>::FFT(): Specified real part is empty.",
                                    pixel_type());

      if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,(T)0);
      if (!real.is_sameXYZC(imag))
        throw CImgInstanceException("CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and "
                                    "imaginary part (%u,%u,%u,%u,%p) have different dimensions.",
                                    pixel_type(),
                                    real._width,real._height,real._depth,real._spectrum,real._data,
                                    imag._width,imag._height,imag._depth,imag._spectrum,imag._data);
#ifdef cimg_use_fftw3
      cimg::mutex(12);
      fftw_complex *data_in;
      fftw_plan data_plan;

      switch (cimg::lowercase(axis)) {
      case 'x' : { // Fourier along X, using FFTW library.
        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width);
        if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) "
                                                  "for computing FFT of image (%u,%u,%u,%u) along the X-axis.",
                                                  pixel_type(),
                                                  cimg::strbuffersize(sizeof(fftw_complex)*real._width),
                                                  real._width,real._height,real._depth,real._spectrum);

        data_plan = fftw_plan_dft_1d(real._width,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
        cimg_forYZC(real,y,z,c) {
          T *ptrr = real.data(0,y,z,c), *ptri = imag.data(0,y,z,c);
          double *ptrd = (double*)data_in;
          cimg_forX(real,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }
          fftw_execute(data_plan);
          const unsigned int fact = real._width;
          if (is_invert) cimg_forX(real,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }
          else cimg_forX(real,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }
        }
      } break;
      case 'y' : { // Fourier along Y, using FFTW library.
        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._height);
        if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) "
                                                  "for computing FFT of image (%u,%u,%u,%u) along the Y-axis.",
                                                  pixel_type(),
                                                  cimg::strbuffersize(sizeof(fftw_complex)*real._height),
                                                  real._width,real._height,real._depth,real._spectrum);

        data_plan = fftw_plan_dft_1d(real._height,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
        const unsigned int off = real._width;
        cimg_forXZC(real,x,z,c) {
          T *ptrr = real.data(x,0,z,c), *ptri = imag.data(x,0,z,c);
          double *ptrd = (double*)data_in;
          cimg_forY(real,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
          fftw_execute(data_plan);
          const unsigned int fact = real._height;
          if (is_invert)
            cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }
          else cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }
        }
      } break;
      case 'z' : { // Fourier along Z, using FFTW library.
        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._depth);
        if (!data_in) throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) "
                                                  "for computing FFT of image (%u,%u,%u,%u) along the Z-axis.",
                                                  pixel_type(),
                                                  cimg::strbuffersize(sizeof(fftw_complex)*real._depth),
                                                  real._width,real._height,real._depth,real._spectrum);

        data_plan = fftw_plan_dft_1d(real._depth,data_in,data_in,is_invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
        const ulongT off = (ulongT)real._width*real._height;
        cimg_forXYC(real,x,y,c) {
          T *ptrr = real.data(x,y,0,c), *ptri = imag.data(x,y,0,c);
          double *ptrd = (double*)data_in;
          cimg_forZ(real,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
          fftw_execute(data_plan);
          const unsigned int fact = real._depth;
          if (is_invert)
            cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }
          else cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }
        }
      } break;
      default :
        throw CImgArgumentException("CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts "
                                    "(%u,%u,%u,%u) "
                                    "(should be { x | y | z }).",
                                    pixel_type(),axis,
                                    real._width,real._height,real._depth,real._spectrum);
      }
      fftw_destroy_plan(data_plan);
      fftw_free(data_in);
      cimg::mutex(12,0);
#else
      switch (cimg::lowercase(axis)) {
      case 'x' : { // Fourier along X, using built-in functions.
        const unsigned int N = real._width, N2 = N>>1;
        if (((N - 1)&N) && N!=1)
          throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) "
                                      "have non 2^N dimension along the X-axis.",
                                      pixel_type(),
                                      real._width,real._height,real._depth,real._spectrum);

        for (unsigned int i = 0, j = 0; i<N2; ++i) {
          if (j>i) cimg_forYZC(real,y,z,c) {
              cimg::swap(real(i,y,z,c),real(j,y,z,c));
              cimg::swap(imag(i,y,z,c),imag(j,y,z,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(ri,y,z,c),real(rj,y,z,c));
                cimg::swap(imag(ri,y,z,c),imag(rj,y,z,c));
              }
            }
          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
        }
        for (unsigned int delta = 2; delta<=N; delta<<=1) {
          const unsigned int delta2 = delta>>1;
          for (unsigned int i = 0; i<N; i+=delta) {
            float wr = 1, wi = 0;
            const float
              angle = (float)((is_invert?+1:-1)*2*cimg::PI/delta),
              ca = (float)std::cos(angle),
              sa = (float)std::sin(angle);
            for (unsigned int k = 0; k<delta2; ++k) {
              const unsigned int j = i + k, nj = j + delta2;
              cimg_forYZC(real,y,z,c) {
                T &ir = real(j,y,z,c), &ii = imag(j,y,z,c), &nir = real(nj,y,z,c), &nii = imag(nj,y,z,c);
                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
                nir = (T)(ir - tmpr);
                nii = (T)(ii - tmpi);
                ir+=(T)tmpr;
                ii+=(T)tmpi;
              }
              const float nwr = wr*ca-wi*sa;
              wi = wi*ca + wr*sa;
              wr = nwr;
            }
          }
        }
        if (is_invert) { real/=N; imag/=N; }
      } break;
      case 'y' : { // Fourier along Y, using built-in functions.
        const unsigned int N = real._height, N2 = N>>1;
        if (((N - 1)&N) && N!=1)
          throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) "
                                      "have non 2^N dimension along the Y-axis.",
                                      pixel_type(),
                                      real._width,real._height,real._depth,real._spectrum);

        for (unsigned int i = 0, j = 0; i<N2; ++i) {
          if (j>i) cimg_forXZC(real,x,z,c) {
              cimg::swap(real(x,i,z,c),real(x,j,z,c));
              cimg::swap(imag(x,i,z,c),imag(x,j,z,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(x,ri,z,c),real(x,rj,z,c));
                cimg::swap(imag(x,ri,z,c),imag(x,rj,z,c));
              }
            }
          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
        }
        for (unsigned int delta = 2; delta<=N; delta<<=1) {
          const unsigned int delta2 = (delta>>1);
          for (unsigned int i = 0; i<N; i+=delta) {
            float wr = 1, wi = 0;
            const float
              angle = (float)((is_invert?+1:-1)*2*cimg::PI/delta),
              ca = (float)std::cos(angle),
              sa = (float)std::sin(angle);
            for (unsigned int k = 0; k<delta2; ++k) {
              const unsigned int j = i + k, nj = j + delta2;
              cimg_forXZC(real,x,z,c) {
                T &ir = real(x,j,z,c), &ii = imag(x,j,z,c), &nir = real(x,nj,z,c), &nii = imag(x,nj,z,c);
                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
                nir = (T)(ir - tmpr);
                nii = (T)(ii - tmpi);
                ir+=(T)tmpr;
                ii+=(T)tmpi;
              }
              const float nwr = wr*ca-wi*sa;
              wi = wi*ca + wr*sa;
              wr = nwr;
            }
          }
        }
        if (is_invert) { real/=N; imag/=N; }
      } break;
      case 'z' : { // Fourier along Z, using built-in functions.
        const unsigned int N = real._depth, N2 = N>>1;
        if (((N - 1)&N) && N!=1)
          throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) "
                                      "have non 2^N dimension along the Z-axis.",
                                      pixel_type(),
                                      real._width,real._height,real._depth,real._spectrum);

        for (unsigned int i = 0, j = 0; i<N2; ++i) {
          if (j>i) cimg_forXYC(real,x,y,c) {
              cimg::swap(real(x,y,i,c),real(x,y,j,c));
              cimg::swap(imag(x,y,i,c),imag(x,y,j,c));
              if (j<N2) {
                const unsigned int ri = N - 1 - i, rj = N - 1 - j;
                cimg::swap(real(x,y,ri,c),real(x,y,rj,c));
                cimg::swap(imag(x,y,ri,c),imag(x,y,rj,c));
              }
            }
          for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
        }
        for (unsigned int delta = 2; delta<=N; delta<<=1) {
          const unsigned int delta2 = (delta>>1);
          for (unsigned int i = 0; i<N; i+=delta) {
            float wr = 1, wi = 0;
            const float
              angle = (float)((is_invert?+1:-1)*2*cimg::PI/delta),
              ca = (float)std::cos(angle),
              sa = (float)std::sin(angle);
            for (unsigned int k = 0; k<delta2; ++k) {
              const unsigned int j = i + k, nj = j + delta2;
              cimg_forXYC(real,x,y,c) {
                T &ir = real(x,y,j,c), &ii = imag(x,y,j,c), &nir = real(x,y,nj,c), &nii = imag(x,y,nj,c);
                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
                nir = (T)(ir - tmpr);
                nii = (T)(ii - tmpi);
                ir+=(T)tmpr;
                ii+=(T)tmpi;
              }
              const float nwr = wr*ca-wi*sa;
              wi = wi*ca + wr*sa;
              wr = nwr;
            }
          }
        }
        if (is_invert) { real/=N; imag/=N; }
      } break;
      default :
        throw CImgArgumentException("CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts "
                                    "(%u,%u,%u,%u) "
                                    "(should be { x | y | z }).",
                                    pixel_type(),axis,
                                    real._width,real._height,real._depth,real._spectrum);
      }
#endif

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to, typename tz>
    CImg<T>& draw_object3d(LibBoard::Board& board,
                           const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors, const CImgList<to>& opacities,
                           const unsigned int render_type,
                           const bool is_double_sided, const float focale,
                           const float lightx, const float lighty, const float lightz,
                           const float specular_lightness, const float specular_shininess,
                           CImg<tz>& zbuffer) {
      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,
                            render_type,is_double_sided,focale,lightx,lighty,lightz,
                            specular_lightness,specular_shininess,1);

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_imagemagick_external(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_other(): File '%s', saving a volumetric image with an external call to "
                   "ImageMagick only writes the first image slice.",
                   cimg_instance,filename);
#ifdef cimg_use_png
#define _cimg_sie_ext1 "png"
#define _cimg_sie_ext2 "png"
#else
#define _cimg_sie_ext1 "pgm"
#define _cimg_sie_ext2 "ppm"
#endif
      CImg<charT> command(1024), filename_tmp(256);
      std::FILE *file;
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",cimg::temporary_path(),
                      cimg_file_separator,cimg::filenamerand(),_spectrum==1?_cimg_sie_ext1:_cimg_sie_ext2);
        if ((file=std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
#ifdef cimg_use_png
      save_png(filename_tmp);
#else
      save_pnm(filename_tmp);
#endif
      cimg_snprintf(command,command._width,"%s -quality %u \"%s\" \"%s\"",
                    cimg::imagemagick_path(),quality,
                    CImg<charT>::string(filename_tmp)._system_strescape().data(),
                    CImg<charT>::string(filename)._system_strescape().data());
      cimg::system(command);
      file = std_fopen(filename,"rb");
      if (!file)
        throw CImgIOException(_cimg_instance
                              "save_imagemagick_external(): Failed to save file '%s' with "
                              "external command 'magick/convert'.",
                              cimg_instance,
                              filename);

      if (file) cimg::fclose(file);
      std::remove(filename_tmp);
      return *this;

Project: CImg
File: CImg.h


      static double mp_jxyzc(_cimg_math_parser& mp) {
        const unsigned int
          interpolation = (unsigned int)_mp_arg(6),
          boundary_conditions = (unsigned int)_mp_arg(7);
        const CImg<T> &img = mp.imgin;
        const double
          ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y],
          oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c],
          x = ox + _mp_arg(2), y = oy + _mp_arg(3),
          z = oz + _mp_arg(4), c = oc + _mp_arg(5);
        if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(),
              mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2),
              mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2);
            return (double)img(mx<img.width()?mx:w2 - mx - 1,
                               my<img.height()?my:h2 - my - 1,
                               mz<img.depth()?mz:d2 - mz - 1,
                               mc<img.spectrum()?mc:s2 - mc - 1);
          }
          case 2 : // Periodic
            return (double)img(cimg::mod((int)x,img.width()),
                               cimg::mod((int)y,img.height()),
                               cimg::mod((int)z,img.depth()),
                               cimg::mod((int)c,img.spectrum()));
          case 1 : // Neumann
            return (double)img._atXYZC((int)x,(int)y,(int)z,(int)c);
          default : // Dirichlet
            return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,(T)0);
          } else switch (boundary_conditions) { // Linear interpolation
          case 3 : { // Mirror
            const float
              w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*img.spectrum(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
              mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
            return (double)img._linear_atXYZC(mx<img.width()?mx:w2 - mx - 1,
                                              my<img.height()?my:h2 - my - 1,
                                              mz<img.depth()?mz:d2 - mz - 1,
                                              mc<img.spectrum()?mc:s2 - mc - 1);
          }
          case 2 : // Periodic
            return (double)img._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
                                              cimg::mod((float)y,(float)img.height()),
                                              cimg::mod((float)z,(float)img.depth()),
                                              cimg::mod((float)c,(float)img.spectrum()));
          case 1 : // Neumann
            return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
          default : // Dirichlet
            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
          }

Project: CImg
File: CImg.h


    //! Return a reference to the maximum pixel value of the instance list.
    /**
    **/
    T& max() {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "max(): Empty instance.",
                                    cimglist_instance);
      T *ptr_max = _data->_data;
      T max_value = *ptr_max;
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to YUV color spaces.
    CImg<T>& RGBtoYUV() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoYUV(): 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 ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=16384))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N]/255,
          G = (Tfloat)p2[N]/255,
          B = (Tfloat)p3[N]/255,
          Y = 0.299f*R + 0.587f*G + 0.114f*B;
        p1[N] = (T)Y;
        p2[N] = (T)(0.492f*(B - Y));
        p3[N] = (T)(0.877*(R - Y));
      }
      return *this;

Project: CImg
File: CImg.h

    //! Compute correspondence map between two images, using the patch-match algorithm \overloading.
    CImg<T>& patchmatch(const CImg<T>& patch_image,
                        const unsigned int patch_width,
                        const unsigned int patch_height,
                        const unsigned int patch_depth=1,
                        const unsigned int nb_iterations=5,
                        const unsigned int nb_randoms=5) {
      return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
                            nb_iterations,nb_randoms).move_to(*this);

Project: CImg
File: CImg.h

    //! Simple interface to select a shape from an image \newinstance.
    CImg<intT> get_select(const char *const title,
    			  const unsigned int feature_type=2, unsigned int *const XYZ=0,
                          const bool exit_on_anykey=false) const {
      CImgDisplay disp;
      return _select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);

Project: CImg
File: CImg.h

      // Count parentheses/brackets level of each character of the expression.
      CImg<uintT> get_level(CImg<charT>& expr) const {
        bool is_escaped = false, next_is_escaped = false;
        unsigned int mode = 0, next_mode = 0; // { 0=normal | 1=char-string | 2=vector-string
        CImg<uintT> res(expr._width - 1);
        unsigned int *pd = res._data;
        int level = 0;
        for (const char *ps = expr._data; *ps && level>=0; ++ps) {
          if (!is_escaped && !next_is_escaped && *ps=='\\') next_is_escaped = true;
          if (!is_escaped && *ps=='\'') { // Non-escaped character
            if (!mode && ps>expr._data && *(ps - 1)=='[') next_mode = mode = 2; // Start vector-string
            else if (mode==2 && *(ps + 1)==']') next_mode = !mode; // End vector-string
            else if (mode<2) next_mode = mode?(mode = 0):1; // Start/end char-string
          }
          *(pd++) = (unsigned int)(mode>=1 || is_escaped?level + (mode==1):
                                   *ps=='(' || *ps=='['?level++:
                                   *ps==')' || *ps==']'?--level:
                                   level);
          mode = next_mode;
          is_escaped = next_is_escaped;
          next_is_escaped = false;
        }
        if (mode) {
          cimg::strellipsize(expr,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: Unterminated string literal, in expression '%s'.",
                                      pixel_type(),_cimg_mp_calling_function,
                                      expr._data);
        }
        if (level) {
          cimg::strellipsize(expr,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.",
                                      pixel_type(),_cimg_mp_calling_function,
                                      expr._data);
        }
        return res;

Project: CImg
File: CImg.h


      unsigned int scalar5(const mp_func op,
                           const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
                           const unsigned int arg4, const unsigned int arg5) {
        const unsigned int pos =
          arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
          arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
          arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:
          arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4:
          arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5:scalar();
        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5).move_to(code);
        return pos;

Project: CImg
File: CImg.h

    //! Convert 3d object into a CImg3d representation \overloading.
    CImg<floatT> get_object3dtoCImg3d(const bool full_check=true) const {
      CImgList<T> opacities, colors;
      CImgList<uintT> primitives(width(),1,1,1,1);
      cimglist_for(primitives,p) primitives(p,0) = p;
      return get_object3dtoCImg3d(primitives,colors,opacities,full_check);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& solve(const CImg<t>& A) {
      if (_depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "solve(): Instance and specified matrix (%u,%u,%u,%u,%p) have "
                                    "incompatible dimensions.",
                                    cimg_instance,
                                    A._width,A._height,A._depth,A._spectrum,A._data);
      typedef _cimg_Ttfloat Ttfloat;
      if (A._width==A._height) { // Classical linear system
        if (_width!=1) {
          CImg<T> res(_width,A._width);
          cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));
          return res.move_to(*this);
        }
#ifdef cimg_use_lapack
        char TRANS = 'N';
        int INFO, N = _height, LWORK = 4*N, *const IPIV = new int[N];
        Ttfloat
          *const lapA = new Ttfloat[N*N],
          *const lapB = new Ttfloat[N],
          *const WORK = new Ttfloat[LWORK];
        cimg_forXY(A,k,l) lapA[k*N + l] = (Ttfloat)(A(k,l));
        cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
        cimg::getrf(N,lapA,IPIV,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "solve(): LAPACK library function dgetrf_() returned error code %d.",
                     cimg_instance,
                     INFO);

        if (!INFO) {
          cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
          if (INFO)
            cimg::warn(_cimg_instance
                       "solve(): LAPACK library function dgetrs_() returned error code %d.",
                       cimg_instance,
                       INFO);
        }
        if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
        delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
#else
        CImg<Ttfloat> lu(A,false);
        CImg<Ttfloat> indx;
        bool d;
        lu._LU(indx,d);
        _solve(lu,indx);
#endif
      } else { // Least-square solution for non-square systems.
#ifdef cimg_use_lapack
        if (_width!=1) {
          CImg<T> res(_width,A._width);
          cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));
          return res.move_to(*this);
        }
	char TRANS = 'N';
        int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width;
	Ttfloat WORK_QUERY;
	Ttfloat
	  * const lapA = new Ttfloat[M*N],
	  * const lapB = new Ttfloat[M*NRHS];
	cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO);
	LWORK = (int) WORK_QUERY;
	Ttfloat *const WORK = new Ttfloat[LWORK];
        cimg_forXY(A,k,l) lapA[k*M + l] = (Ttfloat)(A(k,l));
        cimg_forXY(*this,k,l) lapB[k*M + l] = (Ttfloat)((*this)(k,l));
	cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO);
        if (INFO != 0)
          cimg::warn(_cimg_instance
                     "solve(): LAPACK library function sgels() returned error code %d.",
                     cimg_instance,
                     INFO);
	assign(NRHS, N);
        if (!INFO)
          cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M + l];
        else
          assign(A.get_pseudoinvert()*(*this));
        delete[] lapA; delete[] lapB; delete[] WORK;
#else
	assign(A.get_pseudoinvert()*(*this));
#endif
      }
      return *this;

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 collapse(2) cimg_openmp_if(_width>=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 collapse(2) cimg_openmp_if(_width>=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 collapse(2) cimg_openmp_if(_width>=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 collapse(2) cimg_openmp_if(_width>=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 collapse(2) cimg_openmp_if(_width>=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

    **/
    T cubic_cut_atX(const float fx, const int y, const int z, const int c) const {
      return cimg::type<T>::cut(cubic_atX(fx,y,z,c));

Project: CImg
File: CImg.h

    /**
       \param[out] max_val Value of the maximum value found.
    **/
    template<typename t>
    T& min_max(t& max_val) {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "min_max(): Empty instance.",
                                    cimglist_instance);
      T *ptr_min = _data->_data;
      T min_value = *ptr_min, max_value = min_value;
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];
        cimg_for(img,ptrs,T) {
          const T val = *ptrs;
          if (val<min_value) { min_value = val; ptr_min = ptrs; }
          if (val>max_value) max_value = val;
        }

Project: CImg
File: CImg.h

    **/
    CImg<T>& sqrt() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& boxfilter(const float boxsize, const int order, const char axis='x',
                       const bool boundary_conditions=true,
                       const unsigned int nb_iter=1) {
      if (is_empty() || !boxsize || (boxsize<=1 && !order)) return *this;
      const char naxis = cimg::lowercase(axis);
      const float nboxsize = boxsize>=0?boxsize:-boxsize*
        (naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100;
      switch (naxis) {
      case 'x' : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
        cimg_forYZC(*this,y,z,c)
          _cimg_blur_box_apply(data(0,y,z,c),nboxsize,_width,1U,order,boundary_conditions,nb_iter);
      } break;
      case 'y' : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
        cimg_forXZC(*this,x,z,c)
          _cimg_blur_box_apply(data(x,0,z,c),nboxsize,_height,(ulongT)_width,order,boundary_conditions,nb_iter);
      } break;
      case 'z' : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
        cimg_forXYC(*this,x,y,c)
          _cimg_blur_box_apply(data(x,y,0,c),nboxsize,_depth,(ulongT)_width*_height,order,boundary_conditions,nb_iter);
      } break;
      default : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
        cimg_forXYZ(*this,x,y,z)
          _cimg_blur_box_apply(data(x,y,z,0),nboxsize,_spectrum,(ulongT)_width*_height*_depth,
                               order,boundary_conditions,nb_iter);
      }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_line(const int x0, const int y0,
                       const int x1, const int y1,
                       const CImg<tc>& texture,
                       const int tx0, const int ty0,
                       const int tx1, const int ty1,
                       const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {
      if (is_empty()) return *this;
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
      static unsigned int hatch = ~0U - (~0U>>1);
      if (init_hatch) hatch = ~0U - (~0U>>1);
      const bool xdir = x0<x1, ydir = y0<y1;
      int
        dtx = tx1-tx0, dty = ty1-ty0,
        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
        tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,
        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
        &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,
        &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
      if (xright<0 || xleft>=width()) return *this;
      if (xleft<0) {
        const float D = (float)xright - xleft;
        yleft-=(int)((float)xleft*((float)yright - yleft)/D);
        txleft-=(int)((float)xleft*((float)txright - txleft)/D);
        tyleft-=(int)((float)xleft*((float)tyright - tyleft)/D);
        xleft = 0;
      }
      if (xright>=width()) {
        const float d = (float)xright - width(), D = (float)xright - xleft;
        yright-=(int)(d*((float)yright - yleft)/D);
        txright-=(int)(d*((float)txright - txleft)/D);
        tyright-=(int)(d*((float)tyright - tyleft)/D);
        xright = width() - 1;
      }
      if (ydown<0 || yup>=height()) return *this;
      if (yup<0) {
        const float D = (float)ydown - yup;
        xup-=(int)((float)yup*((float)xdown - xup)/D);
        txup-=(int)((float)yup*((float)txdown - txup)/D);
        tyup-=(int)((float)yup*((float)tydown - tyup)/D);
        yup = 0;
      }
      if (ydown>=height()) {
        const float d = (float)ydown - height(), D = (float)ydown - yup;
        xdown-=(int)(d*((float)xdown - xup)/D);
        txdown-=(int)(d*((float)txdown - txup)/D);
        tydown-=(int)(d*((float)tydown - tyup)/D);
        ydown = height() - 1;
      }
      T *ptrd0 = data(nx0,ny0);
      int dx = xright - xleft, dy = ydown - yup;
      const bool steep = dy>dx;
      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
      const longT
        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),
        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width()),
        ndx = (longT)(dx>0?dx:1);
      const ulongT
        whd = (ulongT)_width*_height*_depth,
        twh = (ulongT)texture._width*texture._height;

      if (opacity>=1) {
        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
          if (pattern&hatch) {
            T *ptrd = ptrd0;
            const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
            const tc *col = &texture._atXY(tx,ty);
            cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }
          }
          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
          T *ptrd = ptrd0;
          const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
          const tc *col = &texture._atXY(tx,ty);
          cimg_forC(*this,c) { *ptrd = (T)*col; ptrd+=whd; col+=twh; }
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        }
      } else {
        const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
          T *ptrd = ptrd0;
          if (pattern&hatch) {
            const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
            const tc *col = &texture._atXY(tx,ty);
            cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }
          }
          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
          T *ptrd = ptrd0;
          const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
          const tc *col = &texture._atXY(tx,ty);
          cimg_forC(*this,c) { *ptrd = (T)(nopacity**col + *ptrd*copacity); ptrd+=whd; col+=twh; }
          ptrd0+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    T& atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) {
      return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_value)=out_value):(*this)(pos,x,y,z,c);

Project: CImg
File: CImg.h


    inline unsigned int srand(const unsigned int seed) {
      std::srand(seed);
      return seed;

Project: CImg
File: CImg.h

      // Insert code instructions for processing scalars.
      unsigned int scalar() { // Insert new scalar in memory.
        if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(mem._width,1,1,1,0); }
        return mempos++;

Project: CImg
File: CImg.h

    template<typename tp, typename tc, typename tt, typename tx>
    const CImg<T>& texturize_object3d(CImgList<tp>& primitives, CImgList<tc>& colors,
                                      const CImg<tt>& texture, const CImg<tx>& coords=CImg<tx>::const_empty()) const {
      if (is_empty()) return *this;
      if (_height!=3)
        throw CImgInstanceException(_cimg_instance
                                    "texturize_object3d(): image instance is not a set of 3d points.",
                                    cimg_instance);
      if (coords && (coords._width!=_width || coords._height!=2))
        throw CImgArgumentException(_cimg_instance
                                    "texturize_object3d(): Invalid specified texture coordinates (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    coords._width,coords._height,coords._depth,coords._spectrum,coords._data);
      CImg<intT> _coords;
      if (!coords) { // If no texture coordinates specified, do a default XY-projection.
        _coords.assign(_width,2);
        float
          xmin, xmax = (float)get_shared_row(0).max_min(xmin),
          ymin, ymax = (float)get_shared_row(1).max_min(ymin),
          dx = xmax>xmin?xmax-xmin:1,
          dy = ymax>ymin?ymax-ymin:1;
        cimg_forX(*this,p) {
          _coords(p,0) = (int)(((*this)(p,0) - xmin)*texture._width/dx);
          _coords(p,1) = (int)(((*this)(p,1) - ymin)*texture._height/dy);
        }
      } else _coords = coords;

      int texture_ind = -1;
      cimglist_for(primitives,l) {
        CImg<tp> &p = primitives[l];
        const unsigned int siz = p.size();
        switch (siz) {
        case 1 : { // Point.
          const unsigned int i0 = (unsigned int)p[0];
          const int x0 = _coords(i0,0), y0 = _coords(i0,1);
          texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0,
                                y0<=0?0:y0>=texture.height()?texture.height() - 1:y0).move_to(colors[l]);
        } break;
        case 2 : case 6 : { // Line.
          const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1];
          const int
            x0 = _coords(i0,0), y0 = _coords(i0,1),
            x1 = _coords(i1,0), y1 = _coords(i1,1);
          if (texture_ind<0) colors[texture_ind=l].assign(texture,false);
          else colors[l].assign(colors[texture_ind],true);
          CImg<tp>::vector(i0,i1,x0,y0,x1,y1).move_to(p);
        } break;
        case 3 : case 9 : { // Triangle.
          const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2];
          const int
            x0 = _coords(i0,0), y0 = _coords(i0,1),
            x1 = _coords(i1,0), y1 = _coords(i1,1),
            x2 = _coords(i2,0), y2 = _coords(i2,1);
          if (texture_ind<0) colors[texture_ind=l].assign(texture,false);
          else colors[l].assign(colors[texture_ind],true);
          CImg<tp>::vector(i0,i1,i2,x0,y0,x1,y1,x2,y2).move_to(p);
        } break;
        case 4 : case 12 : { // Quadrangle.
          const unsigned int
            i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2], i3 = (unsigned int)p[3];
          const int
            x0 = _coords(i0,0), y0 = _coords(i0,1),
            x1 = _coords(i1,0), y1 = _coords(i1,1),
            x2 = _coords(i2,0), y2 = _coords(i2,1),
            x3 = _coords(i3,0), y3 = _coords(i3,1);
          if (texture_ind<0) colors[texture_ind=l].assign(texture,false);
          else colors[l].assign(colors[texture_ind],true);
          CImg<tp>::vector(i0,i1,i2,i3,x0,y0,x1,y1,x2,y2,x3,y3).move_to(p);
        } break;
        }
      }
      return *this;

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.0f*width(), hh = 2.0f*height(), dd = 2.0f*depth();
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(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_cut_atXYZ(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.0f*width(), hh = 2.0f*height(), dd = 2.0f*depth();
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(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 collapse(2) cimg_openmp_if(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 collapse(2) cimg_openmp_if(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),(float)width()),
              Y = cimg::mod((float)(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),(float)height()),
              Z = cimg::mod((float)(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc),(float)depth());
            cimg_forC(res,c) res(x,y,z,c) = _cubic_cut_atXYZ(X,Y,Z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(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),(float)width()),
              Y = cimg::mod((float)(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),(float)height()),
              Z = cimg::mod((float)(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc),(float)depth());
            cimg_forC(res,c) res(x,y,z,c) = (T)_linear_atXYZ(X,Y,Z,c);
          }
        } break;
        default : { // Nearest-neighbor interpolation
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(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 collapse(2) cimg_openmp_if(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_cut_atXYZ(X,Y,Z,c);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(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 collapse(2) cimg_openmp_if(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 collapse(2) cimg_openmp_if(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_cut_atXYZ(X,Y,Z,c,(T)0);
          }
        } break;
        case 1 : { // Linear interpolation
          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(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 collapse(2) cimg_openmp_if(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

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

Project: CImg
File: CImg.h

    // Return a visualizable uchar8 image for display routines.
    CImg<ucharT> __get_select(const CImgDisplay& disp, const int normalization,
                              const int x, const int y, const int z) const {
      if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
      const CImg<T> crop = get_shared_channels(0,std::min(2,spectrum() - 1));
      CImg<Tuchar> img2d;
      if (_depth>1) {
        const int mdisp = std::min(disp.screen_width(),disp.screen_height());
        if (depth()>mdisp) {
          crop.get_resize(-100,-100,mdisp,-100,0).move_to(img2d);
          img2d.projections2d(x,y,z*img2d._depth/_depth);
        } else crop.get_projections2d(x,y,z).move_to(img2d);
      } else CImg<Tuchar>(crop,false).move_to(img2d);

      // Check for inf and NaN values.
      if (cimg::type<T>::is_float() && normalization) {
        bool is_inf = false, is_nan = false;
        cimg_for(img2d,ptr,Tuchar)
          if (cimg::type<T>::is_inf(*ptr)) { is_inf = true; break; }
          else if (cimg::type<T>::is_nan(*ptr)) { is_nan = true; break; }
        if (is_inf || is_nan) {
          Tint m0 = (Tint)cimg::type<T>::max(), M0 = (Tint)cimg::type<T>::min();
          if (!normalization) { m0 = 0; M0 = 255; }
          else if (normalization==2) { m0 = (Tint)disp._min; M0 = (Tint)disp._max; }
          else
            cimg_for(img2d,ptr,Tuchar)
              if (!cimg::type<T>::is_inf(*ptr) && !cimg::type<T>::is_nan(*ptr)) {
                if (*ptr<(Tuchar)m0) m0 = *ptr;
                if (*ptr>(Tuchar)M0) M0 = *ptr;
              }
          const T
            val_minf = (T)(normalization==1 || normalization==3?m0 - (M0 - m0)*20 - 1:m0),
            val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0);
          if (is_nan)
            cimg_for(img2d,ptr,Tuchar)
              if (cimg::type<T>::is_nan(*ptr)) *ptr = val_minf; // Replace NaN values.
          if (is_inf)
            cimg_for(img2d,ptr,Tuchar)
              if (cimg::type<T>::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values.
        }
      }

      switch (normalization) {
      case 1 : img2d.normalize((ucharT)0,(ucharT)255); break;
      case 2 : {
        const float m = disp._min, M = disp._max;
        (img2d-=m)*=255.0f/(M - m>0?M - m:1);
      } break;
      case 3 :
        if (cimg::type<T>::is_float()) img2d.normalize((ucharT)0,(ucharT)255);
        else {
          const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
          (img2d-=m)*=255.0f/(M - m>0?M - m:1);
        } break;
      }
      if (img2d.spectrum()==2) img2d.channels(0,2);
      return img2d;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<intT> get_patchmatch(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 CImg<t> &guide) const {
      return _patchmatch(patch_image,patch_width,patch_height,patch_depth,
                         nb_iterations,nb_randoms,
                         guide,false,CImg<T>::empty());

Project: CImg
File: CImg.h

    //! Compute the absolute value of each pixel value \newinstance.
    CImg<Tfloat> get_abs() const {
      return CImg<Tfloat>(*this,false).abs();

Project: CImg
File: CImg.h

    **/
    CImg<T>& vanvliet(const float sigma, const unsigned int order, const char axis='x',
                      const bool boundary_conditions=true) {
      if (is_empty()) return *this;
      if (!cimg::type<T>::is_float())
        return CImg<Tfloat>(*this,false).vanvliet(sigma,order,axis,boundary_conditions).move_to(*this);
      const char naxis = cimg::lowercase(axis);
      const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100;
      if (is_empty() || (nsigma<0.5f && !order)) return *this;
      const double
	nnsigma = nsigma<0.5f?0.5f:nsigma,
	m0 = 1.16680, m1 = 1.10783, m2 = 1.40586,
        m1sq = m1 * m1, m2sq = m2 * m2,
	q = (nnsigma<3.556?-0.2568 + 0.5784*nnsigma + 0.0561*nnsigma*nnsigma:2.5091 + 0.9804*(nnsigma - 3.556)),
	qsq = q * q,
	scale = (m0 + q) * (m1sq + m2sq + 2 * m1 * q + qsq),
	b1 = -q * (2 * m0 * m1 + m1sq + m2sq + (2 * m0 + 4 * m1) * q + 3 * qsq) / scale,
	b2 = qsq * (m0 + 2 * m1 + 3 * q) / scale,
	b3 = -qsq * q / scale,
	B = ( m0 * (m1sq + m2sq) ) / scale;
      double filter[4];
      filter[0] = B; filter[1] = -b1; filter[2] = -b2; filter[3] = -b3;
      switch (naxis) {
      case 'x' : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
	cimg_forYZC(*this,y,z,c)
	  _cimg_recursive_apply(data(0,y,z,c),filter,_width,1U,order,boundary_conditions);
      } break;
      case 'y' : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
	cimg_forXZC(*this,x,z,c)
	  _cimg_recursive_apply(data(x,0,z,c),filter,_height,(ulongT)_width,order,boundary_conditions);
      } break;
      case 'z' : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
	cimg_forXYC(*this,x,y,c)
	  _cimg_recursive_apply(data(x,y,0,c),filter,_depth,(ulongT)_width*_height,
				order,boundary_conditions);
      } break;
      default : {
        cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=256 && _height*_depth*_spectrum>=16))
	cimg_forXYZ(*this,x,y,z)
	  _cimg_recursive_apply(data(x,y,z,0),filter,_spectrum,(ulongT)_width*_height*_depth,
				order,boundary_conditions);
      }
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& round(const double y=1, const int rounding_type=0) {
      if (y>0)
        cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
        cimg_rof(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type);
      return *this;

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.0 / ( (1.0 + a1 - a2 + a3) * (1.0 - a1 - a2 - a3) * (1.0 + a2 + (a1 - a3) * a3) );
      double M[9]; // Triggs matrix
      M[0] = scaleM * (-a3 * a1 + 1.0 - 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.0) * (a2 + a3 * a1);
      M[5] = -scaleM * a3 * (a3 * a1 + a3 * a3 + a2 - 1.0);
      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.0 - a1 - a2 - a3), vplus = uplus/(1.0 - 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

    //! Display 1d graph in an interactive window \overloading.
    const CImg<T>& display_graph(const char *const title=0,
                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,
                                 const char *const labelx=0, const double xmin=0, const double xmax=0,
                                 const char *const labely=0, const double ymin=0, const double ymax=0,
                                 const bool exit_on_anykey=false) const {
      CImgDisplay disp;
      return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey);

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(_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

    template<typename t>
    CImg<_cimg_Ttfloat> get_correlate(const CImg<t>& kernel, const bool boundary_conditions=true,
                                      const bool is_normalized=false) const {
      return _correlate(kernel,boundary_conditions,is_normalized,false);

Project: CImg
File: CImg.h

    template<typename t>
    static float ___draw_object3d(const CImgList<t>& opacities, const unsigned int n_primitive) {
      return n_primitive<opacities._width && opacities[n_primitive].size()==1?(float)opacities(n_primitive,0):1.0f;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<Tfloat> get_distance_eikonal(const T& value, const CImg<t>& metric) const {
      if (is_empty()) return *this;
      if (!is_sameXYZ(metric))
        throw CImgArgumentException(_cimg_instance
                                    "distance_eikonal(): image instance and metric map (%u,%u,%u,%u) have "
                                    "incompatible dimensions.",
                                    cimg_instance,
                                    metric._width,metric._height,metric._depth,metric._spectrum);
      CImg<Tfloat> result(_width,_height,_depth,_spectrum,cimg::type<Tfloat>::max()), Q;
      CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen.

      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state))
      cimg_forC(*this,c) {
        const CImg<T> img = get_shared_channel(c);
        const CImg<t> met = metric.get_shared_channel(c%metric._spectrum);
        CImg<Tfloat> res = result.get_shared_channel(c);
        unsigned int sizeQ = 0;
        state.fill(-1);

        // Detect initial seeds.
        Tfloat *ptr1 = res._data; char *ptr2 = state._data;
        cimg_for(img,ptr0,T) { if (*ptr0==value) { *ptr1 = 0; *ptr2 = 1; } ++ptr1; ++ptr2; }

        // Initialize seeds neighbors.
        ptr2 = state._data;
        cimg_forXYZ(img,x,y,z) if (*(ptr2++)==1) {
          if (x - 1>=0 && state(x - 1,y,z)==-1) {
            const Tfloat dist = res(x - 1,y,z) = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z);
          }
          if (x + 1<width() && state(x + 1,y,z)==-1) {
            const Tfloat dist = res(x + 1,y,z) = __distance_eikonal(res,met(x + 1,y,z),x + 1,y,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x + 1,y,z);
          }
          if (y - 1>=0 && state(x,y - 1,z)==-1) {
            const Tfloat dist = res(x,y - 1,z) = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z);
          }
          if (y + 1<height() && state(x,y + 1,z)==-1) {
            const Tfloat dist = res(x,y + 1,z) = __distance_eikonal(res,met(x,y + 1,z),x,y + 1,z);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y + 1,z);
          }
          if (z - 1>=0 && state(x,y,z - 1)==-1) {
            const Tfloat dist = res(x,y,z - 1) = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1);
          }
          if (z + 1<depth() && state(x,y,z + 1)==-1) {
            const Tfloat dist = res(x,y,z + 1) = __distance_eikonal(res,met(x,y,z + 1),x,y,z + 1);
            Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z + 1);
          }
        }

        // Propagate front.
        while (sizeQ) {
          int x = -1, y = -1, z = -1;
          while (sizeQ && x<0) {
            x = (int)Q(0,1); y = (int)Q(0,2); z = (int)Q(0,3);
            Q._priority_queue_remove(sizeQ);
            if (state(x,y,z)==1) x = -1; else state(x,y,z) = 1;
          }
          if (x>=0) {
            if (x - 1>=0 && state(x - 1,y,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z);
              if (dist<res(x - 1,y,z)) {
                res(x - 1,y,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z);
              }
            }
            if (x + 1<width() && state(x + 1,y,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x + 1,y,z),x + 1,y,z);
              if (dist<res(x + 1,y,z)) {
                res(x + 1,y,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x + 1,y,z);
              }
            }
            if (y - 1>=0 && state(x,y - 1,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z);
              if (dist<res(x,y - 1,z)) {
                res(x,y - 1,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z);
              }
            }
            if (y + 1<height() && state(x,y + 1,z)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y + 1,z),x,y + 1,z);
              if (dist<res(x,y + 1,z)) {
                res(x,y + 1,z) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y + 1,z);
              }
            }
            if (z - 1>=0 && state(x,y,z - 1)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1);
              if (dist<res(x,y,z - 1)) {
                res(x,y,z - 1) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1);
              }
            }
            if (z + 1<depth() && state(x,y,z + 1)!=1) {
              const Tfloat dist = __distance_eikonal(res,met(x,y,z + 1),x,y,z + 1);
              if (dist<res(x,y,z + 1)) {
                res(x,y,z + 1) = dist; Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z + 1);
              }
            }
          }
        }
      }
      return result;

Project: CImg
File: CImg.h

    template<typename tz,typename tc>
    CImg<T>& draw_line(CImg<tz>& zbuffer,
                       const int x0, const int y0, const float z0,
                       const int x1, const int y1, const float z1,
                       const tc *const color, const float opacity=1,
                       const unsigned int pattern=~0U, const bool init_hatch=true) {
      typedef typename cimg::superset<tz,float>::type tzfloat;
      if (is_empty() || z0<=0 || z1<=0) 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);
      static unsigned int hatch = ~0U - (~0U>>1);
      if (init_hatch) hatch = ~0U - (~0U>>1);
      const bool xdir = x0<x1, ydir = y0<y1;
      int
        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
      tzfloat
        Z0 = 1/(tzfloat)z0, Z1 = 1/(tzfloat)z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,
        &zleft = xdir?nz0:nz1,
        &zright = xdir?nz1:nz0,
        &zup = ydir?nz0:nz1,
        &zdown = ydir?nz1:nz0;
      if (xright<0 || xleft>=width()) return *this;
      if (xleft<0) {
        const float D = (float)xright - xleft;
        yleft-=(int)((float)xleft*((float)yright - yleft)/D);
        zleft-=(tzfloat)xleft*(zright - zleft)/D;
        xleft = 0;
      }
      if (xright>=width()) {
        const float d = (float)xright - width(), D = (float)xright - xleft;
        yright-=(int)(d*((float)yright - yleft)/D);
        zright-=(tzfloat)d*(zright - zleft)/D;
        xright = width() - 1;
      }
      if (ydown<0 || yup>=height()) return *this;
      if (yup<0) {
        const float D = (float)ydown - yup;
        xup-=(int)((float)yup*((float)xdown - xup)/D);
        zup-=(tzfloat)yup*(zdown - zup)/D;
        yup = 0;
      }
      if (ydown>=height()) {
        const float d = (float)ydown - height(), D = (float)ydown - yup;
        xdown-=(int)(d*((float)xdown - xup)/D);
        zdown-=(tzfloat)d*(zdown - zup)/D;
        ydown = height() - 1;
      }
      T *ptrd0 = data(nx0,ny0);
      tz *ptrz = zbuffer.data(nx0,ny0);
      int dx = xright - xleft, dy = ydown - yup;
      const bool steep = dy>dx;
      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
      const longT
        offx = (longT)(nx0<nx1?1:-1)*(steep?width():1),
        offy = (longT)(ny0<ny1?1:-1)*(steep?1:width());
      const ulongT
        wh = (ulongT)_width*_height,
        ndx = (ulongT)(dx>0?dx:1);
      if (opacity>=1) {
        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
          const tzfloat z = Z0 + x*dz/ndx;
          if (z>=(tzfloat)*ptrz && pattern&hatch) {
            *ptrz = (tz)z;
            T *ptrd = ptrd0; const tc *col = color;
            cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; }
          }
          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
          ptrd0+=offx; ptrz+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
          const tzfloat z = Z0 + x*dz/ndx;
          if (z>=(tzfloat)*ptrz) {
            *ptrz = (tz)z;
            T *ptrd = ptrd0; const tc *col = color;
            cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; }
          }
          ptrd0+=offx; ptrz+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
        }
      } else {
        const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
          const tzfloat z = Z0 + x*dz/ndx;
          if (z>=(tzfloat)*ptrz && pattern&hatch) {
            *ptrz = (tz)z;
            T *ptrd = ptrd0; const tc *col = color;
            cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
          }
          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
          ptrd0+=offx; ptrz+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
          const tzfloat z = Z0 + x*dz/ndx;
          if (z>=(tzfloat)*ptrz) {
            *ptrz = (tz)z;
            T *ptrd = ptrd0; const tc *col = color;
            cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
          }
          ptrd0+=offx; ptrz+=offx;
          if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
        }
      }
      return *this;

Project: CImg
File: CImg.h

    //! Construct a 2d representation of a 3d image, with XY,XZ and YZ views \inplace.
    CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) {
      if (_depth<2) return *this;
      return get_projections2d(x0,y0,z0).move_to(*this);

Project: CImg
File: CImg.h


    inline unsigned int _wait(const unsigned int milliseconds, cimg_ulong& timer) {
      if (!timer) timer = cimg::time();
      const cimg_ulong current_time = cimg::time();
      if (current_time>=timer + milliseconds) { timer = current_time; return 0; }
      const unsigned int time_diff = (unsigned int)(timer + milliseconds - current_time);
      timer = current_time + time_diff;
      cimg::sleep(time_diff);
      return time_diff;

Project: CImg
File: CImg.h


    static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2,
                             const unsigned int psizew, const unsigned int psizeh, const unsigned int psized,
                             const int x1, const int y1, const int z1,
                             const int x2, const int y2, const int z2,
                             const float max_ssd) { // 3d version.
      const T *p1 = img1.data(x1,y1,z1), *p2 = img2.data(x2,y2,z2);
      const ulongT
        offx1 = (ulongT)img1._width - psizew,
        offx2 = (ulongT)img2._width - psizew,
        offy1 = (ulongT)img1._width*img1._height - psizeh*img1._width - psizew,
        offy2 = (ulongT)img2._width*img2._height - psizeh*img2._width - psizew,
        offz1 = (ulongT)img1._width*img1._height*img1._depth - psized*img1._width*img1._height -
        psizeh*img1._width - psizew,
        offz2 = (ulongT)img2._width*img2._height*img2._depth - psized*img2._width*img2._height -
        psizeh*img2._width - psizew;
      float ssd = 0;
      cimg_forC(img1,c) {
        for (unsigned int k = 0; k<psized; ++k) {
          for (unsigned int j = 0; j<psizeh; ++j) {
            for (unsigned int i = 0; i<psizew; ++i)
              ssd += cimg::sqr(*(p1++) - *(p2++));
            if (ssd>max_ssd) return max_ssd;
            p1+=offx1; p2+=offx2;
          }
          p1+=offy1; p2+=offy2;
        }
        p1+=offz1; p2+=offz2;
      }
      return ssd;

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
    return instance.get_acos();

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Ttfloat> get_convolve(const CImg<t>& kernel, const bool boundary_conditions=true,
                                     const bool is_normalized=false) const {
      return _correlate(CImg<t>(kernel._data,kernel.size()/kernel._spectrum,1,1,kernel._spectrum,true).
                        get_mirror('x').resize(kernel,-1),boundary_conditions,is_normalized,true);

Project: CImg
File: CImg.h

    template<typename tf, typename tc, typename te>
    CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
      if (!is_sameXY(elevation) || elevation._depth>1 || elevation._spectrum>1)
        throw CImgArgumentException(_cimg_instance
                                    "get_elevation3d(): Instance and specified elevation (%u,%u,%u,%u,%p) "
                                    "have incompatible dimensions.",
                                    cimg_instance,
                                    elevation._width,elevation._height,elevation._depth,
                                    elevation._spectrum,elevation._data);
      if (is_empty()) return *this;
      float m, M = (float)max_min(m);
      if (M==m) ++M;
      colors.assign();
      const unsigned int size_x1 = _width - 1, size_y1 = _height - 1;
      for (unsigned int y = 0; y<size_y1; ++y)
        for (unsigned int x = 0; x<size_x1; ++x) {
          const unsigned char
            r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
            g = (unsigned char)(_spectrum>1?((*this)(x,y,1) - m)*255/(M-m):r),
            b = (unsigned char)(_spectrum>2?((*this)(x,y,2) - m)*255/(M-m):_spectrum>1?0:r);
          CImg<tc>::vector((tc)r,(tc)g,(tc)b).move_to(colors);
        }
      const typename CImg<te>::_functor2d_int func(elevation);
      return elevation3d(primitives,func,0,0,_width - 1.0f,_height - 1.0f,_width,_height);

Project: CImg
File: CImg.h

    template<typename t1, typename t2>
    CImg<intT> _patchmatch(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 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
                                    "patchmatch(): 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
                                    "patchmatch(): 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
                                    "patchmatch(): 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
                                    "patchmatch(): Specified guide (%u,%u,%u,%u,%p) has invalid dimensions "
                                    "considering instance and patch image 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> map(_width,_height,_depth,patch_image._depth>1?3:2);
      CImg<floatT> score(_width,_height,_depth);
      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;

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

        // Initialize correspondence map.
        if (guide) 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 = std::min(std::max((int)guide(x,y,z,0),cx1),patch_image.width() - 1 - cx2),
              v = std::min(std::max((int)guide(x,y,z,1),cy1),patch_image.height() - 1 - cy2),
              w = std::min(std::max((int)guide(x,y,z,2),cz1),patch_image.depth() - 1 - cz2);
            map(x,y,z,0) = u;
            map(x,y,z,1) = v;
            map(x,y,z,2) = w;
            score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                       x - cx1,y - cy1,z - cz1,
                                       u - cx1,v - cy1,w - cz1,cimg::type<float>::inf());
          } else 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)),
              v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2)),
              w = (int)cimg::round(cimg::rand(cz1,patch_image.depth() - 1 - cz2));
            map(x,y,z,0) = u;
            map(x,y,z,1) = v;
            map(x,y,z,2) = w;
            score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                       x - cx1,y - cy1,z - cz1,
                                       u - cx1,v - cy1,w - cz1,cimg::type<float>::inf());
          }

        // Start iteration loop.
        cimg_abort_init;
        for (unsigned int iter = 0; iter<nb_iterations; ++iter) {
          cimg_abort_test;
          const bool is_even = !(iter%2);

          cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(_width>64 && iter<nb_iterations-2))
          cimg_forXYZ(*this,X,Y,Z) {
            const int
              x = is_even?X:width() - 1 - X,
              y = is_even?Y:height() - 1 - Y,
              z = is_even?Z:depth() - 1 - 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;

            // Propagation.
            if (is_even) {
              if (x>0) { // Compare with left neighbor.
                const int u = map(x - 1,y,z,0), v = map(x - 1,y,z,1), w = 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) {
                  const float
                    current_score = score(x,y,z),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                    xp,yp,zp,u + 1 - cx1,v - cy1,w - cz1,current_score);
                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u + 1; map(x,y,z,1) = v; map(x,y,z,2) = w; }
                }
              }
              if (y>0) { // Compare with up neighbor.
                const int u = map(x,y - 1,z,0), v = map(x,y - 1,z,1), w = 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() - cx2) {
                  const float
                    current_score = score(x,y,z),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                    xp,yp,zp,u - cx1,v + 1 - cy1,w - cz1,current_score);
                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v + 1; map(x,y,z,2) = w; }
                }
              }
              if (z>0) { // Compare with backward neighbor.
                const int u = map(x,y,z - 1,0), v = map(x,y,z - 1,1), w = 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) {
                  const float
                    current_score = score(x,y,z),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                    xp,yp,zp,u - cx1,v - cy1,w + 1 - cz1,current_score);
                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w + 1; }
                }
              }
            } else {
              if (x<width() - 1) { // Compare with right neighbor.
                const int u = map(x + 1,y,z,0), v = map(x + 1,y,z,1), w = 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) {
                  const float
                    current_score = score(x,y,z),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                    xp,yp,zp,u - 1 - cx1,v - cy1,w - cz1,current_score);
                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u - 1; map(x,y,z,1) = v; map(x,y,z,2) = w; }
                }
              }
              if (y<height() - 1) { // Compare with bottom neighbor.
                const int u = map(x,y + 1,z,0), v = map(x,y + 1,z,1), w = 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) {
                  const float
                    current_score = score(x,y,z),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                    xp,yp,zp,u - cx1,v - 1 - cy1,w - cz1,current_score);
                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v - 1; map(x,y,z,2) = w; }
                }
              }
              if (z<depth() - 1) { // Compare with forward neighbor.
                const int u = map(x,y,z + 1,0), v = map(x,y,z + 1,1), w = 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) {
                  const float
                    current_score = score(x,y,z),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                    xp,yp,zp,u - cx1,v - cy1,w - 1 - cz1,current_score);
                  if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w - 1; }
                }
              }
            }

            // Randomization.
            const int u = map(x,y,z,0), v = map(x,y,z,1), w = map(x,y,z,2);
            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) {
              const int
                ui = (int)cimg::round(cimg::rand(std::max((float)cx1,u - dw),
                                                 std::min(patch_image.width() - 1.0f - cx2,u + dw))),
                vi = (int)cimg::round(cimg::rand(std::max((float)cy1,v - dh),
                                                 std::min(patch_image.height() - 1.0f - cy2,v + dh))),
                wi = (int)cimg::round(cimg::rand(std::max((float)cz1,w - dd),
                                                 std::min(patch_image.depth() - 1.0f - cz2,w + dd)));
              if (ui!=u || vi!=v || wi!=w) {
                const float
                  current_score = score(x,y,z),
                  D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
                                  xp,yp,zp,ui - cx1,vi - cy1,wi - cz1,current_score);
                if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = ui; map(x,y,z,1) = vi; map(x,y,z,2) = wi; }
                dw = std::max(5.0f,dw*0.5f); dh = std::max(5.0f,dh*0.5f); dd = std::max(5.0f,dd*0.5f);
              }
            }
          }
        }

      } else { // 2d version.

        // Initialize correspondence map.
        if (guide) 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 = std::min(std::max((int)guide(x,y,0),cx1),patch_image.width() - 1 - cx2),
              v = std::min(std::max((int)guide(x,y,1),cy1),patch_image.height() - 1 - cy2);
            map(x,y,0) = u;
            map(x,y,1) = v;
            score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height,
                                     x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf());
          } else 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)),
              v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2));
            map(x,y,0) = u;
            map(x,y,1) = v;
            score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height,
                                     x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf());
          }

        // Start iteration loop.
        for (unsigned int iter = 0; iter<nb_iterations; ++iter) {
          const bool is_even = !(iter%2);

          cimg_pragma_openmp(parallel for cimg_openmp_if(_width>64 && iter<nb_iterations-2))
          cimg_forXY(*this,X,Y) {
            const int
              x = is_even?X:width() - 1 - X,
              y = is_even?Y:height() - 1 - 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;

            // Propagation.
            if (is_even) {
              if (x>0) { // Compare with left neighbor.
                const int u = map(x - 1,y,0), v = map(x - 1,y,1);
                if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2) {
                  const float
                    current_score = score(x,y),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,
                                    xp,yp,u + 1 - cx1,v - cy1,current_score);
                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u + 1; map(x,y,1) = v; }
                }
              }
              if (y>0) { // Compare with up neighbor.
                const int u = map(x,y - 1,0), v = map(x,y - 1,1);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 - 1 && v<patch_image.height() - 1 - cy2) {
                  const float
                    current_score = score(x,y),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,
                                    xp,yp,u - cx1,v + 1 - cy1,current_score);
                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v + 1; }
                }
              }
            } else {
              if (x<width() - 1) { // Compare with right neighbor.
                const int u = map(x + 1,y,0), v = map(x + 1,y,1);
                if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 &&
                    v>=cy1 && v<patch_image.height() - cy2) {
                  const float
                    current_score = score(x,y),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,
                                    xp,yp,u - 1 - cx1,v - cy1,current_score);
                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u - 1; map(x,y,1) = v; }
                }
              }
              if (y<height() - 1) { // Compare with bottom neighbor.
                const int u = map(x,y + 1,0), v = map(x,y + 1,1);
                if (u>=cx1 && u<patch_image.width() - cx2 &&
                    v>=cy1 + 1 && v<patch_image.height() + 1 - cy2) {
                  const float
                    current_score = score(x,y),
                    D = _patchmatch(*this,patch_image,patch_width,patch_height,
                                    xp,yp,u - cx1,v - 1 - cy1,current_score);
                  if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v - 1; }
                }
              }
            }

            // Randomization.
            const int u = map(x,y,0), v = map(x,y,1);
            float dw = (float)patch_image.width(), dh = (float)patch_image.height();
            for (unsigned int i = 0; i<nb_randoms; ++i) {
              const int
                ui = (int)cimg::round(cimg::rand(std::max((float)cx1,u - dw),
                                                 std::min(patch_image.width() - 1.0f - cx2,u + dw))),
                vi = (int)cimg::round(cimg::rand(std::max((float)cy1,v - dh),
                                                 std::min(patch_image.height() - 1.0f - cy2,v + dh)));
              if (ui!=u || vi!=v) {
                const float
                  current_score = score(x,y),
                  D = _patchmatch(*this,patch_image,patch_width,patch_height,
                                  xp,yp,ui - cx1,vi - cy1,current_score);
                if (D<current_score) { score(x,y) = D; map(x,y,0) = ui; map(x,y,1) = vi; }
                dw = std::max(5.0f,dw*0.5f); dh = std::max(5.0f,dh*0.5f);
              }
            }
          }
        }
      }
      if (is_matching_score) score.move_to(matching_score);
      return map;

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
      if (!img)
        throw CImgArgumentException(_cimgdisplay_instance
                                    "render(): Empty specified image.",
                                    cimgdisplay_instance);
      if (is_empty()) return *this;
      if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2,
                                                             (img._depth - 1)/2));
      if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height))
        return render(img.get_resize(_width,_height,1,-100,1));
      if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) {
        static const CImg<typename CImg<T>::ucharT> default_colormap = CImg<typename CImg<T>::ucharT>::default_LUT256();
        return render(img.get_index(default_colormap,1,false));
      }

      const T
        *data1 = img._data,
        *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1,
        *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1;

      if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);
      cimg_lock_display();

      if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
        _min = _max = 0;
        switch (cimg::X11_attr().nb_bits) {
        case 8 : { // 256 colormap, no normalization
          _set_colormap(_colormap,img._spectrum);
          unsigned char
            *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:
            new unsigned char[(size_t)img._width*img._height],
            *ptrd = (unsigned char*)ndata;
          switch (img._spectrum) {
          case 1 :
            for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
              (*ptrd++) = (unsigned char)*(data1++);
            break;
          case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
	      const unsigned char
                R = (unsigned char)*(data1++),
                G = (unsigned char)*(data2++);
	      (*ptrd++) = (R&0xf0) | (G>>4);
	    } break;
          default : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
	      const unsigned char
                R = (unsigned char)*(data1++),
                G = (unsigned char)*(data2++),
                B = (unsigned char)*(data3++);
	      (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
	    }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        case 16 : { // 16 bits colors, no normalization
          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:
            new unsigned short[(size_t)img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          const unsigned int M = 248;
          switch (img._spectrum) {
          case 1 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)*(data1++), G = val>>2;
                ptrd[0] = (val&M) | (G>>3);
                ptrd[1] = (G<<5) | (G>>1);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)*(data1++), G = val>>2;
                ptrd[0] = (G<<5) | (G>>1);
                ptrd[1] = (val&M) | (G>>3);
                ptrd+=2;
              }
            break;
          case 2 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd[1] = (G<<5);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = (G<<5);
                ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd+=2;
              }
            break;
          default :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd[1] = (G<<5) | ((unsigned char)*(data3++)>>3);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = (G<<5) | ((unsigned char)*(data3++)>>3);
                ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd+=2;
              }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        default : { // 24 bits colors, no normalization
          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:
            new unsigned int[(size_t)img._width*img._height];
          if (sizeof(int)==4) { // 32 bits int uses optimized version
            unsigned int *ptrd = ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)*(data1++);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                 const unsigned char val = (unsigned char)*(data1++);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
              break;
            default :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) |
                    (unsigned char)*(data3++);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) |
                    ((unsigned char)*(data1++)<<8);
            }
          } else {
            unsigned char *ptrd = (unsigned char*)ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = (unsigned char)*(data1++);
                  ptrd[2] = 0;
                  ptrd[3] = 0;
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = 0;
                  ptrd[2] = (unsigned char)*(data1++);
                  ptrd[3] = 0;
                  ptrd+=4;
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                ptrd[0] = 0;
                ptrd[1] = (unsigned char)*(data2++);
                ptrd[2] = (unsigned char)*(data1++);
                ptrd[3] = 0;
                ptrd+=4;
              }
              break;
            default :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = (unsigned char)*(data1++);
                  ptrd[2] = (unsigned char)*(data2++);
                  ptrd[3] = (unsigned char)*(data3++);
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = (unsigned char)*(data3++);
                  ptrd[1] = (unsigned char)*(data2++);
                  ptrd[2] = (unsigned char)*(data1++);
                  ptrd[3] = 0;
                  ptrd+=4;
                }
            }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);
            delete[] ndata;
          }
        }
        }
      } else {
        if (_normalization==3) {
          if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);
          else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }
        } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);
        const float delta = _max - _min, mm = 255/(delta?delta:1.0f);
        switch (cimg::X11_attr().nb_bits) {
        case 8 : { // 256 colormap, with normalization
          _set_colormap(_colormap,img._spectrum);
          unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:
            new unsigned char[(size_t)img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          switch (img._spectrum) {
          case 1 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
              const unsigned char R = (unsigned char)((*(data1++) - _min)*mm);
              *(ptrd++) = R;
            } break;
          case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
              const unsigned char
                R = (unsigned char)((*(data1++) - _min)*mm),
                G = (unsigned char)((*(data2++) - _min)*mm);
            (*ptrd++) = (R&0xf0) | (G>>4);
          } break;
          default :
            for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
              const unsigned char
                R = (unsigned char)((*(data1++) - _min)*mm),
                G = (unsigned char)((*(data2++) - _min)*mm),
                B = (unsigned char)((*(data3++) - _min)*mm);
              *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
            }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        case 16 : { // 16 bits colors, with normalization
          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:
            new unsigned short[(size_t)img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          const unsigned int M = 248;
          switch (img._spectrum) {
          case 1 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;
                ptrd[0] = (val&M) | (G>>3);
                ptrd[1] = (G<<5) | (val>>3);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;
                ptrd[0] = (G<<5) | (val>>3);
                ptrd[1] = (val&M) | (G>>3);
                ptrd+=2;
              }
            break;
          case 2 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd[1] = (G<<5);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = (G<<5);
                ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd+=2;
              }
            break;
          default :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd[1] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);
                ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd+=2;
              }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        default : { // 24 bits colors, with normalization
          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:
            new unsigned int[(size_t)img._width*img._height];
          if (sizeof(int)==4) { // 32 bits int uses optimized version
            unsigned int *ptrd = ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data1++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data2++) - _min)*mm)<<8);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data2++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data1++) - _min)*mm)<<8);
              break;
            default :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data1++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data2++) - _min)*mm)<<8) |
                    (unsigned char)((*(data3++) - _min)*mm);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data3++) - _min)*mm)<<24) |
                    ((unsigned char)((*(data2++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data1++) - _min)*mm)<<8);
            }
          } else {
            unsigned char *ptrd = (unsigned char*)ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[0] = 0;
                  ptrd[1] = val;
                  ptrd[2] = val;
                  ptrd[3] = val;
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[0] = val;
                  ptrd[1] = val;
                  ptrd[2] = val;
                  ptrd[3] = 0;
                  ptrd+=4;
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                ptrd[0] = 0;
                ptrd[1] = (unsigned char)((*(data2++) - _min)*mm);
                ptrd[2] = (unsigned char)((*(data1++) - _min)*mm);
                ptrd[3] = 0;
                ptrd+=4;
              }
              break;
            default :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[2] = (unsigned char)((*(data2++) - _min)*mm);
                  ptrd[3] = (unsigned char)((*(data3++) - _min)*mm);
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = (unsigned char)((*(data3++) - _min)*mm);
                  ptrd[1] = (unsigned char)((*(data2++) - _min)*mm);
                  ptrd[2] = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[3] = 0;
                  ptrd+=4;
                }
            }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);
            delete[] ndata;
          }
	}
        }
      }
      cimg_unlock_display();
      return *this;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_medcon_external(const char *const filename) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_medcon_external(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }

      CImg<charT> command(1024), filename_tmp(256), body(256);
      std::FILE *file;
      do {
        cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand());
        if ((file=std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
      } while (file);
      save_analyze(filename_tmp);
      cimg_snprintf(command,command._width,"%s -w -c dicom -o \"%s\" -f \"%s\"",
                    cimg::medcon_path(),
                    CImg<charT>::string(filename)._system_strescape().data(),
                    CImg<charT>::string(filename_tmp)._system_strescape().data());
      cimg::system(command);
      std::remove(filename_tmp);
      cimg::split_filename(filename_tmp,body);
      cimg_snprintf(filename_tmp,filename_tmp._width,"%s.img",body._data);
      std::remove(filename_tmp);

      file = std_fopen(filename,"rb");
      if (!file) {
        cimg_snprintf(command,command._width,"m000-%s",filename);
        file = std_fopen(command,"rb");
        if (!file) {
          cimg::fclose(cimg::fopen(filename,"r"));
          throw CImgIOException(_cimg_instance
                                "save_medcon_external(): Failed to save file '%s' with external command 'medcon'.",
                                cimg_instance,
                                filename);
        }
      }
      cimg::fclose(file);
      std::rename(command,filename);
      return *this;

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
    return instance.get_sin();

Project: CImg
File: CImg.h

    template<typename t1, typename t2>
    CImg<T>& draw_quiver(const CImg<t1>& flow,
                         const CImg<t2>& color, const float opacity=1,
                         const unsigned int sampling=25, const float factor=-20,
                         const bool is_arrow=true, const unsigned int pattern=~0U) {
      if (is_empty()) return *this;
      if (!flow || flow._spectrum!=2)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    flow._width,flow._height,flow._depth,flow._spectrum,flow._data);
      if (sampling<=0)
        throw CImgArgumentException(_cimg_instance
                                    "draw_quiver(): Invalid sampling value %g "
                                    "(should be >0)",
                                    cimg_instance,
                                    sampling);
      const bool colorfield = (color._width==flow._width && color._height==flow._height &&
                               color._depth==1 && color._spectrum==_spectrum);
      if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern);
      float vmax,fact;
      if (factor<=0) {
        float m, M = (float)flow.get_norm(2).max_min(m);
        vmax = (float)std::max(cimg::abs(m),cimg::abs(M));
        if (!vmax) vmax = 1;
        fact = -factor;
      } else { fact = factor; vmax = 1; }

      for (unsigned int y = sampling/2; y<_height; y+=sampling)
        for (unsigned int x = sampling/2; x<_width; x+=sampling) {
          const unsigned int X = x*flow._width/_width, Y = y*flow._height/_height;
          float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
          if (is_arrow) {
            const int xx = (int)(x + u), yy = (int)(y + v);
            if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y)._data,opacity,45,sampling/5.0f,pattern);
            else draw_arrow(x,y,xx,yy,color._data,opacity,45,sampling/5.0f,pattern);
          } else {
            if (colorfield)
              draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v),
                        color.get_vector_at(X,Y)._data,opacity,pattern);
            else draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v),
                           color._data,opacity,pattern);
          }
        }
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& tanh() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h

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

      CImg<Tfloat> res(_width,_height,_depth,4);
      const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2);
      Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2), *pd4 = res.data(0,0,0,3);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=1024))
      for (ulongT N = 0; N<whd; ++N) {
        Tfloat
	  C = (Tfloat)ps1[N],
	  M = (Tfloat)ps2[N],
	  Y = (Tfloat)ps3[N],
	  K = cimg::min(C,M,Y);
	if (K>=255) C = M = Y = 0;
	else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; }
        pd1[N] = (Tfloat)cimg::cut(C,0,255),
        pd2[N] = (Tfloat)cimg::cut(M,0,255),
        pd3[N] = (Tfloat)cimg::cut(Y,0,255),
        pd4[N] = (Tfloat)cimg::cut(K,0,255);
      }
      return res;

Project: CImg
File: CImg.h


      static double mp_memcopy(_cimg_math_parser& mp) {
        longT siz = (longT)_mp_arg(4);
        const longT inc_d = (longT)_mp_arg(5), inc_s = (longT)_mp_arg(6);
        const float
          _opacity = (float)_mp_arg(7),
          opacity = (float)cimg::abs(_opacity),
          omopacity = 1 - std::max(_opacity,0.0f);
        if (siz>0) {
          const bool
            is_doubled = mp.opcode[8]<=1,
            is_doubles = mp.opcode[15]<=1;
          if (is_doubled && is_doubles) { // (double*) <- (double*)
            double *ptrd = _mp_memcopy_double(mp,(unsigned int)mp.opcode[2],&mp.opcode[8],siz,inc_d);
            const double *ptrs = _mp_memcopy_double(mp,(unsigned int)mp.opcode[3],&mp.opcode[15],siz,inc_s);
            if (inc_d==1 && inc_s==1 && _opacity>=1) {
              if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(double));
              else std::memmove(ptrd,ptrs,siz*sizeof(double));
            } else {
              if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d) {
                if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; }
                else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; }
              } else { // Overlapping buffers
                CImg<doubleT> buf((unsigned int)siz);
                cimg_for(buf,ptr,double) { *ptr = *ptrs; ptrs+=inc_s; }
                ptrs = buf;
                if (_opacity>=1) while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }
                else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**(ptrs++); ptrd+=inc_d; }
              }
            }
          } else if (is_doubled && !is_doubles) { // (double*) <- (float*)
            double *ptrd = _mp_memcopy_double(mp,(unsigned int)mp.opcode[2],&mp.opcode[8],siz,inc_d);
            const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[15],siz,inc_s);
            if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; }
            else while (siz-->0) { *ptrd = omopacity**ptrd + _opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; }
          } else if (!is_doubled && is_doubles) { // (float*) <- (double*)
            float *ptrd = _mp_memcopy_float(mp,&mp.opcode[8],siz,inc_d);
            const double *ptrs = _mp_memcopy_double(mp,(unsigned int)mp.opcode[3],&mp.opcode[15],siz,inc_s);
            if (_opacity>=1) while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }
            else while (siz-->0) { *ptrd = (float)(omopacity**ptrd + opacity**ptrs); ptrd+=inc_d; ptrs+=inc_s; }
          } else { // (float*) <- (float*)
            float *ptrd = _mp_memcopy_float(mp,&mp.opcode[8],siz,inc_d);
            const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[15],siz,inc_s);
            if (inc_d==1 && inc_s==1 && _opacity>=1) {
              if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(float));
              else std::memmove(ptrd,ptrs,siz*sizeof(float));
            } else {
              if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d) {
                if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; }
                else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; }
              } else { // Overlapping buffers
                CImg<floatT> buf((unsigned int)siz);
                cimg_for(buf,ptr,float) { *ptr = *ptrs; ptrs+=inc_s; }
                ptrs = buf;
                if (_opacity>=1) while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }
                else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**(ptrs++); ptrd+=inc_d; }
              }
            }
          }
        }
        return _mp_arg(1);

Project: CImg
File: CImg.h

    //! Compute the hyperbolic sine of each pixel value \newinstance.
    CImg<Tfloat> get_sinh() const {
      return CImg<Tfloat>(*this,false).sinh();

Project: CImg
File: CImg.h

    **/
    CImg<T>& cosh() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImg<T>& displacement(const CImg<T>& source, const float smoothness=0.1f, const float precision=5.0f,
                          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()) {
      return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,guide).
        move_to(*this);

Project: CImg
File: CImg.h

    template<typename tz, typename tc, typename tl>
    CImg<T>& draw_triangle(CImg<tz>& zbuffer,
                           const int x0, const int y0, const float z0,
                           const int x1, const int y1, const float z1,
                           const int x2, const int y2, const float z2,
                           const tc *const color,
                           const CImg<tl>& light,
                           const int lx0, const int ly0,
                           const int lx1, const int ly1,
                           const int lx2, const int ly2,
                           const float opacity=1) {
      typedef typename cimg::superset<tz,float>::type tzfloat;
      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 (light._depth>1 || light._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data);
      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);
      if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,
                                                     +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
      static const T maxval = (T)std::min(cimg::type<T>::max(),(T)cimg::type<tc>::max());
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      const ulongT
        whd = (ulongT)_width*_height*_depth,
        lwh = (ulongT)light._width*light._height,
        offx = _spectrum*whd;
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
      tzfloat nz0 = 1/(tzfloat)z0, nz1 = 1/(tzfloat)z1, nz2 = 1/(tzfloat)z2;
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);
      if (ny0>=height() || ny2<0) return *this;
      tzfloat
        pzl = (nz1 - nz0)/(ny1 - ny0),
        pzr = (nz2 - nz0)/(ny2 - ny0),
        pzn = (nz2 - nz1)/(ny2 - ny1),
        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
        if (y==ny1) { zl = nz1; pzl = pzn; }
        int
          xleft = xleft0, xright = xright0,
          lxleft = lxleft0, lxright = lxright0,
          lyleft = lyleft0, lyright = lyright0;
        tzfloat zleft = zl, zright = zr;
        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);
        const int
          dx = xright - xleft,
          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
          rlx = dx?(lxright - lxleft)/dx:0,
          rly = dx?(lyright - lyleft)/dx:0,
          slx = lxright>lxleft?1:-1,
          sly = lyright>lyleft?1:-1,
          ndlx = dlx - (dx?dx*(dlx/dx):0),
          ndly = dly - (dx?dx*(dly/dx):0);
        const tzfloat pentez = (zright - zleft)/dx;
        int errlx = dx>>1, errly = errlx;
        if (xleft<0 && dx) {
          zleft-=xleft*(zright - zleft)/dx;
          lxleft-=xleft*(lxright - lxleft)/dx;
          lyleft-=xleft*(lyright - lyleft)/dx;
        }
        if (xleft<0) xleft = 0;
        if (xright>=width() - 1) xright = width() - 1;
        T *ptrd = data(xleft,y,0,0);
        tz *ptrz = xleft<=xright?zbuffer.data(xleft,y):0;
        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tc *col = color;
              const tl *lig = &light._atXY(lxleft,lyleft);
              cimg_forC(*this,c) {
                const tl l = *lig;
                const tc cval = *(col++);
                *ptrd = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval);
                ptrd+=whd; lig+=lwh;
              }
              ptrd-=offx;
            }
            zleft+=pentez;
            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
            if (zleft>=(tzfloat)*ptrz) {
              *ptrz = (tz)zleft;
              const tc *col = color;
              const tl *lig = &light._atXY(lxleft,lyleft);
              cimg_forC(*this,c) {
                const tl l = *lig;
                const tc cval = *(col++);
                const T val = (T)(l<1?l*cval:(2 - l)*cval + (l - 1)*maxval);
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
                ptrd+=whd; lig+=lwh;
              }
              ptrd-=offx;
            }
            zleft+=pentez;
            lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
            lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
          }
        zr+=pzr; zl+=pzl;
      }
      return *this;

Project: CImg
File: CImg.h

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