24 #ifndef _PHOTOMETRIC_VIGNETTING_CORRECTION_H 
   25 #define _PHOTOMETRIC_VIGNETTING_CORRECTION_H 
   29 #include "hugin_config.h" 
   32 #include <vigra/stdimage.hxx> 
   33 #include <vigra/numerictraits.hxx> 
   34 #include <vigra/array_vector.hxx> 
   42 namespace HuginBase { 
namespace Photometric {
 
   59         typedef std::vector<double> 
LUT;
 
   91         typename vigra::NumericTraits<VT1>::RealPromote
 
   95         typename vigra::NumericTraits<VT1>::RealPromote
 
   99         typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
 
  103         typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
 
  109         typename vigra::NumericTraits<T>::RealPromote
 
  136 template <
class VTIn, 
class VTOut>
 
  147         typedef std::vector<double> 
LUT;
 
  148         typedef std::vector<dest_type> 
LUTD;
 
  171         void setOutput(
double destExposure, 
const LUTD & destLut, 
double scale, 
double rangeCompression = 0.0);
 
  188         double dither(
const double &v) 
const;
 
  191         typename vigra::NumericTraits<dest_type>::RealPromote
 
  195         typename vigra::NumericTraits<dest_type>::RealPromote
 
  199         typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
 
  203         typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
 
  209         typename vigra::NumericTraits<T>::RealPromote 
 
  212             return apply(v, pos);
 
  216         template <
class T, 
class A>
 
  226         void emitGLSL(std::ostringstream& oss, std::vector<double>& invLut, std::vector<double>& destLut) 
const;
 
  238                     const double f = 
static_cast<double>(i) / (
Base::m_lutR.size() - 1);
 
  266 namespace HuginBase { 
namespace Photometric {
 
  269 template <
class VTIn>
 
  276 template <
class VTIn>
 
  283 template <
class VTIn>
 
  289     m_radiusScale = 1.0/sqrt(m_src.getSize().x/2.0*m_src.getSize().x/2.0 + m_src.getSize().y/2.0*m_src.getSize().y/2.0);
 
  290     m_srcExposure = m_src.getExposure();
 
  292     m_RadialVigCorrCoeff = m_src.getRadialVigCorrCoeff();
 
  293     m_RadialVigCorrCenter = m_src.getRadialVigCorrCenter();
 
  294     m_VigCorrMode = m_src.getVigCorrMode();
 
  295     m_WhiteBalanceRed = m_src.getWhiteBalanceRed();
 
  296     m_WhiteBalanceBlue = m_src.getWhiteBalanceBlue();
 
  305         if (lutLenD == 1.0 || (lutLenD > ((1<<10)-1))) {
 
  308             lutLen = size_t(lutLenD) + 1;
 
  310         switch (m_src.getResponseType()) 
 
  314                 if (lutLen == 1<<10) {
 
  320                     m_lutR.resize(lutLen);
 
  326                 m_lutR.resize(lutLen);
 
  331                 vigra_fail(
"ResponseTransform: unknown response function type");
 
  339 template <
class VTIn>
 
  343         d = d - m_RadialVigCorrCenter;
 
  346         double vig = m_RadialVigCorrCoeff[0];
 
  347         double r2 = d.
x*d.
x + d.
y*d.
y;
 
  349         for (
unsigned int i = 1; i < 4; i++) {
 
  350             vig += m_RadialVigCorrCoeff[i] * r;
 
  359             return (*m_flatfield)(x,y);
 
  369 template <
class VTIn>
 
  370 typename vigra::NumericTraits<typename ResponseTransform<VTIn>::VT1>::RealPromote
 
  373     typename vigra::NumericTraits<VT1>::RealPromote ret = v;
 
  376     ret = ret*calcVigFactor(pos)*m_srcExposure;
 
  377     if (!m_lutR.empty()) {
 
  378         return m_lutRFunc(ret);
 
  384 template <
class VTIn>
 
  385 typename vigra::NumericTraits<vigra::RGBValue<typename ResponseTransform<VTIn>::VT1> >::RealPromote
 
  388     typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote ret = v;
 
  390     double common = calcVigFactor(pos)*m_srcExposure;
 
  393     ret.red() = ret.red() * m_WhiteBalanceRed;
 
  394     ret.blue() = ret.blue() * m_WhiteBalanceBlue;
 
  396     if (!m_lutR.empty()) {
 
  397         return m_lutRFunc(ret);
 
  403 template <
class VTIn>
 
  404 typename vigra::NumericTraits<typename ResponseTransform<VTIn>::VT1>::RealPromote
 
  407     typedef typename vigra::NumericTraits<VT1>::isScalar is_scalar;
 
  408     return apply(v, pos, is_scalar());
 
  411 template <
class VTIn>
 
  412 typename vigra::NumericTraits<vigra::RGBValue<typename ResponseTransform<VTIn>::VT1> >::RealPromote
 
  415     typedef typename vigra::NumericTraits<vigra::RGBValue<VT1> >::isScalar is_scalar;
 
  416     return apply(v, pos, is_scalar());
 
  419 template <
class VTIn, 
class VTOut>
 
  422     m_destExposure = 1.0;
 
  424     m_rangeCompression = 0.0;
 
  428 template <
class VTIn, 
class VTOut>
 
  430 : 
Base(src), m_hdrMode(false), m_rangeCompression(0.0)
 
  440 template <
class VTIn, 
class VTOut>
 
  443     m_destExposure = 1.0;
 
  445     m_rangeCompression = 0.0;
 
  447     if (!Base::m_lutR.empty()) {
 
  453 template <
class VTIn, 
class VTOut>
 
  458     m_destExposure = destExposure;
 
  460     m_rangeCompression = 0.0;
 
  463 template <
class VTIn, 
class VTOut>
 
  468     if (!m_destLut.empty()) {
 
  470         m_rangeCompression = rangeCompression;
 
  474         m_rangeCompression = 0.0;
 
  476     m_destExposure = destExposure;
 
  481 template <
class VTIn, 
class VTOut>
 
  484     std::mt19937 &mt = 
const_cast<std::mt19937 &
>(Twister);
 
  485     double vFraction = v - floor(v);
 
  487     if (vFraction > 0.25 && vFraction <= 0.75) {
 
  489         double random = 0.5 * (double)mt() / UINT_MAX;
 
  490         if ((vFraction - 0.25) >= random) {
 
  501 template <
class VTIn, 
class VTOut>
 
  502 typename vigra::NumericTraits<typename InvResponseTransform<VTIn,VTOut>::dest_type>::RealPromote
 
  506     typename vigra::NumericTraits<VT1>::RealPromote ret(v);
 
  507     if (!Base::m_lutR.empty()) {
 
  508         ret = m_lutRInvFunc(v);
 
  513     ret *= m_destExposure / (Base::calcVigFactor(pos) * Base::m_srcExposure);
 
  515     if (!m_destLut.empty()) {
 
  516         if (m_rangeCompression > 0.0)
 
  518             ret = log2(m_rangeCompression*ret + 1) / log2(m_rangeCompression + 1);
 
  520         ret = m_destLutFunc(ret);
 
  523     if ( m_intScale > 1) {
 
  524         return dither(ret * m_intScale);
 
  530 template <
class VTIn, 
class VTOut>
 
  531 typename vigra::NumericTraits<vigra::RGBValue<typename InvResponseTransform<VTIn,VTOut>::VT1> >::RealPromote
 
  534     typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote ret(v);
 
  535     if (!Base::m_lutR.empty()) {
 
  536         ret = m_lutRInvFunc(v);
 
  542     ret *= m_destExposure/(Base::calcVigFactor(pos)*Base::m_srcExposure);
 
  543     ret.red() /= Base::m_WhiteBalanceRed;
 
  544     ret.blue() /= Base::m_WhiteBalanceBlue;
 
  546     if (!m_destLut.empty()) {
 
  547         if (m_rangeCompression > 0)
 
  549             ret.red() = log2(m_rangeCompression*ret.red() + 1) / log2(m_rangeCompression + 1);
 
  550             ret.blue() = log2(m_rangeCompression*ret.blue() + 1) / log2(m_rangeCompression + 1);
 
  551             ret.green() = log2(m_rangeCompression*ret.green() + 1) / log2(m_rangeCompression + 1);
 
  553         ret = m_destLutFunc(ret);
 
  556     if (m_intScale > 1) {
 
  557         for (
size_t i=0; i < 3; i++) {
 
  558             ret[i] = dither(ret[i] * m_intScale);
 
  565 template <
class VTIn, 
class VTOut>
 
  566 typename vigra::NumericTraits<typename InvResponseTransform<VTIn,VTOut>::dest_type>::RealPromote
 
  569     typedef typename vigra::NumericTraits<VT1>::isScalar is_scalar;
 
  570     return apply(v, pos, is_scalar());
 
  573 template <
class VTIn, 
class VTOut>
 
  574 typename vigra::NumericTraits<vigra::RGBValue<typename InvResponseTransform<VTIn,VTOut>::VT1> >::RealPromote
 
  577     typedef typename vigra::NumericTraits<vigra::RGBValue<VT1> >::isScalar is_scalar;
 
  578     return apply(v, pos, is_scalar());
 
  581 template <
class VTIn, 
class VTOut>
 
  588     const double invLutSize = Base::m_lutR.size();
 
  590     const double destLutSize = m_destLut.size();
 
  592     oss << 
"    // invLutSize = " << invLutSize << endl
 
  593         << 
"    // pixelMax = " << pixelMax << endl
 
  594         << 
"    // destLutSize = " << destLutSize << endl
 
  595         << 
"    // destExposure = " << m_destExposure << endl
 
  596         << 
"    // srcExposure = " << Base::m_srcExposure << endl
 
  597         << 
"    // whiteBalanceRed = " << Base::m_src.getWhiteBalanceRed() << endl
 
  598         << 
"    // whiteBalanceBlue = " << Base::m_src.getWhiteBalanceBlue() << endl;
 
  605         oss << 
"    p.a = max(p.r, max(p.g, p.b));" << endl;
 
  608     if (!Base::m_lutR.empty()) {
 
  609         oss << 
"    p.rgb = p.rgb * " << (invLutSize - 1.0) << 
";" << endl
 
  610             << 
"    vec2 invR = texture2DRect(InvLutTexture, vec2(p.r, 0.0)).sq;" << endl
 
  611             << 
"    vec2 invG = texture2DRect(InvLutTexture, vec2(p.g, 0.0)).sq;" << endl
 
  612             << 
"    vec2 invB = texture2DRect(InvLutTexture, vec2(p.b, 0.0)).sq;" << endl
 
  613             << 
"    vec3 invX = vec3(invR.x, invG.x, invB.x);" << endl
 
  614             << 
"    vec3 invY = vec3(invR.y, invG.y, invB.y);" << endl
 
  615             << 
"    vec3 invA = fract(p.rgb);" << endl
 
  616             << 
"    p.rgb = mix(invX, invY, invA);" << endl;
 
  620         oss << 
"    // VigCorrMode=VIGCORR_RADIAL" << endl
 
  621             << 
"    float vig = 1.0;" << endl
 
  623             << 
"        vec2 vigCorrCenter = vec2(" << Base::m_src.getRadialVigCorrCenter().x << 
", " 
  624             << Base::m_src.getRadialVigCorrCenter().y << 
");" << endl
 
  625             << 
"        float radiusScale=" << Base::m_radiusScale << 
";" << endl
 
  626             << 
"        float radialVigCorrCoeff0 = " << Base::m_src.getRadialVigCorrCoeff()[0] << 
";" << endl
 
  627             << 
"        float radialVigCorrCoeff1 = " << Base::m_src.getRadialVigCorrCoeff()[1] << 
";" << endl
 
  628             << 
"        float radialVigCorrCoeff2 = " << Base::m_src.getRadialVigCorrCoeff()[2] << 
";" << endl
 
  629             << 
"        float radialVigCorrCoeff3 = " << Base::m_src.getRadialVigCorrCoeff()[3] << 
";" << endl
 
  630             << 
"        vec2 src = texture2DRect(CoordTexture, gl_TexCoord[0].st).sq;" << endl
 
  631             << 
"        vec2 d = src - vigCorrCenter;" << endl
 
  632             << 
"        d *= radiusScale;" << endl
 
  633             << 
"        vig = radialVigCorrCoeff0;" << endl
 
  634             << 
"        float r2 = dot(d, d);" << endl
 
  635             << 
"        float r = r2;" << endl
 
  636             << 
"        vig += radialVigCorrCoeff1 * r;" << endl
 
  637             << 
"        r *= r2;" << endl
 
  638             << 
"        vig += radialVigCorrCoeff2 * r;" << endl
 
  639             << 
"        r *= r2;" << endl
 
  640             << 
"        vig += radialVigCorrCoeff3 * r;" << endl
 
  643         oss << 
"    // VigCorrMode=VIGCORR_FLATFIELD" << endl
 
  644             << 
"    float vig = 1.0;" << endl;
 
  646         oss << 
"    // VigCorrMode=none" << endl
 
  647             << 
"    float vig = 1.0;" << endl;
 
  650     oss << 
"    vec3 exposure_whitebalance = vec3(" 
  651         << (m_destExposure / (Base::m_srcExposure * Base::m_src.getWhiteBalanceRed())) << 
", " 
  652         << (m_destExposure / (Base::m_srcExposure)) << 
", " 
  653         << (m_destExposure / (Base::m_srcExposure * Base::m_src.getWhiteBalanceBlue())) << 
");" << endl
 
  654         << 
"    p.rgb = (p.rgb * exposure_whitebalance) / vig;" << endl;
 
  656     if (!m_destLut.empty()) {
 
  657         if (m_rangeCompression > 0)
 
  659             oss << 
"    p.rgb = log2(" << m_rangeCompression << 
" * p.rgb + 1.0) / " << log2(m_rangeCompression + 1) << 
";" << endl;
 
  661         oss << 
"    p.rgb = p.rgb * " << (destLutSize - 1.0) << 
";" << endl
 
  662             << 
"    vec2 destR = texture2DRect(DestLutTexture, vec2(p.r, 0.0)).sq;" << endl
 
  663             << 
"    vec2 destG = texture2DRect(DestLutTexture, vec2(p.g, 0.0)).sq;" << endl
 
  664             << 
"    vec2 destB = texture2DRect(DestLutTexture, vec2(p.b, 0.0)).sq;" << endl
 
  665             << 
"    vec3 destX = vec3(destR.x, destG.x, destB.x);" << endl
 
  666             << 
"    vec3 destY = vec3(destR.y, destG.y, destB.y);" << endl
 
  667             << 
"    vec3 destA = fract(p.rgb);" << endl
 
  668             << 
"    p.rgb = mix(destX, destY, destA);" << endl;
 
V getMaxComponent(vigra::RGBValue< V > const &v)
get the maximum component of a vector (also works for single pixel types...) 
void resizeLUT(const VEC &iLUT, VEC2 &oLUT)
misc math function & classes used by other parts of the program 
static const double A(-0.75)
void enforceMonotonicity(LUT &lut)
enforce monotonicity of an array (mostly used for lookup tables) 
functions to manage ROI's 
functor to apply a LUT to gray and color images. 
empirical model of response 
radial vignetting correction 
void createGammaLUT(double gamma, VECTOR &lut)
void createEMoRLUT(const std::vector< float > ¶ms, VECTOR &lut)
a simple gamma response curve 
T1::value_type value_type
All variables of a source image.