]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/enhance.c
Add RobidouxSharp filter depreciate Bessel Filter and Static Gravity
[imagemagick] / MagickCore / enhance.c
index 9a00a21b1adc6ec4dd34ad5efbda93396b02394f..ca2399db09801811fd3630b38d4c4363c4bbfc66 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -47,6 +47,7 @@
 #include "MagickCore/color.h"
 #include "MagickCore/color-private.h"
 #include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
 #include "MagickCore/composite-private.h"
 #include "MagickCore/enhance.h"
 #include "MagickCore/exception.h"
@@ -62,6 +63,7 @@
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/quantum.h"
 #include "MagickCore/quantum-private.h"
@@ -134,10 +136,14 @@ MagickExport MagickBooleanType AutoGammaImage(Image *image,
     ChannelType
       channel_mask;
 
+    PixelChannel
+      channel;
+
     PixelTrait
       traits;
 
-    traits=GetPixelChannelMapTraits(image,i);
+    channel=GetPixelChannelMapChannel(image,i);
+    traits=GetPixelChannelMapTraits(image,channel);
     if ((traits & UpdatePixelTrait) == 0)
       continue;
     channel_mask=SetPixelChannelMask(image,(ChannelType) (1 << i));
@@ -299,20 +305,19 @@ MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
     *clut_view,
     *image_view;
 
-  double
-    *clut_map;
-
   MagickBooleanType
     status;
 
   MagickOffsetType
     progress;
 
+  PixelInfo
+    *clut_map;
+
   register ssize_t
-    x;
+    i;
 
-  ssize_t
-    adjust,
+  ssize_t adjust,
     y;
 
   assert(image != (Image *) NULL);
@@ -323,9 +328,10 @@ MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
   assert(clut_image->signature == MagickSignature);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
-  clut_map=(double *) AcquireQuantumMemory(MaxMap+1UL,GetPixelChannels(image)*
-    sizeof(*clut_map));
-  if (clut_map == (double *) NULL)
+  if (IsGrayColorspace(image->colorspace) != MagickFalse)
+    (void) TransformImageColorspace(image,sRGBColorspace,exception);
+  clut_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*clut_map));
+  if (clut_map == (PixelInfo *) NULL)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   /*
@@ -334,28 +340,27 @@ MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
   status=MagickTrue;
   progress=0;
   adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
-  clut_view=AcquireCacheView(clut_image);
+  clut_view=AcquireVirtualCacheView(clut_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4)
+  #pragma omp parallel for schedule(static,4)
 #endif
-  for (x=0; x <= (ssize_t) MaxMap; x++)
+  for (i=0; i <= (ssize_t) MaxMap; i++)
   {
-    register ssize_t
-      i;
-
-    for (i=0; i < (ssize_t) GetPixelChannels(clut_image); i++)
-      (void) InterpolatePixelChannel(clut_image,clut_view,(PixelChannel) i,
-        method,QuantumScale*x*(clut_image->columns-adjust),QuantumScale*x*
-        (clut_image->rows-adjust),clut_map+x*GetPixelChannels(clut_image)+i,
-        exception);
+    GetPixelInfo(clut_image,clut_map+i);
+    (void) InterpolatePixelInfo(clut_image,clut_view,method,
+      QuantumScale*i*(clut_image->columns-adjust),QuantumScale*i*
+      (clut_image->rows-adjust),clut_map+i,exception);
   }
   clut_view=DestroyCacheView(clut_view);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
+    PixelInfo
+      pixel;
+
     register Quantum
       *restrict q;
 
@@ -370,31 +375,21 @@ MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
         status=MagickFalse;
         continue;
       }
+    GetPixelInfo(image,&pixel);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      register ssize_t
-        i;
-
-      for (i=0; i < (ssize_t) GetPixelChannels(clut_image); i++)
-      {
-        PixelChannel
-          channel;
-
-        PixelTrait
-          clut_traits,
-          traits;
-
-        clut_traits=GetPixelChannelMapTraits(clut_image,i);
-        channel=GetPixelChannelMapChannel(clut_image,i);
-        traits=GetPixelChannelMapTraits(clut_image,channel);
-        if ((traits == UndefinedPixelTrait) ||
-            (clut_traits == UndefinedPixelTrait) ||
-            ((traits & UpdatePixelTrait) == 0))
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
           continue;
-        SetPixelChannel(clut_image,channel,ClampToQuantum(clut_map[
-          ScaleQuantumToMap(GetPixelChannel(clut_image,channel,q))*
-          GetPixelChannels(clut_image)+channel]),q);
-      }
+        }
+      GetPixelInfoPixel(image,q,&pixel);
+      pixel.red=clut_map[ScaleQuantumToMap(pixel.red)].red;
+      pixel.green=clut_map[ScaleQuantumToMap(pixel.green)].green;
+      pixel.blue=clut_map[ScaleQuantumToMap(pixel.blue)].blue;
+      pixel.black=clut_map[ScaleQuantumToMap(pixel.black)].black;
+      pixel.alpha=clut_map[ScaleQuantumToMap(pixel.alpha)].alpha;
+      SetPixelInfoPixel(image,&pixel,q);
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -405,7 +400,7 @@ MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ClutImage)
+        #pragma omp critical (MagickCore_ClutImage)
 #endif
         proceed=SetImageProgress(image,ClutImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -413,7 +408,7 @@ MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image,
       }
   }
   image_view=DestroyCacheView(image_view);
-  clut_map=(double *) RelinquishMagickMemory(clut_map);
+  clut_map=(PixelInfo *) RelinquishMagickMemory(clut_map);
   if ((clut_image->matte != MagickFalse) &&
       ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0))
     (void) SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
@@ -669,8 +664,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
           content=GetXMLTreeContent(saturation);
           p=(const char *) content;
           GetMagickToken(p,&p,token);
-          color_correction.saturation=StringToDouble(token,
-            (char **) NULL);
+          color_correction.saturation=StringToDouble(token,(char **) NULL);
         }
     }
   ccc=DestroyXMLTree(ccc);
@@ -704,7 +698,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4)
+  #pragma omp parallel for schedule(static,4)
 #endif
   for (i=0; i <= (ssize_t) MaxMap; i++)
   {
@@ -724,7 +718,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
         Apply transfer function to colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
@@ -733,15 +727,15 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
 
         luma=0.2126*image->colormap[i].red+0.7152*image->colormap[i].green+
           0.0722*image->colormap[i].blue;
-        image->colormap[i].red=luma+color_correction.saturation*
-          cdl_map[ScaleQuantumToMap(ClampToQuantum(
-          image->colormap[i].red))].red-luma;
-        image->colormap[i].green=luma+color_correction.saturation*
-          cdl_map[ScaleQuantumToMap(ClampToQuantum(
-          image->colormap[i].green))].green-luma;
-        image->colormap[i].blue=luma+color_correction.saturation*
-          cdl_map[ScaleQuantumToMap(ClampToQuantum(
-          image->colormap[i].blue))].blue-luma;
+        image->colormap[i].red=luma+color_correction.saturation*cdl_map[
+          ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red))].red-
+          luma;
+        image->colormap[i].green=luma+color_correction.saturation*cdl_map[
+          ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green))].green-
+          luma;
+        image->colormap[i].blue=luma+color_correction.saturation*cdl_map[
+          ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue))].blue-
+          luma;
       }
     }
   /*
@@ -749,9 +743,9 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -792,7 +786,7 @@ MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ColorDecisionListImageChannel)
+        #pragma omp critical (MagickCore_ColorDecisionListImageChannel)
 #endif
         proceed=SetImageProgress(image,ColorDecisionListCorrectImageTag,
           progress++,image->rows);
@@ -904,9 +898,9 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -948,7 +942,7 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ContrastImage)
+        #pragma omp critical (MagickCore_ContrastImage)
 #endif
         proceed=SetImageProgress(image,ContrastImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -971,11 +965,11 @@ MagickExport MagickBooleanType ContrastImage(Image *image,
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  ContrastStretchImage() is a simple image enhancement technique that attempts
-%  to improve the contrast in an image by `stretching' the range of intensity
+%  to improve the contrast in an image by 'stretching' the range of intensity
 %  values it contains to span a desired range of values. It differs from the
 %  more sophisticated histogram equalization in that it can only apply a
 %  linear scaling function to the image pixel values.  As a result the
-%  `enhancement' is less harsh.
+%  'enhancement' is less harsh.
 %
 %  The format of the ContrastStretchImage method is:
 %
@@ -1020,6 +1014,9 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
   register ssize_t
     i;
 
+  size_t
+    number_channels;
+
   ssize_t
     y;
 
@@ -1032,8 +1029,8 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   black=(double *) AcquireQuantumMemory(GetPixelChannels(image),sizeof(*black));
   white=(double *) AcquireQuantumMemory(GetPixelChannels(image),sizeof(*white));
-  histogram=(double *) AcquireQuantumMemory(MaxMap+1UL,
-    GetPixelChannels(image)*sizeof(*histogram));
+  histogram=(double *) AcquireQuantumMemory(MaxMap+1UL,GetPixelChannels(image)*
+    sizeof(*histogram));
   stretch_map=(double *) AcquireQuantumMemory(MaxMap+1UL,
     GetPixelChannels(image)*sizeof(*stretch_map));
   if ((black == (double *) NULL) || (white == (double *) NULL) ||
@@ -1056,7 +1053,7 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
   status=MagickTrue;
   (void) ResetMagickMemory(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
     sizeof(*histogram));
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -1083,13 +1080,15 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
       p+=GetPixelChannels(image);
     }
   }
+  image_view=DestroyCacheView(image_view);
   /*
     Find the histogram boundaries by locating the black/white levels.
   */
