#ifndef BILINEARINT_HEADER #define BILINEARINT_HEADER 1 /////////////////////////////////////////////////////////////// //! docentry="Image.Image Processing.Interpolation" //! lib=IPFilter //! author="Kieron Messer" //! rcsid="$Id: BiLinearInt.hh,v 1.6 2000/02/16 14:12:30 ees1cg Exp $" //! file="amma/Image/IPStream/IPFilter/BiLinearInt.hh" //! date="05/05/99" #include "amma/DP/Process.hh" #include "amma/Image.hh" #include "amma/RGBImage.hh" #include "amma/ReRGBImg.hh" #include "amma/Image2Iter.hh" //! userlevel=Develop //: Perform Bi-Linear Interpolation of any image type template class IPBiLinearIntBodyC : public DPProcessBodyC,ImageC > { public: IPBiLinearIntBodyC(const ImageRectangleC &ir); //: Constructor. IPBiLinearIntBodyC(const IPBiLinearIntBodyC &oth) : DPProcessBodyC,ImageC >(oth), rec(oth.rec) {} //: Copy constructor. virtual ImageC Apply(const ImageC &img); //: Interpolate input image working rectangle into //: output image rectangle (specified in constructor. virtual BodyRefCounterVC &Copy() const; //: Creat a copy of this object. protected: ImageRectangleC rec; }; template IPBiLinearIntBodyC::IPBiLinearIntBodyC(const ImageRectangleC & ir) : rec(ir) {} inline RGBPointC operator*(RealT val,const ByteRGBValueC &rgb) { return val * RGBPointC(rgb); } template ImageC IPBiLinearIntBodyC::Apply(const ImageC &im) { ImageC res(rec); IntT imRnum = im.Rectangle().Rnum(); IntT imCnum = im.Rectangle().Cnum(); PixelC y1,y2,y3,y4; RealT t, u; RealT minC, minR; RealT jOff = im.Rectangle().LCol(); RealT j,i = im.Rectangle().TRow(); // First check for degenerate cases... if(imRnum <= 0 && imCnum <= 0) // Empty image. return res; if(imRnum == 1 && imCnum == 1) { // Just one pixel. res[res.Rectangle().Origin()] = im[im.Rectangle().Origin()]; return res; } RealT stepC = ((RealT)imCnum-1.01)/(RealT)rec.Rectangle().Cnum(); RealT stepR = ((RealT)imRnum-1.01)/(RealT)rec.Rectangle().Rnum(); if(imRnum == 1) { // Just one row. y3.Row() = im.Rectangle().Origin().Row(); y4.Row() = y3.Row(); j = jOff; for(ImageIterC it(res);it.IsElm();it.Next()) { minC = Floor(j); t = (j - minC); j += stepC; IntT iMinC = (IntT) minC; y4.Col() = iMinC; y3.Col() = iMinC+1; if(iMinC == im.Rectangle().RCol()) {// Hack!!! cerr << "ERROR: Overflow in interpolation (C). \n"; break; } it.Data() = (OutT)(((1.0-t) * im[y4]) + ( t * im[y3]) ); } return res; } if(imCnum == 1) { // Just one columb. y2.Col() = im.Rectangle().Origin().Col(); y4.Col() = y2.Col(); for(ImageIterC it(res);it.IsElm();it.Next()) { minR = Floor(i); u = (i - minR); i += stepR; IntT iMinR = (IntT) minR; y4.Row() = iMinR; y2.Row() = iMinR+1; if(iMinR == im.Rectangle().BRow()) {// Hack!!! cerr << "ERROR: Overflow in interpolation (R) \n"; break; } it.Data() = (OutT)(((1.0-u) * im[y4]) + ( u * im[y2]) ); } return res; } for(ImageIterC it(res);it.IsElm();) { minR = Floor(i); u = (i - minR); i += stepR; IntT iMinR = (IntT) minR; j = jOff; y1.Row() = iMinR+1; y2.Row() = iMinR+1; y3.Row() = iMinR; y4.Row() = iMinR; do { minC = Floor(j); t = (j - minC); j += stepC; IntT iMinC = (IntT) minC; y1.Col() = iMinC+1; y3.Col() = iMinC+1; y2.Col() = iMinC; y4.Col() = iMinC; it.Data() = (OutT)( ((1.0-t) * (1.0-u) * im[y4]) + (t*(1.0-u)*im[y3]) + ((1.0-t)*u*im[y2]) + (t*u*im[y1]) ); } while(it.RNext()); // True while in same row. } return res; } //! userlevel=Normal //: Perform bi-linear interpolation on most image amma image types template class IPBiLinearIntC : public DPProcessC,ImageC > { public: IPBiLinearIntC(const ImageRectangleC & ir); //: Image rectangle into which interpolated image will be returned }; //: Creat a copy of this object. template BodyRefCounterVC &IPBiLinearIntBodyC::Copy() const { return *new IPBiLinearIntBodyC(*this); } //////////////////////////////////////////// //: Constructor. template IPBiLinearIntC::IPBiLinearIntC(const ImageRectangleC & ir) : DPProcessC,ImageC >(*new IPBiLinearIntBodyC(ir)) {} //: Overloads stream operator to apply filters to images of any type template inline ImageC operator>> (const ImageC &oth, IPBiLinearIntC &op) { return op.Apply (oth); } #endif