CVD 0.8
cvd/image_interpolate.h
00001 #ifndef CVD_IMAGE_INTERPOLATE_H
00002 #define CVD_IMAGE_INTERPOLATE_H
00003 
00004 #include <TooN/TooN.h>
00005 #include <cvd/internal/pixel_operations.h>
00006 #include <cvd/internal/rgb_components.h>
00007 #include <cvd/vector_image_ref.h>
00008 #include <math.h>
00009 
00010 namespace CVD
00011 {
00015     namespace Interpolate
00016     {
00023         class NearestNeighbour{};
00024 
00042         class Bilinear{};
00043 
00056         class Bicubic{};
00057     };
00058 
00059     #ifdef DOXYGEN_INCLUDE_ONLY_FOR_DOCS
00060 
00061 
00062 
00063 
00064 
00065         template<class I, class P> class image_interpolate
00066         {
00067           public:
00070             image_interpolate(const BasicImage<P>& i);
00071 
00074             bool in_image(const TooN::Vector<2>& pos) const;
00075 
00079             float_type operator[](const TooN::Vector<2>& pos) const;
00080 
00082             TooN::Vector<2> min() const;
00084             TooN::Vector<2> max() const;
00085         };
00086     #endif
00087 
00088 
00089 
00090     #ifndef DOXYGEN_IGNORE_INTERNAL
00091 
00092     template<class I, class C> class image_interpolate;
00093 
00094     //Zero order (nearest neighbour)
00095 
00096     template<class C> class image_interpolate<Interpolate::NearestNeighbour, C>
00097     {
00098         private:
00099             const BasicImage<C>* im;
00100 
00101             int round(double d) const
00102             {
00103                 if(d < 0)
00104                     return (int)ceil(d - .5);
00105                 else
00106                     return (int)floor(d + .5);
00107             }
00108 
00109             ImageRef to_ir(const TooN::Vector<2>& v) const
00110             {
00111                 return ImageRef(round(v[0]), round(v[1]));
00112             }
00113 
00114             typedef typename Pixel::traits<C>::float_type FT;
00115     
00116         public:
00117             image_interpolate(const BasicImage<C>& i)
00118             :im(&i)
00119             {}
00120 
00121             bool in_image(const TooN::Vector<2>& pos) const
00122             {
00123                 return im->in_image(to_ir(pos));
00124             }
00125 
00126             FT operator[](const TooN::Vector<2>& pos) const
00127             {
00128                 return (*im)[to_ir(pos)];
00129             }
00130 
00131             TooN::Vector<2> min() const
00132             {
00133                 return TooN::makeVector( 0, 0);
00134             }
00135 
00136             TooN::Vector<2> max() const
00137             {
00138                 return vec(im->size());
00139             }
00140 
00141             
00142     };
00143 
00144     template<class T> class image_interpolate<Interpolate::Bilinear, T>
00145     {
00146         private:
00147             const BasicImage<T>* im;
00148 
00149             TooN::Vector<2> floor(const TooN::Vector<2>& v) const
00150             {
00151                 return TooN::makeVector( ::floor(v[0]), ::floor(v[1]));
00152             }
00153 
00154             TooN::Vector<2> ceil(const TooN::Vector<2>& v) const
00155             {
00156                 return TooN::makeVector( ::ceil(v[0]), ::ceil(v[1]));
00157             }
00158 
00159             typedef typename Pixel::traits<T>::float_type FT;
00160 
00161         public:
00162             image_interpolate(const BasicImage<T>& i)
00163             :im(&i)
00164             {}
00165 
00166             bool in_image(const TooN::Vector<2>& pos) const
00167             {
00168                 return im->in_image(ir(floor(pos))) && im->in_image(ir(ceil(pos)));
00169             }
00170 
00171             FT operator[](const TooN::Vector<2>& pos) const
00172             {
00173                 TooN::Vector<2> delta =  pos - floor(pos);
00174 
00175                 ImageRef p = ir(floor(pos));
00176 
00177                 double x = delta[0];
00178                 double y = delta[1];
00179 
00180                 FT ret;
00181 
00182                 for(unsigned int i=0; i < Pixel::Component<T>::count; i++)
00183                 {
00184                     float a, b=0, c=0, d=0;
00185 
00186                     a = Pixel::Component<T>::get((*im)[p + ImageRef(0,0)], i) * (1-x) * (1-y);
00187 
00188                     if(x != 0)
00189                         b = Pixel::Component<T>::get((*im)[p + ImageRef(1,0)], i) * x * (1-y);
00190                     
00191                     if(y != 0)
00192                     c = Pixel::Component<T>::get((*im)[p + ImageRef(0,1)], i) * (1-x) * y;
00193 
00194                     if(x !=0 && y != 0)
00195                         d = Pixel::Component<T>::get((*im)[p + ImageRef(1,1)], i) * x * y;
00196                     
00197                     Pixel::Component<FT>::get(ret, i) = a + b + c + d;
00198                 }
00199 
00200                 return ret;
00201             }
00202 
00203             TooN::Vector<2> min() const
00204             {
00205                 return TooN::makeVector( 0, 0);
00206             }
00207 
00208             TooN::Vector<2> max() const
00209             {
00210                 return vec(im->size());
00211             }
00212 
00213     };
00214 
00215 
00216     template<class T> class image_interpolate<Interpolate::Bicubic, T>
00217     {
00218         private:
00219             const BasicImage<T>* im;
00220 
00221             float p(float f) const
00222             {
00223                 return f <0 ? 0 : f;
00224             }
00225 
00226             float r(float x) const
00227             {
00228                 return (  pow(p(x+2), 3) - 4 * pow(p(x+1),3) + 6 * pow(p(x), 3) - 4* pow(p(x-1),3))/6;
00229             }
00230 
00231             typedef typename Pixel::traits<T>::float_type FT;
00232 
00233         public:
00234             image_interpolate(const BasicImage<T>& i)
00235             :im(&i)
00236             {}
00237 
00238             bool in_image(const TooN::Vector<2>& pos) const
00239             {
00240                 return pos[0] >= 1 && pos[1] >=1 && pos[0] < im->size().x-2 && pos[1] < im->size().y - 2;
00241             }
00242 
00243             FT operator[](const TooN::Vector<2>& pos) const
00244             {
00245                 int x = (int)floor(pos[0]);
00246                 int y = (int)floor(pos[1]);
00247                 float dx = pos[0] - x;
00248                 float dy = pos[1] - y;
00249 
00250                 //Algorithm as described in http://astronomy.swin.edu.au/~pbourke/colour/bicubic/
00251                 FT ret;
00252                 for(unsigned int i=0; i < Pixel::Component<T>::count; i++)
00253                 {
00254                     float s=0;
00255 
00256                     for(int m = -1; m < 3; m++)
00257                         for(int n = -1; n < 3; n++)
00258                             s += Pixel::Component<T>::get((*im)[y+n][x+m], i) * r(m - dx) * r(dy-n);
00259                         
00260                     Pixel::Component<FT>::get(ret, i)= s;
00261                 }
00262 
00263                 return ret;
00264             }
00265 
00266             TooN::Vector<2> min() const
00267             {
00268                 return TooN::makeVector( 1, 1);
00269             }
00270 
00271             TooN::Vector<2> max() const
00272             {
00273                 return TooN::makeVector( im->size().x - 2, im->size().y - 2);
00274             }
00275 
00276     };
00277     #endif
00278 
00279 }
00280 
00281 #endif