+  number_channels=GetPixelChannels(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  for (i=0; i < (ssize_t) number_channels; i++)
   {
     double
       intensity;
@@ -1122,10 +1121,11 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
   */
   (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*GetPixelChannels(image)*
     sizeof(*stretch_map));
+  number_channels=GetPixelChannels(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  for (i=0; i < (ssize_t) number_channels; i++)
   {
     register ssize_t
       j;
@@ -1154,7 +1154,7 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
         Stretch-contrast colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (j=0; j < (ssize_t) image->colors; j++)
       {
@@ -1193,8 +1193,9 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1217,15 +1218,25 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
       register ssize_t
         i;
 
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
+        PixelChannel
+          channel;
+
         PixelTrait
           traits;
 
-        traits=GetPixelChannelMapTraits(image,i);
-        if (((traits & UpdatePixelTrait) != 0) && (black[i] != white[i]))
-          q[i]=ClampToQuantum(stretch_map[GetPixelChannels(image)*
-            ScaleQuantumToMap(q[i])+i]);
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if (((traits & UpdatePixelTrait) == 0) || (black[i] == white[i]))
+          continue;
+        q[i]=ClampToQuantum(stretch_map[GetPixelChannels(image)*
+          ScaleQuantumToMap(q[i])+i]);
       }
       q+=GetPixelChannels(image);
     }
@@ -1237,7 +1248,7 @@ MagickExport MagickBooleanType ContrastStretchImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ContrastStretchImage)
+        #pragma omp critical (MagickCore_ContrastStretchImage)
 #endif
         proceed=SetImageProgress(image,ContrastStretchImageTag,progress++,
           image->rows);
@@ -1333,10 +1344,10 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  enhance_view=AcquireCacheView(enhance_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  enhance_view=AcquireAuthenticCacheView(enhance_image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1368,6 +1379,12 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
       register ssize_t
         i;
 
+      if (GetPixelMask(image,p) != 0)
+        {
+          p+=GetPixelChannels(image);
+          q+=GetPixelChannels(enhance_image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
         MagickRealType
@@ -1387,8 +1404,8 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
         register const Quantum
           *restrict r;
 
-        traits=GetPixelChannelMapTraits(image,i);
         channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
         enhance_traits=GetPixelChannelMapTraits(enhance_image,channel);
         if ((traits == UndefinedPixelTrait) ||
             (enhance_traits == UndefinedPixelTrait))
@@ -1430,7 +1447,7 @@ MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_EnhanceImage)
+        #pragma omp critical (MagickCore_EnhanceImage)
 #endif
         proceed=SetImageProgress(image,EnhanceImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -1490,6 +1507,9 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
   register ssize_t
     i;
 
+  size_t
+    number_channels;
+
   ssize_t
     y;
 
@@ -1525,7 +1545,7 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
   status=MagickTrue;
   (void) ResetMagickMemory(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
     sizeof(*histogram));
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -1552,13 +1572,15 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
       p+=GetPixelChannels(image);
     }
   }
+  image_view=DestroyCacheView(image_view);
   /*
     Integrate the histogram to get the equalization map.
   */
+  number_channels=GetPixelChannels(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  for (i=0; i < (ssize_t) number_channels; i++)
   {
     MagickRealType
       intensity;
@@ -1575,10 +1597,11 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
   }
   (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*GetPixelChannels(image)*
     sizeof(*equalize_map));
+  number_channels=GetPixelChannels(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  for (i=0; i < (ssize_t) number_channels; i++)
   {
     register ssize_t
       j;
@@ -1605,7 +1628,7 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
         Equalize colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (j=0; j < (ssize_t) image->colors; j++)
       {
@@ -1647,8 +1670,9 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
     Equalize image.
   */
   progress=0;
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1671,15 +1695,25 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
       register ssize_t
         i;
 
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
+        PixelChannel
+          channel;
+
         PixelTrait
           traits;
 
-        traits=GetPixelChannelMapTraits(image,i);
-        if (((traits & UpdatePixelTrait) != 0) && (black[i] != white[i]))
-          q[i]=ClampToQuantum(equalize_map[GetPixelChannels(image)*
-            ScaleQuantumToMap(q[i])+i]);
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if (((traits & UpdatePixelTrait) == 0) || (black[i] == white[i]))
+          continue;
+        q[i]=ClampToQuantum(equalize_map[GetPixelChannels(image)*
+          ScaleQuantumToMap(q[i])+i]);
       }
       q+=GetPixelChannels(image);
     }
@@ -1691,7 +1725,7 @@ MagickExport MagickBooleanType EqualizeImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_EqualizeImage)
+        #pragma omp critical (MagickCore_EqualizeImage)
 #endif
         proceed=SetImageProgress(image,EqualizeImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -1745,15 +1779,15 @@ MagickExport MagickBooleanType GammaImage(Image *image,const double gamma,
   CacheView
     *image_view;
 
-  double
-    *gamma_map;
-
   MagickBooleanType
     status;
 
   MagickOffsetType
     progress;
 
+  Quantum
+    *gamma_map;
+
   register ssize_t
     i;
 
@@ -1769,39 +1803,39 @@ MagickExport MagickBooleanType GammaImage(Image *image,const double gamma,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if (gamma == 1.0)
     return(MagickTrue);
-  gamma_map=(double *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*gamma_map));
-  if (gamma_map == (double *) NULL)
+  gamma_map=(Quantum *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*gamma_map));
+  if (gamma_map == (Quantum *) NULL)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   (void) ResetMagickMemory(gamma_map,0,(MaxMap+1)*sizeof(*gamma_map));
   if (gamma != 0.0)
 #if defined(MAGICKCORE_OPENMP_SUPPORT) && (MaxMap > 256)
-  #pragma omp parallel for
+    #pragma omp parallel for
 #endif
     for (i=0; i <= (ssize_t) MaxMap; i++)
-      gamma_map[i]=(MagickRealType) ScaleMapToQuantum((
-        MagickRealType) (MaxMap*pow((double) i/MaxMap,1.0/gamma)));
+      gamma_map[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*pow((double) i/
+        MaxMap,1.0/gamma)));
   if (image->storage_class == PseudoClass)
     {
       /*
         Gamma-correct colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-          image->colormap[i].red=gamma_map[
+          image->colormap[i].red=(MagickRealType) gamma_map[
             ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red))];
         if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-          image->colormap[i].green=gamma_map[
+          image->colormap[i].green=(MagickRealType) gamma_map[
             ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green))];
         if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-          image->colormap[i].blue=gamma_map[
+          image->colormap[i].blue=(MagickRealType) gamma_map[
             ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue))];
         if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-          image->colormap[i].alpha=gamma_map[
+          image->colormap[i].alpha=(MagickRealType) gamma_map[
             ScaleQuantumToMap(ClampToQuantum(image->colormap[i].alpha))];
       }
     }
@@ -1810,9 +1844,9 @@ MagickExport MagickBooleanType GammaImage(Image *image,const double gamma,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1835,14 +1869,24 @@ MagickExport MagickBooleanType GammaImage(Image *image,const double gamma,
       register ssize_t
         i;
 
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
+        PixelChannel
+          channel;
+
         PixelTrait
           traits;
 
-        traits=GetPixelChannelMapTraits(image,i);
-        if ((traits & UpdatePixelTrait) != 0)
-          q[i]=ClampToQuantum(gamma_map[ScaleQuantumToMap(q[i])]);
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=gamma_map[ScaleQuantumToMap(q[i])];
       }
       q+=GetPixelChannels(image);
     }
@@ -1854,7 +1898,7 @@ MagickExport MagickBooleanType GammaImage(Image *image,const double gamma,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_GammaImage)
+        #pragma omp critical (MagickCore_GammaImage)
 #endif
         proceed=SetImageProgress(image,GammaCorrectImageTag,progress++,
           image->rows);
@@ -1863,7 +1907,7 @@ MagickExport MagickBooleanType GammaImage(Image *image,const double gamma,
       }
   }
   image_view=DestroyCacheView(image_view);
-  gamma_map=(double *) RelinquishMagickMemory(gamma_map);
+  gamma_map=(Quantum *) RelinquishMagickMemory(gamma_map);
   if (image->gamma != 0.0)
     image->gamma*=gamma;
   return(status);
@@ -1953,6 +1997,8 @@ MagickExport MagickBooleanType HaldClutImage(Image *image,
   assert(hald_image->signature == MagickSignature);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
+  if (IsGrayColorspace(image->colorspace) != MagickFalse)
+    (void) TransformImageColorspace(image,sRGBColorspace,exception);
   if (image->matte == MagickFalse)
     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   /*
@@ -1966,10 +2012,10 @@ MagickExport MagickBooleanType HaldClutImage(Image *image,
   cube_size=level*level;
   width=(double) hald_image->columns;
   GetPixelInfo(hald_image,&zero);
-  image_view=AcquireCacheView(image);
-  hald_view=AcquireCacheView(hald_image);
+  hald_view=AcquireVirtualCacheView(hald_image,exception);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2051,7 +2097,7 @@ MagickExport MagickBooleanType HaldClutImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_HaldClutImage)
+        #pragma omp critical (MagickCore_HaldClutImage)
 #endif
         proceed=SetImageProgress(image,HaldClutImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2106,12 +2152,28 @@ MagickExport MagickBooleanType HaldClutImage(Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
+
+static inline MagickRealType LevelPixel(const double black_point,
+  const double white_point,const double gamma,const MagickRealType pixel)
+{
+  double
+    level_pixel,
+    scale;
+
+  if (pixel < black_point)
+    return(0.0);
+  if (pixel > white_point)
+    return((MagickRealType) QuantumRange);
+  scale=(white_point != black_point) ? 1.0/(white_point-black_point) : 1.0;
+  level_pixel=(MagickRealType) QuantumRange*pow(scale*((double) pixel-
+    black_point),1.0/gamma);
+  return(level_pixel);
+}
+
 MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
   const double white_point,const double gamma,ExceptionInfo *exception)
 {
 #define LevelImageTag  "Level/Image"
-#define LevelQuantum(x) (ClampToQuantum((MagickRealType) QuantumRange* \
-  pow(scale*((double) (x)-black_point),1.0/gamma)))
 
   CacheView
     *image_view;
@@ -2122,9 +2184,6 @@ MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
   MagickOffsetType
     progress;
 
-  register double
-    scale;
-
   register ssize_t
     i;
 
@@ -2138,10 +2197,9 @@ MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  scale=(white_point != black_point) ? 1.0/(white_point-black_point) : 1.0;
   if (image->storage_class == PseudoClass)
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+    #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
     for (i=0; i < (ssize_t) image->colors; i++)
     {
@@ -2149,26 +2207,26 @@ MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
         Level colormap.
       */
       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        image->colormap[i].red=(double) LevelQuantum(
-          image->colormap[i].red);
+        image->colormap[i].red=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].red));
       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        image->colormap[i].green=(double) LevelQuantum(
-          image->colormap[i].green);
+        image->colormap[i].green=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].green));
       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        image->colormap[i].blue=(double) LevelQuantum(
-          image->colormap[i].blue);
+        image->colormap[i].blue=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].blue));
       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        image->colormap[i].alpha=(double) LevelQuantum(
-          image->colormap[i].alpha);
+        image->colormap[i].alpha=(double) ClampToQuantum(LevelPixel(black_point,
+          white_point,gamma,image->colormap[i].alpha));
       }
   /*
     Level image.
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2191,16 +2249,25 @@ MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
       register ssize_t
         i;
 
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
+        PixelChannel
+          channel;
+
         PixelTrait
           traits;
 
-        traits=GetPixelChannelMapTraits(image,i);
-        if ((traits == UndefinedPixelTrait) ||
-            ((traits & UpdatePixelTrait) == 0))
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
           continue;
-        q[i]=LevelQuantum(q[i]);
+        q[i]=ClampToQuantum(LevelPixel(black_point,white_point,gamma,
+          (MagickRealType) q[i]));
       }
       q+=GetPixelChannels(image);
     }
@@ -2212,7 +2279,7 @@ MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_LevelImage)
+        #pragma omp critical (MagickCore_LevelImage)
 #endif
         proceed=SetImageProgress(image,LevelImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2242,10 +2309,10 @@ MagickExport MagickBooleanType LevelImage(Image *image,const double black_point,
 %  LevelizeImage() can be called with by using a +level command line
 %  API option, or using a '!' on a -level or LevelImage() geometry string.
 %
-%  It can be used for example de-contrast a greyscale image to the exact
-%  levels specified.  Or by using specific levels for each channel of an image
-%  you can convert a gray-scale image to any linear color gradient, according
-%  to those levels.
+%  It can be used to de-contrast a greyscale image to the exact levels
+%  specified.  Or by using specific levels for each channel of an image you
+%  can convert a gray-scale image to any linear color gradient, according to
+%  those levels.
 %
 %  The format of the LevelizeImage method is:
 %
@@ -2298,7 +2365,7 @@ MagickExport MagickBooleanType LevelizeImage(Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if (image->storage_class == PseudoClass)
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+    #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
     for (i=0; i < (ssize_t) image->colors; i++)
     {
@@ -2323,9 +2390,9 @@ MagickExport MagickBooleanType LevelizeImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2348,14 +2415,24 @@ MagickExport MagickBooleanType LevelizeImage(Image *image,
       register ssize_t
         i;
 
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
+        PixelChannel
+          channel;
+
         PixelTrait
           traits;
 
-        traits=GetPixelChannelMapTraits(image,i);
-        if ((traits & UpdatePixelTrait) != 0)
-          q[i]=LevelizeValue(q[i]);
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=LevelizeValue(q[i]);
       }
       q+=GetPixelChannels(image);
     }
@@ -2367,7 +2444,7 @@ MagickExport MagickBooleanType LevelizeImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_LevelizeImage)
+        #pragma omp critical (MagickCore_LevelizeImage)
 #endif
         proceed=SetImageProgress(image,LevelizeImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2585,7 +2662,7 @@ MagickExport MagickBooleanType LinearStretchImage(Image *image,
     Form histogram.
   */
   (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -2799,7 +2876,7 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate,
         Modulate colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
         switch (colorspace)
@@ -2833,9 +2910,9 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2898,7 +2975,7 @@ MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ModulateImage)
+        #pragma omp critical (MagickCore_ModulateImage)
 #endif
         proceed=SetImageProgress(image,ModulateImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2967,7 +3044,7 @@ MagickExport MagickBooleanType NegateImage(Image *image,
         Negate colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
@@ -2991,11 +3068,11 @@ MagickExport MagickBooleanType NegateImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
   if (grayscale != MagickFalse)
     {
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
       for (y=0; y < (ssize_t) image->rows; y++)
       {
@@ -3022,19 +3099,25 @@ MagickExport MagickBooleanType NegateImage(Image *image,
           register ssize_t
             i;
 
-          if (IsPixelGray(image,q) != MagickFalse)
+          if ((GetPixelMask(image,q) != 0) ||
+              (IsPixelGray(image,q) != MagickFalse))
             {
               q+=GetPixelChannels(image);
               continue;
             }
           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
           {
+            PixelChannel
+              channel;
+
             PixelTrait
               traits;
 
-            traits=GetPixelChannelMapTraits(image,i);
-            if ((traits & UpdatePixelTrait) != 0)
-              q[i]=QuantumRange-q[i];
+            channel=GetPixelChannelMapChannel(image,i);
+            traits=GetPixelChannelMapTraits(image,channel);
+            if ((traits & UpdatePixelTrait) == 0)
+              continue;
+            q[i]=QuantumRange-q[i];
           }
           q+=GetPixelChannels(image);
         }
@@ -3047,7 +3130,7 @@ MagickExport MagickBooleanType NegateImage(Image *image,
               proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_NegateImage)
+            #pragma omp critical (MagickCore_NegateImage)
 #endif
             proceed=SetImageProgress(image,NegateImageTag,progress++,
               image->rows);
@@ -3062,7 +3145,7 @@ MagickExport MagickBooleanType NegateImage(Image *image,
     Negate image.
   */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3085,14 +3168,24 @@ MagickExport MagickBooleanType NegateImage(Image *image,
       register ssize_t
         i;
 
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
+        PixelChannel
+          channel;
+
         PixelTrait
           traits;
 
-        traits=GetPixelChannelMapTraits(image,i);
-        if ((traits & UpdatePixelTrait) != 0)
-          q[i]=QuantumRange-q[i];
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=QuantumRange-q[i];
       }
       q+=GetPixelChannels(image);
     }
@@ -3104,7 +3197,7 @@ MagickExport MagickBooleanType NegateImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_NegateImage)
+        #pragma omp critical (MagickCore_NegateImage)
 #endif
         proceed=SetImageProgress(image,NegateImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -3126,8 +3219,9 @@ MagickExport MagickBooleanType NegateImage(Image *image,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  NormalizeImage() enhances the contrast of a color image by mapping the
-%  darkest 2 percent of all pixel to black and the brightest 1 percent to white.
+%  The NormalizeImage() method enhances the contrast of a color image by
+%  mapping the darkest 2 percent of all pixel to black and the brightest
+%  1 percent to white.
 %
 %  The format of the NormalizeImage method is:
 %
@@ -3230,28 +3324,62 @@ MagickExport MagickBooleanType SigmoidalContrastImage(Image *image,
       image->filename);
   (void) ResetMagickMemory(sigmoidal_map,0,(MaxMap+1)*sizeof(*sigmoidal_map));
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static) shared(progress,status)
 #endif
   for (i=0; i <= (ssize_t) MaxMap; i++)
   {
     if (sharpen != MagickFalse)
       {
+#define sigmoidal(a,b,x)  (1/(1+exp((a)*((b)-(x)))))
+#if 1
+        /* Simpilified function scaling,
+         * with better 'contrast=0' or 'flatline' handling (greyscale)
+         */
+        double
+          u0 = sigmoidal(contrast,QuantumScale*midpoint,0.0),
+          u1 = sigmoidal(contrast,QuantumScale*midpoint,1.0);
+        sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum(
+           (MagickRealType)(MaxMap*(
+               (sigmoidal(contrast,QuantumScale*midpoint,(double)i/MaxMap)
+                  -(u0+u1)/2.0)/(u1-u0+MagickEpsilon)+0.5)   ));
+#else
+        /* Scaled sigmoidal formula...
+             (1/(1+exp(a*(b-u))) - 1/(1+exp(a))) /
+                     (1/(1+exp(a*(b-1)))/(1+exp(a)))) */
         sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
           (MaxMap*((1.0/(1.0+exp(contrast*(midpoint/(double) QuantumRange-
-          (double) i/MaxMap))))-(1.0/(1.0+exp(contrast*(midpoint/(double)
-          QuantumRange)))))/((1.0/(1.0+exp(contrast*(midpoint/(double)
-          QuantumRange-1.0))))-(1.0/(1.0+exp(contrast*(midpoint/(double)
-          QuantumRange)))))+0.5));
+          (double) i/MaxMap))))-(1.0/(1.0+exp(contrast*(midpoint/
+          (double) QuantumRange)))))/((1.0/(1.0+exp(contrast*(midpoint/
+          (double) QuantumRange-1.0))))-(1.0/(1.0+exp(contrast*(midpoint/
+          (double) QuantumRange)))))+0.5));
+#endif
         continue;
       }
