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::min(std::min(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 minVal = vigra_ext::getMinComponent(*xd);
00321             const double maxVal = vigra_ext::getMaxComponent(*xd);
00322             if (minVal < LowerLimit || maxVal > UpperLimit)
00323             {
00324                 *xmd = 0;
00325             };
00326         }
00327     }
00328 }
00329 
00331 struct OverlapSizeCounter
00332 {
00333     OverlapSizeCounter()
00334         : size(0)
00335     { }
00336 
00337     template<typename PIXEL>
00338     void operator()(PIXEL const & img1, PIXEL const & img2)
00339     {
00340         if (img1 > 0 && img2 > 0) {
00341             size++;
00342         }
00343     }
00344 
00345     unsigned int getSize()
00346     {
00347         return size;
00348     }
00349 
00350     unsigned int size;
00351 };
00352 
00353 
00361 template <class F1, class F2>
00362 struct NestFunctor
00363 {
00364     F1 f1;
00365     F2 f2;
00366     NestFunctor(const F1 & fu1, const F2 & fu2)
00367     : f1(fu1), f2(fu2)
00368     { }
00369 
00372     typedef typename F1::result_type result_type;
00373 
00374     template <class T1>
00375     result_type operator()(T1 const & v) const
00376     {
00377         return f1(f2(v));
00378     }
00379 
00381     template <class T1, class T2>
00382     result_type operator()(T1 const & v1, T2 const & v2) const
00383     {
00384         return f1(f2(v1,v2));
00385     }
00386 
00388     template <class T1, class T2, class T3>
00389     result_type operator()(T1 const & v1, T2 const & v2, T3 const & v3) const
00390     {
00391         return f1(f2(v1,v2,v3));
00392     }
00393 };
00394 
00395 
00397 struct MaskPixelCounter
00398 {
00399     MaskPixelCounter()
00400         : count(0)
00401     { }
00402 
00403     template<typename PIXEL>
00404     void operator()(PIXEL const & img1)
00405     {
00406         if (img1 > 0) {
00407             count++;
00408         }
00409     }
00410 
00411     int getCount()
00412     {
00413         return count;
00414     }
00415 
00416     int count;
00417 };
00418 
00425 template <class SrcImageIterator, class SrcAccessor>
00426 void circularCrop(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img,
00427                   hugin_utils::FDiff2D middle, double radius)
00428 {
00429     vigra::Diff2D imgSize = img.second - img.first;
00430     double r2 = radius*radius;
00431 
00432     // create dest y iterator
00433     SrcImageIterator yd(img.first);
00434     // loop over the image and transform
00435     for(int y=0; y < imgSize.y; ++y, ++yd.y)
00436     {
00437         // create x iterators
00438         SrcImageIterator xd(yd);
00439         for(int x=0; x < imgSize.x; ++x, ++xd.x)
00440         {
00441             double dx = x-middle.x;
00442             double dy = y-middle.y;
00443             if (dx*dx+dy*dy > r2) {
00444                 *xd = 0;
00445             }
00446         }
00447     }
00448 }
00449 
00451 template <class T>
00452 struct PassThroughFunctor
00453 {
00454     typedef T result_type;
00455 
00456     T operator()(const T & a) const
00457     {
00458         return a;
00459     }
00460 
00461     template <class T2>
00462     T2 operator()(const T2 & a, const hugin_utils::FDiff2D & p) const
00463     {
00464         return a;
00465     }
00466 
00467     template <class T2, class A>
00468     A
00469     hdrWeight(T2 v, A a) const
00470     {
00471         return a;
00472     }
00473 
00474 };
00475 
00476 
00480 template <class T>
00481 typename vigra::NumericTraits<T>::RealPromote
00482 normalizeValue(T v, vigra::VigraTrueType)
00483 {
00484     return vigra::NumericTraits<T>::toRealPromote(v) / vigra::NumericTraits<T>::max();
00485 }
00486 
00487 template <class T>
00488 typename vigra::NumericTraits<T>::RealPromote
00489 normalizeValue(T v, vigra::VigraFalseType)
00490 {
00491     return v;
00492 }
00493 
00494 
00495 
00496 template <class DestValueType>
00497 struct LinearTransform
00498 {
00499   public:
00500         /* the functors argument type (actually, since 
00501            <tt>operator()</tt> is a template, much more types are possible)
00502         */
00503     typedef DestValueType argument_type;
00504 
00505         /* the functors result type
00506         */
00507     typedef DestValueType result_type;
00508 
00509         /* init scale and offset
00510         */
00511     LinearTransform(float scale, float offset)
00512     : scale_(scale), offset_(offset)
00513     {}
00514     template <class SrcValueType>
00515     result_type operator()(SrcValueType const & s) const
00516     {
00517         return vigra::NumericTraits<result_type>::fromRealPromote(scale_ * (vigra::NumericTraits<SrcValueType>::toRealPromote(s) + offset_));
00518     }
00519   private:
00520 
00521     float scale_;
00522     float offset_;
00523 };
00524 
00525 
00526 struct ApplyLogFunctor
00527 {
00528     float minv;
00529     float maxv;
00530     float scale;
00531 
00532     ApplyLogFunctor(float min_, float max_)
00533     {
00534         // protect against zeros in image data
00535         if (min_ == 0.0f) {
00536             min_ = 1e-5f;
00537         }
00538         minv = std::log10(min_);
00539         maxv = std::log10(max_);
00540         scale = (maxv - minv)/255;
00541     }
00542 
00543     template <class T>
00544     unsigned char operator()(T v) const
00545     {
00546         typedef vigra::NumericTraits<vigra::UInt8>  DestTraits;
00547         return DestTraits::fromRealPromote((std::log10(float(v))-minv)/scale);
00548     }
00549 
00550     template <class T, unsigned int R, unsigned int G, unsigned int B>
00551     vigra::RGBValue<vigra::UInt8,0,1,2> operator()(const vigra::RGBValue<T,R,G,B> & v) const
00552     {
00553         typedef vigra::NumericTraits< vigra::RGBValue<vigra::UInt8,0,1,2> >  DestTraits;
00554         typedef vigra::NumericTraits< vigra::RGBValue<T,R,G,B> >  SrcTraits;
00555         return DestTraits::fromRealPromote((log10(SrcTraits::toRealPromote(v)) + (-minv))/scale);
00556     }
00557 };
00558 
00559 
00560 template <class TIn, class TOut=vigra::UInt8>
00561 struct ApplyGammaFunctor
00562 {
00563     float minv;
00564     float maxv;
00565     float gamma;
00566     float scale;
00567 
00568     ApplyGammaFunctor(TIn min_, TIn max_, float gamma_)
00569     {
00570         minv = min_;
00571         maxv = max_;
00572         gamma = gamma_;
00573         scale = float(maxv) - minv;
00574     }
00575 
00576     TOut operator()(TIn v) const
00577     {
00578         typedef vigra::NumericTraits<TOut>  DestTraits;
00579         return DestTraits::fromRealPromote(pow((float(v)-minv)/scale, gamma)*255);
00580     }
00581 
00582     vigra::RGBValue<TOut> operator()(const vigra::RGBValue<TIn> & v) const
00583     {
00584         typedef vigra::NumericTraits< vigra::RGBValue<TOut> >  DestTraits;
00585         typedef vigra::NumericTraits< vigra::RGBValue<TIn> >  SrcTraits;
00586         return DestTraits::fromRealPromote(vigra_ext::pow((SrcTraits::toRealPromote(v)+(-minv))/scale, gamma)*255);
00587     }
00588 };
00589 
00590 // gamma correction with lookup table
00591 template <>
00592 struct ApplyGammaFunctor<vigra::UInt16, vigra::UInt8>
00593 {
00594     vigra::UInt8 lut[65536];
00595 
00596     ApplyGammaFunctor(vigra::UInt16 min, vigra::UInt16 max, float gamma)
00597     {
00598         float scale = float(max) - min;
00599         for (int i=0; i<65536; i++) {
00600             lut[i] = hugin_utils::roundi(pow((float(i)-min)/scale, gamma)*255);
00601         }
00602     }
00603 
00604     vigra::UInt8 operator()(vigra::UInt16 v) const
00605     {
00606         return lut[v];
00607     }
00608 
00609     vigra::RGBValue<vigra::UInt8> operator()(const vigra::RGBValue<vigra::UInt16> & v) const
00610     {
00611         return vigra::RGBValue<vigra::UInt8>(lut[v[0]], lut[v[1]], lut[v[2]]);
00612     }
00613 };
00614 
00615 template <class SrcIterator, class SrcAccessor, class DestIterator, class DestAccessor, class T>
00616         void applyMapping(vigra::triple<SrcIterator, SrcIterator, SrcAccessor> img,
00617                           vigra::pair<DestIterator, DestAccessor> dest, T min, T max, int mapping )
00618 {
00619 
00620     switch (mapping)
00621     {
00622         case 0:
00623         {
00624             // linear
00625             float offset_ = -float(min);
00626             float scale_ = 255/float(max)-float(min);
00627             vigra::transformImage(img, dest,
00628                                   LinearTransform<typename DestAccessor::value_type>( scale_, offset_)
00629                                  );
00630             break;
00631         }
00632         case 1:
00633         {
00634             // log
00635             ApplyLogFunctor logfunc(min, max);
00636             transformImage(img, dest,
00637                            logfunc);
00638             break;
00639         }
00640         case 2:
00641         {
00642             // gamma
00643             ApplyGammaFunctor<T> logfunc(min, max, 1/2.2f);
00644             transformImage(img, dest,
00645                            logfunc);
00646             break;
00647         }
00648         default:
00649             vigra_fail("Unknown image mapping mode");
00650     }
00651 }
00652 
00653 template <class SrcImageIterator, class SrcAccessor,
00654 class DestImageIterator, class DestAccessor, class Functor>
00655 void
00656 transformImageSpatial(SrcImageIterator src_upperleft,
00657                       SrcImageIterator src_lowerright, SrcAccessor sa,
00658                       DestImageIterator dest_upperleft, DestAccessor da,
00659                       Functor const & f, vigra::Diff2D ul) 
00660 {
00661     vigra::Diff2D destSize = src_lowerright - src_upperleft;
00662 
00663     int offsetX=ul.x;
00664     for(; src_upperleft.y < src_lowerright.y; ++src_upperleft.y, ++dest_upperleft.y, ++ul.y)
00665     {
00666         typename SrcImageIterator::row_iterator s(src_upperleft.rowIterator());
00667         typename SrcImageIterator::row_iterator send(s+ destSize.x);
00668         typename DestImageIterator::row_iterator d(dest_upperleft.rowIterator());
00669         ul.x=offsetX;
00670         for(; s != send; ++s, ++d, ++ul.x) {
00671             da.set(f(sa(s), ul), d);
00672         }
00673     }
00674 }
00675 
00676 template <class SrcImageIterator, class SrcAccessor,
00677 class DestImageIterator, class DestAccessor, class Functor>
00678 void
00679 transformImageSpatial(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
00680                       vigra::pair<DestImageIterator, DestAccessor> dest,
00681                       Functor const & f, vigra::Diff2D ul)
00682 {
00683     transformImageSpatial(src.first, src.second, src.third, dest.first, dest.second, f, ul);
00684 }
00685 
00687 template <class ImageType>
00688 void ConvertTo8Bit(ImageType& image)
00689 {
00690     typedef vigra::NumericTraits<typename ImageType::PixelType> DestTraits;
00691     double maxVal = vigra::NumericTraits<typename DestTraits::ValueType>::max();
00692     double minVal = vigra::NumericTraits<typename DestTraits::ValueType>::min();
00693     const std::string pixelType = vigra::TypeAsString<typename DestTraits::ValueType>::result();
00694     int mapping = 0;
00695     if (pixelType == "FLOAT" || pixelType == "DOUBLE")
00696     {
00697         vigra::FindMinMax<typename ImageType::PixelType> minmax;
00698         vigra::inspectImage(srcImageRange(image), minmax);
00699         minVal = vigra_ext::getMaxComponent(minmax.min);
00700         maxVal = vigra_ext::getMaxComponent(minmax.max);
00701         mapping = 1;
00702     }
00703     if (minVal != 0 || maxVal != 255)
00704     {
00705         vigra_ext::applyMapping(srcImageRange(image), destImage(image), minVal, maxVal, mapping);
00706     };
00707 };
00708 
00709 } // namespace
00710 
00711 #endif // VIGRA_EXT_UTILS_H

Generated on 27 Jul 2016 for Hugintrunk by  doxygen 1.4.7