From: cristy Date: Wed, 12 Sep 2012 13:12:43 +0000 (+0000) Subject: (no commit message) X-Git-Tag: 7.0.1-0~4958 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5eab53559e8311ef3ff0a137353cb0d348fbe863;p=imagemagick --- diff --git a/MagickCore/enhance.c b/MagickCore/enhance.c index 5e2551536..2b42da1cd 100644 --- a/MagickCore/enhance.c +++ b/MagickCore/enhance.c @@ -3292,30 +3292,6 @@ MagickExport MagickBooleanType NormalizeImage(Image *image, % o exception: return any errors or warnings in this structure. % */ -MagickExport MagickBooleanType SigmoidalContrastImage(Image *image, - const MagickBooleanType sharpen,const double contrast,const double midpoint, - ExceptionInfo *exception) -{ -#define SigmoidalContrastImageTag "SigmoidalContrast/Image" - - CacheView - *image_view; - - MagickBooleanType - status; - - MagickOffsetType - progress; - - ssize_t - y; - - /* - Side effect: clamps values unless contrast0 is the identity, but a=0 gives a - division by zero. This is fixed above by exiting immediately when - contrast is small, leaving the image (or colormap) unmodified. This - appears to be safe because the series expansion of the logistic - sigmoidal function around x=b is 1/2-a*(b-x)/4+... so that the key - denominator s(1)-s(0) is about a/4 (a/2 with tanh). - */ + + See http://osdir.com/ml/video.image-magick.devel/2005-04/msg00006.html and + http://www.cs.dartmouth.edu/farid/downloads/tutorials/fip.pdf. The limit + of ScaledSigmoidal as a->0 is the identity, but a=0 gives a division by + zero. This is fixed above by exiting immediately when contrast is small, + leaving the image (or colormap) unmodified. This appears to be safe because + the series expansion of the logistic sigmoidal function around x=b is + 1/2-a*(b-x)/4+... so that the key denominator s(1)-s(0) is about a/4 + (a/2 with tanh). +*/ #define ScaledSigmoidal(a,b,x) ( \ (Sigmoidal((a),(b),(x))-Sigmoidal((a),(b),0.0)) / \ (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) ) - /* - Inverse of ScaledSigmoidal, used for +sigmoidal-contrast. - Because b may be 0 or 1, the argument of the hyperbolic tangent - (resp. logistic sigmoidal) may be outside of the interval (-1,1) - (resp. (0,1)), even when creating a LUT, hence the branching. - In addition, HDRI may have out of gamut values. - InverseScaledSigmoidal is not a two-side inverse of - ScaledSigmoidal: It is only a right inverse. This is unavoidable. - */ +/* + Inverse of ScaledSigmoidal, used for +sigmoidal-contrast. Because b may be + 0 or 1, the argument of the hyperbolic tangent (resp. logistic sigmoidal) + may be outside of the interval (-1,1) (resp. (0,1)), even when creating a + LUT, hence the branching. In addition, HDRI may have out of gamut values. + InverseScaledSigmoidal is not a two-side inverse of ScaledSigmoidal: + It is only a right inverse. This is unavoidable. +*/ #if defined(MAGICKCORE_HAVE_ATANH) -#define InverseScaledSigmoidal(a,b,x) ({ \ - const double _argument = \ - (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) * (x) + \ - Sigmoidal((a),(b),0.0); \ - const double _clamped_argument = \ - ( _argument < -1+MagickEpsilon ? -1+MagickEpsilon : \ - ( _argument > 1-MagickEpsilon ? 1-MagickEpsilon : _argument ) ); \ - (b) + (2.0/(a)) * atanh(_clamped_argument); }) +static inline double InverseScaledSigmoidal(const double a,const double b, + const double x) +{ + const double _argument = + (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) * (x) + + Sigmoidal((a),(b),0.0); + + const double _clamped_argument = + ( _argument < -1+MagickEpsilon ? -1+MagickEpsilon : + ( _argument > 1-MagickEpsilon ? 1-MagickEpsilon : _argument ) ); + + return((b) + (2.0/(a)) * atanh(_clamped_argument)); +} #else -#define InverseScaledSigmoidal(a,b,x) ({ \ - const double _argument = \ - (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) * (x) + \ - Sigmoidal((a),(b),0.0); \ - const double _clamped_argument = \ - ( _argument < MagickEpsilon ? MagickEpsilon : \ - ( _argument > 1-MagickEpsilon ? 1-MagickEpsilon : _argument ) ); \ - (b) + (-1.0/(a)) * log(1.0/_clamped_argument+-1.0); }) +static inline double InverseScaledSigmoidal(const double a,const double b, + const double x) +{ + const double _argument = + (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) * (x) + + Sigmoidal((a),(b),0.0); + + const double _clamped_argument = + ( _argument < MagickEpsilon ? MagickEpsilon : + ( _argument > 1-MagickEpsilon ? 1-MagickEpsilon : _argument ) ); + + return((b) + (-1.0/(a)) * log(1.0/_clamped_argument+-1.0)); +} #endif - /* - Convenience macros. - */ + +MagickExport MagickBooleanType SigmoidalContrastImage(Image *image, + const MagickBooleanType sharpen,const double contrast,const double midpoint, + ExceptionInfo *exception) +{ +#define SigmoidalContrastImageTag "SigmoidalContrast/Image" #define ScaledSig(x) ( ClampToQuantum(QuantumRange* \ ScaledSigmoidal(contrast,QuantumScale*midpoint,QuantumScale*(x))) ) #define InverseScaledSig(x) ( ClampToQuantum(QuantumRange* \ InverseScaledSigmoidal(contrast,QuantumScale*midpoint,QuantumScale*(x))) ) + CacheView + *image_view; + + MagickBooleanType + status; + + MagickOffsetType + progress; + + ssize_t + y; + + /* + Convenience macros. + */ assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + /* + Side effect: clamps values unless contrast