Hugin trunk 0.1
Loading...
Searching...
No Matches
VignettingCorrection.h
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
24#ifndef VIGRA_EXT_VIGNETTING_CORRECTION_H
25#define VIGRA_EXT_VIGNETTING_CORRECTION_H
26
27#include <vector>
28#include <functional>
29#include "hugin_config.h"
30
31#include <vigra/stdimage.hxx>
32#include <vigra/transformimage.hxx>
33#include <vigra/inspectimage.hxx>
34#include <vigra/combineimages.hxx>
35#include <vigra/functorexpression.hxx>
36
37#include <vigra_ext/utils.h>
38
39#include <random>
40
41//#define DEBUG_WRITE_FILES
42
43namespace vigra_ext{
44
45template <class VT1, class VT2, class InvResp, class Adjust>
47{
48public:
52
56
59 typedef typename vigra::NumericTraits<VT1>::RealPromote result_type;
60
62 typedef typename vigra::NumericTraits<VT2>::RealPromote RVT2;
63
67
71
75 {
76 // apply inverse response/gamma correction, vignetting correction by
77 // division and possible brightness adjust
79 RVT2 corr((v2)/m_mean);
80 i /= corr;
81 return m_Adjust( i );
82 }
83};
84
85template <class VT1, class InvResp, class VigFunc, class Adjust>
87{
88public:
92
95 typedef typename vigra::NumericTraits<VT1>::RealPromote result_type;
97
98 VigCorrDivFunctor(const InvResp & fr, const VigFunc & vf, const Adjust & adj)
100 { }
101
105
108 result_type operator()(first_argument_type const & v1, float x, float y) const
109 {
110 // apply inverse response/gamma correction, vignetting correction by
111 // division and possible brightness adjust
112 return m_Adjust(m_InvResp(v1) / m_VigFunc(x,y));
113 }
114};
115
116
117
118template <class VT1, class VT2, class InvResp, class Adjust>
120{
121public:
125
129
132 typedef typename vigra::NumericTraits<VT1>::RealPromote result_type;
133
135 typedef typename vigra::NumericTraits<VT2>::RealPromote RVT2;
136
139 { }
140
143
147 {
148 // apply inverse response/gamma correction, vignetting correction by
149 // division and possible brightness adjust
150 return m_Adjust(m_InvResp(v1) + v2);
151 }
152};
153
154template <class VT1, class InvResp, class VigFunc, class Adjust>
156{
157public:
161
164 typedef typename vigra::NumericTraits<VT1>::RealPromote result_type;
165
167
168 VigCorrAddFunctor(const InvResp & fr, const VigFunc & vf, const Adjust & adj)
170 { }
171
175
178 result_type operator()(first_argument_type const & v1, float x, float y) const
179 {
180 // apply inverse response/gamma correction, vignetting correction by
181 // division and possible brightness adjust
182 return m_Adjust(m_InvResp(v1) + m_VigFunc(x,y));
183 }
184};
185
186
187template <int NTERMS=4>
189{
191
192 PolySqDistFunctor(const std::vector<double> & coeff)
193 {
194 for (unsigned int i=0; i<NTERMS; i++) m_coeff[i] = coeff[i];
195 };
196
197 double operator()(double x, double y) const
198 {
199 double ret = m_coeff[0];
200 double r2 = x*x + y*y;
201 double r = r2;
202 for (unsigned int i = 1; i < NTERMS; i++) {
203 ret += m_coeff[i] * r;
204 r *= r2;
205 }
206 return ret;
207 }
208};
209
210inline bool isTrueType(vigra::VigraFalseType) {
211 return false;
212}
213
214inline bool isTrueType(vigra::VigraTrueType) {
215 return true;
216}
217
218template<class T>
219bool ditheringNeeded(T const &)
220{
221 typedef typename vigra::NumericTraits<T>::isIntegral is_integral;
222 return isTrueType(is_integral());
223}
224
226 // Dithering is used to fool the eye into seeing gradients that are finer
227 // than the precision of the pixel type.
228 // This prevents the occurence of cleanly-bordered regions in the output where
229 // the pixel values suddenly change from N to N+1.
230 // Such regions are especially objectionable in the green channel of 8-bit images.
231template <class T>
233{
234 std::mt19937 Twister;
235
236 typedef T result_type;
237
238 // Dithering is used to fool the eye into seeing gradients that are finer
239 // than the precision of the pixel type.
240 // This prevents the occurence of cleanly-bordered regions in the output where
241 // the pixel values suddenly change from N to N+1.
242 // Such regions are especially objectionable in the green channel of 8-bit images.
243 double dither(const double &v) const
244 {
245 std::mt19937 &mt = const_cast<std::mt19937 &>(Twister);
246 double vFraction = v - floor(v);
247 // Only dither values within a certain range of the rounding cutoff point.
248 if (vFraction > 0.25 && vFraction <= 0.75) {
249 // Generate a random number between 0 and 0.5.
250 double random = 0.5 * (double)mt() / UINT_MAX;
251 if ((vFraction - 0.25) >= random) {
252 return ceil(v);
253 } else {
254 return floor(v);
255 }
256 } else {
257 return v;
258 }
259 }
260
261 // dither vector
262 T dither(const T &v, vigra::VigraFalseType) const
263 {
264 T ret;
265 for (size_t i=0; i < v.size(); i++) {
266 ret[i] = dither(v[i]);
267 }
268 return ret;
269 }
270
271 // dither scalar type
272 T dither(const T & v, vigra::VigraTrueType) const
273 {
274 return dither(v);
275 }
276
277 T operator()(const T &v) const
278 {
279 typedef typename vigra::NumericTraits<T>::isScalar is_scalar;
280
281 return dither(v, is_scalar());
282 }
283};
284
285
286
288{
289 double gamma;
290 double maxval;
291 GammaFunctor(double g, double m)
292 : gamma(g), maxval(m)
293 {}
294
295 template <class T>
296 typename vigra::NumericTraits<T>::RealPromote operator()(T p) const
297 {
298 typedef typename vigra::NumericTraits<T>::RealPromote RT;
299 RT pix(p);
300 pix /= maxval;
302// return vigra::NumericTraits<T>::fromRealPromote(vigra_ext::pow(pix, gamma)*maxval);
303// return pow(pix, gamma)*maxval;
304 }
305};
306
309template <class PT>
311{
313
317 : m_a(a), m_b(b)
318 { };
319
320 PT operator()(PT p) const
321 {
322 return p * m_a + m_b;
323 }
324};
325
326
327template <class SrcImageIterator, class SrcAccessor,
328 class DestImageIterator, class DestAccessor, class Functor>
329void
330applyRadialVigCorrection(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
331 vigra::pair<DestImageIterator, DestAccessor> dest,
332 double cx, double cy,
333 Functor const & f)
334{
335 applyRadialVigCorrection(src.first, src.second, src.third, dest.first, dest.second,
336 cx, cy, f);
337}
338
339template <class SrcImageIterator, class SrcAccessor,
340 class DestImageIterator, class DestAccessor, class Functor>
341void
345 double cx, double cy,
346 Functor const & f)
347{
348 vigra::Diff2D destSize = src_lowerright - src_upperleft;
349
350 double sf = 1.0/sqrt(destSize.x/2.0*destSize.x/2.0 + destSize.y/2.0*destSize.y/2.0);
351 double ynorm = -cy * sf;
352
354 {
355 typename SrcImageIterator::row_iterator s(src_upperleft.rowIterator());
356 typename SrcImageIterator::row_iterator send(s+ destSize.x);
357 typename DestImageIterator::row_iterator d(dest_upperleft.rowIterator());
358 double xnorm = -cx*sf;
359 for(; s != send; ++s, ++d) {
360 da.set(f(sa(s), xnorm, ynorm), d);
361 xnorm +=sf;
362 }
363 ynorm += sf;
364 }
365}
366
371template <class SrcImageIterator, class SrcAccessor,
372 class DestImageIterator, class DestAccessor, class Functor>
373void
374applyRadialVigCorrectionDither(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
375 vigra::pair<DestImageIterator, DestAccessor> dest,
376 double cx, double cy,
377 Functor const & f, bool dither)
378{
380 if (dither) {
381 DF df;
384 } else {
386 }
387}
388
389
394template <class ImgIter, class ImgAccessor,
395 class FFIter, class FFAccessor,
396 class DestIter, class DestAccessor,
397 class Functor>
398void
399combineTwoImagesDither(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
400 vigra::pair<FFIter, FFAccessor> ffImg,
401 vigra::pair<DestIter, DestAccessor> destImg,
402 Functor const & f, bool dither)
403{
405 if (dither) {
406 DF df;
407 vigra::combineTwoImages(srcImg, ffImg, destImg,
409 } else {
410 vigra::combineTwoImages(srcImg, ffImg, destImg, f);
411 }
412}
413
414
415template <class ImgIter, class ImgAccessor, class FFIter, class FFAccessor, class DestIter, class DestAccessor>
416void flatfieldVigCorrection(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
417 vigra::pair<FFIter, FFAccessor> ffImg,
418 vigra::pair<DestIter, DestAccessor> destImg,
419 double gamma, double gammaMaxVal, bool division,
420 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote a,
421 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote b,
422 bool dither)
423{
424 typedef typename ImgAccessor::value_type PT;
425 typedef typename vigra::NumericTraits<PT>::RealPromote RPT;
426 typedef typename FFAccessor::value_type FFT;
427 typedef typename vigra::NumericTraits<FFT>::RealPromote RFFT;
428
431 LTF adjust(a,b);
432
433 RFFT mean;
434 if (division) {
435 // calculate mean of flatfield image
436 vigra::FindAverage<FFT> average; // init functor
437 vigra::inspectImage(ffImg.first, ffImg.first + (srcImg.second - srcImg.first), ffImg.second, average);
438 mean = average();
439 }
440
441 if (gamma == 1.0) {
442 RnF Rf;
443 if (division) {
446 dither);
447 } else {
450 dither);
451 }
452 } else {
454 if (division) {
457 dither);
458 } else {
461 dither);
462 }
463 }
464}
465
466
467template <class ImgIter, class ImgAccessor, class DestIter, class DestAccessor>
468void radialVigCorrection(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
469 vigra::pair<DestIter, DestAccessor> destImg, double gamma, double gammaMaxVal,
470 const std::vector<double> & radCoeff, hugin_utils::FDiff2D center, bool division,
471 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote a,
472 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote b,
473 bool dither)
474{
475 typedef typename ImgAccessor::value_type PT;
476 typedef typename vigra::NumericTraits<PT>::RealPromote RPT;
477
481
483 LTF adjust(a,b);
484
485 // adjust functor
486
487 if (gamma == 1.0) {
488 RnF Rf;
489 if (division) {
492 dither);
493 } else {
496 dither);
497 }
498 } else {
500 if (division) {
503 dither);
504 } else {
507 dither);
508 }
509 }
510}
511
512template <class ImgIter, class ImgAccessor, class DestIter, class DestAccessor>
513void applyBrightnessCorrection(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
514 vigra::pair<DestIter, DestAccessor> destImg,
515 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote a,
516 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote b)
517{
518 typedef typename ImgAccessor::value_type PT;
519 typedef typename vigra::NumericTraits<PT>::RealPromote RPT;
520
521 vigra::transformImage(srcImg, destImg, LinearTransformFunctor<RPT>(a,b));
522}
523
524
525template <class ImgIter, class ImgAccessor, class DestIter, class DestAccessor>
526void applyGammaAndBrightCorrection(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
527 vigra::pair<DestIter, DestAccessor> destImg,
528 double gamma, double maxGVal,
529 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote a,
530 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote b)
531{
532 typedef typename ImgAccessor::value_type PT;
533 typedef typename vigra::NumericTraits<PT>::RealPromote RPT;
535
536 LTF ltf(a,b);
537 GammaFunctor gf(gamma, maxGVal);
538 vigra::transformImage(srcImg, destImg, NestFunctor<LTF, GammaFunctor>(ltf, gf));
539}
540
541template <class ImgIter, class ImgAccessor, class DestIter, class DestAccessor>
542void applyGammaCorrection(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
543 vigra::pair<DestIter, DestAccessor> destImg,
544 double gamma, double maxGVal)
545{
546 GammaFunctor gf(gamma, maxGVal);
547 vigra::transformImage(srcImg, destImg, gf );
548}
549
550
551/*
552template <class ImgIter, class ImgAccessor, class DestIter, class DestAccessor>
553void correctRespVigExpInv(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
554 vigra::pair<DestIter, DestAccessor> destImg,
555 const std::vector<double> & EMoRCoeff, double maxGreyVal,
556 const std::vector<double> & radCoeff, hugin_utils::FDiff2D center, bool division,
557 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote a,
558 typename vigra::NumericTraits<typename ImgAccessor::value_type>::RealPromote b,
559 bool dither)
560{
561 typedef typename ImgAccessor::value_type PT;
562 typedef typename vigra::NumericTraits<PT>::RealPromote RPT;
563 typedef typename ImgAccessor::value_type OutPixelType;
564
565 typedef PolySqDistFunctor<4> PolyF;
566 typedef PassThroughFunctor<RPT> RnF;
567 typedef LinearTransformFunctor<RPT> LTF;
568
569 PolyF poly(radCoeff);
570 LTF adjust(a,b);
571
572 // adjust functor
573
574 if (EMoRCoeff.empty()) {
575 RnF Rf;
576 if (division) {
577 applyRadialVigCorrectionDither(srcImg, destImg, center.x, center.y,
578 VigCorrDivFunctor<PT, RnF, PolyF, LTF>(Rf, poly, adjust),
579 dither);
580 } else {
581 applyRadialVigCorrectionDither(srcImg, destImg, center.x, center.y,
582 VigCorrAddFunctor<PT, RnF, PolyF, LTF>(Rf, poly, adjust),
583 dither);
584 }
585 } else {
586 // prepare lookup table
587 // create a camera response lut
588 std::vector<float> lut10;
589 vigra_ext::createEMoRLUT(params, lut10);
590 // create inverse lut
591 std::vector<float> invlut10(1<<10);
592 vigra_ext::invertLUT(lut10, invlut10);
593
594 GammaFunctor Rf(gamma, gammaMaxVal);
595 if (division) {
596 applyRadialVigCorrectionDither(srcImg, destImg, center.x, center.y,
597 VigCorrDivFunctor<PT, GammaFunctor, PolyF, LTF>(Rf, poly, adjust),
598 dither);
599 } else {
600 applyRadialVigCorrectionDither(srcImg, destImg, center.x, center.y,
601 VigCorrAddFunctor<PT, GammaFunctor, PolyF, LTF>(Rf, poly, adjust),
602 dither);
603 }
604 }
605}
606
607*/
608
609} // namespace
610
611#endif // VIGRA_EXT_VIGNETTING_CORRECTION_H
result_type operator()(first_argument_type const &v1, float x, float y) const
calculate transform.
VigCorrAddFunctor(const InvResp &fr, const VigFunc &vf, const Adjust &adj)
VT1 first_argument_type
the functor's first argument type
vigra::NumericTraits< VT1 >::RealPromote result_type
the functor's result type
VT1 first_argument_type
the functor's first argument type
result_type operator()(first_argument_type const &v1, float x, float y) const
calculate transform.
vigra::NumericTraits< VT1 >::RealPromote result_type
the functor's result type
VigCorrDivFunctor(const InvResp &fr, const VigFunc &vf, const Adjust &adj)
VT2 second_argument_type
the functor's second argument type
VigCorrFlatAddFunctor(const InvResp &fr, const Adjust &adj)
VT1 first_argument_type
the functor's first argument type
result_type operator()(first_argument_type const &v1, second_argument_type const &v2) const
calculate transform.
vigra::NumericTraits< VT2 >::RealPromote RVT2
vigra::NumericTraits< VT1 >::RealPromote result_type
the functor's result type
result_type operator()(first_argument_type const &v1, second_argument_type const &v2) const
calculate transform.
vigra::NumericTraits< VT2 >::RealPromote RVT2
VigCorrFlatDivFunctor(RVT2 mean, const InvResp &fr, const Adjust &adj)
VT1 first_argument_type
the functor's first argument type
VT2 second_argument_type
the functor's second argument type
vigra::NumericTraits< VT1 >::RealPromote result_type
the functor's result type
void flatfieldVigCorrection(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra::pair< FFIter, FFAccessor > ffImg, vigra::pair< DestIter, DestAccessor > destImg, double gamma, double gammaMaxVal, bool division, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote a, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote b, bool dither)
bool isTrueType(vigra::VigraFalseType)
void applyRadialVigCorrectionDither(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::pair< DestImageIterator, DestAccessor > dest, double cx, double cy, Functor const &f, bool dither)
Apply flatfield correction with dithering.
void applyBrightnessCorrection(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra::pair< DestIter, DestAccessor > destImg, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote a, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote b)
bool ditheringNeeded(T const &)
float pow(float a, double b)
Definition utils.h:181
void radialVigCorrection(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra::pair< DestIter, DestAccessor > destImg, double gamma, double gammaMaxVal, const std::vector< double > &radCoeff, hugin_utils::FDiff2D center, bool division, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote a, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote b, bool dither)
void applyRadialVigCorrection(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::pair< DestImageIterator, DestAccessor > dest, double cx, double cy, Functor const &f)
void applyGammaAndBrightCorrection(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra::pair< DestIter, DestAccessor > destImg, double gamma, double maxGVal, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote a, typename vigra::NumericTraits< typename ImgAccessor::value_type >::RealPromote b)
void applyGammaCorrection(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra::pair< DestIter, DestAccessor > destImg, double gamma, double maxGVal)
void combineTwoImagesDither(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra::pair< FFIter, FFAccessor > ffImg, vigra::pair< DestIter, DestAccessor > destImg, Functor const &f, bool dither)
Apply combine two images.
Dither code taken from enblend and adapted to a standalone functor.
T dither(const T &v, vigra::VigraFalseType) const
double dither(const double &v) const
T dither(const T &v, vigra::VigraTrueType) const
vigra::NumericTraits< T >::RealPromote operator()(T p) const
GammaFunctor(double g, double m)
functor to combine two functors: result = f1( f2(v) )
Definition utils.h:432
PolySqDistFunctor(const std::vector< double > &coeff)
double operator()(double x, double y) const
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
functions to manage ROI's