utils.h

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00026 #ifndef VIGRA_EXT_UTILS_H
00027 #define VIGRA_EXT_UTILS_H
00028 
00029 #include <hugin_math/hugin_math.h>
00030 #include <vigra/rgbvalue.hxx>
00031 #include <vigra/transformimage.hxx>
00032 #include <vigra/codec.hxx>
00033 #include <cmath>
00034 
00035 namespace vigra {
00036 
00037 template <class T1, unsigned int R, unsigned int G, unsigned int B, class T2>
00038 struct PromoteTraits<RGBValue<T1, R, G, B>, T2 >
00039 {
00040     typedef RGBValue<typename PromoteTraits<T1, T2>::Promote> Promote;
00041 };
00042 
00043 }
00044 
00045 namespace vigra_ext {
00046 
00049 #define LUT_TRAITS(T1, Smin, Smax) \
00050 template<> \
00051 struct LUTTraits<T1> \
00052 { \
00053     static T1 max() \
00054 { \
00055     return Smax; \
00056 } \
00057     static T1 min() \
00058 { \
00059     return Smin; \
00060 } \
00061 }; \
00062 template<> \
00063 struct LUTTraits<vigra::RGBValue<T1> > \
00064 { \
00065     static T1 max() \
00066 { \
00067     return Smax; \
00068 } \
00069     static T1 min() \
00070 { \
00071     return Smin; \
00072 } \
00073 };
00074 
00075     template <class T1>
00076     struct LUTTraits;
00077 
00078     LUT_TRAITS(unsigned char, 0, UCHAR_MAX);
00079     LUT_TRAITS(signed char, SCHAR_MIN, SCHAR_MAX);
00080     LUT_TRAITS(unsigned short, 0, USHRT_MAX);
00081     LUT_TRAITS(signed short, SHRT_MIN, SHRT_MAX);
00082     LUT_TRAITS(unsigned int, 0, UINT_MAX);
00083     LUT_TRAITS(signed int, INT_MIN, INT_MAX);
00084     LUT_TRAITS(float, 0.0f, 1.0f);
00085     LUT_TRAITS(double, 0.0, 1.0);
00086 
00087 #undef LUT_TRAITS
00088 
00089 inline double getMaxValForPixelType(const std::string & v)
00090 {
00091     if (v == "UINT8") {
00092         return 255;
00093     } else if (v == "INT8") {
00094         return 127;
00095     } else if (v == "UINT16") {
00096         return 65535;
00097     } else if (v == "INT16") {
00098         return 32767;
00099     } else if (v == "UINT32") {
00100         return 4294967295u;
00101     } else if (v == "INT32") {
00102         return 2147483647;
00103     }
00104     return 1.0;
00105 }
00106 
00107 template <class VALUE>
00108 struct PointPairT
00109 {
00110     PointPairT()
00111     {
00112     }
00113 
00114     PointPairT(short img1, VALUE val1, const hugin_utils::FDiff2D & p1, float r1,
00115               short img2, VALUE val2, const hugin_utils::FDiff2D & p2, float r2)
00116     : imgNr1(img1), i1(val1), p1(p1), r1(r1), imgNr2(img2), i2(val2), p2(p2), r2(r2)
00117     {
00118     }
00119 
00120     short imgNr1;
00121     VALUE i1;
00122     hugin_utils::FDiff2D p1;
00123     float r1;
00124     short imgNr2;
00125     VALUE i2;
00126     hugin_utils::FDiff2D p2;
00127     float r2;
00128 };
00129 
00130 typedef PointPairT<float> PointPair;
00131 typedef PointPairT<vigra::RGBValue<float> > PointPairRGB;
00132 
00133 
00134 
00135 // get the value_type of vector pixels and also single channel pixels.
00136 #define VT_TRAITS_VEC(T1) \
00137 template<> \
00138 struct ValueTypeTraits<vigra::RGBValue<T1, 0u, 1u, 2u> > \
00139 { \
00140     typedef vigra::RGBValue<T1, 0u, 1u, 2u>::value_type value_type; \
00141 };
00142 
00143 #define VT_TRAITS(T1) \
00144 template<> \
00145 struct ValueTypeTraits<T1> \
00146 { \
00147     typedef T1 value_type; \
00148 };
00149 
00150 template <class T1>
00151 struct ValueTypeTraits
00152 {
00153     typedef typename T1::value_type value_type;
00154 };
00155 
00156 #if 0
00157 VT_TRAITS_VEC(vigra::UInt8);
00158 VT_TRAITS_VEC(vigra::Int16);
00159 VT_TRAITS_VEC(vigra::UInt16);
00160 VT_TRAITS_VEC(vigra::Int32);
00161 VT_TRAITS_VEC(vigra::UInt32);
00162 VT_TRAITS_VEC(float);
00163 VT_TRAITS_VEC(double);
00164 #endif
00165 
00166 VT_TRAITS(vigra::UInt8);
00167 VT_TRAITS(vigra::Int16);
00168 VT_TRAITS(vigra::UInt16);
00169 VT_TRAITS(vigra::Int32);
00170 VT_TRAITS(vigra::UInt32);
00171 VT_TRAITS(float);
00172 VT_TRAITS(double);
00173 
00174 #undef VT_TRAITS
00175 #undef VT_TRAITS_VEC
00176 
00177 
00178 using VIGRA_CSTD::pow;
00179 using VIGRA_CSTD::log;
00180 
00181 inline float pow(float a, double b)
00182 {
00183     return std::pow(a,(float) b);
00184 }
00185 
00187 template <class T, unsigned int R, unsigned int G, unsigned int B>
00188 inline
00189 vigra::RGBValue<T, R, G, B> pow(vigra::RGBValue<T, R, G, B> const & v, double e) {
00190     return vigra::RGBValue<T, R, G, B>(pow(v.red(),e), pow(v.green(),e),  pow(v.blue(),e));
00191 }
00192 
00194 template <class V1, unsigned int R, unsigned int G, unsigned int B, class V2>
00195 inline
00196 vigra::RGBValue<V1, R, G, B> &
00197 operator+=(vigra::RGBValue<V1, R, G, B> & l, V2 const & r)
00198 {
00199     l.red() += r;
00200     l.green() += r;
00201     l.blue() += r;
00202     return l;
00203 }
00204 
00206 template <class T, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX>
00207 inline
00208 vigra::RGBValue<T, RIDX, GIDX, BIDX>
00209 log(vigra::RGBValue<T, RIDX, GIDX, BIDX> const & v)
00210 {
00211     return vigra::RGBValue<T, RIDX, GIDX, BIDX>(std::log(v.red()), std::log(v.green()), std::log(v.blue()));
00212 }
00213 
00215 template <class T, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX>
00216 inline
00217 vigra::RGBValue<T, RIDX, GIDX, BIDX>
00218 log10(vigra::RGBValue<T, RIDX, GIDX, BIDX> const & v)
00219 {
00220     return vigra::RGBValue<T, RIDX, GIDX, BIDX>(std::log10(v.red()), std::log10(v.green()), std::log10(v.blue()));
00221 }
00222 
00224 template <class V1, unsigned int R, unsigned int G, unsigned int B, class V2>
00225 inline
00226 // WARNING: This is a hack.. 
00227 //vigra::RGBValue<V1>
00228 typename vigra::PromoteTraits<vigra::RGBValue<V1, R, G, B>, V2 >::Promote
00229 operator+(vigra::RGBValue<V1, R, G, B> const & r1, V2 const & r2)
00230 {
00231     typename vigra::PromoteTraits<vigra::RGBValue<V1, R, G, B>, V2 >::Promote res(r1);
00232 
00233     res += r2;
00234 
00235     return res;
00236 }
00237 
00240 template <class V, int SIZE, class D1, class D2>
00241 inline
00242 vigra::TinyVector<V, SIZE>
00243 pow(vigra::TinyVector<V, SIZE> const & v, double e)
00244 {
00245     vigra::TinyVector<V, SIZE> res;
00246     for (int i=0; i<SIZE; i++)
00247         res[i] = std::pow(v[i], e);
00248     return res;
00249 } 
00250 
00253 template <class V, int SIZE, class D1, class D2>
00254 inline
00255 vigra::TinyVector<V, SIZE>
00256 log(vigra::TinyVector<V, SIZE> const & v, double e)
00257 {
00258     vigra::TinyVector<V, SIZE> res;
00259     for (int i=0; i<SIZE; i++)
00260         res[i] = std::log(v[i], e);
00261     return res;
00262 } 
00263 
00265 template <class V>
00266 inline
00267 V
00268 getMaxComponent(vigra::RGBValue<V> const & v)
00269 {
00270     return std::max(std::max(v.red(), v.green()), v.blue());
00271 }
00272 
00274 template <class V>
00275 inline
00276 V
00277 getMaxComponent(V v)
00278 {
00279     return v;
00280 }
00281 
00283 template <class V>
00284 inline
00285 V
00286 getMinComponent(vigra::RGBValue<V> const & v)
00287 {
00288     return std::max(std::max(v.red(), v.green()), v.blue());
00289 }
00290 
00292 template <class V>
00293 inline
00294 V
00295 getMinComponent(V v)
00296 {
00297     return v;
00298 }
00299 
00300 template<class ImgIter, class ImgAccessor, class AlphaIter, class AlphaAccessor>
00301 void applyExposureClipMask(vigra::triple<ImgIter, ImgIter, ImgAccessor> image, vigra::triple<AlphaIter, AlphaIter, AlphaAccessor> mask, double lowerLimit, double upperLimit)
00302 {
00303     typedef typename ImgAccessor::value_type ImageValueType;
00304     vigra_precondition((image.second - image.first) == (mask.second - mask.first), "applyExposureMask: image and mask have different sizes");
00305     const vigra::Diff2D imgSize = image.second - image.first;
00306     const double LowerLimit = lowerLimit * LUTTraits<ImageValueType>::max();
00307     const double UpperLimit = upperLimit * LUTTraits<ImageValueType>::max();
00308 
00309     // create dest y iterator
00310     ImgIter yd(image.first);
00311     AlphaIter ymd(mask.first);
00312     // loop over the image and transform
00313     for (int y = 0; y < imgSize.y; ++y, ++yd.y, ++ymd.y)
00314     {
00315         // create x iterators
00316         ImgIter xd(yd);
00317         AlphaIter xmd(ymd);
00318         for (int x = 0; x < imgSize.x; ++x, ++xd.x, ++xmd.x)
00319         {
00320             const double val = getMaxComponent(*xd);
00321             if (val < LowerLimit || val>UpperLimit)
00322             {
00323                 *xmd = 0;
00324             };
00325         }
00326     }
00327 }
00328 
00330 struct OverlapSizeCounter
00331 {
00332     OverlapSizeCounter()
00333         : size(0)
00334     { }
00335 
00336     template<typename PIXEL>
00337     void operator()(PIXEL const & img1, PIXEL const & img2)
00338     {
00339         if (img1 > 0 && img2 > 0) {
00340             size++;
00341         }
00342     }
00343 
00344     unsigned int getSize()
00345     {
00346         return size;
00347     }
00348 
00349     unsigned int size;
00350 };
00351 
00352 
00360 template <class F1, class F2>
00361 struct NestFunctor
00362 {
00363     F1 f1;
00364     F2 f2;
00365     NestFunctor(const F1 & fu1, const F2 & fu2)
00366     : f1(fu1), f2(fu2)
00367     { }
00368 
00371     typedef typename F1::result_type result_type;
00372 
00373     template <class T1>
00374     result_type operator()(T1 const & v) const
00375     {
00376         return f1(f2(v));
00377     }
00378 
00380     template <class T1, class T2>
00381     result_type operator()(T1 const & v1, T2 const & v2) const
00382     {
00383         return f1(f2(v1,v2));
00384     }
00385 
00387     template <class T1, class T2, class T3>
00388     result_type operator()(T1 const & v1, T2 const & v2, T3 const & v3) const
00389     {
00390         return f1(f2(v1,v2,v3));
00391     }
00392 };
00393 
00394 
00396 struct MaskPixelCounter
00397 {
00398     MaskPixelCounter()
00399         : count(0)
00400     { }
00401 
00402     template<typename PIXEL>
00403     void operator()(PIXEL const & img1)
00404     {
00405         if (img1 > 0) {
00406             count++;
00407         }
00408     }
00409 
00410     int getCount()
00411     {
00412         return count;
00413     }
00414 
00415     int count;
00416 };
00417 
00424 template <class SrcImageIterator, class SrcAccessor>
00425 void circularCrop(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img,
00426                   hugin_utils::FDiff2D middle, double radius)
00427 {
00428     vigra::Diff2D imgSize = img.second - img.first;
00429     double r2 = radius*radius;
00430 
00431     // create dest y iterator
00432     SrcImageIterator yd(img.first);
00433     // loop over the image and transform
00434     for(int y=0; y < imgSize.y; ++y, ++yd.y)
00435     {
00436         // create x iterators
00437         SrcImageIterator xd(yd);
00438         for(int x=0; x < imgSize.x; ++x, ++xd.x)
00439         {
00440             double dx = x-middle.x;
00441             double dy = y-middle.y;
00442             if (dx*dx+dy*dy > r2) {
00443                 *xd = 0;
00444             }
00445         }
00446     }
00447 }
00448 
00450 template <class T>
00451 struct PassThroughFunctor
00452 {
00453     typedef T result_type;
00454 
00455     T operator()(const T & a) const
00456     {
00457         return a;
00458     }
00459 
00460     template <class T2>
00461     T2 operator()(const T2 & a, const hugin_utils::FDiff2D & p) const
00462     {
00463         return a;
00464     }
00465 
00466     template <class T2, class A>
00467     A
00468     hdrWeight(T2 v, A a) const
00469     {
00470         return a;
00471     }
00472 
00473 };
00474 
00475 
00479 template <class T>
00480 typename vigra::NumericTraits<T>::RealPromote
00481 normalizeValue(T v, vigra::VigraTrueType)
00482 {
00483     return vigra::NumericTraits<T>::toRealPromote(v) / vigra::NumericTraits<T>::max();
00484 }
00485 
00486 template <class T>
00487 typename vigra::NumericTraits<T>::RealPromote
00488 normalizeValue(T v, vigra::VigraFalseType)
00489 {
00490     return v;
00491 }
00492 
00493 
00494 
00495 template <class DestValueType>
00496 struct LinearTransform
00497 {
00498   public:
00499         /* the functors argument type (actually, since 
00500            <tt>operator()</tt> is a template, much more types are possible)
00501         */
00502     typedef DestValueType argument_type;
00503 
00504         /* the functors result type
00505         */
00506     typedef DestValueType result_type;
00507 
00508         /* init scale and offset
00509         */
00510     LinearTransform(float scale, float offset)
00511     : scale_(scale), offset_(offset)
00512     {}
00513     template <class SrcValueType>
00514     result_type operator()(SrcValueType const & s) const
00515     {
00516         return vigra::NumericTraits<result_type>::fromRealPromote(scale_ * (vigra::NumericTraits<SrcValueType>::toRealPromote(s) + offset_));
00517     }
00518   private:
00519 
00520     float scale_;
00521     float offset_;
00522 };
00523 
00524 
00525 struct ApplyLogFunctor
00526 {
00527     float minv;
00528     float maxv;
00529     float scale;
00530 
00531     ApplyLogFunctor(float min_, float max_)
00532     {
00533         // protect against zeros in image data
00534         if (min_ == 0.0f) {
00535             min_ = 1e-5f;
00536         }
00537         minv = std::log10(min_);
00538         maxv = std::log10(max_);
00539         scale = (maxv - minv)/255;
00540     }
00541 
00542     template <class T>
00543     unsigned char operator()(T v) const
00544     {
00545         typedef vigra::NumericTraits<vigra::UInt8>  DestTraits;
00546         return DestTraits::fromRealPromote((std::log10(float(v))-minv)/scale);
00547     }
00548 
00549     template <class T, unsigned int R, unsigned int G, unsigned int B>
00550     vigra::RGBValue<vigra::UInt8,0,1,2> operator()(const vigra::RGBValue<T,R,G,B> & v) const
00551     {
00552         typedef vigra::NumericTraits< vigra::RGBValue<vigra::UInt8,0,1,2> >  DestTraits;
00553         typedef vigra::NumericTraits< vigra::RGBValue<T,R,G,B> >  SrcTraits;
00554         return DestTraits::fromRealPromote((log10(SrcTraits::toRealPromote(v)) + (-minv))/scale);
00555     }
00556 };
00557 
00558 
00559 template <class TIn, class TOut=vigra::UInt8>
00560 struct ApplyGammaFunctor
00561 {
00562     float minv;
00563     float maxv;
00564     float gamma;
00565     float scale;
00566 
00567     ApplyGammaFunctor(TIn min_, TIn max_, float gamma_)
00568     {
00569         minv = min_;
00570         maxv = max_;
00571         gamma = gamma_;
00572         scale = float(maxv) - minv;
00573     }
00574 
00575     TOut operator()(TIn v) const
00576     {
00577         typedef vigra::NumericTraits<TOut>  DestTraits;
00578         return DestTraits::fromRealPromote(pow((float(v)-minv)/scale, gamma)*255);
00579     }
00580 
00581     vigra::RGBValue<TOut> operator()(const vigra::RGBValue<TIn> & v) const
00582     {
00583         typedef vigra::NumericTraits< vigra::RGBValue<TOut> >  DestTraits;
00584         typedef vigra::NumericTraits< vigra::RGBValue<TIn> >  SrcTraits;
00585         return DestTraits::fromRealPromote(vigra_ext::pow((SrcTraits::toRealPromote(v)+(-minv))/scale, gamma)*255);
00586     }
00587 };
00588 
00589 // gamma correction with lookup table
00590 template <>
00591 struct ApplyGammaFunctor<vigra::UInt16, vigra::UInt8>
00592 {
00593     vigra::UInt8 lut[65536];
00594 
00595     ApplyGammaFunctor(vigra::UInt16 min, vigra::UInt16 max, float gamma)
00596     {
00597         float scale = float(max) - min;
00598         for (int i=0; i<65536; i++) {
00599             lut[i] = hugin_utils::roundi(pow((float(i)-min)/scale, gamma)*255);
00600         }
00601     }
00602 
00603     vigra::UInt8 operator()(vigra::UInt16 v) const
00604     {
00605         return lut[v];
00606     }
00607 
00608     vigra::RGBValue<vigra::UInt8> operator()(const vigra::RGBValue<vigra::UInt16> & v) const
00609     {
00610         return vigra::RGBValue<vigra::UInt8>(lut[v[0]], lut[v[1]], lut[v[2]]);
00611     }
00612 };
00613 
00614 template <class SrcIterator, class SrcAccessor, class DestIterator, class DestAccessor, class T>
00615         void applyMapping(vigra::triple<SrcIterator, SrcIterator, SrcAccessor> img,
00616                           vigra::pair<DestIterator, DestAccessor> dest, T min, T max, int mapping )
00617 {
00618 
00619     switch (mapping)
00620     {
00621         case 0:
00622         {
00623             // linear
00624             float offset_ = -float(min);
00625             float scale_ = 255/float(max)-float(min);
00626             vigra::transformImage(img, dest,
00627                                   LinearTransform<typename DestAccessor::value_type>( scale_, offset_)
00628                                  );
00629             break;
00630         }
00631         case 1:
00632         {
00633             // log
00634             ApplyLogFunctor logfunc(min, max);
00635             transformImage(img, dest,
00636                            logfunc);
00637             break;
00638         }
00639         case 2:
00640         {
00641             // gamma
00642             ApplyGammaFunctor<T> logfunc(min, max, 1/2.2f);
00643             transformImage(img, dest,
00644                            logfunc);
00645             break;
00646         }
00647         default:
00648             vigra_fail("Unknown image mapping mode");
00649     }
00650 }
00651 
00652 template <class SrcImageIterator, class SrcAccessor,
00653 class DestImageIterator, class DestAccessor, class Functor>
00654 void
00655 transformImageSpatial(SrcImageIterator src_upperleft,
00656                       SrcImageIterator src_lowerright, SrcAccessor sa,
00657                       DestImageIterator dest_upperleft, DestAccessor da,
00658                       Functor const & f, vigra::Diff2D ul) 
00659 {
00660     vigra::Diff2D destSize = src_lowerright - src_upperleft;
00661 
00662     int offsetX=ul.x;
00663     for(; src_upperleft.y < src_lowerright.y; ++src_upperleft.y, ++dest_upperleft.y, ++ul.y)
00664     {
00665         typename SrcImageIterator::row_iterator s(src_upperleft.rowIterator());
00666         typename SrcImageIterator::row_iterator send(s+ destSize.x);
00667         typename DestImageIterator::row_iterator d(dest_upperleft.rowIterator());
00668         ul.x=offsetX;
00669         for(; s != send; ++s, ++d, ++ul.x) {
00670             da.set(f(sa(s), ul), d);
00671         }
00672     }
00673 }
00674 
00675 template <class SrcImageIterator, class SrcAccessor,
00676 class DestImageIterator, class DestAccessor, class Functor>
00677 void
00678 transformImageSpatial(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
00679                       vigra::pair<DestImageIterator, DestAccessor> dest,
00680                       Functor const & f, vigra::Diff2D ul)
00681 {
00682     transformImageSpatial(src.first, src.second, src.third, dest.first, dest.second, f, ul);
00683 }
00684 
00686 template <class ImageType>
00687 void ConvertTo8Bit(ImageType& image)
00688 {
00689     typedef vigra::NumericTraits<typename ImageType::PixelType> DestTraits;
00690     double maxVal = vigra::NumericTraits<typename DestTraits::ValueType>::max();
00691     double minVal = vigra::NumericTraits<typename DestTraits::ValueType>::min();
00692     const std::string pixelType = vigra::TypeAsString<typename DestTraits::ValueType>::result();
00693     int mapping = 0;
00694     if (pixelType == "FLOAT" || pixelType == "DOUBLE")
00695     {
00696         vigra::FindMinMax<typename ImageType::PixelType> minmax;
00697         vigra::inspectImage(srcImageRange(image), minmax);
00698         minVal = vigra_ext::getMaxComponent(minmax.min);
00699         maxVal = vigra_ext::getMaxComponent(minmax.max);
00700         mapping = 1;
00701     }
00702     if (minVal != 0 || maxVal != 255)
00703     {
00704         vigra_ext::applyMapping(srcImageRange(image), destImage(image), minVal, maxVal, mapping);
00705     };
00706 };
00707 
00708 } // namespace
00709 
00710 #endif // VIGRA_EXT_UTILS_H

Generated on 2 Sep 2015 for Hugintrunk by  doxygen 1.4.7