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