Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %        SSSSS  TTTTT   AAA   TTTTT  IIIII  SSSSS  TTTTT  IIIII   CCCC        %
      7 %        SS       T    A   A    T      I    SS       T      I    C            %
      8 %         SSS     T    AAAAA    T      I     SSS     T      I    C            %
      9 %           SS    T    A   A    T      I       SS    T      I    C            %
     10 %        SSSSS    T    A   A    T    IIIII  SSSSS    T    IIIII   CCCC        %
     11 %                                                                             %
     12 %                                                                             %
     13 %                     MagickCore Image Statistical Methods                    %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    http://www.imagemagick.org/script/license.php                            %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 %
     38 */
     39 
     40 /*
     42   Include declarations.
     43 */
     44 #include "MagickCore/studio.h"
     45 #include "MagickCore/property.h"
     46 #include "MagickCore/accelerate-private.h"
     47 #include "MagickCore/animate.h"
     48 #include "MagickCore/blob.h"
     49 #include "MagickCore/blob-private.h"
     50 #include "MagickCore/cache.h"
     51 #include "MagickCore/cache-private.h"
     52 #include "MagickCore/cache-view.h"
     53 #include "MagickCore/client.h"
     54 #include "MagickCore/color.h"
     55 #include "MagickCore/color-private.h"
     56 #include "MagickCore/colorspace.h"
     57 #include "MagickCore/colorspace-private.h"
     58 #include "MagickCore/composite.h"
     59 #include "MagickCore/composite-private.h"
     60 #include "MagickCore/compress.h"
     61 #include "MagickCore/constitute.h"
     62 #include "MagickCore/display.h"
     63 #include "MagickCore/draw.h"
     64 #include "MagickCore/enhance.h"
     65 #include "MagickCore/exception.h"
     66 #include "MagickCore/exception-private.h"
     67 #include "MagickCore/gem.h"
     68 #include "MagickCore/gem-private.h"
     69 #include "MagickCore/geometry.h"
     70 #include "MagickCore/list.h"
     71 #include "MagickCore/image-private.h"
     72 #include "MagickCore/magic.h"
     73 #include "MagickCore/magick.h"
     74 #include "MagickCore/memory_.h"
     75 #include "MagickCore/module.h"
     76 #include "MagickCore/monitor.h"
     77 #include "MagickCore/monitor-private.h"
     78 #include "MagickCore/option.h"
     79 #include "MagickCore/paint.h"
     80 #include "MagickCore/pixel-accessor.h"
     81 #include "MagickCore/profile.h"
     82 #include "MagickCore/quantize.h"
     83 #include "MagickCore/quantum-private.h"
     84 #include "MagickCore/random_.h"
     85 #include "MagickCore/random-private.h"
     86 #include "MagickCore/resource_.h"
     87 #include "MagickCore/segment.h"
     88 #include "MagickCore/semaphore.h"
     89 #include "MagickCore/signature-private.h"
     90 #include "MagickCore/statistic.h"
     91 #include "MagickCore/string_.h"
     92 #include "MagickCore/thread-private.h"
     93 #include "MagickCore/timer.h"
     94 #include "MagickCore/utility.h"
     95 #include "MagickCore/version.h"
     96 
     97 /*
     99 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    100 %                                                                             %
    101 %                                                                             %
    102 %                                                                             %
    103 %     E v a l u a t e I m a g e                                               %
    104 %                                                                             %
    105 %                                                                             %
    106 %                                                                             %
    107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    108 %
    109 %  EvaluateImage() applies a value to the image with an arithmetic, relational,
    110 %  or logical operator to an image. Use these operations to lighten or darken
    111 %  an image, to increase or decrease contrast in an image, or to produce the
    112 %  "negative" of an image.
    113 %
    114 %  The format of the EvaluateImage method is:
    115 %
    116 %      MagickBooleanType EvaluateImage(Image *image,
    117 %        const MagickEvaluateOperator op,const double value,
    118 %        ExceptionInfo *exception)
    119 %      MagickBooleanType EvaluateImages(Image *images,
    120 %        const MagickEvaluateOperator op,const double value,
    121 %        ExceptionInfo *exception)
    122 %
    123 %  A description of each parameter follows:
    124 %
    125 %    o image: the image.
    126 %
    127 %    o op: A channel op.
    128 %
    129 %    o value: A value value.
    130 %
    131 %    o exception: return any errors or warnings in this structure.
    132 %
    133 */
    134 
    135 typedef struct _PixelChannels
    136 {
    137   double
    138     channel[CompositePixelChannel];
    139 } PixelChannels;
    140 
    141 static PixelChannels **DestroyPixelThreadSet(PixelChannels **pixels)
    142 {
    143   register ssize_t
    144     i;
    145 
    146   assert(pixels != (PixelChannels **) NULL);
    147   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
    148     if (pixels[i] != (PixelChannels *) NULL)
    149       pixels[i]=(PixelChannels *) RelinquishMagickMemory(pixels[i]);
    150   pixels=(PixelChannels **) RelinquishMagickMemory(pixels);
    151   return(pixels);
    152 }
    153 
    154 static PixelChannels **AcquirePixelThreadSet(const Image *image)
    155 {
    156   PixelChannels
    157     **pixels;
    158 
    159   register ssize_t
    160     i;
    161 
    162   size_t
    163     number_threads;
    164 
    165   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
    166   pixels=(PixelChannels **) AcquireQuantumMemory(number_threads,
    167     sizeof(*pixels));
    168   if (pixels == (PixelChannels **) NULL)
    169     return((PixelChannels **) NULL);
    170   (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
    171   for (i=0; i < (ssize_t) number_threads; i++)
    172   {
    173     register ssize_t
    174       j;
    175 
    176     pixels[i]=(PixelChannels *) AcquireQuantumMemory(image->columns,
    177       sizeof(**pixels));
    178     if (pixels[i] == (PixelChannels *) NULL)
    179       return(DestroyPixelThreadSet(pixels));
    180     for (j=0; j < (ssize_t) image->columns; j++)
    181     {
    182       register ssize_t
    183         k;
    184 
    185       for (k=0; k < MaxPixelChannels; k++)
    186         pixels[i][j].channel[k]=0.0;
    187     }
    188   }
    189   return(pixels);
    190 }
    191 
    192 static inline double EvaluateMax(const double x,const double y)
    193 {
    194   if (x > y)
    195     return(x);
    196   return(y);
    197 }
    198 
    199 #if defined(__cplusplus) || defined(c_plusplus)
    200 extern "C" {
    201 #endif
    202 
    203 static int IntensityCompare(const void *x,const void *y)
    204 {
    205   const PixelChannels
    206     *color_1,
    207     *color_2;
    208 
    209   double
    210     distance;
    211 
    212   register ssize_t
    213     i;
    214 
    215   color_1=(const PixelChannels *) x;
    216   color_2=(const PixelChannels *) y;
    217   distance=0.0;
    218   for (i=0; i < MaxPixelChannels; i++)
    219     distance+=color_1->channel[i]-(double) color_2->channel[i];
    220   return(distance < 0 ? -1 : distance > 0 ? 1 : 0);
    221 }
    222 
    223 #if defined(__cplusplus) || defined(c_plusplus)
    224 }
    225 #endif
    226 
    227 static double ApplyEvaluateOperator(RandomInfo *random_info,const Quantum pixel,
    228   const MagickEvaluateOperator op,const double value)
    229 {
    230   double
    231     result;
    232 
    233   result=0.0;
    234   switch (op)
    235   {
    236     case UndefinedEvaluateOperator:
    237       break;
    238     case AbsEvaluateOperator:
    239     {
    240       result=(double) fabs((double) (pixel+value));
    241       break;
    242     }
    243     case AddEvaluateOperator:
    244     {
    245       result=(double) (pixel+value);
    246       break;
    247     }
    248     case AddModulusEvaluateOperator:
    249     {
    250       /*
    251         This returns a 'floored modulus' of the addition which is a positive
    252         result.  It differs from % or fmod() that returns a 'truncated modulus'
    253         result, where floor() is replaced by trunc() and could return a
    254         negative result (which is clipped).
    255       */
    256       result=pixel+value;
    257       result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
    258       break;
    259     }
    260     case AndEvaluateOperator:
    261     {
    262       result=(double) ((size_t) pixel & (size_t) (value+0.5));
    263       break;
    264     }
    265     case CosineEvaluateOperator:
    266     {
    267       result=(double) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
    268         QuantumScale*pixel*value))+0.5));
    269       break;
    270     }
    271     case DivideEvaluateOperator:
    272     {
    273       result=pixel/(value == 0.0 ? 1.0 : value);
    274       break;
    275     }
    276     case ExponentialEvaluateOperator:
    277     {
    278       result=(double) (QuantumRange*exp((double) (value*QuantumScale*pixel)));
    279       break;
    280     }
    281     case GaussianNoiseEvaluateOperator:
    282     {
    283       result=(double) GenerateDifferentialNoise(random_info,pixel,
    284         GaussianNoise,value);
    285       break;
    286     }
    287     case ImpulseNoiseEvaluateOperator:
    288     {
    289       result=(double) GenerateDifferentialNoise(random_info,pixel,ImpulseNoise,
    290         value);
    291       break;
    292     }
    293     case LaplacianNoiseEvaluateOperator:
    294     {
    295       result=(double) GenerateDifferentialNoise(random_info,pixel,
    296         LaplacianNoise,value);
    297       break;
    298     }
    299     case LeftShiftEvaluateOperator:
    300     {
    301       result=(double) ((size_t) pixel << (size_t) (value+0.5));
    302       break;
    303     }
    304     case LogEvaluateOperator:
    305     {
    306       if ((QuantumScale*pixel) >= MagickEpsilon)
    307         result=(double) (QuantumRange*log((double) (QuantumScale*value*pixel+
    308           1.0))/log((double) (value+1.0)));
    309       break;
    310     }
    311     case MaxEvaluateOperator:
    312     {
    313       result=(double) EvaluateMax((double) pixel,value);
    314       break;
    315     }
    316     case MeanEvaluateOperator:
    317     {
    318       result=(double) (pixel+value);
    319       break;
    320     }
    321     case MedianEvaluateOperator:
    322     {
    323       result=(double) (pixel+value);
    324       break;
    325     }
    326     case MinEvaluateOperator:
    327     {
    328       result=(double) MagickMin((double) pixel,value);
    329       break;
    330     }
    331     case MultiplicativeNoiseEvaluateOperator:
    332     {
    333       result=(double) GenerateDifferentialNoise(random_info,pixel,
    334         MultiplicativeGaussianNoise,value);
    335       break;
    336     }
    337     case MultiplyEvaluateOperator:
    338     {
    339       result=(double) (value*pixel);
    340       break;
    341     }
    342     case OrEvaluateOperator:
    343     {
    344       result=(double) ((size_t) pixel | (size_t) (value+0.5));
    345       break;
    346     }
    347     case PoissonNoiseEvaluateOperator:
    348     {
    349       result=(double) GenerateDifferentialNoise(random_info,pixel,PoissonNoise,
    350         value);
    351       break;
    352     }
    353     case PowEvaluateOperator:
    354     {
    355       result=(double) (QuantumRange*pow((double) (QuantumScale*pixel),(double)
    356         value));
    357       break;
    358     }
    359     case RightShiftEvaluateOperator:
    360     {
    361       result=(double) ((size_t) pixel >> (size_t) (value+0.5));
    362       break;
    363     }
    364     case RootMeanSquareEvaluateOperator:
    365     {
    366       result=(double) (pixel*pixel+value);
    367       break;
    368     }
    369     case SetEvaluateOperator:
    370     {
    371       result=value;
    372       break;
    373     }
    374     case SineEvaluateOperator:
    375     {
    376       result=(double) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
    377         QuantumScale*pixel*value))+0.5));
    378       break;
    379     }
    380     case SubtractEvaluateOperator:
    381     {
    382       result=(double) (pixel-value);
    383       break;
    384     }
    385     case SumEvaluateOperator:
    386     {
    387       result=(double) (pixel+value);
    388       break;
    389     }
    390     case ThresholdEvaluateOperator:
    391     {
    392       result=(double) (((double) pixel <= value) ? 0 : QuantumRange);
    393       break;
    394     }
    395     case ThresholdBlackEvaluateOperator:
    396     {
    397       result=(double) (((double) pixel <= value) ? 0 : pixel);
    398       break;
    399     }
    400     case ThresholdWhiteEvaluateOperator:
    401     {
    402       result=(double) (((double) pixel > value) ? QuantumRange : pixel);
    403       break;
    404     }
    405     case UniformNoiseEvaluateOperator:
    406     {
    407       result=(double) GenerateDifferentialNoise(random_info,pixel,UniformNoise,
    408         value);
    409       break;
    410     }
    411     case XorEvaluateOperator:
    412     {
    413       result=(double) ((size_t) pixel ^ (size_t) (value+0.5));
    414       break;
    415     }
    416   }
    417   return(result);
    418 }
    419 
    420 MagickExport Image *EvaluateImages(const Image *images,
    421   const MagickEvaluateOperator op,ExceptionInfo *exception)
    422 {
    423 #define EvaluateImageTag  "Evaluate/Image"
    424 
    425   CacheView
    426     *evaluate_view;
    427 
    428   Image
    429     *image;
    430 
    431   MagickBooleanType
    432     status;
    433 
    434   MagickOffsetType
    435     progress;
    436 
    437   PixelChannels
    438     **magick_restrict evaluate_pixels;
    439 
    440   RandomInfo
    441     **magick_restrict random_info;
    442 
    443   size_t
    444     number_images;
    445 
    446   ssize_t
    447     y;
    448 
    449 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    450   unsigned long
    451     key;
    452 #endif
    453 
    454   assert(images != (Image *) NULL);
    455   assert(images->signature == MagickCoreSignature);
    456   if (images->debug != MagickFalse)
    457     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
    458   assert(exception != (ExceptionInfo *) NULL);
    459   assert(exception->signature == MagickCoreSignature);
    460   image=CloneImage(images,images->columns,images->rows,MagickTrue,
    461     exception);
    462   if (image == (Image *) NULL)
    463     return((Image *) NULL);
    464   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
    465     {
    466       image=DestroyImage(image);
    467       return((Image *) NULL);
    468     }
    469   number_images=GetImageListLength(images);
    470   evaluate_pixels=AcquirePixelThreadSet(images);
    471   if (evaluate_pixels == (PixelChannels **) NULL)
    472     {
    473       image=DestroyImage(image);
    474       (void) ThrowMagickException(exception,GetMagickModule(),
    475         ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
    476       return((Image *) NULL);
    477     }
    478   /*
    479     Evaluate image pixels.
    480   */
    481   status=MagickTrue;
    482   progress=0;
    483   random_info=AcquireRandomInfoThreadSet();
    484   evaluate_view=AcquireAuthenticCacheView(image,exception);
    485   if (op == MedianEvaluateOperator)
    486     {
    487 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    488       key=GetRandomSecretKey(random_info[0]);
    489       #pragma omp parallel for schedule(static,4) shared(progress,status) \
    490         magick_threads(image,images,image->rows,key == ~0UL)
    491 #endif
    492       for (y=0; y < (ssize_t) image->rows; y++)
    493       {
    494         CacheView
    495           *image_view;
    496 
    497         const Image
    498           *next;
    499 
    500         const int
    501           id = GetOpenMPThreadId();
    502 
    503         register PixelChannels
    504           *evaluate_pixel;
    505 
    506         register Quantum
    507           *magick_restrict q;
    508 
    509         register ssize_t
    510           x;
    511 
    512         if (status == MagickFalse)
    513           continue;
    514         q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
    515           exception);
    516         if (q == (Quantum *) NULL)
    517           {
    518             status=MagickFalse;
    519             continue;
    520           }
    521         evaluate_pixel=evaluate_pixels[id];
    522         for (x=0; x < (ssize_t) image->columns; x++)
    523         {
    524           register ssize_t
    525             j,
    526             k;
    527 
    528           for (j=0; j < (ssize_t) number_images; j++)
    529             for (k=0; k < MaxPixelChannels; k++)
    530               evaluate_pixel[j].channel[k]=0.0;
    531           next=images;
    532           for (j=0; j < (ssize_t) number_images; j++)
    533           {
    534             register const Quantum
    535               *p;
    536 
    537             register ssize_t
    538               i;
    539 
    540             image_view=AcquireVirtualCacheView(next,exception);
    541             p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
    542             if (p == (const Quantum *) NULL)
    543               {
    544                 image_view=DestroyCacheView(image_view);
    545                 break;
    546               }
    547             for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    548             {
    549               PixelChannel channel=GetPixelChannelChannel(image,i);
    550               PixelTrait evaluate_traits=GetPixelChannelTraits(image,channel);
    551               PixelTrait traits=GetPixelChannelTraits(next,channel);
    552               if ((traits == UndefinedPixelTrait) ||
    553                   (evaluate_traits == UndefinedPixelTrait))
    554                 continue;
    555               if ((evaluate_traits & UpdatePixelTrait) == 0)
    556                 continue;
    557               evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
    558                 random_info[id],GetPixelChannel(image,channel,p),op,
    559                 evaluate_pixel[j].channel[i]);
    560             }
    561             image_view=DestroyCacheView(image_view);
    562             next=GetNextImageInList(next);
    563           }
    564           qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
    565             IntensityCompare);
    566           for (k=0; k < (ssize_t) GetPixelChannels(image); k++)
    567             q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
    568           q+=GetPixelChannels(image);
    569         }
    570         if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
    571           status=MagickFalse;
    572         if (images->progress_monitor != (MagickProgressMonitor) NULL)
    573           {
    574             MagickBooleanType
    575               proceed;
    576 
    577 #if   defined(MAGICKCORE_OPENMP_SUPPORT)
    578             #pragma omp critical (MagickCore_EvaluateImages)
    579 #endif
    580             proceed=SetImageProgress(images,EvaluateImageTag,progress++,
    581               image->rows);
    582             if (proceed == MagickFalse)
    583               status=MagickFalse;
    584           }
    585       }
    586     }
    587   else
    588     {
    589 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    590       key=GetRandomSecretKey(random_info[0]);
    591       #pragma omp parallel for schedule(static,4) shared(progress,status) \
    592         magick_threads(image,images,image->rows,key == ~0UL)
    593 #endif
    594       for (y=0; y < (ssize_t) image->rows; y++)
    595       {
    596         CacheView
    597           *image_view;
    598 
    599         const Image
    600           *next;
    601 
    602         const int
    603           id = GetOpenMPThreadId();
    604 
    605         register ssize_t
    606           i,
    607           x;
    608 
    609         register PixelChannels
    610           *evaluate_pixel;
    611 
    612         register Quantum
    613           *magick_restrict q;
    614 
    615         ssize_t
    616           j;
    617 
    618         if (status == MagickFalse)
    619           continue;
    620         q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
    621           exception);
    622         if (q == (Quantum *) NULL)
    623           {
    624             status=MagickFalse;
    625             continue;
    626           }
    627         evaluate_pixel=evaluate_pixels[id];
    628         for (j=0; j < (ssize_t) image->columns; j++)
    629           for (i=0; i < MaxPixelChannels; i++)
    630             evaluate_pixel[j].channel[i]=0.0;
    631         next=images;
    632         for (j=0; j < (ssize_t) number_images; j++)
    633         {
    634           register const Quantum
    635             *p;
    636 
    637           image_view=AcquireVirtualCacheView(next,exception);
    638           p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
    639             exception);
    640           if (p == (const Quantum *) NULL)
    641             {
    642               image_view=DestroyCacheView(image_view);
    643               break;
    644             }
    645           for (x=0; x < (ssize_t) image->columns; x++)
    646           {
    647             register ssize_t
    648               i;
    649 
    650             if (GetPixelReadMask(next,p) == 0)
    651               {
    652                 p+=GetPixelChannels(next);
    653                 continue;
    654               }
    655             for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
    656             {
    657               PixelChannel channel=GetPixelChannelChannel(image,i);
    658               PixelTrait traits=GetPixelChannelTraits(next,channel);
    659               PixelTrait evaluate_traits=GetPixelChannelTraits(image,channel);
    660               if ((traits == UndefinedPixelTrait) ||
    661                   (evaluate_traits == UndefinedPixelTrait))
    662                 continue;
    663               if ((traits & UpdatePixelTrait) == 0)
    664                 continue;
    665               evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
    666                 random_info[id],GetPixelChannel(image,channel,p),j == 0 ?
    667                 AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
    668             }
    669             p+=GetPixelChannels(next);
    670           }
    671           image_view=DestroyCacheView(image_view);
    672           next=GetNextImageInList(next);
    673         }
    674         for (x=0; x < (ssize_t) image->columns; x++)
    675         {
    676           register ssize_t
    677              i;
    678 
    679           switch (op)
    680           {
    681             case MeanEvaluateOperator:
    682             {
    683               for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    684                 evaluate_pixel[x].channel[i]/=(double) number_images;
    685               break;
    686             }
    687             case MultiplyEvaluateOperator:
    688             {
    689               for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    690               {
    691                 register ssize_t
    692                   j;
    693 
    694                 for (j=0; j < (ssize_t) (number_images-1); j++)
    695                   evaluate_pixel[x].channel[i]*=QuantumScale;
    696               }
    697               break;
    698             }
    699             case RootMeanSquareEvaluateOperator:
    700             {
    701               for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    702                 evaluate_pixel[x].channel[i]=sqrt(evaluate_pixel[x].channel[i]/
    703                   number_images);
    704               break;
    705             }
    706             default:
    707               break;
    708           }
    709         }
    710         for (x=0; x < (ssize_t) image->columns; x++)
    711         {
    712           register ssize_t
    713             i;
    714 
    715           if (GetPixelReadMask(image,q) == 0)
    716             {
    717               q+=GetPixelChannels(image);
    718               continue;
    719             }
    720           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    721           {
    722             PixelChannel channel=GetPixelChannelChannel(image,i);
    723             PixelTrait traits=GetPixelChannelTraits(image,channel);
    724             if (traits == UndefinedPixelTrait)
    725               continue;
    726             if ((traits & UpdatePixelTrait) == 0)
    727               continue;
    728             q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
    729           }
    730           q+=GetPixelChannels(image);
    731         }
    732         if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
    733           status=MagickFalse;
    734         if (images->progress_monitor != (MagickProgressMonitor) NULL)
    735           {
    736             MagickBooleanType
    737               proceed;
    738 
    739 #if   defined(MAGICKCORE_OPENMP_SUPPORT)
    740             #pragma omp critical (MagickCore_EvaluateImages)
    741 #endif
    742             proceed=SetImageProgress(images,EvaluateImageTag,progress++,
    743               image->rows);
    744             if (proceed == MagickFalse)
    745               status=MagickFalse;
    746           }
    747       }
    748     }
    749   evaluate_view=DestroyCacheView(evaluate_view);
    750   evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
    751   random_info=DestroyRandomInfoThreadSet(random_info);
    752   if (status == MagickFalse)
    753     image=DestroyImage(image);
    754   return(image);
    755 }
    756 
    757 MagickExport MagickBooleanType EvaluateImage(Image *image,
    758   const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
    759 {
    760   CacheView
    761     *image_view;
    762 
    763   MagickBooleanType
    764     status;
    765 
    766   MagickOffsetType
    767     progress;
    768 
    769   RandomInfo
    770     **magick_restrict random_info;
    771 
    772   ssize_t
    773     y;
    774 
    775 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    776   unsigned long
    777     key;
    778 #endif
    779 
    780   assert(image != (Image *) NULL);
    781   assert(image->signature == MagickCoreSignature);
    782   if (image->debug != MagickFalse)
    783     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    784   assert(exception != (ExceptionInfo *) NULL);
    785   assert(exception->signature == MagickCoreSignature);
    786   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
    787     return(MagickFalse);
    788   status=MagickTrue;
    789   progress=0;
    790   random_info=AcquireRandomInfoThreadSet();
    791   image_view=AcquireAuthenticCacheView(image,exception);
    792 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    793   key=GetRandomSecretKey(random_info[0]);
    794   #pragma omp parallel for schedule(static,4) shared(progress,status) \
    795     magick_threads(image,image,image->rows,key == ~0UL)
    796 #endif
    797   for (y=0; y < (ssize_t) image->rows; y++)
    798   {
    799     const int
    800       id = GetOpenMPThreadId();
    801 
    802     register Quantum
    803       *magick_restrict q;
    804 
    805     register ssize_t
    806       x;
    807 
    808     if (status == MagickFalse)
    809       continue;
    810     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    811     if (q == (Quantum *) NULL)
    812       {
    813         status=MagickFalse;
    814         continue;
    815       }
    816     for (x=0; x < (ssize_t) image->columns; x++)
    817     {
    818       double
    819         result;
    820 
    821       register ssize_t
    822         i;
    823 
    824       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    825       {
    826         PixelChannel channel=GetPixelChannelChannel(image,i);
    827         PixelTrait traits=GetPixelChannelTraits(image,channel);
    828         if (traits == UndefinedPixelTrait)
    829           continue;
    830         if (((traits & CopyPixelTrait) != 0) ||
    831             (GetPixelReadMask(image,q) == 0))
    832           continue;
    833         result=ApplyEvaluateOperator(random_info[id],q[i],op,value);
    834         if (op == MeanEvaluateOperator)
    835           result/=2.0;
    836         q[i]=ClampToQuantum(result);
    837       }
    838       q+=GetPixelChannels(image);
    839     }
    840     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
    841       status=MagickFalse;
    842     if (image->progress_monitor != (MagickProgressMonitor) NULL)
    843       {
    844         MagickBooleanType
    845           proceed;
    846 
    847 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    848         #pragma omp critical (MagickCore_EvaluateImage)
    849 #endif
    850         proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
    851         if (proceed == MagickFalse)
    852           status=MagickFalse;
    853       }
    854   }
    855   image_view=DestroyCacheView(image_view);
    856   random_info=DestroyRandomInfoThreadSet(random_info);
    857   return(status);
    858 }
    859 
    860 /*
    862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    863 %                                                                             %
    864 %                                                                             %
    865 %                                                                             %
    866 %     F u n c t i o n I m a g e                                               %
    867 %                                                                             %
    868 %                                                                             %
    869 %                                                                             %
    870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    871 %
    872 %  FunctionImage() applies a value to the image with an arithmetic, relational,
    873 %  or logical operator to an image. Use these operations to lighten or darken
    874 %  an image, to increase or decrease contrast in an image, or to produce the
    875 %  "negative" of an image.
    876 %
    877 %  The format of the FunctionImage method is:
    878 %
    879 %      MagickBooleanType FunctionImage(Image *image,
    880 %        const MagickFunction function,const ssize_t number_parameters,
    881 %        const double *parameters,ExceptionInfo *exception)
    882 %
    883 %  A description of each parameter follows:
    884 %
    885 %    o image: the image.
    886 %
    887 %    o function: A channel function.
    888 %
    889 %    o parameters: one or more parameters.
    890 %
    891 %    o exception: return any errors or warnings in this structure.
    892 %
    893 */
    894 
    895 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
    896   const size_t number_parameters,const double *parameters,
    897   ExceptionInfo *exception)
    898 {
    899   double
    900     result;
    901 
    902   register ssize_t
    903     i;
    904 
    905   (void) exception;
    906   result=0.0;
    907   switch (function)
    908   {
    909     case PolynomialFunction:
    910     {
    911       /*
    912         Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
    913         c1*x^2+c2*x+c3).
    914       */
    915       result=0.0;
    916       for (i=0; i < (ssize_t) number_parameters; i++)
    917         result=result*QuantumScale*pixel+parameters[i];
    918       result*=QuantumRange;
    919       break;
    920     }
    921     case SinusoidFunction:
    922     {
    923       double
    924         amplitude,
    925         bias,
    926         frequency,
    927         phase;
    928 
    929       /*
    930         Sinusoid: frequency, phase, amplitude, bias.
    931       */
    932       frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
    933       phase=(number_parameters >= 2) ? parameters[1] : 0.0;
    934       amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
    935       bias=(number_parameters >= 4) ? parameters[3] : 0.5;
    936       result=(double) (QuantumRange*(amplitude*sin((double) (2.0*
    937         MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
    938       break;
    939     }
    940     case ArcsinFunction:
    941     {
    942       double
    943         bias,
    944         center,
    945         range,
    946         width;
    947 
    948       /*
    949         Arcsin (peged at range limits for invalid results): width, center,
    950         range, and bias.
    951       */
    952       width=(number_parameters >= 1) ? parameters[0] : 1.0;
    953       center=(number_parameters >= 2) ? parameters[1] : 0.5;
    954       range=(number_parameters >= 3) ? parameters[2] : 1.0;
    955       bias=(number_parameters >= 4) ? parameters[3] : 0.5;
    956       result=2.0/width*(QuantumScale*pixel-center);
    957       if ( result <= -1.0 )
    958         result=bias-range/2.0;
    959       else
    960         if (result >= 1.0)
    961           result=bias+range/2.0;
    962         else
    963           result=(double) (range/MagickPI*asin((double) result)+bias);
    964       result*=QuantumRange;
    965       break;
    966     }
    967     case ArctanFunction:
    968     {
    969       double
    970         center,
    971         bias,
    972         range,
    973         slope;
    974 
    975       /*
    976         Arctan: slope, center, range, and bias.
    977       */
    978       slope=(number_parameters >= 1) ? parameters[0] : 1.0;
    979       center=(number_parameters >= 2) ? parameters[1] : 0.5;
    980       range=(number_parameters >= 3) ? parameters[2] : 1.0;
    981       bias=(number_parameters >= 4) ? parameters[3] : 0.5;
    982       result=(double) (MagickPI*slope*(QuantumScale*pixel-center));
    983       result=(double) (QuantumRange*(range/MagickPI*atan((double)
    984         result)+bias));
    985       break;
    986     }
    987     case UndefinedFunction:
    988       break;
    989   }
    990   return(ClampToQuantum(result));
    991 }
    992 
    993 MagickExport MagickBooleanType FunctionImage(Image *image,
    994   const MagickFunction function,const size_t number_parameters,
    995   const double *parameters,ExceptionInfo *exception)
    996 {
    997 #define FunctionImageTag  "Function/Image "
    998 
    999   CacheView
   1000     *image_view;
   1001 
   1002   MagickBooleanType
   1003     status;
   1004 
   1005   MagickOffsetType
   1006     progress;
   1007 
   1008   ssize_t
   1009     y;
   1010 
   1011   assert(image != (Image *) NULL);
   1012   assert(image->signature == MagickCoreSignature);
   1013   if (image->debug != MagickFalse)
   1014     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1015   assert(exception != (ExceptionInfo *) NULL);
   1016   assert(exception->signature == MagickCoreSignature);
   1017 #if defined(MAGICKCORE_OPENCL_SUPPORT)
   1018   if (AccelerateFunctionImage(image,function,number_parameters,parameters,
   1019         exception) != MagickFalse)
   1020     return(MagickTrue);
   1021 #endif
   1022   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
   1023     return(MagickFalse);
   1024   status=MagickTrue;
   1025   progress=0;
   1026   image_view=AcquireAuthenticCacheView(image,exception);
   1027 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1028   #pragma omp parallel for schedule(static,4) shared(progress,status) \
   1029     magick_threads(image,image,image->rows,1)
   1030 #endif
   1031   for (y=0; y < (ssize_t) image->rows; y++)
   1032   {
   1033     register Quantum
   1034       *magick_restrict q;
   1035 
   1036     register ssize_t
   1037       x;
   1038 
   1039     if (status == MagickFalse)
   1040       continue;
   1041     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
   1042     if (q == (Quantum *) NULL)
   1043       {
   1044         status=MagickFalse;
   1045         continue;
   1046       }
   1047     for (x=0; x < (ssize_t) image->columns; x++)
   1048     {
   1049       register ssize_t
   1050         i;
   1051 
   1052       if (GetPixelReadMask(image,q) == 0)
   1053         {
   1054           q+=GetPixelChannels(image);
   1055           continue;
   1056         }
   1057       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1058       {
   1059         PixelChannel channel=GetPixelChannelChannel(image,i);
   1060         PixelTrait traits=GetPixelChannelTraits(image,channel);
   1061         if (traits == UndefinedPixelTrait)
   1062           continue;
   1063         if ((traits & UpdatePixelTrait) == 0)
   1064           continue;
   1065         q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
   1066           exception);
   1067       }
   1068       q+=GetPixelChannels(image);
   1069     }
   1070     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
   1071       status=MagickFalse;
   1072     if (image->progress_monitor != (MagickProgressMonitor) NULL)
   1073       {
   1074         MagickBooleanType
   1075           proceed;
   1076 
   1077 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1078         #pragma omp critical (MagickCore_FunctionImage)
   1079 #endif
   1080         proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
   1081         if (proceed == MagickFalse)
   1082           status=MagickFalse;
   1083       }
   1084   }
   1085   image_view=DestroyCacheView(image_view);
   1086   return(status);
   1087 }
   1088 
   1089 /*
   1091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1092 %                                                                             %
   1093 %                                                                             %
   1094 %                                                                             %
   1095 %   G e t I m a g e E n t r o p y                                             %
   1096 %                                                                             %
   1097 %                                                                             %
   1098 %                                                                             %
   1099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1100 %
   1101 %  GetImageEntropy() returns the entropy of one or more image channels.
   1102 %
   1103 %  The format of the GetImageEntropy method is:
   1104 %
   1105 %      MagickBooleanType GetImageEntropy(const Image *image,double *entropy,
   1106 %        ExceptionInfo *exception)
   1107 %
   1108 %  A description of each parameter follows:
   1109 %
   1110 %    o image: the image.
   1111 %
   1112 %    o entropy: the average entropy of the selected channels.
   1113 %
   1114 %    o exception: return any errors or warnings in this structure.
   1115 %
   1116 */
   1117 MagickExport MagickBooleanType GetImageEntropy(const Image *image,
   1118   double *entropy,ExceptionInfo *exception)
   1119 {
   1120   double
   1121     area;
   1122 
   1123   ChannelStatistics
   1124     *channel_statistics;
   1125 
   1126   register ssize_t
   1127     i;
   1128 
   1129   assert(image != (Image *) NULL);
   1130   assert(image->signature == MagickCoreSignature);
   1131   if (image->debug != MagickFalse)
   1132     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1133   channel_statistics=GetImageStatistics(image,exception);
   1134   if (channel_statistics == (ChannelStatistics *) NULL)
   1135     return(MagickFalse);
   1136   area=0.0;
   1137   channel_statistics[CompositePixelChannel].entropy=0.0;
   1138   channel_statistics[CompositePixelChannel].standard_deviation=0.0;
   1139   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1140   {
   1141     PixelChannel channel=GetPixelChannelChannel(image,i);
   1142     PixelTrait traits=GetPixelChannelTraits(image,channel);
   1143     if (traits == UndefinedPixelTrait)
   1144       continue;
   1145     if ((traits & UpdatePixelTrait) == 0)
   1146       continue;
   1147     channel_statistics[CompositePixelChannel].entropy+=
   1148       channel_statistics[i].entropy;
   1149     area++;
   1150   }
   1151   if (area > MagickEpsilon)
   1152     {
   1153       channel_statistics[CompositePixelChannel].entropy/=area;
   1154       channel_statistics[CompositePixelChannel].standard_deviation=
   1155         sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
   1156     }
   1157   *entropy=channel_statistics[CompositePixelChannel].entropy;
   1158   channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
   1159     channel_statistics);
   1160   return(MagickTrue);
   1161 }
   1162 
   1163 /*
   1165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1166 %                                                                             %
   1167 %                                                                             %
   1168 %                                                                             %
   1169 %   G e t I m a g e E x t r e m a                                             %
   1170 %                                                                             %
   1171 %                                                                             %
   1172 %                                                                             %
   1173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1174 %
   1175 %  GetImageExtrema() returns the extrema of one or more image channels.
   1176 %
   1177 %  The format of the GetImageExtrema method is:
   1178 %
   1179 %      MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
   1180 %        size_t *maxima,ExceptionInfo *exception)
   1181 %
   1182 %  A description of each parameter follows:
   1183 %
   1184 %    o image: the image.
   1185 %
   1186 %    o minima: the minimum value in the channel.
   1187 %
   1188 %    o maxima: the maximum value in the channel.
   1189 %
   1190 %    o exception: return any errors or warnings in this structure.
   1191 %
   1192 */
   1193 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
   1194   size_t *minima,size_t *maxima,ExceptionInfo *exception)
   1195 {
   1196   double
   1197     max,
   1198     min;
   1199 
   1200   MagickBooleanType
   1201     status;
   1202 
   1203   assert(image != (Image *) NULL);
   1204   assert(image->signature == MagickCoreSignature);
   1205   if (image->debug != MagickFalse)
   1206     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1207   status=GetImageRange(image,&min,&max,exception);
   1208   *minima=(size_t) ceil(min-0.5);
   1209   *maxima=(size_t) floor(max+0.5);
   1210   return(status);
   1211 }
   1212 
   1213 /*
   1215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1216 %                                                                             %
   1217 %                                                                             %
   1218 %                                                                             %
   1219 %   G e t I m a g e K u r t o s i s                                           %
   1220 %                                                                             %
   1221 %                                                                             %
   1222 %                                                                             %
   1223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1224 %
   1225 %  GetImageKurtosis() returns the kurtosis and skewness of one or more image
   1226 %  channels.
   1227 %
   1228 %  The format of the GetImageKurtosis method is:
   1229 %
   1230 %      MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
   1231 %        double *skewness,ExceptionInfo *exception)
   1232 %
   1233 %  A description of each parameter follows:
   1234 %
   1235 %    o image: the image.
   1236 %
   1237 %    o kurtosis: the kurtosis of the channel.
   1238 %
   1239 %    o skewness: the skewness of the channel.
   1240 %
   1241 %    o exception: return any errors or warnings in this structure.
   1242 %
   1243 */
   1244 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
   1245   double *kurtosis,double *skewness,ExceptionInfo *exception)
   1246 {
   1247   CacheView
   1248     *image_view;
   1249 
   1250   double
   1251     area,
   1252     mean,
   1253     standard_deviation,
   1254     sum_squares,
   1255     sum_cubes,
   1256     sum_fourth_power;
   1257 
   1258   MagickBooleanType
   1259     status;
   1260 
   1261   ssize_t
   1262     y;
   1263 
   1264   assert(image != (Image *) NULL);
   1265   assert(image->signature == MagickCoreSignature);
   1266   if (image->debug != MagickFalse)
   1267     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1268   status=MagickTrue;
   1269   *kurtosis=0.0;
   1270   *skewness=0.0;
   1271   area=0.0;
   1272   mean=0.0;
   1273   standard_deviation=0.0;
   1274   sum_squares=0.0;
   1275   sum_cubes=0.0;
   1276   sum_fourth_power=0.0;
   1277   image_view=AcquireVirtualCacheView(image,exception);
   1278 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1279   #pragma omp parallel for schedule(static,4) shared(status) \
   1280     magick_threads(image,image,image->rows,1)
   1281 #endif
   1282   for (y=0; y < (ssize_t) image->rows; y++)
   1283   {
   1284     register const Quantum
   1285       *magick_restrict p;
   1286 
   1287     register ssize_t
   1288       x;
   1289 
   1290     if (status == MagickFalse)
   1291       continue;
   1292     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
   1293     if (p == (const Quantum *) NULL)
   1294       {
   1295         status=MagickFalse;
   1296         continue;
   1297       }
   1298     for (x=0; x < (ssize_t) image->columns; x++)
   1299     {
   1300       register ssize_t
   1301         i;
   1302 
   1303       if (GetPixelReadMask(image,p) == 0)
   1304         {
   1305           p+=GetPixelChannels(image);
   1306           continue;
   1307         }
   1308       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1309       {
   1310         PixelChannel channel=GetPixelChannelChannel(image,i);
   1311         PixelTrait traits=GetPixelChannelTraits(image,channel);
   1312         if (traits == UndefinedPixelTrait)
   1313           continue;
   1314         if ((traits & UpdatePixelTrait) == 0)
   1315           continue;
   1316 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1317         #pragma omp critical (MagickCore_GetImageKurtosis)
   1318 #endif
   1319         {
   1320           mean+=p[i];
   1321           sum_squares+=(double) p[i]*p[i];
   1322           sum_cubes+=(double) p[i]*p[i]*p[i];
   1323           sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
   1324           area++;
   1325         }
   1326       }
   1327       p+=GetPixelChannels(image);
   1328     }
   1329   }
   1330   image_view=DestroyCacheView(image_view);
   1331   if (area != 0.0)
   1332     {
   1333       mean/=area;
   1334       sum_squares/=area;
   1335       sum_cubes/=area;
   1336       sum_fourth_power/=area;
   1337     }
   1338   standard_deviation=sqrt(sum_squares-(mean*mean));
   1339   if (standard_deviation != 0.0)
   1340     {
   1341       *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
   1342         3.0*mean*mean*mean*mean;
   1343       *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
   1344         standard_deviation;
   1345       *kurtosis-=3.0;
   1346       *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
   1347       *skewness/=standard_deviation*standard_deviation*standard_deviation;
   1348     }
   1349   return(status);
   1350 }
   1351 
   1352 /*
   1354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1355 %                                                                             %
   1356 %                                                                             %
   1357 %                                                                             %
   1358 %   G e t I m a g e M e a n                                                   %
   1359 %                                                                             %
   1360 %                                                                             %
   1361 %                                                                             %
   1362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1363 %
   1364 %  GetImageMean() returns the mean and standard deviation of one or more image
   1365 %  channels.
   1366 %
   1367 %  The format of the GetImageMean method is:
   1368 %
   1369 %      MagickBooleanType GetImageMean(const Image *image,double *mean,
   1370 %        double *standard_deviation,ExceptionInfo *exception)
   1371 %
   1372 %  A description of each parameter follows:
   1373 %
   1374 %    o image: the image.
   1375 %
   1376 %    o mean: the average value in the channel.
   1377 %
   1378 %    o standard_deviation: the standard deviation of the channel.
   1379 %
   1380 %    o exception: return any errors or warnings in this structure.
   1381 %
   1382 */
   1383 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
   1384   double *standard_deviation,ExceptionInfo *exception)
   1385 {
   1386   double
   1387     area;
   1388 
   1389   ChannelStatistics
   1390     *channel_statistics;
   1391 
   1392   register ssize_t
   1393     i;
   1394 
   1395   assert(image != (Image *) NULL);
   1396   assert(image->signature == MagickCoreSignature);
   1397   if (image->debug != MagickFalse)
   1398     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1399   channel_statistics=GetImageStatistics(image,exception);
   1400   if (channel_statistics == (ChannelStatistics *) NULL)
   1401     return(MagickFalse);
   1402   area=0.0;
   1403   channel_statistics[CompositePixelChannel].mean=0.0;
   1404   channel_statistics[CompositePixelChannel].standard_deviation=0.0;
   1405   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1406   {
   1407     PixelChannel channel=GetPixelChannelChannel(image,i);
   1408     PixelTrait traits=GetPixelChannelTraits(image,channel);
   1409     if (traits == UndefinedPixelTrait)
   1410       continue;
   1411     if ((traits & UpdatePixelTrait) == 0)
   1412       continue;
   1413     channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
   1414     channel_statistics[CompositePixelChannel].standard_deviation+=
   1415       channel_statistics[i].variance-channel_statistics[i].mean*
   1416       channel_statistics[i].mean;
   1417     area++;
   1418   }
   1419   if (area > MagickEpsilon)
   1420     {
   1421       channel_statistics[CompositePixelChannel].mean/=area;
   1422       channel_statistics[CompositePixelChannel].standard_deviation=
   1423         sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
   1424     }
   1425   *mean=channel_statistics[CompositePixelChannel].mean;
   1426   *standard_deviation=
   1427     channel_statistics[CompositePixelChannel].standard_deviation;
   1428   channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
   1429     channel_statistics);
   1430   return(MagickTrue);
   1431 }
   1432 
   1433 /*
   1435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1436 %                                                                             %
   1437 %                                                                             %
   1438 %                                                                             %
   1439 %   G e t I m a g e M o m e n t s                                             %
   1440 %                                                                             %
   1441 %                                                                             %
   1442 %                                                                             %
   1443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1444 %
   1445 %  GetImageMoments() returns the normalized moments of one or more image
   1446 %  channels.
   1447 %
   1448 %  The format of the GetImageMoments method is:
   1449 %
   1450 %      ChannelMoments *GetImageMoments(const Image *image,
   1451 %        ExceptionInfo *exception)
   1452 %
   1453 %  A description of each parameter follows:
   1454 %
   1455 %    o image: the image.
   1456 %
   1457 %    o exception: return any errors or warnings in this structure.
   1458 %
   1459 */
   1460 
   1461 static size_t GetImageChannels(const Image *image)
   1462 {
   1463   register ssize_t
   1464     i;
   1465 
   1466   size_t
   1467     channels;
   1468 
   1469   channels=0;
   1470   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1471   {
   1472     PixelChannel channel=GetPixelChannelChannel(image,i);
   1473     PixelTrait traits=GetPixelChannelTraits(image,channel);
   1474     if ((traits & UpdatePixelTrait) != 0)
   1475       channels++;
   1476   }
   1477   return((size_t) (channels == 0 ? 1 : channels));
   1478 }
   1479 
   1480 MagickExport ChannelMoments *GetImageMoments(const Image *image,
   1481   ExceptionInfo *exception)
   1482 {
   1483 #define MaxNumberImageMoments  8
   1484 
   1485   CacheView
   1486     *image_view;
   1487 
   1488   ChannelMoments
   1489     *channel_moments;
   1490 
   1491   double
   1492     M00[MaxPixelChannels+1],
   1493     M01[MaxPixelChannels+1],
   1494     M02[MaxPixelChannels+1],
   1495     M03[MaxPixelChannels+1],
   1496     M10[MaxPixelChannels+1],
   1497     M11[MaxPixelChannels+1],
   1498     M12[MaxPixelChannels+1],
   1499     M20[MaxPixelChannels+1],
   1500     M21[MaxPixelChannels+1],
   1501     M22[MaxPixelChannels+1],
   1502     M30[MaxPixelChannels+1];
   1503 
   1504   PointInfo
   1505     centroid[MaxPixelChannels+1];
   1506 
   1507   ssize_t
   1508     channel,
   1509     y;
   1510 
   1511   assert(image != (Image *) NULL);
   1512   assert(image->signature == MagickCoreSignature);
   1513   if (image->debug != MagickFalse)
   1514     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1515   channel_moments=(ChannelMoments *) AcquireQuantumMemory(MaxPixelChannels+1,
   1516     sizeof(*channel_moments));
   1517   if (channel_moments == (ChannelMoments *) NULL)
   1518     return(channel_moments);
   1519   (void) ResetMagickMemory(channel_moments,0,(MaxPixelChannels+1)*
   1520     sizeof(*channel_moments));
   1521   (void) ResetMagickMemory(centroid,0,sizeof(centroid));
   1522   (void) ResetMagickMemory(M00,0,sizeof(M00));
   1523   (void) ResetMagickMemory(M01,0,sizeof(M01));
   1524   (void) ResetMagickMemory(M02,0,sizeof(M02));
   1525   (void) ResetMagickMemory(M03,0,sizeof(M03));
   1526   (void) ResetMagickMemory(M10,0,sizeof(M10));
   1527   (void) ResetMagickMemory(M11,0,sizeof(M11));
   1528   (void) ResetMagickMemory(M12,0,sizeof(M12));
   1529   (void) ResetMagickMemory(M20,0,sizeof(M20));
   1530   (void) ResetMagickMemory(M21,0,sizeof(M21));
   1531   (void) ResetMagickMemory(M22,0,sizeof(M22));
   1532   (void) ResetMagickMemory(M30,0,sizeof(M30));
   1533   image_view=AcquireVirtualCacheView(image,exception);
   1534   for (y=0; y < (ssize_t) image->rows; y++)
   1535   {
   1536     register const Quantum
   1537       *magick_restrict p;
   1538 
   1539     register ssize_t
   1540       x;
   1541 
   1542     /*
   1543       Compute center of mass (centroid).
   1544     */
   1545     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
   1546     if (p == (const Quantum *) NULL)
   1547       break;
   1548     for (x=0; x < (ssize_t) image->columns; x++)
   1549     {
   1550       register ssize_t
   1551         i;
   1552 
   1553       if (GetPixelReadMask(image,p) == 0)
   1554         {
   1555           p+=GetPixelChannels(image);
   1556           continue;
   1557         }
   1558       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1559       {
   1560         PixelChannel channel=GetPixelChannelChannel(image,i);
   1561         PixelTrait traits=GetPixelChannelTraits(image,channel);
   1562         if (traits == UndefinedPixelTrait)
   1563           continue;
   1564         if ((traits & UpdatePixelTrait) == 0)
   1565           continue;
   1566         M00[channel]+=QuantumScale*p[i];
   1567         M00[MaxPixelChannels]+=QuantumScale*p[i];
   1568         M10[channel]+=x*QuantumScale*p[i];
   1569         M10[MaxPixelChannels]+=x*QuantumScale*p[i];
   1570         M01[channel]+=y*QuantumScale*p[i];
   1571         M01[MaxPixelChannels]+=y*QuantumScale*p[i];
   1572       }
   1573       p+=GetPixelChannels(image);
   1574     }
   1575   }
   1576   for (channel=0; channel <= MaxPixelChannels; channel++)
   1577   {
   1578     /*
   1579        Compute center of mass (centroid).
   1580     */
   1581     if (M00[channel] < MagickEpsilon)
   1582       {
   1583         M00[channel]+=MagickEpsilon;
   1584         centroid[channel].x=(double) image->columns/2.0;
   1585         centroid[channel].y=(double) image->rows/2.0;
   1586         continue;
   1587       }
   1588     M00[channel]+=MagickEpsilon;
   1589     centroid[channel].x=M10[channel]/M00[channel];
   1590     centroid[channel].y=M01[channel]/M00[channel];
   1591   }
   1592   for (y=0; y < (ssize_t) image->rows; y++)
   1593   {
   1594     register const Quantum
   1595       *magick_restrict p;
   1596 
   1597     register ssize_t
   1598       x;
   1599 
   1600     /*
   1601       Compute the image moments.
   1602     */
   1603     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
   1604     if (p == (const Quantum *) NULL)
   1605       break;
   1606     for (x=0; x < (ssize_t) image->columns; x++)
   1607     {
   1608       register ssize_t
   1609         i;
   1610 
   1611       if (GetPixelReadMask(image,p) == 0)
   1612         {
   1613           p+=GetPixelChannels(image);
   1614           continue;
   1615         }
   1616       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1617       {
   1618         PixelChannel channel=GetPixelChannelChannel(image,i);
   1619         PixelTrait traits=GetPixelChannelTraits(image,channel);
   1620         if (traits == UndefinedPixelTrait)
   1621           continue;
   1622         if ((traits & UpdatePixelTrait) == 0)
   1623           continue;
   1624         M11[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
   1625           QuantumScale*p[i];
   1626         M11[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
   1627           QuantumScale*p[i];
   1628         M20[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1629           QuantumScale*p[i];
   1630         M20[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1631           QuantumScale*p[i];
   1632         M02[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
   1633           QuantumScale*p[i];
   1634         M02[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
   1635           QuantumScale*p[i];
   1636         M21[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1637           (y-centroid[channel].y)*QuantumScale*p[i];
   1638         M21[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1639           (y-centroid[channel].y)*QuantumScale*p[i];
   1640         M12[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
   1641           (y-centroid[channel].y)*QuantumScale*p[i];
   1642         M12[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
   1643           (y-centroid[channel].y)*QuantumScale*p[i];
   1644         M22[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1645           (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*p[i];
   1646         M22[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1647           (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*p[i];
   1648         M30[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1649           (x-centroid[channel].x)*QuantumScale*p[i];
   1650         M30[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
   1651           (x-centroid[channel].x)*QuantumScale*p[i];
   1652         M03[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
   1653           (y-centroid[channel].y)*QuantumScale*p[i];
   1654         M03[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
   1655           (y-centroid[channel].y)*QuantumScale*p[i];
   1656       }
   1657       p+=GetPixelChannels(image);
   1658     }
   1659   }
   1660   M00[MaxPixelChannels]/=GetImageChannels(image);
   1661   M01[MaxPixelChannels]/=GetImageChannels(image);
   1662   M02[MaxPixelChannels]/=GetImageChannels(image);
   1663   M03[MaxPixelChannels]/=GetImageChannels(image);
   1664   M10[MaxPixelChannels]/=GetImageChannels(image);
   1665   M11[MaxPixelChannels]/=GetImageChannels(image);
   1666   M12[MaxPixelChannels]/=GetImageChannels(image);
   1667   M20[MaxPixelChannels]/=GetImageChannels(image);
   1668   M21[MaxPixelChannels]/=GetImageChannels(image);
   1669   M22[MaxPixelChannels]/=GetImageChannels(image);
   1670   M30[MaxPixelChannels]/=GetImageChannels(image);
   1671   for (channel=0; channel <= MaxPixelChannels; channel++)
   1672   {
   1673     /*
   1674       Compute elliptical angle, major and minor axes, eccentricity, & intensity.
   1675     */
   1676     channel_moments[channel].centroid=centroid[channel];
   1677     channel_moments[channel].ellipse_axis.x=sqrt((2.0/M00[channel])*
   1678       ((M20[channel]+M02[channel])+sqrt(4.0*M11[channel]*M11[channel]+
   1679       (M20[channel]-M02[channel])*(M20[channel]-M02[channel]))));
   1680     channel_moments[channel].ellipse_axis.y=sqrt((2.0/M00[channel])*
   1681       ((M20[channel]+M02[channel])-sqrt(4.0*M11[channel]*M11[channel]+
   1682       (M20[channel]-M02[channel])*(M20[channel]-M02[channel]))));
   1683     channel_moments[channel].ellipse_angle=RadiansToDegrees(0.5*atan(2.0*
   1684       M11[channel]/(M20[channel]-M02[channel]+MagickEpsilon)));
   1685     channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
   1686       channel_moments[channel].ellipse_axis.y/
   1687       (channel_moments[channel].ellipse_axis.x+MagickEpsilon)));
   1688     channel_moments[channel].ellipse_intensity=M00[channel]/
   1689       (MagickPI*channel_moments[channel].ellipse_axis.x*
   1690       channel_moments[channel].ellipse_axis.y+MagickEpsilon);
   1691   }
   1692   for (channel=0; channel <= MaxPixelChannels; channel++)
   1693   {
   1694     /*
   1695       Normalize image moments.
   1696     */
   1697     M10[channel]=0.0;
   1698     M01[channel]=0.0;
   1699     M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
   1700     M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
   1701     M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
   1702     M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
   1703     M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
   1704     M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
   1705     M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
   1706     M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
   1707     M00[channel]=1.0;
   1708   }
   1709   image_view=DestroyCacheView(image_view);
   1710   for (channel=0; channel <= MaxPixelChannels; channel++)
   1711   {
   1712     /*
   1713       Compute Hu invariant moments.
   1714     */
   1715     channel_moments[channel].invariant[0]=M20[channel]+M02[channel];
   1716     channel_moments[channel].invariant[1]=(M20[channel]-M02[channel])*
   1717       (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
   1718     channel_moments[channel].invariant[2]=(M30[channel]-3.0*M12[channel])*
   1719       (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
   1720       (3.0*M21[channel]-M03[channel]);
   1721     channel_moments[channel].invariant[3]=(M30[channel]+M12[channel])*
   1722       (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
   1723       (M21[channel]+M03[channel]);
   1724     channel_moments[channel].invariant[4]=(M30[channel]-3.0*M12[channel])*
   1725       (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
   1726       (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
   1727       (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
   1728       (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
   1729       (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
   1730       (M21[channel]+M03[channel]));
   1731     channel_moments[channel].invariant[5]=(M20[channel]-M02[channel])*
   1732       ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
   1733       (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
   1734       4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
   1735     channel_moments[channel].invariant[6]=(3.0*M21[channel]-M03[channel])*
   1736       (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
   1737       (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
   1738       (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
   1739       (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
   1740       (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
   1741       (M21[channel]+M03[channel]));
   1742     channel_moments[channel].invariant[7]=M11[channel]*((M30[channel]+
   1743       M12[channel])*(M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
   1744       (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
   1745       (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
   1746   }
   1747   if (y < (ssize_t) image->rows)
   1748     channel_moments=(ChannelMoments *) RelinquishMagickMemory(channel_moments);
   1749   return(channel_moments);
   1750 }
   1751 
   1752 /*
   1754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1755 %                                                                             %
   1756 %                                                                             %
   1757 %                                                                             %
   1758 %   G e t I m a g e C h a n n e l P e r c e p t u a l H a s h                 %
   1759 %                                                                             %
   1760 %                                                                             %
   1761 %                                                                             %
   1762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1763 %
   1764 %  GetImagePerceptualHash() returns the perceptual hash of one or more
   1765 %  image channels.
   1766 %
   1767 %  The format of the GetImagePerceptualHash method is:
   1768 %
   1769 %      ChannelPerceptualHash *GetImagePerceptualHash(const Image *image,
   1770 %        ExceptionInfo *exception)
   1771 %
   1772 %  A description of each parameter follows:
   1773 %
   1774 %    o image: the image.
   1775 %
   1776 %    o exception: return any errors or warnings in this structure.
   1777 %
   1778 */
   1779 
   1780 static inline double MagickLog10(const double x)
   1781 {
   1782 #define Log10Epsilon  (1.0e-11)
   1783 
   1784  if (fabs(x) < Log10Epsilon)
   1785    return(log10(Log10Epsilon));
   1786  return(log10(fabs(x)));
   1787 }
   1788 
   1789 MagickExport ChannelPerceptualHash *GetImagePerceptualHash(
   1790   const Image *image,ExceptionInfo *exception)
   1791 {
   1792   ChannelMoments
   1793     *moments;
   1794 
   1795   ChannelPerceptualHash
   1796     *perceptual_hash;
   1797 
   1798   Image
   1799     *hash_image;
   1800 
   1801   MagickBooleanType
   1802     status;
   1803 
   1804   register ssize_t
   1805     i;
   1806 
   1807   ssize_t
   1808     channel;
   1809 
   1810   /*
   1811     Blur then transform to sRGB colorspace.
   1812   */
   1813   hash_image=BlurImage(image,0.0,1.0,exception);
   1814   if (hash_image == (Image *) NULL)
   1815     return((ChannelPerceptualHash *) NULL);
   1816   hash_image->depth=8;
   1817   status=TransformImageColorspace(hash_image,sRGBColorspace,exception);
   1818   if (status == MagickFalse)
   1819     return((ChannelPerceptualHash *) NULL);
   1820   moments=GetImageMoments(hash_image,exception);
   1821   hash_image=DestroyImage(hash_image);
   1822   if (moments == (ChannelMoments *) NULL)
   1823     return((ChannelPerceptualHash *) NULL);
   1824   perceptual_hash=(ChannelPerceptualHash *) AcquireQuantumMemory(
   1825     MaxPixelChannels+1UL,sizeof(*perceptual_hash));
   1826   if (perceptual_hash == (ChannelPerceptualHash *) NULL)
   1827     return((ChannelPerceptualHash *) NULL);
   1828   for (channel=0; channel <= MaxPixelChannels; channel++)
   1829     for (i=0; i < MaximumNumberOfImageMoments; i++)
   1830       perceptual_hash[channel].srgb_hu_phash[i]=
   1831         (-MagickLog10(moments[channel].invariant[i]));
   1832   moments=(ChannelMoments *) RelinquishMagickMemory(moments);
   1833   /*
   1834     Blur then transform to HCLp colorspace.
   1835   */
   1836   hash_image=BlurImage(image,0.0,1.0,exception);
   1837   if (hash_image == (Image *) NULL)
   1838     {
   1839       perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
   1840         perceptual_hash);
   1841       return((ChannelPerceptualHash *) NULL);
   1842     }
   1843   hash_image->depth=8;
   1844   status=TransformImageColorspace(hash_image,HCLpColorspace,exception);
   1845   if (status == MagickFalse)
   1846     {
   1847       perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
   1848         perceptual_hash);
   1849       return((ChannelPerceptualHash *) NULL);
   1850     }
   1851   moments=GetImageMoments(hash_image,exception);
   1852   hash_image=DestroyImage(hash_image);
   1853   if (moments == (ChannelMoments *) NULL)
   1854     {
   1855       perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
   1856         perceptual_hash);
   1857       return((ChannelPerceptualHash *) NULL);
   1858     }
   1859   for (channel=0; channel <= MaxPixelChannels; channel++)
   1860     for (i=0; i < MaximumNumberOfImageMoments; i++)
   1861       perceptual_hash[channel].hclp_hu_phash[i]=
   1862         (-MagickLog10(moments[channel].invariant[i]));
   1863   moments=(ChannelMoments *) RelinquishMagickMemory(moments);
   1864   return(perceptual_hash);
   1865 }
   1866 
   1867 /*
   1869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1870 %                                                                             %
   1871 %                                                                             %
   1872 %                                                                             %
   1873 %   G e t I m a g e R a n g e                                                 %
   1874 %                                                                             %
   1875 %                                                                             %
   1876 %                                                                             %
   1877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1878 %
   1879 %  GetImageRange() returns the range of one or more image channels.
   1880 %
   1881 %  The format of the GetImageRange method is:
   1882 %
   1883 %      MagickBooleanType GetImageRange(const Image *image,double *minima,
   1884 %        double *maxima,ExceptionInfo *exception)
   1885 %
   1886 %  A description of each parameter follows:
   1887 %
   1888 %    o image: the image.
   1889 %
   1890 %    o minima: the minimum value in the channel.
   1891 %
   1892 %    o maxima: the maximum value in the channel.
   1893 %
   1894 %    o exception: return any errors or warnings in this structure.
   1895 %
   1896 */
   1897 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
   1898   double *maxima,ExceptionInfo *exception)
   1899 {
   1900   CacheView
   1901     *image_view;
   1902 
   1903   MagickBooleanType
   1904     initialize,
   1905     status;
   1906 
   1907   ssize_t
   1908     y;
   1909 
   1910   assert(image != (Image *) NULL);
   1911   assert(image->signature == MagickCoreSignature);
   1912   if (image->debug != MagickFalse)
   1913     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1914   status=MagickTrue;
   1915   initialize=MagickTrue;
   1916   *maxima=0.0;
   1917   *minima=0.0;
   1918   image_view=AcquireVirtualCacheView(image,exception);
   1919 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1920   #pragma omp parallel for schedule(static,4) shared(status,initialize) \
   1921     magick_threads(image,image,image->rows,1)
   1922 #endif
   1923   for (y=0; y < (ssize_t) image->rows; y++)
   1924   {
   1925     double
   1926       row_maxima = 0.0,
   1927       row_minima = 0.0;
   1928 
   1929     MagickBooleanType
   1930       row_initialize;
   1931 
   1932     register const Quantum
   1933       *magick_restrict p;
   1934 
   1935     register ssize_t
   1936       x;
   1937 
   1938     if (status == MagickFalse)
   1939       continue;
   1940     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
   1941     if (p == (const Quantum *) NULL)
   1942       {
   1943         status=MagickFalse;
   1944         continue;
   1945       }
   1946     row_initialize=MagickTrue;
   1947     for (x=0; x < (ssize_t) image->columns; x++)
   1948     {
   1949       register ssize_t
   1950         i;
   1951 
   1952       if (GetPixelReadMask(image,p) == 0)
   1953         {
   1954           p+=GetPixelChannels(image);
   1955           continue;
   1956         }
   1957       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1958       {
   1959         PixelChannel channel=GetPixelChannelChannel(image,i);
   1960         PixelTrait traits=GetPixelChannelTraits(image,channel);
   1961         if (traits == UndefinedPixelTrait)
   1962           continue;
   1963         if ((traits & UpdatePixelTrait) == 0)
   1964           continue;
   1965         if (row_initialize != MagickFalse)
   1966           {
   1967             row_minima=(double) p[i];
   1968             row_maxima=(double) p[i];
   1969             row_initialize=MagickFalse;
   1970           }
   1971         else
   1972           {
   1973             if ((double) p[i] < row_minima)
   1974               row_minima=(double) p[i];
   1975             if ((double) p[i] > row_maxima)
   1976               row_maxima=(double) p[i];
   1977          }
   1978       }
   1979       p+=GetPixelChannels(image);
   1980     }
   1981 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1982 #pragma omp critical (MagickCore_GetImageRange)
   1983 #endif
   1984     {
   1985       if (initialize != MagickFalse)
   1986         {
   1987           *minima=row_minima;
   1988           *maxima=row_maxima;
   1989           initialize=MagickFalse;
   1990         }
   1991       else
   1992         {
   1993           if (row_minima < *minima)
   1994             *minima=row_minima;
   1995           if (row_maxima > *maxima)
   1996             *maxima=row_maxima;
   1997         }
   1998     }
   1999   }
   2000   image_view=DestroyCacheView(image_view);
   2001   return(status);
   2002 }
   2003 
   2004 /*
   2006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2007 %                                                                             %
   2008 %                                                                             %
   2009 %                                                                             %
   2010 %   G e t I m a g e S t a t i s t i c s                                       %
   2011 %                                                                             %
   2012 %                                                                             %
   2013 %                                                                             %
   2014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2015 %
   2016 %  GetImageStatistics() returns statistics for each channel in the image.  The
   2017 %  statistics include the channel depth, its minima, maxima, mean, standard
   2018 %  deviation, kurtosis and skewness.  You can access the red channel mean, for
   2019 %  example, like this:
   2020 %
   2021 %      channel_statistics=GetImageStatistics(image,exception);
   2022 %      red_mean=channel_statistics[RedPixelChannel].mean;
   2023 %
   2024 %  Use MagickRelinquishMemory() to free the statistics buffer.
   2025 %
   2026 %  The format of the GetImageStatistics method is:
   2027 %
   2028 %      ChannelStatistics *GetImageStatistics(const Image *image,
   2029 %        ExceptionInfo *exception)
   2030 %
   2031 %  A description of each parameter follows:
   2032 %
   2033 %    o image: the image.
   2034 %
   2035 %    o exception: return any errors or warnings in this structure.
   2036 %
   2037 */
   2038 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
   2039   ExceptionInfo *exception)
   2040 {
   2041   ChannelStatistics
   2042     *channel_statistics;
   2043 
   2044   double
   2045     *histogram;
   2046 
   2047   MagickStatusType
   2048     status;
   2049 
   2050   QuantumAny
   2051     range;
   2052 
   2053   register ssize_t
   2054     i;
   2055 
   2056   size_t
   2057     channels,
   2058     depth;
   2059 
   2060   ssize_t
   2061     y;
   2062 
   2063   assert(image != (Image *) NULL);
   2064   assert(image->signature == MagickCoreSignature);
   2065   if (image->debug != MagickFalse)
   2066     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   2067   histogram=(double *) AcquireQuantumMemory(MaxMap+1UL,MaxPixelChannels*
   2068     sizeof(*histogram));
   2069   channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
   2070     MaxPixelChannels+1,sizeof(*channel_statistics));
   2071   if ((channel_statistics == (ChannelStatistics *) NULL) ||
   2072       (histogram == (double *) NULL))
   2073     {
   2074       if (histogram != (double *) NULL)
   2075         histogram=(double *) RelinquishMagickMemory(histogram);
   2076       if (channel_statistics != (ChannelStatistics *) NULL)
   2077         channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
   2078           channel_statistics);
   2079       return(channel_statistics);
   2080     }
   2081   (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
   2082     sizeof(*channel_statistics));
   2083   for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
   2084   {
   2085     channel_statistics[i].depth=1;
   2086     channel_statistics[i].maxima=(-MagickMaximumValue);
   2087     channel_statistics[i].minima=MagickMaximumValue;
   2088   }
   2089   (void) ResetMagickMemory(histogram,0,(MaxMap+1)*MaxPixelChannels*
   2090     sizeof(*histogram));
   2091   for (y=0; y < (ssize_t) image->rows; y++)
   2092   {
   2093     register const Quantum
   2094       *magick_restrict p;
   2095 
   2096     register ssize_t
   2097       x;
   2098 
   2099     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
   2100     if (p == (const Quantum *) NULL)
   2101       break;
   2102     for (x=0; x < (ssize_t) image->columns; x++)
   2103     {
   2104       register ssize_t
   2105         i;
   2106 
   2107       if (GetPixelReadMask(image,p) == 0)
   2108         {
   2109           p+=GetPixelChannels(image);
   2110           continue;
   2111         }
   2112       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   2113       {
   2114         PixelChannel channel=GetPixelChannelChannel(image,i);
   2115         PixelTrait traits=GetPixelChannelTraits(image,channel);
   2116         if (traits == UndefinedPixelTrait)
   2117           continue;
   2118         if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
   2119           {
   2120             depth=channel_statistics[channel].depth;
   2121             range=GetQuantumRange(depth);
   2122             status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
   2123               range) ? MagickTrue : MagickFalse;
   2124             if (status != MagickFalse)
   2125               {
   2126                 channel_statistics[channel].depth++;
   2127                 i--;
   2128                 continue;
   2129               }
   2130           }
   2131         if ((double) p[i] < channel_statistics[channel].minima)
   2132           channel_statistics[channel].minima=(double) p[i];
   2133         if ((double) p[i] > channel_statistics[channel].maxima)
   2134           channel_statistics[channel].maxima=(double) p[i];
   2135         channel_statistics[channel].sum+=p[i];
   2136         channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
   2137         channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
   2138         channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
   2139           p[i];
   2140         channel_statistics[channel].area++;
   2141         histogram[GetPixelChannels(image)*ScaleQuantumToMap(
   2142           ClampToQuantum((double) p[i]))+i]++;
   2143       }
   2144       p+=GetPixelChannels(image);
   2145     }
   2146   }
   2147   for (i=0; i < (ssize_t) MaxPixelChannels; i++)
   2148   {
   2149     double
   2150       area,
   2151       number_bins;
   2152 
   2153     register ssize_t
   2154       j;
   2155 
   2156     area=PerceptibleReciprocal(channel_statistics[i].area);
   2157     channel_statistics[i].sum*=area;
   2158     channel_statistics[i].sum_squared*=area;
   2159     channel_statistics[i].sum_cubed*=area;
   2160     channel_statistics[i].sum_fourth_power*=area;
   2161     channel_statistics[i].mean=channel_statistics[i].sum;
   2162     channel_statistics[i].variance=channel_statistics[i].sum_squared;
   2163     channel_statistics[i].standard_deviation=sqrt(
   2164       channel_statistics[i].variance-(channel_statistics[i].mean*
   2165       channel_statistics[i].mean));
   2166     number_bins=0.0;
   2167     for (j=0; j < (ssize_t) (MaxMap+1U); j++)
   2168       if (histogram[GetPixelChannels(image)*j+i] > 0.0)
   2169         number_bins++;
   2170     for (j=0; j < (ssize_t) (MaxMap+1U); j++)
   2171     {
   2172       double
   2173         count;
   2174 
   2175       count=histogram[GetPixelChannels(image)*j+i]*area;
   2176       channel_statistics[i].entropy+=-count*MagickLog10(count)/
   2177         MagickLog10(number_bins);
   2178     }
   2179   }
   2180   for (i=0; i < (ssize_t) MaxPixelChannels; i++)
   2181   {
   2182     PixelTrait traits=GetPixelChannelTraits(image,(PixelChannel) i);
   2183     if ((traits & UpdatePixelTrait) == 0)
   2184       continue;
   2185     channel_statistics[CompositePixelChannel].area+=channel_statistics[i].area;
   2186     channel_statistics[CompositePixelChannel].minima=MagickMin(
   2187       channel_statistics[CompositePixelChannel].minima,
   2188       channel_statistics[i].minima);
   2189     channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
   2190       channel_statistics[CompositePixelChannel].maxima,
   2191       channel_statistics[i].maxima);
   2192     channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
   2193     channel_statistics[CompositePixelChannel].sum_squared+=
   2194       channel_statistics[i].sum_squared;
   2195     channel_statistics[CompositePixelChannel].sum_cubed+=
   2196       channel_statistics[i].sum_cubed;
   2197     channel_statistics[CompositePixelChannel].sum_fourth_power+=
   2198       channel_statistics[i].sum_fourth_power;
   2199     channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
   2200     channel_statistics[CompositePixelChannel].variance+=
   2201       channel_statistics[i].variance-channel_statistics[i].mean*
   2202       channel_statistics[i].mean;
   2203     channel_statistics[CompositePixelChannel].standard_deviation+=
   2204       channel_statistics[i].variance-channel_statistics[i].mean*
   2205       channel_statistics[i].mean;
   2206     if (channel_statistics[i].entropy > MagickEpsilon)
   2207       channel_statistics[CompositePixelChannel].entropy+=
   2208         channel_statistics[i].entropy;
   2209   }
   2210   channels=GetImageChannels(image);
   2211   channel_statistics[CompositePixelChannel].area/=channels;
   2212   channel_statistics[CompositePixelChannel].sum/=channels;
   2213   channel_statistics[CompositePixelChannel].sum_squared/=channels;
   2214   channel_statistics[CompositePixelChannel].sum_cubed/=channels;
   2215   channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
   2216   channel_statistics[CompositePixelChannel].mean/=channels;
   2217   channel_statistics[CompositePixelChannel].variance/=channels;
   2218   channel_statistics[CompositePixelChannel].standard_deviation=
   2219     sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
   2220   channel_statistics[CompositePixelChannel].kurtosis/=channels;
   2221   channel_statistics[CompositePixelChannel].skewness/=channels;
   2222   channel_statistics[CompositePixelChannel].entropy/=channels;
   2223   for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
   2224   {
   2225     double
   2226       standard_deviation;
   2227 
   2228     if (channel_statistics[i].standard_deviation == 0.0)
   2229       continue;
   2230     standard_deviation=PerceptibleReciprocal(
   2231       channel_statistics[i].standard_deviation);
   2232     channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
   2233       channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
   2234       channel_statistics[i].mean*channel_statistics[i].mean*
   2235       channel_statistics[i].mean)*(standard_deviation*standard_deviation*
   2236       standard_deviation);
   2237     channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
   2238       channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
   2239       channel_statistics[i].mean*channel_statistics[i].mean*
   2240       channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
   2241       channel_statistics[i].mean*1.0*channel_statistics[i].mean*
   2242       channel_statistics[i].mean)*(standard_deviation*standard_deviation*
   2243       standard_deviation*standard_deviation)-3.0;
   2244   }
   2245   histogram=(double *) RelinquishMagickMemory(histogram);
   2246   if (y < (ssize_t) image->rows)
   2247     channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
   2248       channel_statistics);
   2249   return(channel_statistics);
   2250 }
   2251 
   2252 /*
   2254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2255 %                                                                             %
   2256 %                                                                             %
   2257 %                                                                             %
   2258 %     P o l y n o m i a l I m a g e                                           %
   2259 %                                                                             %
   2260 %                                                                             %
   2261 %                                                                             %
   2262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2263 %
   2264 %  PolynomialImage() returns a new image where each pixel is the sum of the
   2265 %  pixels in the image sequence after applying its corresponding terms
   2266 %  (coefficient and degree pairs).
   2267 %
   2268 %  The format of the PolynomialImage method is:
   2269 %
   2270 %      Image *PolynomialImage(const Image *images,const size_t number_terms,
   2271 %        const double *terms,ExceptionInfo *exception)
   2272 %
   2273 %  A description of each parameter follows:
   2274 %
   2275 %    o images: the image sequence.
   2276 %
   2277 %    o number_terms: the number of terms in the list.  The actual list length
   2278 %      is 2 x number_terms + 1 (the constant).
   2279 %
   2280 %    o terms: the list of polynomial coefficients and degree pairs and a
   2281 %      constant.
   2282 %
   2283 %    o exception: return any errors or warnings in this structure.
   2284 %
   2285 */
   2286 
   2287 MagickExport Image *PolynomialImage(const Image *images,
   2288   const size_t number_terms,const double *terms,ExceptionInfo *exception)
   2289 {
   2290 #define PolynomialImageTag  "Polynomial/Image"
   2291 
   2292   CacheView
   2293     *polynomial_view;
   2294 
   2295   Image
   2296     *image;
   2297 
   2298   MagickBooleanType
   2299     status;
   2300 
   2301   MagickOffsetType
   2302     progress;
   2303 
   2304   PixelChannels
   2305     **magick_restrict polynomial_pixels;
   2306 
   2307   size_t
   2308     number_images;
   2309 
   2310   ssize_t
   2311     y;
   2312 
   2313   assert(images != (Image *) NULL);
   2314   assert(images->signature == MagickCoreSignature);
   2315   if (images->debug != MagickFalse)
   2316     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
   2317   assert(exception != (ExceptionInfo *) NULL);
   2318   assert(exception->signature == MagickCoreSignature);
   2319   image=CloneImage(images,images->columns,images->rows,MagickTrue,
   2320     exception);
   2321   if (image == (Image *) NULL)
   2322     return((Image *) NULL);
   2323   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
   2324     {
   2325       image=DestroyImage(image);
   2326       return((Image *) NULL);
   2327     }
   2328   number_images=GetImageListLength(images);
   2329   polynomial_pixels=AcquirePixelThreadSet(images);
   2330   if (polynomial_pixels == (PixelChannels **) NULL)
   2331     {
   2332       image=DestroyImage(image);
   2333       (void) ThrowMagickException(exception,GetMagickModule(),
   2334         ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
   2335       return((Image *) NULL);
   2336     }
   2337   /*
   2338     Polynomial image pixels.
   2339   */
   2340   status=MagickTrue;
   2341   progress=0;
   2342   polynomial_view=AcquireAuthenticCacheView(image,exception);
   2343 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   2344   #pragma omp parallel for schedule(static,4) shared(progress,status) \
   2345     magick_threads(image,image,image->rows,1)
   2346 #endif
   2347   for (y=0; y < (ssize_t) image->rows; y++)
   2348   {
   2349     CacheView
   2350       *image_view;
   2351 
   2352     const Image
   2353       *next;
   2354 
   2355     const int
   2356       id = GetOpenMPThreadId();
   2357 
   2358     register ssize_t
   2359       i,
   2360       x;
   2361 
   2362     register PixelChannels
   2363       *polynomial_pixel;
   2364 
   2365     register Quantum
   2366       *magick_restrict q;
   2367 
   2368     ssize_t
   2369       j;
   2370 
   2371     if (status == MagickFalse)
   2372       continue;
   2373     q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
   2374       exception);
   2375     if (q == (Quantum *) NULL)
   2376       {
   2377         status=MagickFalse;
   2378         continue;
   2379       }
   2380     polynomial_pixel=polynomial_pixels[id];
   2381     for (j=0; j < (ssize_t) image->columns; j++)
   2382       for (i=0; i < MaxPixelChannels; i++)
   2383         polynomial_pixel[j].channel[i]=0.0;
   2384     next=images;
   2385     for (j=0; j < (ssize_t) number_images; j++)
   2386     {
   2387       register const Quantum
   2388         *p;
   2389 
   2390       if (j >= (ssize_t) number_terms)
   2391         continue;
   2392       image_view=AcquireVirtualCacheView(next,exception);
   2393       p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
   2394       if (p == (const Quantum *) NULL)
   2395         {
   2396           image_view=DestroyCacheView(image_view);
   2397           break;
   2398         }
   2399       for (x=0; x < (ssize_t) image->columns; x++)
   2400       {
   2401         register ssize_t
   2402           i;
   2403 
   2404         if (GetPixelReadMask(next,p) == 0)
   2405           {
   2406             p+=GetPixelChannels(next);
   2407             continue;
   2408           }
   2409         for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
   2410         {
   2411           MagickRealType
   2412             coefficient,
   2413             degree;
   2414 
   2415           PixelChannel channel=GetPixelChannelChannel(image,i);
   2416           PixelTrait traits=GetPixelChannelTraits(next,channel);
   2417           PixelTrait polynomial_traits=GetPixelChannelTraits(image,channel);
   2418           if ((traits == UndefinedPixelTrait) ||
   2419               (polynomial_traits == UndefinedPixelTrait))
   2420             continue;
   2421           if ((traits & UpdatePixelTrait) == 0)
   2422             continue;
   2423           coefficient=(MagickRealType) terms[2*j];
   2424           degree=(MagickRealType) terms[(j << 1)+1];
   2425           polynomial_pixel[x].channel[i]+=coefficient*
   2426             pow(QuantumScale*GetPixelChannel(image,channel,p),degree);
   2427         }
   2428         p+=GetPixelChannels(next);
   2429       }
   2430       image_view=DestroyCacheView(image_view);
   2431       next=GetNextImageInList(next);
   2432     }
   2433     for (x=0; x < (ssize_t) image->columns; x++)
   2434     {
   2435       register ssize_t
   2436         i;
   2437 
   2438       if (GetPixelReadMask(image,q) == 0)
   2439         {
   2440           q+=GetPixelChannels(image);
   2441           continue;
   2442         }
   2443       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   2444       {
   2445         PixelChannel channel=GetPixelChannelChannel(image,i);
   2446         PixelTrait traits=GetPixelChannelTraits(image,channel);
   2447         if (traits == UndefinedPixelTrait)
   2448           continue;
   2449         if ((traits & UpdatePixelTrait) == 0)
   2450           continue;
   2451         q[i]=ClampToQuantum(QuantumRange*polynomial_pixel[x].channel[i]);
   2452       }
   2453       q+=GetPixelChannels(image);
   2454     }
   2455     if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
   2456       status=MagickFalse;
   2457     if (images->progress_monitor != (MagickProgressMonitor) NULL)
   2458       {
   2459         MagickBooleanType
   2460           proceed;
   2461 
   2462 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   2463         #pragma omp critical (MagickCore_PolynomialImages)
   2464 #endif
   2465         proceed=SetImageProgress(images,PolynomialImageTag,progress++,
   2466           image->rows);
   2467         if (proceed == MagickFalse)
   2468           status=MagickFalse;
   2469       }
   2470   }
   2471   polynomial_view=DestroyCacheView(polynomial_view);
   2472   polynomial_pixels=DestroyPixelThreadSet(polynomial_pixels);
   2473   if (status == MagickFalse)
   2474     image=DestroyImage(image);
   2475   return(image);
   2476 }
   2477 
   2478 /*
   2480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2481 %                                                                             %
   2482 %                                                                             %
   2483 %                                                                             %
   2484 %     S t a t i s t i c I m a g e                                             %
   2485 %                                                                             %
   2486 %                                                                             %
   2487 %                                                                             %
   2488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2489 %
   2490 %  StatisticImage() makes each pixel the min / max / median / mode / etc. of
   2491 %  the neighborhood of the specified width and height.
   2492 %
   2493 %  The format of the StatisticImage method is:
   2494 %
   2495 %      Image *StatisticImage(const Image *image,const StatisticType type,
   2496 %        const size_t width,const size_t height,ExceptionInfo *exception)
   2497 %
   2498 %  A description of each parameter follows:
   2499 %
   2500 %    o image: the image.
   2501 %
   2502 %    o type: the statistic type (median, mode, etc.).
   2503 %
   2504 %    o width: the width of the pixel neighborhood.
   2505 %
   2506 %    o height: the height of the pixel neighborhood.
   2507 %
   2508 %    o exception: return any errors or warnings in this structure.
   2509 %
   2510 */
   2511 
   2512 typedef struct _SkipNode
   2513 {
   2514   size_t
   2515     next[9],
   2516     count,
   2517     signature;
   2518 } SkipNode;
   2519 
   2520 typedef struct _SkipList
   2521 {
   2522   ssize_t
   2523     level;
   2524 
   2525   SkipNode
   2526     *nodes;
   2527 } SkipList;
   2528 
   2529 typedef struct _PixelList
   2530 {
   2531   size_t
   2532     length,
   2533     seed;
   2534 
   2535   SkipList
   2536     skip_list;
   2537 
   2538   size_t
   2539     signature;
   2540 } PixelList;
   2541 
   2542 static PixelList *DestroyPixelList(PixelList *pixel_list)
   2543 {
   2544   if (pixel_list == (PixelList *) NULL)
   2545     return((PixelList *) NULL);
   2546   if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
   2547     pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
   2548       pixel_list->skip_list.nodes);
   2549   pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
   2550   return(pixel_list);
   2551 }
   2552 
   2553 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
   2554 {
   2555   register ssize_t
   2556     i;
   2557 
   2558   assert(pixel_list != (PixelList **) NULL);
   2559   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
   2560     if (pixel_list[i] != (PixelList *) NULL)
   2561       pixel_list[i]=DestroyPixelList(pixel_list[i]);
   2562   pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
   2563   return(pixel_list);
   2564 }
   2565 
   2566 static PixelList *AcquirePixelList(const size_t width,const size_t height)
   2567 {
   2568   PixelList
   2569     *pixel_list;
   2570 
   2571   pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
   2572   if (pixel_list == (PixelList *) NULL)
   2573     return(pixel_list);
   2574   (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
   2575   pixel_list->length=width*height;
   2576   pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
   2577     sizeof(*pixel_list->skip_list.nodes));
   2578   if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
   2579     return(DestroyPixelList(pixel_list));
   2580   (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
   2581     sizeof(*pixel_list->skip_list.nodes));
   2582   pixel_list->signature=MagickCoreSignature;
   2583   return(pixel_list);
   2584 }
   2585 
   2586 static PixelList **AcquirePixelListThreadSet(const size_t width,
   2587   const size_t height)
   2588 {
   2589   PixelList
   2590     **pixel_list;
   2591 
   2592   register ssize_t
   2593     i;
   2594 
   2595   size_t
   2596     number_threads;
   2597 
   2598   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
   2599   pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
   2600     sizeof(*pixel_list));
   2601   if (pixel_list == (PixelList **) NULL)
   2602     return((PixelList **) NULL);
   2603   (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
   2604   for (i=0; i < (ssize_t) number_threads; i++)
   2605   {
   2606     pixel_list[i]=AcquirePixelList(width,height);
   2607     if (pixel_list[i] == (PixelList *) NULL)
   2608       return(DestroyPixelListThreadSet(pixel_list));
   2609   }
   2610   return(pixel_list);
   2611 }
   2612 
   2613 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
   2614 {
   2615   register SkipList
   2616     *p;
   2617 
   2618   register ssize_t
   2619     level;
   2620 
   2621   size_t
   2622     search,
   2623     update[9];
   2624 
   2625   /*
   2626     Initialize the node.
   2627   */
   2628   p=(&pixel_list->skip_list);
   2629   p->nodes[color].signature=pixel_list->signature;
   2630   p->nodes[color].count=1;
   2631   /*
   2632     Determine where it belongs in the list.
   2633   */
   2634   search=65536UL;
   2635   for (level=p->level; level >= 0; level--)
   2636   {
   2637     while (p->nodes[search].next[level] < color)
   2638       search=p->nodes[search].next[level];
   2639     update[level]=search;
   2640   }
   2641   /*
   2642     Generate a pseudo-random level for this node.
   2643   */
   2644   for (level=0; ; level++)
   2645   {
   2646     pixel_list->seed=(pixel_list->seed*42893621L)+1L;
   2647     if ((pixel_list->seed & 0x300) != 0x300)
   2648       break;
   2649   }
   2650   if (level > 8)
   2651     level=8;
   2652   if (level > (p->level+2))
   2653     level=p->level+2;
   2654   /*
   2655     If we're raising the list's level, link back to the root node.
   2656   */
   2657   while (level > p->level)
   2658   {
   2659     p->level++;
   2660     update[p->level]=65536UL;
   2661   }
   2662   /*
   2663     Link the node into the skip-list.
   2664   */
   2665   do
   2666   {
   2667     p->nodes[color].next[level]=p->nodes[update[level]].next[level];
   2668     p->nodes[update[level]].next[level]=color;
   2669   } while (level-- > 0);
   2670 }
   2671 
   2672 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
   2673 {
   2674   register SkipList
   2675     *p;
   2676 
   2677   size_t
   2678     color,
   2679     maximum;
   2680 
   2681   ssize_t
   2682     count;
   2683 
   2684   /*
   2685     Find the maximum value for each of the color.
   2686   */
   2687   p=(&pixel_list->skip_list);
   2688   color=65536L;
   2689   count=0;
   2690   maximum=p->nodes[color].next[0];
   2691   do
   2692   {
   2693     color=p->nodes[color].next[0];
   2694     if (color > maximum)
   2695       maximum=color;
   2696     count+=p->nodes[color].count;
   2697   } while (count < (ssize_t) pixel_list->length);
   2698   *pixel=ScaleShortToQuantum((unsigned short) maximum);
   2699 }
   2700 
   2701 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
   2702 {
   2703   double
   2704     sum;
   2705 
   2706   register SkipList
   2707     *p;
   2708 
   2709   size_t
   2710     color;
   2711 
   2712   ssize_t
   2713     count;
   2714 
   2715   /*
   2716     Find the mean value for each of the color.
   2717   */
   2718   p=(&pixel_list->skip_list);
   2719   color=65536L;
   2720   count=0;
   2721   sum=0.0;
   2722   do
   2723   {
   2724     color=p->nodes[color].next[0];
   2725     sum+=(double) p->nodes[color].count*color;
   2726     count+=p->nodes[color].count;
   2727   } while (count < (ssize_t) pixel_list->length);
   2728   sum/=pixel_list->length;
   2729   *pixel=ScaleShortToQuantum((unsigned short) sum);
   2730 }
   2731 
   2732 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
   2733 {
   2734   register SkipList
   2735     *p;
   2736 
   2737   size_t
   2738     color;
   2739 
   2740   ssize_t
   2741     count;
   2742 
   2743   /*
   2744     Find the median value for each of the color.
   2745   */
   2746   p=(&pixel_list->skip_list);
   2747   color=65536L;
   2748   count=0;
   2749   do
   2750   {
   2751     color=p->nodes[color].next[0];
   2752     count+=p->nodes[color].count;
   2753   } while (count <= (ssize_t) (pixel_list->length >> 1));
   2754   *pixel=ScaleShortToQuantum((unsigned short) color);
   2755 }
   2756 
   2757 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
   2758 {
   2759   register SkipList
   2760     *p;
   2761 
   2762   size_t
   2763     color,
   2764     minimum;
   2765 
   2766   ssize_t
   2767     count;
   2768 
   2769   /*
   2770     Find the minimum value for each of the color.
   2771   */
   2772   p=(&pixel_list->skip_list);
   2773   count=0;
   2774   color=65536UL;
   2775   minimum=p->nodes[color].next[0];
   2776   do
   2777   {
   2778     color=p->nodes[color].next[0];
   2779     if (color < minimum)
   2780       minimum=color;
   2781     count+=p->nodes[color].count;
   2782   } while (count < (ssize_t) pixel_list->length);
   2783   *pixel=ScaleShortToQuantum((unsigned short) minimum);
   2784 }
   2785 
   2786 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
   2787 {
   2788   register SkipList
   2789     *p;
   2790 
   2791   size_t
   2792     color,
   2793     max_count,
   2794     mode;
   2795 
   2796   ssize_t
   2797     count;
   2798 
   2799   /*
   2800     Make each pixel the 'predominant color' of the specified neighborhood.
   2801   */
   2802   p=(&pixel_list->skip_list);
   2803   color=65536L;
   2804   mode=color;
   2805   max_count=p->nodes[mode].count;
   2806   count=0;
   2807   do
   2808   {
   2809     color=p->nodes[color].next[0];
   2810     if (p->nodes[color].count > max_count)
   2811       {
   2812         mode=color;
   2813         max_count=p->nodes[mode].count;
   2814       }
   2815     count+=p->nodes[color].count;
   2816   } while (count < (ssize_t) pixel_list->length);
   2817   *pixel=ScaleShortToQuantum((unsigned short) mode);
   2818 }
   2819 
   2820 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
   2821 {
   2822   register SkipList
   2823     *p;
   2824 
   2825   size_t
   2826     color,
   2827     next,
   2828     previous;
   2829 
   2830   ssize_t
   2831     count;
   2832 
   2833   /*
   2834     Finds the non peak value for each of the colors.
   2835   */
   2836   p=(&pixel_list->skip_list);
   2837   color=65536L;
   2838   next=p->nodes[color].next[0];
   2839   count=0;
   2840   do
   2841   {
   2842     previous=color;
   2843     color=next;
   2844     next=p->nodes[color].next[0];
   2845     count+=p->nodes[color].count;
   2846   } while (count <= (ssize_t) (pixel_list->length >> 1));
   2847   if ((previous == 65536UL) && (next != 65536UL))
   2848     color=next;
   2849   else
   2850     if ((previous != 65536UL) && (next == 65536UL))
   2851       color=previous;
   2852   *pixel=ScaleShortToQuantum((unsigned short) color);
   2853 }
   2854 
   2855 static inline void GetRootMeanSquarePixelList(PixelList *pixel_list,
   2856   Quantum *pixel)
   2857 {
   2858   double
   2859     sum;
   2860 
   2861   register SkipList
   2862     *p;
   2863 
   2864   size_t
   2865     color;
   2866 
   2867   ssize_t
   2868     count;
   2869 
   2870   /*
   2871     Find the root mean square value for each of the color.
   2872   */
   2873   p=(&pixel_list->skip_list);
   2874   color=65536L;
   2875   count=0;
   2876   sum=0.0;
   2877   do
   2878   {
   2879     color=p->nodes[color].next[0];
   2880     sum+=(double) (p->nodes[color].count*color*color);
   2881     count+=p->nodes[color].count;
   2882   } while (count < (ssize_t) pixel_list->length);
   2883   sum/=pixel_list->length;
   2884   *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum));
   2885 }
   2886 
   2887 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
   2888   Quantum *pixel)
   2889 {
   2890   double
   2891     sum,
   2892     sum_squared;
   2893 
   2894   register SkipList
   2895     *p;
   2896 
   2897   size_t
   2898     color;
   2899 
   2900   ssize_t
   2901     count;
   2902 
   2903   /*
   2904     Find the standard-deviation value for each of the color.
   2905   */
   2906   p=(&pixel_list->skip_list);
   2907   color=65536L;
   2908   count=0;
   2909   sum=0.0;
   2910   sum_squared=0.0;
   2911   do
   2912   {
   2913     register ssize_t
   2914       i;
   2915 
   2916     color=p->nodes[color].next[0];
   2917     sum+=(double) p->nodes[color].count*color;
   2918     for (i=0; i < (ssize_t) p->nodes[color].count; i++)
   2919       sum_squared+=((double) color)*((double) color);
   2920     count+=p->nodes[color].count;
   2921   } while (count < (ssize_t) pixel_list->length);
   2922   sum/=pixel_list->length;
   2923   sum_squared/=pixel_list->length;
   2924   *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
   2925 }
   2926 
   2927 static inline void InsertPixelList(const Quantum pixel,PixelList *pixel_list)
   2928 {
   2929   size_t
   2930     signature;
   2931 
   2932   unsigned short
   2933     index;
   2934 
   2935   index=ScaleQuantumToShort(pixel);
   2936   signature=pixel_list->skip_list.nodes[index].signature;
   2937   if (signature == pixel_list->signature)
   2938     {
   2939       pixel_list->skip_list.nodes[index].count++;
   2940       return;
   2941     }
   2942   AddNodePixelList(pixel_list,index);
   2943 }
   2944 
   2945 static void ResetPixelList(PixelList *pixel_list)
   2946 {
   2947   int
   2948     level;
   2949 
   2950   register SkipNode
   2951     *root;
   2952 
   2953   register SkipList
   2954     *p;
   2955 
   2956   /*
   2957     Reset the skip-list.
   2958   */
   2959   p=(&pixel_list->skip_list);
   2960   root=p->nodes+65536UL;
   2961   p->level=0;
   2962   for (level=0; level < 9; level++)
   2963     root->next[level]=65536UL;
   2964   pixel_list->seed=pixel_list->signature++;
   2965 }
   2966 
   2967 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
   2968   const size_t width,const size_t height,ExceptionInfo *exception)
   2969 {
   2970 #define StatisticImageTag  "Statistic/Image"
   2971 
   2972   CacheView
   2973     *image_view,
   2974     *statistic_view;
   2975 
   2976   Image
   2977     *statistic_image;
   2978 
   2979   MagickBooleanType
   2980     status;
   2981 
   2982   MagickOffsetType
   2983     progress;
   2984 
   2985   PixelList
   2986     **magick_restrict pixel_list;
   2987 
   2988   ssize_t
   2989     center,
   2990     y;
   2991 
   2992   /*
   2993     Initialize statistics image attributes.
   2994   */
   2995   assert(image != (Image *) NULL);
   2996   assert(image->signature == MagickCoreSignature);
   2997   if (image->debug != MagickFalse)
   2998     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   2999   assert(exception != (ExceptionInfo *) NULL);
   3000   assert(exception->signature == MagickCoreSignature);
   3001   statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
   3002     exception);
   3003   if (statistic_image == (Image *) NULL)
   3004     return((Image *) NULL);
   3005   status=SetImageStorageClass(statistic_image,DirectClass,exception);
   3006   if (status == MagickFalse)
   3007     {
   3008       statistic_image=DestroyImage(statistic_image);
   3009       return((Image *) NULL);
   3010     }
   3011   pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
   3012   if (pixel_list == (PixelList **) NULL)
   3013     {
   3014       statistic_image=DestroyImage(statistic_image);
   3015       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   3016     }
   3017   /*
   3018     Make each pixel the min / max / median / mode / etc. of the neighborhood.
   3019   */
   3020   center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
   3021     (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
   3022   status=MagickTrue;
   3023   progress=0;
   3024   image_view=AcquireVirtualCacheView(image,exception);
   3025   statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
   3026 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   3027   #pragma omp parallel for schedule(static,4) shared(progress,status) \
   3028     magick_threads(image,statistic_image,statistic_image->rows,1)
   3029 #endif
   3030   for (y=0; y < (ssize_t) statistic_image->rows; y++)
   3031   {
   3032     const int
   3033       id = GetOpenMPThreadId();
   3034 
   3035     register const Quantum
   3036       *magick_restrict p;
   3037 
   3038     register Quantum
   3039       *magick_restrict q;
   3040 
   3041     register ssize_t
   3042       x;
   3043 
   3044     if (status == MagickFalse)
   3045       continue;
   3046     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
   3047       (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
   3048       MagickMax(height,1),exception);
   3049     q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns,      1,exception);
   3050     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
   3051       {
   3052         status=MagickFalse;
   3053         continue;
   3054       }
   3055     for (x=0; x < (ssize_t) statistic_image->columns; x++)
   3056     {
   3057       register ssize_t
   3058         i;
   3059 
   3060       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   3061       {
   3062         Quantum
   3063           pixel;
   3064 
   3065         register const Quantum
   3066           *magick_restrict pixels;
   3067 
   3068         register ssize_t
   3069           u;
   3070 
   3071         ssize_t
   3072           v;
   3073 
   3074         PixelChannel channel=GetPixelChannelChannel(image,i);
   3075         PixelTrait traits=GetPixelChannelTraits(image,channel);
   3076         PixelTrait statistic_traits=GetPixelChannelTraits(statistic_image,
   3077           channel);
   3078         if ((traits == UndefinedPixelTrait) ||
   3079             (statistic_traits == UndefinedPixelTrait))
   3080           continue;
   3081         if (((statistic_traits & CopyPixelTrait) != 0) ||
   3082             (GetPixelReadMask(image,p) == 0))
   3083           {
   3084             SetPixelChannel(statistic_image,channel,p[center+i],q);
   3085             continue;
   3086           }
   3087         pixels=p;
   3088         ResetPixelList(pixel_list[id]);
   3089         for (v=0; v < (ssize_t) MagickMax(height,1); v++)
   3090         {
   3091           for (u=0; u < (ssize_t) MagickMax(width,1); u++)
   3092           {
   3093             InsertPixelList(pixels[i],pixel_list[id]);
   3094             pixels+=GetPixelChannels(image);
   3095           }
   3096           pixels+=GetPixelChannels(image)*image->columns;
   3097         }
   3098         switch (type)
   3099         {
   3100           case GradientStatistic:
   3101           {
   3102             double
   3103               maximum,
   3104               minimum;
   3105 
   3106             GetMinimumPixelList(pixel_list[id],&pixel);
   3107             minimum=(double) pixel;
   3108             GetMaximumPixelList(pixel_list[id],&pixel);
   3109             maximum=(double) pixel;
   3110             pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
   3111             break;
   3112           }
   3113           case MaximumStatistic:
   3114           {
   3115             GetMaximumPixelList(pixel_list[id],&pixel);
   3116             break;
   3117           }
   3118           case MeanStatistic:
   3119           {
   3120             GetMeanPixelList(pixel_list[id],&pixel);
   3121             break;
   3122           }
   3123           case MedianStatistic:
   3124           default:
   3125           {
   3126             GetMedianPixelList(pixel_list[id],&pixel);
   3127             break;
   3128           }
   3129           case MinimumStatistic:
   3130           {
   3131             GetMinimumPixelList(pixel_list[id],&pixel);
   3132             break;
   3133           }
   3134           case ModeStatistic:
   3135           {
   3136             GetModePixelList(pixel_list[id],&pixel);
   3137             break;
   3138           }
   3139           case NonpeakStatistic:
   3140           {
   3141             GetNonpeakPixelList(pixel_list[id],&pixel);
   3142             break;
   3143           }
   3144           case RootMeanSquareStatistic:
   3145           {
   3146             GetRootMeanSquarePixelList(pixel_list[id],&pixel);
   3147             break;
   3148           }
   3149           case StandardDeviationStatistic:
   3150           {
   3151             GetStandardDeviationPixelList(pixel_list[id],&pixel);
   3152             break;
   3153           }
   3154         }
   3155         SetPixelChannel(statistic_image,channel,pixel,q);
   3156       }
   3157       p+=GetPixelChannels(image);
   3158       q+=GetPixelChannels(statistic_image);
   3159     }
   3160     if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
   3161       status=MagickFalse;
   3162     if (image->progress_monitor != (MagickProgressMonitor) NULL)
   3163       {
   3164         MagickBooleanType
   3165           proceed;
   3166 
   3167 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   3168         #pragma omp critical (MagickCore_StatisticImage)
   3169 #endif
   3170         proceed=SetImageProgress(image,StatisticImageTag,progress++,
   3171           image->rows);
   3172         if (proceed == MagickFalse)
   3173           status=MagickFalse;
   3174       }
   3175   }
   3176   statistic_view=DestroyCacheView(statistic_view);
   3177   image_view=DestroyCacheView(image_view);
   3178   pixel_list=DestroyPixelListThreadSet(pixel_list);
   3179   if (status == MagickFalse)
   3180     statistic_image=DestroyImage(statistic_image);
   3181   return(statistic_image);
   3182 }
   3183