+#if 1
+    {
+      /* Inverse -- See
+         http://osdir.com/ml/video.image-magick.devel/2005-04/msg00006.html
+      */
+      double
+        min = sigmoidal(contrast,1.0,0.0),
+        max = sigmoidal(contrast,QuantumScale*midpoint,1.0),
+        xi  = min+(double)i/MaxMap*(max-min);
+      sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum(
+         (MagickRealType)(MaxMap*(
+             QuantumScale*midpoint-log((1-xi)/xi)/contrast) ));
+    }
+#else
+    /* expanded form of the above */
     sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
-      (MaxMap*(QuantumScale*midpoint-log((1.0-(1.0/(1.0+exp(midpoint/(double)
-      QuantumRange*contrast))+((double) i/MaxMap)*((1.0/(1.0+exp(contrast*(
-      midpoint/(double) QuantumRange-1.0))))-(1.0/(1.0+exp(midpoint/(double)
-      QuantumRange*contrast))))))/(1.0/(1.0+exp(midpoint/(double) QuantumRange*
-      contrast))+((double) i/MaxMap)*((1.0/(1.0+exp(contrast*(midpoint/(double)
-      QuantumRange-1.0))))-(1.0/(1.0+exp(midpoint/(double) QuantumRange*
-      contrast))))))/contrast)));
+      (MaxMap*(QuantumScale*midpoint-log((1.0-(1.0/(1.0+exp(midpoint/
+      (double) QuantumRange*contrast))+((double) i/MaxMap)*((1.0/
+      (1.0+exp(contrast*(midpoint/(double) QuantumRange-1.0))))-(1.0/
+      (1.0+exp(midpoint/(double) QuantumRange*contrast))))))/
+      (1.0/(1.0+exp(midpoint/(double) QuantumRange*contrast))+
+      ((double) i/MaxMap)*((1.0/(1.0+exp(contrast*(midpoint/
+      (double) QuantumRange-1.0))))-(1.0/(1.0+exp(midpoint/
+      (double) QuantumRange*contrast))))))/contrast)));
+#endif
   }
   if (image->storage_class == PseudoClass)
     {
@@ -3259,7 +3387,7 @@ MagickExport MagickBooleanType SigmoidalContrastImage(Image *image,
         Sigmoidal-contrast enhance colormap.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+      #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
@@ -3282,9 +3410,9 @@ MagickExport MagickBooleanType SigmoidalContrastImage(Image *image,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3307,14 +3435,24 @@ MagickExport MagickBooleanType SigmoidalContrastImage(Image *image,
       register ssize_t
         i;
 
+      if (GetPixelMask(image,q) != 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
+        PixelChannel
+          channel;
+
         PixelTrait
           traits;
 
-        traits=GetPixelChannelMapTraits(image,i);
-        if ((traits & UpdatePixelTrait) != 0)
-          q[i]=ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(q[i])]);
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        if ((traits & UpdatePixelTrait) == 0)
+          continue;
+        q[i]=ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(q[i])]);
       }
       q+=GetPixelChannels(image);
     }
@@ -3326,7 +3464,7 @@ MagickExport MagickBooleanType SigmoidalContrastImage(Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_SigmoidalContrastImage)
+        #pragma omp critical (MagickCore_SigmoidalContrastImage)
 #endif
         proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress++,
           image->rows);