text: /*                       
  	This file is part of the CVD Library.
  
  	Copyright (C) 2005 The Authors
  
  	This library is free software; you can redistribute it and/or
  	modify it under the terms of the GNU Lesser General Public
  	License as published by the Free Software Foundation; either
  	version 2.1 of the License, or (at your option) any later version.
  
  	This library is distributed in the hope that it will be useful,
  	but WITHOUT ANY WARRANTY; without even the implied warranty of
  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  	Lesser General Public License for more details.
  
  	You should have received a copy of the GNU Lesser General Public
  	License along with this library; if not, write to the Free Software
  	Foundation, Inc., 
      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
  #ifndef CVD_CONVERT_PIXEL_TYPES_H
  #define CVD_CONVERT_PIXEL_TYPES_H
  
  #include <math.h>
  #include <string.h>
  
  #include <cvd/abs.h>
  #include <cvd/internal/scalar_convert.h>
  #include <cvd/internal/builtin_components.h>
  #include <cvd/internal/rgb_components.h>
  #include <cvd/internal/is_pod.h>
  #include <limits>
  
  namespace CVD{namespace Pixel
  {
    //All "conversion" classes must have a "void convert_pixel(from, to)"
    //nonstatic templated member.
    
    //This conversion knows how to convert from any size pixel to any other.
    
    template <class From, class To, int CF=Pixel::Component<From>::count, int CT=Pixel::Component<To>::count> struct GenericConversion;
  
    template <class From, class To> struct GenericConversion<From,To,1,1> {
      static inline void convert(const From& from, To& to) { 
        to = scalar_convert<To,From>(from);
      }
    };
    
    template <class From, class To, int N> struct GenericConversion<From,To,N,N> {
      typedef typename Pixel::Component<From>::type FromS;
      typedef typename Pixel::Component<To>::type ToS;
      static inline void convert(const From& from, To& to) { 
        for (int i=0; i<N; i++)
  	Pixel::Component<To>::get(to,i) = scalar_convert<ToS,FromS>(Pixel::Component<From>::get(from,i));
      }
    };
  
    template <class T, int N> struct GenericConversion<T,T,N,N> { 
      static inline void convert(const T& from, T& to) { 
        to = from;
      }
    };
  
    template <class T, int N> struct GenericConversion<T[N],T[N], N, N> { 
      typedef T array[N];
      static inline void convert(const array& from, array& to) { 
        for (int i=0; i<N; i++)
  	to[i] = from[i];
      }
    };
  
    template <class Rgbish, class Scalar> struct CIE {
      static inline void convert(const Rgbish& from, Scalar& to) {
        // "Correct" values are:
  	  // const double wr=0.299, wg=0.587, wb=0.114;
  	  // Since these are not representable as floating point values
  	  // They do not sum exactly to 1.
  	  // Instead, convert them using  floor(x *  0x10000 + 0.5)/0x10000
  	  // So that they use exactly 16 bits of precision.
  	  // This should be OK for pretty mych everything
  	  // 0.299 ~= 19595/0x10000  == 0x4c8bp-16  == 0.2989959716796875
  	  // 0.587 ~= 38470/0x10000  == 0x9646p-16  == 0.587005615234375
  	  // 0.114 ~= 7471/0x10000   == 0x1d2fp-16  == 0.1139984130859375
  	  // These will sum exactly to 1. C++ does not yet allow hex floating point
  	  // literals
  	  const double wr=0.2989959716796875, wg=0.587005615234375, wb=0.1139984130859375;
  	  
  	  /* 
        The old method does not work properly because the conversion to double from int_type
  	  is inexact. Ttuncation of this causes errors. However, it is unnecessary to convert
  	  to the double pixel type first: the arithmetic merely needs to be done with doubles.
  	  
        to = scalar_convert<Scalar,double>(wr*scalar_convert<double,typename Pixel::Component<Rgbish>::type>(from.red) + 
  					 wg*scalar_convert<double,typename Pixel::Component<Rgbish>::type>(from.green) + 
  					 wb*scalar_convert<double,typename Pixel::Component<Rgbish>::type>(from.blue));
  					 
  	  Fortunately, we have forseen this eventuality, and scalar_convert can convert from
  	  type A, to type B when pixel type B is held in a variable of type C
  	  */
  	  to = scalar_convert<Scalar,typename Pixel::Component<Rgbish>::type,double>(wr*from.red + wg*from.green + wb*from.blue);
  
  	  /* The following method could be used (for speed):
  	  
  	  to = scalar_convert<Scalar,typename Pixel::Component<Rgbish>::type>(
  				static_cast<typename Pixel::Component<Rgbish>::type>(wr*from.red + wg*from.green + wb*from.blue));
  
  	  but this looses precision and may produce odd results for rgb(x,y,z) (x!=y!=z). Does this matter? Bear
  	  in mind that wr, wg, wb are only approximations of "average" human eye response anyway.
  	  */
  	
      }
    };
  
    template <class P, class Scalar> struct Uniform {
      static inline void convert(const P& from, Scalar& to) {
        typedef typename Pixel::Component<P>::type T;
        typename traits<T>::wider_type sum = Pixel::Component<P>::get(from,0);
        for (unsigned int i=1; i<Pixel::Component<P>::count; i++)
  	sum += Pixel::Component<P>::get(from,i);
        to = scalar_convert<Scalar,T>(sum/Pixel::Component<P>::count);
      }
    };
  
    template <class P, class Scalar> struct RMS {
      static inline void convert(const P& from, Scalar& to) {
        typedef typename Pixel::Component<P>::type T;
        double sum = Pixel::Component<P>::get(from,0);
        sum *= sum;
        for (unsigned int i=1; i<Pixel::Component<P>::count; i++) {
  	double w = Pixel::Component<P>::get(from,i);
  	sum += w*w;
        }
        to = scalar_convert<Scalar,T,double>(sqrt(sum/(Pixel::Component<P>::count)));
      }
    };  
  
    template <class P, class Scalar> struct AverageAbs {
      static inline void convert(const P& from, Scalar& to) {
        typedef typename Pixel::Component<P>::type T;
        typedef typename Pixel::traits<T>::wider_type sum_type;
        sum_type sum = CVD::abs(Pixel::Component<P>::get(from,0));
        for (unsigned int i=1; i<Pixel::Component<P>::count; i++) {
  	  sum += CVD::abs(Pixel::Component<P>::get(from,i));
        }
        to = scalar_convert<Scalar,T,sum_type>(sum/Pixel::Component<P>::count);
      }
    };  
  
    template <class P, class Scalar> struct L2Norm {
      static inline void convert(const P& from, Scalar& to) {
        typedef typename Pixel::Component<P>::type T;
        double sum = Pixel::Component<P>::get(from,0);
        sum *= sum;
        for (unsigned int i=1; i<Pixel::Component<P>::count; i++) {
  	double w = Pixel::Component<P>::get(from,i);
  	sum += w*w;
        }
        to = scalar_convert<Scalar,T,double>(sqrt(sum));
      }
    };  
  
    template <class P, class Scalar> struct SumOfSquares {
      static inline void convert(const P& from, Scalar& to) {
        typedef typename Pixel::Component<P>::type T;
        double sum = Pixel::Component<P>::get(from,0);
        sum *= sum;
        for (unsigned int i=1; i<Pixel::Component<P>::count; i++) {
      double w = Pixel::Component<P>::get(from,i);
      sum += w*w;
        }
        to = scalar_convert<Scalar,T,double>(sum);
      }
    };
  
    template <class Scalar, class Vec> struct Replicate {
      static inline void convert(const Scalar& from, Vec& to) {
        typedef typename Pixel::Component<Vec>::type T;
        Pixel::Component<Vec>::get(to,0) = scalar_convert<T, Scalar>(from);
        for (size_t i=1; i<Pixel::Component<Vec>::count; i++) 
  	Pixel::Component<Vec>::get(to,i) = Pixel::Component<Vec>::get(to,0);
      }
    };
    
    template <class Scalar, class T> struct GreyToRgba {
      static inline void convert(const Scalar& from, Rgba<T>& to) {
        to.red = to.green = to.blue = scalar_convert<T, Scalar>(from);
        to.alpha = traits<T>::max_intensity;
      }
    };
  
    template <class A, class B> inline void RgbToRgb(const A& from, B& to) {
      typedef typename Pixel::Component<A>::type T;
      typedef typename Pixel::Component<B>::type S;
      to.red = scalar_convert<S,T>(from.red);
      to.green = scalar_convert<S,T>(from.green);
      to.blue = scalar_convert<S,T>(from.blue);
    }
    
    template <class A, class B> struct RgbishToRgbish {
      static inline void convert(const A& from, B& to) {
        RgbToRgb(from,to);
      }
    };
    
    template <class A,class T> struct RgbishToRgbish<A,Rgba<T> > {
      static inline void convert(const A& from, Rgba<T>& to) {
        RgbToRgb(from,to);
        to.alpha = traits<T>::max_intensity;
      }
    };
  
    template <class S,class T> struct RgbishToRgbish<Rgba<S>,Rgba<T> > {
      static inline void convert(const Rgba<S>& from, Rgba<T>& to) {
        RgbToRgb(from,to);
        to.alpha = scalar_convert<T,S>(from.alpha);
      }
    };
  
    // Default conversions
  
    template <class From, class To, int FN=Pixel::Component<From>::count, int TN=Pixel::Component<To>::count> struct DefaultConversion { 
      typedef GenericConversion<From,To> type; 
    };
  
    // Scalar to X
    template <class S, class T> struct DefaultConversion<S,Rgb<T>,1,3> { typedef Replicate<S,Rgb<T> > type; };
    template <class S> struct DefaultConversion<S,Rgb8,1,3> { typedef Replicate<S,Rgb8> type; };
    template <class S, class T> struct DefaultConversion<S,Rgba<T>,1,4> { typedef GreyToRgba<S,T> type; };
  
    // Rgb<T> to X
    template <class T, class S> struct DefaultConversion<Rgb<T>,S,3,1> { typedef CIE<Rgb<T>,S> type; };
    template <class T> struct DefaultConversion<Rgb<T>,Rgb8, 3,3> { typedef RgbishToRgbish<Rgb<T>, Rgb8> type; };
    template <class T, class S> struct DefaultConversion<Rgb<T>,Rgba<S>,3,4> { typedef RgbishToRgbish<Rgb<T>, Rgba<S> > type; };
    template <class T, class S> struct DefaultConversion<Rgb<T>,Rgb<S>,3,3> { typedef RgbishToRgbish<Rgb<T>, Rgb<S> > type; };
    template <class T> struct DefaultConversion<Rgb<T>,Rgb<T>,3,3> { typedef GenericConversion<Rgb<T>, Rgb<T> > type; };
  
    // Rgb8 to X
    template <class S> struct DefaultConversion<Rgb8,S,3,1> { typedef CIE<Rgb8,S> type; };
    template <class S> struct DefaultConversion<Rgb8,Rgb<S>,3,3> { typedef RgbishToRgbish<Rgb8, Rgb<S> > type; };
    template <class S> struct DefaultConversion<Rgb8,Rgba<S>,3,4> { typedef RgbishToRgbish<Rgb8, Rgba<S> > type; };
    template <> struct DefaultConversion<Rgb8,Rgb8,3,3> { typedef GenericConversion<Rgb8, Rgb8> type; };
  
    // Rgba<T> to X
    template <class T, class S> struct DefaultConversion<Rgba<T>,S,4,1> { typedef CIE<Rgba<T>,S> type; };
    template <class T, class S> struct DefaultConversion<Rgba<T>,Rgb<S>,4,3> { typedef RgbishToRgbish<Rgba<T>, Rgb<S> > type; };
    template <class T> struct DefaultConversion<Rgba<T>,Rgb8,4,3> { typedef RgbishToRgbish<Rgba<T>, Rgb8> type; };
    template <class T, class S> struct DefaultConversion<Rgba<T>,Rgba<S>,4,4> { typedef RgbishToRgbish<Rgba<T>, Rgba<S> > type; };
    template <class T> struct DefaultConversion<Rgba<T>,Rgba<T>,4,4> { typedef GenericConversion<Rgba<T>, Rgba<T> > type; };
  
    
    template <class From, class To, class Conv=typename DefaultConversion<From,To>::type, 
      bool both_pod=CVD::Internal::is_POD<From>::is_pod && CVD::Internal::is_POD<To>::is_pod> struct ConvertPixels {
      static inline void convert(const From* from, To* to, size_t count) {
        for (size_t i=0; i<count; i++) 
  	Conv::convert(from[i], to[i]);
      }
    };
  
    template <class T> struct ConvertPixels<T,T,GenericConversion<T,T>,true> {
      static inline void convert(const T* from, T* to, size_t count) {
        memcpy(to, from, count*sizeof(T));
      }
    };
    
  }}
  #endif
  