/*****************************************************************************/ // Copyright 2008 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in // accordance with the terms of the Adobe license agreement accompanying it. /*****************************************************************************/ /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_lens_correction.h#2 $ */ /* $DateTime: 2012/08/02 06:09:06 $ */ /* $Change: 841096 $ */ /* $Author: erichan $ */ /** \file * Opcodes to fix lens aberrations such as geometric distortion, lateral chromatic * aberration, and vignetting (peripheral illumination falloff). */ /*****************************************************************************/ #ifndef __dng_lens_correction__ #define __dng_lens_correction__ /*****************************************************************************/ #include "dng_1d_function.h" #include "dng_matrix.h" #include "dng_memory.h" #include "dng_opcodes.h" #include "dng_pixel_buffer.h" #include "dng_point.h" #include "dng_resample.h" #include "dng_sdk_limits.h" #include <vector> /*****************************************************************************/ /// \brief Abstract base class holding common warp opcode parameters (e.g., /// number of planes, optical center) and common warp routines. class dng_warp_params { public: // Number of planes to be warped. Must be either 1 or equal to the // number of planes of the image to be processed. If set to 1, then a // single set of warp parameters applies to all planes of the image. // fPlanes must be at least 1 and no greater than kMaxColorPlanes (see // dng_sdk_limits.h). uint32 fPlanes; // The optical center of the lens in normalized [0,1] coordinates with // respect to the image's active area. For example, a value of (0.5, // 0.5) indicates that the optical center of the lens is at the center // of the image's active area. A normalized radius of 1.0 corresponds to // the distance from fCenter to the farthest corner of the image's // active area. Each component of fCenter must lie in the range [0,1]. dng_point_real64 fCenter; public: /// Create empty (invalid) warp parameters. dng_warp_params (); /// Create warp parameters with specified number of planes and image /// center. /// /// \param planes The number of planes of parameters specified: It must /// be either 1 or equal to the number of planes of the image to be /// processed. /// /// \param fCenter The image center in relative coordinates. dng_warp_params (uint32 planes, const dng_point_real64 &fCenter); virtual ~dng_warp_params (); /// Is the entire correction a NOP for all planes? virtual bool IsNOPAll () const; /// Is the entire correction a NOP for the specified plane? virtual bool IsNOP (uint32 plane) const; /// Is the radial correction a NOP for all planes? virtual bool IsRadNOPAll () const; /// Is the radial correction a NOP for the specified plane? virtual bool IsRadNOP (uint32 plane) const; /// Is the tangential correction a NOP for all planes? virtual bool IsTanNOPAll () const; /// Is the tangential correction a NOP for the specified plane? virtual bool IsTanNOP (uint32 plane) const; /// Do these warp params appear valid? virtual bool IsValid () const; /// Are these warp params valid for the specified negative? virtual bool IsValidForNegative (const dng_negative &negative) const; /// Propagate warp parameters from first plane to all other planes. virtual void PropagateToAllPlanes (uint32 totalPlanes) = 0; /// Evaluate the 1D radial warp function for the specified plane. /// Parameter r is the destination (i.e., corrected) normalized radius, /// i.e., the normalized Euclidean distance between a corrected pixel /// position and the optical center in the image. r lies in the range /// [0,1]. The returned result is non-negative. virtual real64 Evaluate (uint32 plane, real64 r) const = 0; /// Compute and return the inverse of Evaluate () above. The base /// implementation uses Newton's method to perform the inversion. /// Parameter r is the source (i.e., uncorrected) normalized radius, /// i.e., normalized Euclidean distance between a corrected pixel /// position and the optical center in the image. Both r and the /// computed result are non-negative. virtual real64 EvaluateInverse (uint32 plane, real64 r) const; /// Evaluate the 1D radial warp ratio function for the specified plane. /// Parameter r2 is the square of the destination (i.e., corrected) /// normalized radius, i.e., the square of the normalized Euclidean /// distance between a corrected pixel position and the optical center /// in the image. r2 must lie in the range [0,1]. Note that this is /// different than the Evaluate () function, above, in that the argument /// to EvaluateRatio () is the square of the radius, not the radius /// itself. The returned result is non-negative. Mathematically, /// EvaluateRatio (r * r) is the same as Evaluate (r) / r. virtual real64 EvaluateRatio (uint32 plane, real64 r2) const = 0; /// Evaluate the 2D tangential warp for the specified plane. Parameter /// r2 is the square of the destination (i.e., corrected) normalized /// radius, i.e., the square of the normalized Euclidean distance /// between a corrected pixel position P and the optical center in the /// image. r2 must lie in the range [0,1]. diff contains the vertical /// and horizontal Euclidean distances (in pixels) between P and the /// optical center. diff2 contains the squares of the vertical and /// horizontal Euclidean distances (in pixels) between P and the optical /// center. The returned result is the tangential warp offset, measured /// in pixels. virtual dng_point_real64 EvaluateTangential (uint32 plane, real64 r2, const dng_point_real64 &diff, const dng_point_real64 &diff2) const = 0; /// Evaluate the 2D tangential warp for the specified plane. diff /// contains the vertical and horizontal Euclidean distances (in pixels) /// between the destination (i.e., corrected) pixel position and the /// optical center in the image. The returned result is the tangential /// warp offset, measured in pixels. dng_point_real64 EvaluateTangential2 (uint32 plane, const dng_point_real64 &diff) const; /// Evaluate the 2D tangential warp for the specified plane. Parameter /// r2 is the square of the destination (i.e., corrected) normalized /// radius, i.e., the square of the normalized Euclidean distance /// between a corrected pixel position P and the optical center in the /// image. r2 must lie in the range [0,1]. diff contains the vertical /// and horizontal Euclidean distances (in pixels) between P and the /// optical center. The returned result is the tangential warp offset, /// measured in pixels. dng_point_real64 EvaluateTangential3 (uint32 plane, real64 r2, const dng_point_real64 &diff) const; /// Compute and return the maximum warped radius gap. Let D be a /// rectangle in a destination (corrected) image. Let rDstFar and /// rDstNear be the farthest and nearest points to the image center, /// respectively. Then the specified parameter maxDstGap is the /// Euclidean distance between rDstFar and rDstNear. Warp D through this /// warp function to a closed and bounded (generally not rectangular) /// region S. Let rSrcfar and rSrcNear be the farthest and nearest /// points to the image center, respectively. This routine returns a /// value that is at least (rSrcFar - rSrcNear). virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const = 0; /// Compute and return the maximum warped tangential gap. minDst is the /// top-left pixel of the image in normalized pixel coordinates. maxDst /// is the bottom-right pixel of the image in normalized pixel /// coordinates. MaxSrcTanGap () computes the maximum absolute shift in /// normalized pixels in the horizontal and vertical directions that can /// occur as a result of the tangential warp. virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst, dng_point_real64 maxDst) const = 0; /// Debug parameters. virtual void Dump () const; }; /*****************************************************************************/ /// \brief Warp parameters for pinhole perspective rectilinear (not fisheye) /// camera model. Supports radial and tangential (decentering) distortion /// correction parameters. /// /// Note the restrictions described below. class dng_warp_params_rectilinear: public dng_warp_params { public: // Radial and tangential polynomial coefficients. These define a warp // from corrected pixel coordinates (xDst, yDst) to uncorrected pixel // coordinates (xSrc, ySrc) for each plane P as follows: // // Let kr0 = fRadParams [P][0] // kr1 = fRadParams [P][1] // kr2 = fRadParams [P][2] // kr3 = fRadParams [P][3] // // kt0 = fTanParams [P][0] // kt1 = fTanParams [P][1] // // Let (xCenter, yCenter) be the optical image center (see fCenter, // below) expressed in pixel coordinates. Let maxDist be the Euclidean // distance (in pixels) from (xCenter, yCenter) to the farthest image // corner. // // First, compute the normalized distance of the corrected pixel // position (xDst, yDst) from the image center: // // dx = (xDst - xCenter) / maxDist // dy = (yDst - yCenter) / maxDist // // r^2 = dx^2 + dy^2 // // Compute the radial correction term: // // ratio = kr0 + (kr1 * r^2) + (kr2 * r^4) + (kr3 * r^6) // // dxRad = dx * ratio // dyRad = dy * ratio // // Compute the tangential correction term: // // dxTan = (2 * kt0 * dx * dy) + kt1 * (r^2 + 2 * dx^2) // dyTan = (2 * kt1 * dx * dy) + kt0 * (r^2 + 2 * dy^2) // // Compute the uncorrected pixel position (xSrc, ySrc): // // xSrc = xCenter + (dxRad + dxTan) * maxDist // ySrc = yCenter + (dyRad + dyTan) * maxDist // // Mathematical definitions and restrictions: // // Let { xSrc, ySrc } = f (xDst, yDst) be the warp function defined // above. // // Let xSrc = fx (xDst, yDst) be the x-component of the warp function. // Let ySrc = fy (xDst, yDst) be the y-component of the warp function. // // f (x, y) must be an invertible function. // // fx (x, y) must be an increasing function of x. // fy (x, y) must be an increasing function of x. // // The parameters kr0, kr1, kr2, and kr3 must define an increasing // radial warp function. Specifically, let w (r) be the radial warp // function: // // w (r) = (kr0 * r) + (kr1 * r^3) + (kr2 * r^5) + (kr3 * r^7). // // w (r) must be an increasing function. dng_vector fRadParams [kMaxColorPlanes]; dng_vector fTanParams [kMaxColorPlanes]; public: /// Create empty (invalid) rectilinear warp parameters. dng_warp_params_rectilinear (); /// Create rectilinear warp parameters with the specified number of /// planes, radial component terms, tangential component terms, and /// image center in relative coordinates. dng_warp_params_rectilinear (uint32 planes, const dng_vector radParams [], const dng_vector tanParams [], const dng_point_real64 &fCenter); virtual ~dng_warp_params_rectilinear (); // Overridden methods. virtual bool IsRadNOP (uint32 plane) const; virtual bool IsTanNOP (uint32 plane) const; virtual bool IsValid () const; virtual void PropagateToAllPlanes (uint32 totalPlanes); virtual real64 Evaluate (uint32 plane, real64 r) const; virtual real64 EvaluateRatio (uint32 plane, real64 r2) const; virtual dng_point_real64 EvaluateTangential (uint32 plane, real64 r2, const dng_point_real64 &diff, const dng_point_real64 &diff2) const; virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const; virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst, dng_point_real64 maxDst) const; virtual void Dump () const; }; /*****************************************************************************/ /// \brief Warp parameters for fisheye camera model (radial component only). /// Note the restrictions described below. class dng_warp_params_fisheye: public dng_warp_params { public: // Radial warp coefficients. These define a warp from corrected pixel // coordinates (xDst, yDst) to uncorrected pixel coordinates (xSrc, // ySrc) for each plane P as follows: // // Let kr0 = fRadParams [P][0] // kr1 = fRadParams [P][1] // kr2 = fRadParams [P][2] // kr3 = fRadParams [P][3] // // Let (xCenter, yCenter) be the optical image center (see fCenter, // below) expressed in pixel coordinates. Let maxDist be the Euclidean // distance (in pixels) from (xCenter, yCenter) to the farthest image // corner. // // First, compute the normalized distance of the corrected pixel // position (xDst, yDst) from the image center: // // dx = (xDst - xCenter) / maxDist // dy = (yDst - yCenter) / maxDist // // r = sqrt (dx^2 + dy^2) // // Compute the radial correction term: // // t = atan (r) // // rWarp = (kr0 * t) + (kr1 * t^3) + (kr2 * t^5) + (kr3 * t^7) // // ratio = rWarp / r // // dxRad = dx * ratio // dyRad = dy * ratio // // Compute the uncorrected pixel position (xSrc, ySrc): // // xSrc = xCenter + (dxRad * maxDist) // ySrc = yCenter + (dyRad * maxDist) // // The parameters kr0, kr1, kr2, and kr3 must define an increasing // radial warp function. Specifically, let w (r) be the radial warp // function: // // t = atan (r) // // w (r) = (kr0 * t) + (kr1 * t^3) + (kr2 * t^5) + (kr3 * t^7). // // w (r) must be an increasing function. dng_vector fRadParams [kMaxColorPlanes]; public: /// Create empty (invalid) fisheye warp parameters. dng_warp_params_fisheye (); /// Create rectilinear warp parameters with the specified number of /// planes, radial component terms, and image center in relative /// coordinates. dng_warp_params_fisheye (uint32 planes, const dng_vector radParams [], const dng_point_real64 &fCenter); virtual ~dng_warp_params_fisheye (); // Overridden methods. virtual bool IsRadNOP (uint32 plane) const; virtual bool IsTanNOP (uint32 plane) const; virtual bool IsValid () const; virtual void PropagateToAllPlanes (uint32 totalPlanes); virtual real64 Evaluate (uint32 plane, real64 r) const; virtual real64 EvaluateRatio (uint32 plane, real64 r2) const; virtual dng_point_real64 EvaluateTangential (uint32 plane, real64 r2, const dng_point_real64 &diff, const dng_point_real64 &diff2) const; virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const; virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst, dng_point_real64 maxDst) const; virtual void Dump () const; }; /*****************************************************************************/ /// \brief Warp opcode for pinhole perspective (rectilinear) camera model. class dng_opcode_WarpRectilinear: public dng_opcode { protected: dng_warp_params_rectilinear fWarpParams; public: dng_opcode_WarpRectilinear (const dng_warp_params_rectilinear ¶ms, uint32 flags); explicit dng_opcode_WarpRectilinear (dng_stream &stream); // Overridden methods. virtual bool IsNOP () const; virtual bool IsValidForNegative (const dng_negative &negative) const; virtual void PutData (dng_stream &stream) const; virtual void Apply (dng_host &host, dng_negative &negative, AutoPtr<dng_image> &image); protected: static uint32 ParamBytes (uint32 planes); }; /*****************************************************************************/ /// \brief Warp opcode for fisheye camera model. class dng_opcode_WarpFisheye: public dng_opcode { protected: dng_warp_params_fisheye fWarpParams; public: dng_opcode_WarpFisheye (const dng_warp_params_fisheye ¶ms, uint32 flags); explicit dng_opcode_WarpFisheye (dng_stream &stream); // Overridden methods. virtual bool IsNOP () const; virtual bool IsValidForNegative (const dng_negative &negative) const; virtual void PutData (dng_stream &stream) const; virtual void Apply (dng_host &host, dng_negative &negative, AutoPtr<dng_image> &image); protected: static uint32 ParamBytes (uint32 planes); }; /*****************************************************************************/ /// \brief Radially-symmetric vignette (peripheral illuminational falloff) /// correction parameters. class dng_vignette_radial_params { public: static const uint32 kNumTerms = 5; public: // Let v be an uncorrected pixel value of a pixel p in linear space. // // Let r be the Euclidean distance between p and the optical center. // // Compute corrected pixel value v' = v * g, where g is the gain. // // Let k0 = fParams [0] // Let k1 = fParams [1] // Let k2 = fParams [2] // Let k3 = fParams [3] // Let k4 = fParams [4] // // Gain g = 1 + (k0 * r^2) + (k1 * r^4) + (k2 * r^6) + (k3 * r^8) + (k4 * r^10) dng_std_vector<real64> fParams; dng_point_real64 fCenter; public: dng_vignette_radial_params (); dng_vignette_radial_params (const dng_std_vector<real64> ¶ms, const dng_point_real64 ¢er); bool IsNOP () const; bool IsValid () const; // For debugging. void Dump () const; }; /*****************************************************************************/ /// \brief Radially-symmetric lens vignette correction opcode. class dng_opcode_FixVignetteRadial: public dng_inplace_opcode { protected: dng_vignette_radial_params fParams; uint32 fImagePlanes; int64 fSrcOriginH; int64 fSrcOriginV; int64 fSrcStepH; int64 fSrcStepV; uint32 fTableInputBits; uint32 fTableOutputBits; AutoPtr<dng_memory_block> fGainTable; AutoPtr<dng_memory_block> fMaskBuffers [kMaxMPThreads]; public: dng_opcode_FixVignetteRadial (const dng_vignette_radial_params ¶ms, uint32 flags); explicit dng_opcode_FixVignetteRadial (dng_stream &stream); virtual bool IsNOP () const; virtual bool IsValidForNegative (const dng_negative &) const; virtual void PutData (dng_stream &stream) const; virtual uint32 BufferPixelType (uint32 /* imagePixelType */) { return ttFloat; } virtual void Prepare (dng_negative &negative, uint32 threadCount, const dng_point &tileSize, const dng_rect &imageBounds, uint32 imagePlanes, uint32 bufferPixelType, dng_memory_allocator &allocator); virtual void ProcessArea (dng_negative &negative, uint32 threadIndex, dng_pixel_buffer &buffer, const dng_rect &dstArea, const dng_rect &imageBounds); protected: static uint32 ParamBytes (); }; /*****************************************************************************/ #endif /*****************************************************************************/