statistic.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %        SSSSS  TTTTT   AAA   TTTTT  IIIII  SSSSS  TTTTT  IIIII   CCCC        %
00007 %        SS       T    A   A    T      I    SS       T      I    C            %
00008 %         SSS     T    AAAAA    T      I     SSS     T      I    C            %
00009 %           SS    T    A   A    T      I       SS    T      I    C            %
00010 %        SSSSS    T    A   A    T    IIIII  SSSSS    T    IIIII   CCCC        %
00011 %                                                                             %
00012 %                                                                             %
00013 %                          MagickCore Image Methods                           %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1992                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "magick/studio.h"
00044 #include "magick/property.h"
00045 #include "magick/animate.h"
00046 #include "magick/blob.h"
00047 #include "magick/blob-private.h"
00048 #include "magick/cache.h"
00049 #include "magick/cache-private.h"
00050 #include "magick/cache-view.h"
00051 #include "magick/client.h"
00052 #include "magick/color.h"
00053 #include "magick/color-private.h"
00054 #include "magick/colorspace.h"
00055 #include "magick/colorspace-private.h"
00056 #include "magick/composite.h"
00057 #include "magick/composite-private.h"
00058 #include "magick/compress.h"
00059 #include "magick/constitute.h"
00060 #include "magick/deprecate.h"
00061 #include "magick/display.h"
00062 #include "magick/draw.h"
00063 #include "magick/enhance.h"
00064 #include "magick/exception.h"
00065 #include "magick/exception-private.h"
00066 #include "magick/gem.h"
00067 #include "magick/geometry.h"
00068 #include "magick/list.h"
00069 #include "magick/image-private.h"
00070 #include "magick/magic.h"
00071 #include "magick/magick.h"
00072 #include "magick/memory_.h"
00073 #include "magick/module.h"
00074 #include "magick/monitor.h"
00075 #include "magick/option.h"
00076 #include "magick/paint.h"
00077 #include "magick/pixel-private.h"
00078 #include "magick/profile.h"
00079 #include "magick/quantize.h"
00080 #include "magick/random_.h"
00081 #include "magick/segment.h"
00082 #include "magick/semaphore.h"
00083 #include "magick/signature-private.h"
00084 #include "magick/statistic.h"
00085 #include "magick/string_.h"
00086 #include "magick/timer.h"
00087 #include "magick/utility.h"
00088 #include "magick/version.h"
00089 
00090 /*
00091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00092 %                                                                             %
00093 %                                                                             %
00094 %                                                                             %
00095 +   G e t I m a g e B o u n d i n g B o x                                     %
00096 %                                                                             %
00097 %                                                                             %
00098 %                                                                             %
00099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00100 %
00101 %  GetImageBoundingBox() returns the bounding box of an image canvas.
00102 %
00103 %  The format of the GetImageBoundingBox method is:
00104 %
00105 %      RectangleInfo GetImageBoundingBox(const Image *image,
00106 %        ExceptionInfo *exception)
00107 %
00108 %  A description of each parameter follows:
00109 %
00110 %    o bounds: Method GetImageBoundingBox returns the bounding box of an
00111 %      image canvas.
00112 %
00113 %    o image: the image.
00114 %
00115 %    o exception: return any errors or warnings in this structure.
00116 %
00117 */
00118 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
00119   ExceptionInfo *exception)
00120 {
00121   long
00122     y;
00123 
00124   MagickBooleanType
00125     status;
00126 
00127   MagickPixelPacket
00128     target[3],
00129     zero;
00130 
00131   RectangleInfo
00132     bounds;
00133 
00134   register const PixelPacket
00135     *p;
00136 
00137   ViewInfo
00138     *image_view;
00139 
00140   assert(image != (Image *) NULL);
00141   assert(image->signature == MagickSignature);
00142   if (image->debug != MagickFalse)
00143     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00144   bounds.width=0;
00145   bounds.height=0;
00146   bounds.x=(long) image->columns;
00147   bounds.y=(long) image->rows;
00148   GetMagickPixelPacket(image,&target[0]);
00149   image_view=AcquireCacheView(image);
00150   p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
00151   if (p == (const PixelPacket *) NULL)
00152     {
00153       image_view=DestroyCacheView(image_view);
00154       return(bounds);
00155     }
00156   SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
00157     &target[0]);
00158   GetMagickPixelPacket(image,&target[1]);
00159   p=GetCacheViewVirtualPixels(image_view,(long) image->columns-1,0,1,1,
00160     exception);
00161   SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
00162     &target[1]);
00163   GetMagickPixelPacket(image,&target[2]);
00164   p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-1,1,1,
00165     exception);
00166   SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
00167     &target[2]);
00168   status=MagickTrue;
00169   GetMagickPixelPacket(image,&zero);
00170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00171   #pragma omp parallel for schedule(dynamic,8) shared(status)
00172 #endif
00173   for (y=0; y < (long) image->rows; y++)
00174   {
00175     MagickPixelPacket
00176       pixel;
00177 
00178     register const IndexPacket
00179       *indexes;
00180 
00181     register const PixelPacket
00182       *p;
00183 
00184     register long
00185       x;
00186 
00187     if (status == MagickFalse)
00188       continue;
00189     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00190     if (p == (const PixelPacket *) NULL)
00191       {
00192         status=MagickFalse;
00193         continue;
00194       }
00195     indexes=GetCacheViewVirtualIndexQueue(image_view);
00196     pixel=zero;
00197     for (x=0; x < (long) image->columns; x++)
00198     {
00199       SetMagickPixelPacket(image,p,indexes+x,&pixel);
00200       if ((x < bounds.x) &&
00201           (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
00202         bounds.x=x;
00203       if ((x > (long) bounds.width) &&
00204           (IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
00205         bounds.width=(unsigned long) x;
00206       if ((y < bounds.y) &&
00207           (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
00208         bounds.y=y;
00209       if ((y > (long) bounds.height) &&
00210           (IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
00211         bounds.height=(unsigned long) y;
00212       p++;
00213     }
00214   }
00215   image_view=DestroyCacheView(image_view);
00216   if ((bounds.width == 0) || (bounds.height == 0))
00217     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
00218       "GeometryDoesNotContainImage","`%s'",image->filename);
00219   else
00220     {
00221       bounds.width-=(bounds.x-1);
00222       bounds.height-=(bounds.y-1);
00223     }
00224   return(bounds);
00225 }
00226 
00227 /*
00228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00229 %                                                                             %
00230 %                                                                             %
00231 %                                                                             %
00232 %   G e t I m a g e C h a n n e l D e p t h                                   %
00233 %                                                                             %
00234 %                                                                             %
00235 %                                                                             %
00236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00237 %
00238 %  GetImageChannelDepth() returns the depth of a particular image channel.
00239 %
00240 %  The format of the GetImageChannelDepth method is:
00241 %
00242 %      unsigned long GetImageDepth(const Image *image,ExceptionInfo *exception)
00243 %      unsigned long GetImageChannelDepth(const Image *image,
00244 %        const ChannelType channel,ExceptionInfo *exception)
00245 %
00246 %  A description of each parameter follows:
00247 %
00248 %    o image: the image.
00249 %
00250 %    o channel: the channel.
00251 %
00252 %    o exception: return any errors or warnings in this structure.
00253 %
00254 */
00255 
00256 MagickExport unsigned long GetImageDepth(const Image *image,
00257   ExceptionInfo *exception)
00258 {
00259   return(GetImageChannelDepth(image,AllChannels,exception));
00260 }
00261 
00262 MagickExport unsigned long GetImageChannelDepth(const Image *image,
00263   const ChannelType channel,ExceptionInfo *exception)
00264 {
00265   long
00266     y;
00267 
00268   MagickBooleanType
00269     status;
00270 
00271   register long
00272     id;
00273 
00274   unsigned long
00275     *current_depth,
00276     depth,
00277     number_threads;
00278     
00279   ViewInfo
00280     *image_view;
00281   
00282   /*
00283     Compute image depth.
00284   */
00285   assert(image != (Image *) NULL);
00286   assert(image->signature == MagickSignature);
00287   if (image->debug != MagickFalse)
00288     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00289   number_threads=GetPixelCacheMaximumThreads();
00290   current_depth=(unsigned long *) AcquireQuantumMemory(number_threads,
00291     sizeof(*current_depth));
00292   if (current_depth == (unsigned long *) NULL)
00293     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00294   status=MagickTrue;
00295   for (id=0; id < (long) number_threads; id++)
00296     current_depth[id]=1;
00297   if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
00298     {
00299       register const PixelPacket
00300         *p;
00301 
00302       register long
00303         i;
00304 
00305       p=image->colormap;
00306 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00307   #pragma omp parallel for schedule(dynamic,8) shared(status)
00308 #endif
00309       for (i=0; i < (long) image->colors; i++)
00310       {  
00311         if (status == MagickFalse)
00312           continue;
00313         id=GetPixelCacheThreadId();
00314         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
00315         {
00316           MagickStatusType
00317             status;
00318 
00319           QuantumAny
00320             scale;
00321 
00322           status=0;
00323           scale=GetQuantumScale(current_depth[id]);
00324           if ((channel & RedChannel) != 0)
00325             status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
00326               current_depth[id],scale),current_depth[id],scale);
00327           if ((channel & GreenChannel) != 0)
00328             status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
00329               current_depth[id],scale),current_depth[id],scale);
00330           if ((channel & BlueChannel) != 0)
00331             status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
00332               current_depth[id],scale),current_depth[id],scale);
00333           if (status == 0)
00334             break;
00335           current_depth[id]++;
00336         }
00337         p++;
00338       }
00339       depth=current_depth[0];
00340       for (id=1; id < (long) number_threads; id++)
00341         if (depth < current_depth[id])
00342           depth=current_depth[id];
00343       current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
00344       return(depth);
00345     }
00346   image_view=AcquireCacheView(image);
00347 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00348   #pragma omp parallel for schedule(dynamic,8) shared(status)
00349 #endif
00350   for (y=0; y < (long) image->rows; y++)
00351   {
00352     register const IndexPacket
00353       *indexes;
00354 
00355     register const PixelPacket
00356       *p;
00357 
00358     register long
00359       id,
00360       x;
00361 
00362     if (status == MagickFalse)
00363       continue;
00364     id=GetPixelCacheThreadId();
00365     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00366     if (p == (const PixelPacket *) NULL)
00367       continue;
00368     indexes=GetCacheViewVirtualIndexQueue(image_view);
00369     for (x=0; x < (long) image->columns; x++)
00370     {  
00371       while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
00372       {
00373         MagickStatusType
00374           status;
00375 
00376         QuantumAny
00377           scale;
00378 
00379         status=0;
00380         scale=GetQuantumScale(current_depth[id]);
00381         if ((channel & RedChannel) != 0)
00382           status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
00383             current_depth[id],scale),current_depth[id],scale);
00384         if ((channel & GreenChannel) != 0)
00385           status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
00386             current_depth[id],scale),current_depth[id],scale);
00387         if ((channel & BlueChannel) != 0)
00388           status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
00389             current_depth[id],scale),current_depth[id],scale);
00390         if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
00391           status|=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
00392             current_depth[id],scale),current_depth[id],scale);
00393         if (((channel & IndexChannel) != 0) &&
00394             (image->colorspace == CMYKColorspace))
00395           status|=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],
00396             current_depth[id],scale),current_depth[id],scale);
00397         if (status == 0)
00398           break;
00399         current_depth[id]++;
00400       }
00401       p++;
00402     }
00403     if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
00404       status=MagickFalse;
00405   }
00406   image_view=DestroyCacheView(image_view);
00407   depth=current_depth[0];
00408   for (id=1; id < (long) number_threads; id++)
00409     if (depth < current_depth[id])
00410       depth=current_depth[id];
00411   current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
00412   return(depth);
00413 }
00414 
00415 /*
00416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00417 %                                                                             %
00418 %                                                                             %
00419 %                                                                             %
00420 +   G e t I m a g e C h a n n e l E x t r e m a                               %
00421 %                                                                             %
00422 %                                                                             %
00423 %                                                                             %
00424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00425 %
00426 %  GetImageChannelExtrema() returns the extrema of one or more image channels.
00427 %
00428 %  The format of the GetImageChannelExtrema method is:
00429 %
00430 %      MagickBooleanType GetImageChannelExtrema(const Image *image,
00431 %        const ChannelType channel,unsigned long *minima,unsigned long *maxima,
00432 %        ExceptionInfo *exception)
00433 %
00434 %  A description of each parameter follows:
00435 %
00436 %    o image: the image.
00437 %
00438 %    o channel: the channel.
00439 %
00440 %    o minima: the minimum value in the channel.
00441 %
00442 %    o maxima: the maximum value in the channel.
00443 %
00444 %    o exception: return any errors or warnings in this structure.
00445 %
00446 */
00447 
00448 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
00449   unsigned long *minima,unsigned long *maxima,ExceptionInfo *exception)
00450 {
00451   return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
00452 }
00453 
00454 MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
00455   const ChannelType channel,unsigned long *minima,unsigned long *maxima,
00456   ExceptionInfo *exception)
00457 {
00458   double
00459     max,
00460     min;
00461 
00462   MagickBooleanType
00463     status;
00464 
00465   assert(image != (Image *) NULL);
00466   assert(image->signature == MagickSignature);
00467   if (image->debug != MagickFalse)
00468     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00469   status=GetImageChannelRange(image,channel,&min,&max,exception);
00470   *minima=(unsigned long) (min+0.5);
00471   *maxima=(unsigned long) (max+0.5);
00472   return(status);
00473 }
00474 
00475 /*
00476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00477 %                                                                             %
00478 %                                                                             %
00479 %                                                                             %
00480 %   G e t I m a g e C h a n n e l M e a n                                     %
00481 %                                                                             %
00482 %                                                                             %
00483 %                                                                             %
00484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00485 %
00486 %  GetImageChannelMean() returns the mean and standard deviation of one or more
00487 %  image channels.
00488 %
00489 %  The format of the GetImageChannelMean method is:
00490 %
00491 %      MagickBooleanType GetImageChannelMean(const Image *image,
00492 %        const ChannelType channel,double *mean,double *standard_deviation,
00493 %        ExceptionInfo *exception)
00494 %
00495 %  A description of each parameter follows:
00496 %
00497 %    o image: the image.
00498 %
00499 %    o channel: the channel.
00500 %
00501 %    o mean: the average value in the channel.
00502 %
00503 %    o standard_deviation: the standard deviation of the channel.
00504 %
00505 %    o exception: return any errors or warnings in this structure.
00506 %
00507 */
00508 
00509 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
00510   double *standard_deviation,ExceptionInfo *exception)
00511 {
00512   MagickBooleanType
00513     status;
00514 
00515   status=GetImageChannelMean(image,AllChannels,mean,standard_deviation,
00516     exception);
00517   return(status);
00518 }
00519 
00520 MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
00521   const ChannelType channel,double *mean,double *standard_deviation,
00522   ExceptionInfo *exception)
00523 {
00524 #define PixelSquared(x)  ((x)*(x))
00525 
00526   double
00527     area;
00528 
00529   long
00530     y;
00531 
00532   register const IndexPacket
00533     *indexes;
00534 
00535   register const PixelPacket
00536     *p;
00537 
00538   register long
00539     x;
00540 
00541   assert(image != (Image *) NULL);
00542   assert(image->signature == MagickSignature);
00543   if (image->debug != MagickFalse)
00544     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00545   *mean=0.0;
00546   *standard_deviation=0.0;
00547   area=0.0;
00548   for (y=0; y < (long) image->rows; y++)
00549   {
00550     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
00551     if (p == (const PixelPacket *) NULL)
00552       break;
00553     indexes=GetVirtualIndexQueue(image);
00554     for (x=0; x < (long) image->columns; x++)
00555     {
00556       if ((channel & RedChannel) != 0)
00557         {
00558           *mean+=p->red;
00559           *standard_deviation+=(double) p->red*p->red;
00560           area++;
00561         }
00562       if ((channel & GreenChannel) != 0)
00563         {
00564           *mean+=p->green;
00565           *standard_deviation+=(double) p->green*p->green;
00566           area++;
00567         }
00568       if ((channel & BlueChannel) != 0)
00569         {
00570           *mean+=p->blue;
00571           *standard_deviation+=(double) p->blue*p->blue;
00572           area++;
00573         }
00574       if ((channel & OpacityChannel) != 0)
00575         {
00576           *mean+=p->opacity;
00577           *standard_deviation+=(double) p->opacity*p->opacity;
00578           area++;
00579         }
00580       if (((channel & IndexChannel) != 0) &&
00581           (image->colorspace == CMYKColorspace))
00582         {
00583           *mean+=indexes[x];
00584           *standard_deviation+=(double) indexes[x]*indexes[x];
00585           area++;
00586         }
00587       p++;
00588     }
00589   }
00590   if (y < (long) image->rows)
00591     return(MagickFalse);
00592   if (area != 0)
00593     {
00594       *mean/=area;
00595       *standard_deviation/=area;
00596     }
00597   *standard_deviation=sqrt(*standard_deviation-(*mean*(*mean)));
00598   return(y == (long) image->rows ? MagickTrue : MagickFalse);
00599 }
00600 
00601 /*
00602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00603 %                                                                             %
00604 %                                                                             %
00605 %                                                                             %
00606 %   G e t I m a g e C h a n n e l R a n g e                                   %
00607 %                                                                             %
00608 %                                                                             %
00609 %                                                                             %
00610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00611 %
00612 %  GetImageChannelRange() returns the range of one or more image channels.
00613 %
00614 %  The format of the GetImageChannelRange method is:
00615 %
00616 %      MagickBooleanType GetImageChannelRange(const Image *image,
00617 %        const ChannelType channel,double *minima,double *maxima,
00618 %        ExceptionInfo *exception)
00619 %
00620 %  A description of each parameter follows:
00621 %
00622 %    o image: the image.
00623 %
00624 %    o channel: the channel.
00625 %
00626 %    o minima: the minimum value in the channel.
00627 %
00628 %    o maxima: the maximum value in the channel.
00629 %
00630 %    o exception: return any errors or warnings in this structure.
00631 %
00632 */
00633 
00634 MagickExport MagickBooleanType GetImageRange(const Image *image,
00635   double *minima,double *maxima,ExceptionInfo *exception)
00636 {
00637   return(GetImageChannelRange(image,AllChannels,minima,maxima,exception));
00638 }
00639 
00640 MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
00641   const ChannelType channel,double *minima,double *maxima,
00642   ExceptionInfo *exception)
00643 {
00644   long
00645     y;
00646 
00647   MagickPixelPacket
00648     pixel;
00649 
00650   register const IndexPacket
00651     *indexes;
00652 
00653   register const PixelPacket
00654     *p;
00655 
00656   register long
00657     x;
00658 
00659   assert(image != (Image *) NULL);
00660   assert(image->signature == MagickSignature);
00661   if (image->debug != MagickFalse)
00662     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00663   *maxima=(-1.0E-37);
00664   *minima=1.0E+37;
00665   GetMagickPixelPacket(image,&pixel);
00666   for (y=0; y < (long) image->rows; y++)
00667   {
00668     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
00669     if (p == (const PixelPacket *) NULL)
00670       break;
00671     indexes=GetVirtualIndexQueue(image);
00672     for (x=0; x < (long) image->columns; x++)
00673     {
00674       SetMagickPixelPacket(image,p,indexes+x,&pixel);
00675       if ((channel & RedChannel) != 0)
00676         {
00677           if (pixel.red < *minima)
00678             *minima=(double) pixel.red;
00679           if (pixel.red > *maxima)
00680             *maxima=(double) pixel.red;
00681         }
00682       if ((channel & GreenChannel) != 0)
00683         {
00684           if (pixel.green < *minima)
00685             *minima=(double) pixel.green;
00686           if (pixel.green > *maxima)
00687             *maxima=(double) pixel.green;
00688         }
00689       if ((channel & BlueChannel) != 0)
00690         {
00691           if (pixel.blue < *minima)
00692             *minima=(double) pixel.blue;
00693           if (pixel.blue > *maxima)
00694             *maxima=(double) pixel.blue;
00695         }
00696       if ((channel & OpacityChannel) != 0)
00697         {
00698           if (pixel.opacity < *minima)
00699             *minima=(double) pixel.opacity;
00700           if (pixel.opacity > *maxima)
00701             *maxima=(double) pixel.opacity;
00702         }
00703       if (((channel & IndexChannel) != 0) &&
00704           (image->colorspace == CMYKColorspace))
00705         {
00706           if ((double) indexes[x] < *minima)
00707             *minima=(double) indexes[x];
00708           if ((double) indexes[x] > *maxima)
00709             *maxima=(double) indexes[x];
00710         }
00711       p++;
00712     }
00713   }
00714   return(y == (long) image->rows ? MagickTrue : MagickFalse);
00715 }
00716 
00717 /*
00718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00719 %                                                                             %
00720 %                                                                             %
00721 %                                                                             %
00722 %   G e t I m a g e C h a n n e l S t a t i s t i c s                         %
00723 %                                                                             %
00724 %                                                                             %
00725 %                                                                             %
00726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00727 %
00728 %  GetImageChannelStatistics() returns statistics for each channel in the
00729 %  image.  The statistics incude the channel depth, its minima, maxima, mean,
00730 %  and the standard deviation.  You can access the red channel mean, for
00731 %  example, like this:
00732 %
00733 %      channel_statistics=GetImageChannelStatistics(image,excepton);
00734 %      red_mean=channel_statistics[RedChannel].mean;
00735 %
00736 %  Use MagickRelinquishMemory() to free the statistics buffer.
00737 %
00738 %  The format of the GetImageChannelStatistics method is:
00739 %
00740 %      ChannelStatistics *GetImageChannelStatistics(const Image *image,
00741 %        ExceptionInfo *exception)
00742 %
00743 %  A description of each parameter follows:
00744 %
00745 %    o image: the image.
00746 %
00747 %    o exception: return any errors or warnings in this structure.
00748 %
00749 */
00750 
00751 static inline double MagickMax(const double x,const double y)
00752 {
00753   if (x > y)
00754     return(x);
00755   return(y);
00756 }
00757 
00758 static inline double MagickMin(const double x,const double y)
00759 {
00760   if (x < y)
00761     return(x);
00762   return(y);
00763 }
00764 
00765 MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
00766   ExceptionInfo *exception)
00767 {
00768   ChannelStatistics
00769     *channel_statistics;
00770 
00771   double
00772     area;
00773 
00774   long
00775     y;
00776 
00777   MagickStatusType
00778     status;
00779 
00780   QuantumAny
00781     scale;
00782 
00783   register const IndexPacket
00784     *indexes;
00785 
00786   register const PixelPacket
00787     *p;
00788 
00789   register long
00790     i,
00791     x;
00792 
00793   size_t
00794     length;
00795 
00796   unsigned long
00797     channels,
00798     depth;
00799 
00800   assert(image != (Image *) NULL);
00801   assert(image->signature == MagickSignature);
00802   if (image->debug != MagickFalse)
00803     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00804   length=AllChannels+1UL;
00805   channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
00806     sizeof(*channel_statistics));
00807   if (channel_statistics == (ChannelStatistics *) NULL)
00808     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00809   (void) ResetMagickMemory(channel_statistics,0,length*
00810     sizeof(*channel_statistics));
00811   for (i=0; i <= AllChannels; i++)
00812   {
00813     channel_statistics[i].depth=1;
00814     channel_statistics[i].maxima=(-1.0E-37);
00815     channel_statistics[i].minima=1.0E+37;
00816     channel_statistics[i].mean=0.0;
00817     channel_statistics[i].standard_deviation=0.0;
00818   }
00819   y=(long) image->rows;
00820   for (y=0; y < (long) image->rows; y++)
00821   {
00822     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
00823     if (p == (const PixelPacket *) NULL)
00824       break;
00825     indexes=GetVirtualIndexQueue(image);
00826     for (x=0; x < (long) image->columns; )
00827     {
00828       if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
00829         {
00830           depth=channel_statistics[RedChannel].depth;
00831           scale=GetQuantumScale(depth);
00832           status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,depth,
00833             scale),depth,scale) ? MagickTrue : MagickFalse;
00834           if (status != MagickFalse)
00835             {
00836               channel_statistics[RedChannel].depth++;
00837               continue;
00838             }
00839         }
00840       if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
00841         {
00842           depth=channel_statistics[GreenChannel].depth;
00843           scale=GetQuantumScale(depth);
00844           status=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
00845             depth,scale),depth,scale) ? MagickTrue : MagickFalse;
00846           if (status != MagickFalse)
00847             {
00848               channel_statistics[GreenChannel].depth++;
00849               continue;
00850             }
00851         }
00852       if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
00853         {
00854           depth=channel_statistics[BlueChannel].depth;
00855           scale=GetQuantumScale(depth);
00856           status=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
00857             depth,scale),depth,scale) ? MagickTrue : MagickFalse;
00858           if (status != MagickFalse)
00859             {
00860               channel_statistics[BlueChannel].depth++;
00861               continue;
00862             }
00863         }
00864       if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
00865         {
00866           depth=channel_statistics[OpacityChannel].depth;
00867           scale=GetQuantumScale(depth);
00868           status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
00869             depth,scale),depth,scale) ? MagickTrue : MagickFalse;
00870           if (status != MagickFalse)
00871             {
00872               channel_statistics[OpacityChannel].depth++;
00873               continue;
00874             }
00875         }
00876       if (image->colorspace == CMYKColorspace)
00877         {
00878           if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
00879             {
00880               depth=channel_statistics[BlackChannel].depth;
00881               scale=GetQuantumScale(depth);
00882               status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
00883                 indexes[x],depth,scale),depth,scale) ? MagickTrue : MagickFalse;
00884               if (status != MagickFalse)
00885                 {
00886                   channel_statistics[BlackChannel].depth++;
00887                   continue;
00888                 }
00889             }
00890         }
00891       if ((double) p->red < channel_statistics[RedChannel].minima)
00892         channel_statistics[RedChannel].minima=(double) p->red;
00893       if ((double) p->red > channel_statistics[RedChannel].maxima)
00894         channel_statistics[RedChannel].maxima=(double) p->red;
00895       channel_statistics[RedChannel].mean+=p->red;
00896       channel_statistics[RedChannel].standard_deviation+=(double)
00897         p->red*p->red;
00898       if ((double) p->green < channel_statistics[GreenChannel].minima)
00899         channel_statistics[GreenChannel].minima=(double) p->green;
00900       if ((double) p->green > channel_statistics[GreenChannel].maxima)
00901         channel_statistics[GreenChannel].maxima=(double) p->green;
00902       channel_statistics[GreenChannel].mean+=p->green;
00903       channel_statistics[GreenChannel].standard_deviation+=(double)
00904         p->green*p->green;
00905       if ((double) p->blue < channel_statistics[BlueChannel].minima)
00906         channel_statistics[BlueChannel].minima=(double) p->blue;
00907       if ((double) p->blue > channel_statistics[BlueChannel].maxima)
00908         channel_statistics[BlueChannel].maxima=(double) p->blue;
00909       channel_statistics[BlueChannel].mean+=p->blue;
00910       channel_statistics[BlueChannel].standard_deviation+=(double)
00911         p->blue*p->blue;
00912       if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
00913         channel_statistics[OpacityChannel].minima=(double) p->opacity;
00914       if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
00915         channel_statistics[OpacityChannel].maxima=(double) p->opacity;
00916       channel_statistics[OpacityChannel].mean+=p->opacity;
00917       channel_statistics[OpacityChannel].standard_deviation+=(double)
00918         p->opacity*p->opacity;
00919       if (image->colorspace == CMYKColorspace)
00920         {
00921           if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
00922             channel_statistics[BlackChannel].minima=(double) indexes[x];
00923           if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
00924             channel_statistics[BlackChannel].maxima=(double) indexes[x];
00925           channel_statistics[BlackChannel].mean+=indexes[x];
00926           channel_statistics[BlackChannel].standard_deviation+=(double)
00927             indexes[x]*indexes[x];
00928         }
00929       x++;
00930       p++;
00931     }
00932   }
00933   area=(double) image->columns*image->rows;
00934   for (i=0; i < AllChannels; i++)
00935   {
00936     channel_statistics[i].mean/=area;
00937     channel_statistics[i].standard_deviation/=area;
00938   }
00939   for (i=0; i < AllChannels; i++)
00940   {
00941     channel_statistics[AllChannels].depth=(unsigned long) MagickMax((double) 
00942       channel_statistics[AllChannels].depth,(double)
00943       channel_statistics[i].depth);
00944     channel_statistics[AllChannels].minima=MagickMin(
00945       channel_statistics[AllChannels].minima,channel_statistics[i].minima);
00946     channel_statistics[AllChannels].maxima=MagickMax(
00947       channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
00948     channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
00949     channel_statistics[AllChannels].standard_deviation+=
00950       channel_statistics[i].standard_deviation;
00951   }
00952   channels=4;
00953   if (image->colorspace == CMYKColorspace)
00954     channels++;
00955   channel_statistics[AllChannels].mean/=channels;
00956   channel_statistics[AllChannels].standard_deviation/=channels;
00957   for (i=0; i <= AllChannels; i++)
00958     channel_statistics[i].standard_deviation=sqrt(
00959       channel_statistics[i].standard_deviation-
00960        (channel_statistics[i].mean*channel_statistics[i].mean));
00961   return(channel_statistics);
00962 }
00963 
00964 /*
00965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00966 %                                                                             %
00967 %                                                                             %
00968 %                                                                             %
00969 %   G e t I m a g e Q u a n t u m D e p t h                                   %
00970 %                                                                             %
00971 %                                                                             %
00972 %                                                                             %
00973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00974 %
00975 %  GetImageQuantumDepth() returns the depth of the image rounded to a legal
00976 %  quantum depth: 8, 16, or 32.
00977 %
00978 %  The format of the GetImageQuantumDepth method is:
00979 %
00980 %      unsigned long GetImageQuantumDepth(const Image *image,
00981 %        const MagickBooleanType constrain)