2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % MagickCore Image Methods %
20 % Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "magick/studio.h"
44 #include "magick/property.h"
45 #include "magick/animate.h"
46 #include "magick/blob.h"
47 #include "magick/blob-private.h"
48 #include "magick/cache.h"
49 #include "magick/cache-private.h"
50 #include "magick/cache-view.h"
51 #include "magick/client.h"
52 #include "magick/color.h"
53 #include "magick/color-private.h"
54 #include "magick/colorspace.h"
55 #include "magick/colorspace-private.h"
56 #include "magick/composite.h"
57 #include "magick/composite-private.h"
58 #include "magick/compress.h"
59 #include "magick/constitute.h"
60 #include "magick/deprecate.h"
61 #include "magick/display.h"
62 #include "magick/draw.h"
63 #include "magick/enhance.h"
64 #include "magick/exception.h"
65 #include "magick/exception-private.h"
66 #include "magick/gem.h"
67 #include "magick/geometry.h"
68 #include "magick/list.h"
69 #include "magick/image-private.h"
70 #include "magick/magic.h"
71 #include "magick/magick.h"
72 #include "magick/memory_.h"
73 #include "magick/module.h"
74 #include "magick/monitor.h"
75 #include "magick/option.h"
76 #include "magick/paint.h"
77 #include "magick/pixel-private.h"
78 #include "magick/profile.h"
79 #include "magick/quantize.h"
80 #include "magick/random_.h"
81 #include "magick/segment.h"
82 #include "magick/semaphore.h"
83 #include "magick/signature-private.h"
84 #include "magick/statistic.h"
85 #include "magick/string_.h"
86 #include "magick/thread-private.h"
87 #include "magick/timer.h"
88 #include "magick/utility.h"
89 #include "magick/version.h"
92 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 % A v e r a g e I m a g e s %
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 % AverageImages() takes a set of images and averages them together. Each
103 % image in the set must have the same width and height. AverageImages()
104 % returns a single image with each corresponding pixel component of each
105 % image averaged. On failure, a NULL image is returned and exception
106 % describes the reason for the failure.
108 % The format of the AverageImages method is:
110 % Image *AverageImages(Image *image,ExceptionInfo *exception)
112 % A description of each parameter follows:
114 % o image: the image sequence.
116 % o exception: return any errors or warnings in this structure.
120 static MagickPixelPacket **DestroyPixelThreadSet(MagickPixelPacket **pixels)
125 assert(pixels != (MagickPixelPacket **) NULL);
126 for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
127 if (pixels[i] != (MagickPixelPacket *) NULL)
128 pixels[i]=(MagickPixelPacket *) RelinquishMagickMemory(pixels[i]);
129 pixels=(MagickPixelPacket **) RelinquishAlignedMemory(pixels);
133 static MagickPixelPacket **AcquirePixelThreadSet(const Image *image)
145 number_threads=GetOpenMPMaximumThreads();
146 pixels=(MagickPixelPacket **) AcquireAlignedMemory(number_threads,
148 if (pixels == (MagickPixelPacket **) NULL)
149 return((MagickPixelPacket **) NULL);
150 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
151 for (i=0; i < (long) number_threads; i++)
153 pixels[i]=(MagickPixelPacket *) AcquireQuantumMemory(image->columns,
155 if (pixels[i] == (MagickPixelPacket *) NULL)
156 return(DestroyPixelThreadSet(pixels));
157 for (j=0; j < (long) image->columns; j++)
158 GetMagickPixelPacket(image,&pixels[i][j]);
163 MagickExport Image *AverageImages(const Image *image,ExceptionInfo *exception)
165 #define AverageImageTag "Average/Image"
191 Ensure the image are the same size.
193 assert(image != (Image *) NULL);
194 assert(image->signature == MagickSignature);
195 if (image->debug != MagickFalse)
196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
197 assert(exception != (ExceptionInfo *) NULL);
198 assert(exception->signature == MagickSignature);
199 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
200 if ((next->columns != image->columns) || (next->rows != image->rows))
201 ThrowImageException(OptionError,"ImageWidthsOrHeightsDiffer");
203 Initialize average next attributes.
205 average_image=CloneImage(image,image->columns,image->rows,MagickTrue,
207 if (average_image == (Image *) NULL)
208 return((Image *) NULL);
209 if (SetImageStorageClass(average_image,DirectClass) == MagickFalse)
211 InheritException(exception,&average_image->exception);
212 average_image=DestroyImage(average_image);
213 return((Image *) NULL);
215 average_pixels=AcquirePixelThreadSet(image);
216 if (average_pixels == (MagickPixelPacket **) NULL)
218 average_image=DestroyImage(average_image);
219 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
222 Average image pixels.
226 GetMagickPixelPacket(image,&zero);
227 number_images=GetImageListLength(image);
228 average_view=AcquireCacheView(average_image);
229 #if defined(_OPENMP) && (_OPENMP >= 200203)
230 #pragma omp parallel for schedule(static,1) shared(progress,status)
232 for (y=0; y < (long) average_image->rows; y++)
244 *__restrict average_indexes;
251 register MagickPixelPacket
257 if (status == MagickFalse)
259 q=QueueCacheViewAuthenticPixels(average_view,0,y,average_image->columns,1,
261 if (q == (PixelPacket *) NULL)
266 average_indexes=GetCacheViewAuthenticIndexQueue(average_view);
268 id=GetOpenMPThreadId();
269 average_pixel=average_pixels[id];
270 for (x=0; x < (long) average_image->columns; x++)
271 average_pixel[x]=zero;
273 for (i=0; i < (long) number_images; i++)
275 register const IndexPacket
278 register const PixelPacket
281 image_view=AcquireCacheView(next);
282 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
283 if (p == (const PixelPacket *) NULL)
285 image_view=DestroyCacheView(image_view);
288 indexes=GetCacheViewVirtualIndexQueue(image_view);
289 for (x=0; x < (long) next->columns; x++)
291 SetMagickPixelPacket(next,p,indexes+x,&pixel);
292 average_pixel[x].red+=QuantumScale*pixel.red;
293 average_pixel[x].green+=QuantumScale*pixel.green;
294 average_pixel[x].blue+=QuantumScale*pixel.blue;
295 average_pixel[x].opacity+=QuantumScale*pixel.opacity;
296 if (average_image->colorspace == CMYKColorspace)
297 average_pixel[x].index+=QuantumScale*pixel.index;
300 image_view=DestroyCacheView(image_view);
301 next=GetNextImageInList(next);
303 for (x=0; x < (long) average_image->columns; x++)
305 average_pixel[x].red=(MagickRealType) (QuantumRange*
306 average_pixel[x].red/number_images);
307 average_pixel[x].green=(MagickRealType) (QuantumRange*
308 average_pixel[x].green/number_images);
309 average_pixel[x].blue=(MagickRealType) (QuantumRange*
310 average_pixel[x].blue/number_images);
311 average_pixel[x].opacity=(MagickRealType) (QuantumRange*
312 average_pixel[x].opacity/number_images);
313 if (average_image->colorspace == CMYKColorspace)
314 average_pixel[x].index=(MagickRealType) (QuantumRange*
315 average_pixel[x].index/number_images);
316 SetPixelPacket(average_image,&average_pixel[x],q,average_indexes+x);
319 if (SyncCacheViewAuthenticPixels(average_view,exception) == MagickFalse)
321 if (image->progress_monitor != (MagickProgressMonitor) NULL)
326 #if defined(_OPENMP) && (_OPENMP >= 200203)
327 #pragma omp critical (MagickCore_AverageImages)
329 proceed=SetImageProgress(image,AverageImageTag,progress++,
330 average_image->rows);
331 if (proceed == MagickFalse)
335 average_view=DestroyCacheView(average_view);
336 average_pixels=DestroyPixelThreadSet(average_pixels);
337 if (status == MagickFalse)
338 average_image=DestroyImage(average_image);
339 return(average_image);
343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 + G e t I m a g e B o u n d i n g B o x %
351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353 % GetImageBoundingBox() returns the bounding box of an image canvas.
355 % The format of the GetImageBoundingBox method is:
357 % RectangleInfo GetImageBoundingBox(const Image *image,
358 % ExceptionInfo *exception)
360 % A description of each parameter follows:
362 % o bounds: Method GetImageBoundingBox returns the bounding box of an
365 % o image: the image.
367 % o exception: return any errors or warnings in this structure.
370 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
371 ExceptionInfo *exception)
386 register const PixelPacket
392 assert(image != (Image *) NULL);
393 assert(image->signature == MagickSignature);
394 if (image->debug != MagickFalse)
395 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
398 bounds.x=(long) image->columns;
399 bounds.y=(long) image->rows;
400 GetMagickPixelPacket(image,&target[0]);
401 image_view=AcquireCacheView(image);
402 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
403 if (p == (const PixelPacket *) NULL)
405 image_view=DestroyCacheView(image_view);
408 SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
410 GetMagickPixelPacket(image,&target[1]);
411 p=GetCacheViewVirtualPixels(image_view,(long) image->columns-1,0,1,1,
413 SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
415 GetMagickPixelPacket(image,&target[2]);
416 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-1,1,1,exception);
417 SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
420 GetMagickPixelPacket(image,&zero);
421 #if defined(_OPENMP) && (_OPENMP >= 200203)
422 #pragma omp parallel for schedule(static,1) shared(status)
424 for (y=0; y < (long) image->rows; y++)
432 register const IndexPacket
435 register const PixelPacket
441 if (status == MagickFalse)
443 #if defined(HAVE_OPENMP)
444 # pragma omp critical (MagickCore_GetImageBoundingBox)
447 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
448 if (p == (const PixelPacket *) NULL)
453 indexes=GetCacheViewVirtualIndexQueue(image_view);
455 for (x=0; x < (long) image->columns; x++)
457 SetMagickPixelPacket(image,p,indexes+x,&pixel);
458 if ((x < bounding_box.x) &&
459 (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
461 if ((x > (long) bounding_box.width) &&
462 (IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
463 bounding_box.width=(unsigned long) x;
464 if ((y < bounding_box.y) &&
465 (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
467 if ((y > (long) bounding_box.height) &&
468 (IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
469 bounding_box.height=(unsigned long) y;
472 #if defined(HAVE_OPENMP)
473 # pragma omp critical (MagickCore_GetImageBoundingBox)
476 if (bounding_box.x < bounds.x)
477 bounds.x=bounding_box.x;
478 if (bounding_box.y < bounds.y)
479 bounds.y=bounding_box.y;
480 if (bounding_box.width > bounds.width)
481 bounds.width=bounding_box.width;
482 if (bounding_box.height > bounds.height)
483 bounds.height=bounding_box.height;
486 image_view=DestroyCacheView(image_view);
487 if ((bounds.width == 0) || (bounds.height == 0))
488 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
489 "GeometryDoesNotContainImage","`%s'",image->filename);
492 bounds.width-=(bounds.x-1);
493 bounds.height-=(bounds.y-1);
499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
503 % G e t I m a g e C h a n n e l D e p t h %
507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
509 % GetImageChannelDepth() returns the depth of a particular image channel.
511 % The format of the GetImageChannelDepth method is:
513 % unsigned long GetImageDepth(const Image *image,ExceptionInfo *exception)
514 % unsigned long GetImageChannelDepth(const Image *image,
515 % const ChannelType channel,ExceptionInfo *exception)
517 % A description of each parameter follows:
519 % o image: the image.
521 % o channel: the channel.
523 % o exception: return any errors or warnings in this structure.
527 MagickExport unsigned long GetImageDepth(const Image *image,
528 ExceptionInfo *exception)
530 return(GetImageChannelDepth(image,AllChannels,exception));
533 MagickExport unsigned long GetImageChannelDepth(const Image *image,
534 const ChannelType channel,ExceptionInfo *exception)
556 assert(image != (Image *) NULL);
557 assert(image->signature == MagickSignature);
558 if (image->debug != MagickFalse)
559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
560 number_threads=GetOpenMPMaximumThreads();
561 current_depth=(unsigned long *) AcquireQuantumMemory(number_threads,
562 sizeof(*current_depth));
563 if (current_depth == (unsigned long *) NULL)
564 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
566 for (id=0; id < (long) number_threads; id++)
568 if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
570 register const PixelPacket
577 #if defined(_OPENMP) && (_OPENMP >= 200203)
578 #pragma omp parallel for schedule(static,1) shared(status)
580 for (i=0; i < (long) image->colors; i++)
582 if (status == MagickFalse)
584 id=GetOpenMPThreadId();
585 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
594 range=GetQuantumRange(current_depth[id]);
595 if ((channel & RedChannel) != 0)
596 status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
598 if ((channel & GreenChannel) != 0)
599 status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
601 if ((channel & BlueChannel) != 0)
602 status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
610 depth=current_depth[0];
611 for (id=1; id < (long) number_threads; id++)
612 if (depth < current_depth[id])
613 depth=current_depth[id];
614 current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
617 image_view=AcquireCacheView(image);
618 #if defined(_OPENMP) && (_OPENMP >= 200203)
619 #pragma omp parallel for schedule(static,1) shared(status)
621 for (y=0; y < (long) image->rows; y++)
623 register const IndexPacket
626 register const PixelPacket
633 if (status == MagickFalse)
635 id=GetOpenMPThreadId();
636 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
637 if (p == (const PixelPacket *) NULL)
639 indexes=GetCacheViewVirtualIndexQueue(image_view);
640 for (x=0; x < (long) image->columns; x++)
642 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
651 range=GetQuantumRange(current_depth[id]);
652 if ((channel & RedChannel) != 0)
653 status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
655 if ((channel & GreenChannel) != 0)
656 status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
658 if ((channel & BlueChannel) != 0)
659 status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),
661 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
662 status|=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
664 if (((channel & IndexChannel) != 0) &&
665 (image->colorspace == CMYKColorspace))
666 status|=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],
674 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
677 image_view=DestroyCacheView(image_view);
678 depth=current_depth[0];
679 for (id=1; id < (long) number_threads; id++)
680 if (depth < current_depth[id])
681 depth=current_depth[id];
682 current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
687 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691 + G e t I m a g e C h a n n e l E x t r e m a %
695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 % GetImageChannelExtrema() returns the extrema of one or more image channels.
699 % The format of the GetImageChannelExtrema method is:
701 % MagickBooleanType GetImageChannelExtrema(const Image *image,
702 % const ChannelType channel,unsigned long *minima,unsigned long *maxima,
703 % ExceptionInfo *exception)
705 % A description of each parameter follows:
707 % o image: the image.
709 % o channel: the channel.
711 % o minima: the minimum value in the channel.
713 % o maxima: the maximum value in the channel.
715 % o exception: return any errors or warnings in this structure.
719 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
720 unsigned long *minima,unsigned long *maxima,ExceptionInfo *exception)
722 return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
725 MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
726 const ChannelType channel,unsigned long *minima,unsigned long *maxima,
727 ExceptionInfo *exception)
736 assert(image != (Image *) NULL);
737 assert(image->signature == MagickSignature);
738 if (image->debug != MagickFalse)
739 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
740 status=GetImageChannelRange(image,channel,&min,&max,exception);
741 *minima=(unsigned long) (min+0.5);
742 *maxima=(unsigned long) (max+0.5);
747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751 % G e t I m a g e C h a n n e l M e a n %
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757 % GetImageChannelMean() returns the mean and standard deviation of one or more
760 % The format of the GetImageChannelMean method is:
762 % MagickBooleanType GetImageChannelMean(const Image *image,
763 % const ChannelType channel,double *mean,double *standard_deviation,
764 % ExceptionInfo *exception)
766 % A description of each parameter follows:
768 % o image: the image.
770 % o channel: the channel.
772 % o mean: the average value in the channel.
774 % o standard_deviation: the standard deviation of the channel.
776 % o exception: return any errors or warnings in this structure.
780 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
781 double *standard_deviation,ExceptionInfo *exception)
786 status=GetImageChannelMean(image,AllChannels,mean,standard_deviation,
791 MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
792 const ChannelType channel,double *mean,double *standard_deviation,
793 ExceptionInfo *exception)
801 assert(image != (Image *) NULL);
802 assert(image->signature == MagickSignature);
803 if (image->debug != MagickFalse)
804 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
806 *standard_deviation=0.0;
808 for (y=0; y < (long) image->rows; y++)
810 register const IndexPacket
813 register const PixelPacket
819 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
820 if (p == (const PixelPacket *) NULL)
822 indexes=GetVirtualIndexQueue(image);
823 for (x=0; x < (long) image->columns; x++)
825 if ((channel & RedChannel) != 0)
828 *standard_deviation+=(double) p->red*p->red;
831 if ((channel & GreenChannel) != 0)
834 *standard_deviation+=(double) p->green*p->green;
837 if ((channel & BlueChannel) != 0)
840 *standard_deviation+=(double) p->blue*p->blue;
843 if ((channel & OpacityChannel) != 0)
846 *standard_deviation+=(double) p->opacity*p->opacity;
849 if (((channel & IndexChannel) != 0) &&
850 (image->colorspace == CMYKColorspace))
853 *standard_deviation+=(double) indexes[x]*indexes[x];
859 if (y < (long) image->rows)
864 *standard_deviation/=area;
866 *standard_deviation=sqrt(*standard_deviation-(*mean*(*mean)));
867 return(y == (long) image->rows ? MagickTrue : MagickFalse);
871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875 % G e t I m a g e C h a n n e l K u r t o s i s %
879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
881 % GetImageChannelKurtosis() returns the kurtosis and skewness of one or more
884 % The format of the GetImageChannelKurtosis method is:
886 % MagickBooleanType GetImageChannelKurtosis(const Image *image,
887 % const ChannelType channel,double *kurtosis,double *skewness,
888 % ExceptionInfo *exception)
890 % A description of each parameter follows:
892 % o image: the image.
894 % o channel: the channel.
896 % o kurtosis: the kurtosis of the channel.
898 % o skewness: the skewness of the channel.
900 % o exception: return any errors or warnings in this structure.
904 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
905 double *kurtosis,double *skewness,ExceptionInfo *exception)
910 status=GetImageChannelKurtosis(image,AllChannels,kurtosis,skewness,
915 MagickExport MagickBooleanType GetImageChannelKurtosis(const Image *image,
916 const ChannelType channel,double *kurtosis,double *skewness,
917 ExceptionInfo *exception)
930 assert(image != (Image *) NULL);
931 assert(image->signature == MagickSignature);
932 if (image->debug != MagickFalse)
933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
938 standard_deviation=0.0;
941 sum_fourth_power=0.0;
942 for (y=0; y < (long) image->rows; y++)
944 register const IndexPacket
947 register const PixelPacket
953 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
954 if (p == (const PixelPacket *) NULL)
956 indexes=GetVirtualIndexQueue(image);
957 for (x=0; x < (long) image->columns; x++)
959 if ((channel & RedChannel) != 0)
962 sum_squares+=(double) p->red*p->red;
963 sum_cubes+=(double) p->red*p->red*p->red;
964 sum_fourth_power+=(double) p->red*p->red*p->red*p->red;
967 if ((channel & GreenChannel) != 0)
970 sum_squares+=(double) p->green*p->green;
971 sum_cubes+=(double) p->green*p->green*p->green;
972 sum_fourth_power+=(double) p->green*p->green*p->green*p->green;
975 if ((channel & BlueChannel) != 0)
978 sum_squares+=(double) p->blue*p->blue;
979 sum_cubes+=(double) p->blue*p->blue*p->blue;
980 sum_fourth_power+=(double) p->blue*p->blue*p->blue*p->blue;
983 if ((channel & OpacityChannel) != 0)
986 sum_squares+=(double) p->opacity*p->opacity;
987 sum_cubes+=(double) p->opacity*p->opacity*p->opacity;
988 sum_fourth_power+=(double) p->opacity*p->opacity*p->opacity*
992 if (((channel & IndexChannel) != 0) &&
993 (image->colorspace == CMYKColorspace))
996 sum_squares+=(double) indexes[x]*indexes[x];
997 sum_cubes+=(double) indexes[x]*indexes[x]*indexes[x];
998 sum_fourth_power+=(double) indexes[x]*indexes[x]*indexes[x]*
1005 if (y < (long) image->rows)
1006 return(MagickFalse);
1012 sum_fourth_power/=area;
1014 standard_deviation=sqrt(sum_squares-(mean*mean));
1015 if (standard_deviation != 0.0)
1017 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1018 3.0*mean*mean*mean*mean;
1019 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1022 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1023 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1025 return(y == (long) image->rows ? MagickTrue : MagickFalse);
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 % G e t I m a g e C h a n n e l R a n g e %
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1039 % GetImageChannelRange() returns the range of one or more image channels.
1041 % The format of the GetImageChannelRange method is:
1043 % MagickBooleanType GetImageChannelRange(const Image *image,
1044 % const ChannelType channel,double *minima,double *maxima,
1045 % ExceptionInfo *exception)
1047 % A description of each parameter follows:
1049 % o image: the image.
1051 % o channel: the channel.
1053 % o minima: the minimum value in the channel.
1055 % o maxima: the maximum value in the channel.
1057 % o exception: return any errors or warnings in this structure.
1061 MagickExport MagickBooleanType GetImageRange(const Image *image,
1062 double *minima,double *maxima,ExceptionInfo *exception)
1064 return(GetImageChannelRange(image,AllChannels,minima,maxima,exception));
1067 MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
1068 const ChannelType channel,double *minima,double *maxima,
1069 ExceptionInfo *exception)
1077 assert(image != (Image *) NULL);
1078 assert(image->signature == MagickSignature);
1079 if (image->debug != MagickFalse)
1080 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1083 GetMagickPixelPacket(image,&pixel);
1084 for (y=0; y < (long) image->rows; y++)
1086 register const IndexPacket
1087 *__restrict indexes;
1089 register const PixelPacket
1095 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1096 if (p == (const PixelPacket *) NULL)
1098 indexes=GetVirtualIndexQueue(image);
1099 for (x=0; x < (long) image->columns; x++)
1101 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1102 if ((channel & RedChannel) != 0)
1104 if (pixel.red < *minima)
1105 *minima=(double) pixel.red;
1106 if (pixel.red > *maxima)
1107 *maxima=(double) pixel.red;
1109 if ((channel & GreenChannel) != 0)
1111 if (pixel.green < *minima)
1112 *minima=(double) pixel.green;
1113 if (pixel.green > *maxima)
1114 *maxima=(double) pixel.green;
1116 if ((channel & BlueChannel) != 0)
1118 if (pixel.blue < *minima)
1119 *minima=(double) pixel.blue;
1120 if (pixel.blue > *maxima)
1121 *maxima=(double) pixel.blue;
1123 if ((channel & OpacityChannel) != 0)
1125 if (pixel.opacity < *minima)
1126 *minima=(double) pixel.opacity;
1127 if (pixel.opacity > *maxima)
1128 *maxima=(double) pixel.opacity;
1130 if (((channel & IndexChannel) != 0) &&
1131 (image->colorspace == CMYKColorspace))
1133 if ((double) indexes[x] < *minima)
1134 *minima=(double) indexes[x];
1135 if ((double) indexes[x] > *maxima)
1136 *maxima=(double) indexes[x];
1141 return(y == (long) image->rows ? MagickTrue : MagickFalse);
1145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149 % 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 %
1153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155 % GetImageChannelStatistics() returns statistics for each channel in the
1156 % image. The statistics include the channel depth, its minima, maxima, mean,
1157 % standard deviation, kurtosis and skewness. You can access the red channel
1158 % mean, for example, like this:
1160 % channel_statistics=GetImageChannelStatistics(image,excepton);
1161 % red_mean=channel_statistics[RedChannel].mean;
1163 % Use MagickRelinquishMemory() to free the statistics buffer.
1165 % The format of the GetImageChannelStatistics method is:
1167 % ChannelStatistics *GetImageChannelStatistics(const Image *image,
1168 % ExceptionInfo *exception)
1170 % A description of each parameter follows:
1172 % o image: the image.
1174 % o exception: return any errors or warnings in this structure.
1178 static inline double MagickMax(const double x,const double y)
1185 static inline double MagickMin(const double x,const double y)
1192 MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
1193 ExceptionInfo *exception)
1196 *channel_statistics;
1222 assert(image != (Image *) NULL);
1223 assert(image->signature == MagickSignature);
1224 if (image->debug != MagickFalse)
1225 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1226 length=AllChannels+1UL;
1227 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
1228 sizeof(*channel_statistics));
1229 if (channel_statistics == (ChannelStatistics *) NULL)
1230 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1231 (void) ResetMagickMemory(channel_statistics,0,length*
1232 sizeof(*channel_statistics));
1233 for (i=0; i <= AllChannels; i++)
1235 channel_statistics[i].depth=1;
1236 channel_statistics[i].maxima=(-1.0E-37);
1237 channel_statistics[i].minima=1.0E+37;
1238 channel_statistics[i].mean=0.0;
1239 channel_statistics[i].standard_deviation=0.0;
1240 channel_statistics[i].kurtosis=0.0;
1241 channel_statistics[i].skewness=0.0;
1243 for (y=0; y < (long) image->rows; y++)
1245 register const IndexPacket
1246 *__restrict indexes;
1248 register const PixelPacket
1254 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1255 if (p == (const PixelPacket *) NULL)
1257 indexes=GetVirtualIndexQueue(image);
1258 for (x=0; x < (long) image->columns; )
1260 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1262 depth=channel_statistics[RedChannel].depth;
1263 range=GetQuantumRange(depth);
1264 status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
1265 range) ? MagickTrue : MagickFalse;
1266 if (status != MagickFalse)
1268 channel_statistics[RedChannel].depth++;
1272 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1274 depth=channel_statistics[GreenChannel].depth;
1275 range=GetQuantumRange(depth);
1276 status=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
1277 range),range) ? MagickTrue : MagickFalse;
1278 if (status != MagickFalse)
1280 channel_statistics[GreenChannel].depth++;
1284 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1286 depth=channel_statistics[BlueChannel].depth;
1287 range=GetQuantumRange(depth);
1288 status=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
1289 range),range) ? MagickTrue : MagickFalse;
1290 if (status != MagickFalse)
1292 channel_statistics[BlueChannel].depth++;
1296 if (image->matte != MagickFalse)
1298 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1300 depth=channel_statistics[OpacityChannel].depth;
1301 range=GetQuantumRange(depth);
1302 status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(
1303 p->opacity,range),range) ? MagickTrue : MagickFalse;
1304 if (status != MagickFalse)
1306 channel_statistics[OpacityChannel].depth++;
1311 if (image->colorspace == CMYKColorspace)
1313 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1315 depth=channel_statistics[BlackChannel].depth;
1316 range=GetQuantumRange(depth);
1317 status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
1318 indexes[x],range),range) ? MagickTrue : MagickFalse;
1319 if (status != MagickFalse)
1321 channel_statistics[BlackChannel].depth++;
1326 if ((double) p->red < channel_statistics[RedChannel].minima)
1327 channel_statistics[RedChannel].minima=(double) p->red;
1328 if ((double) p->red > channel_statistics[RedChannel].maxima)
1329 channel_statistics[RedChannel].maxima=(double) p->red;
1330 channel_statistics[RedChannel].mean+=p->red;
1331 channel_statistics[RedChannel].standard_deviation+=(double) p->red*p->red;
1332 channel_statistics[RedChannel].kurtosis+=(double) p->red*p->red*
1334 channel_statistics[RedChannel].skewness+=(double) p->red*p->red*p->red;
1335 if ((double) p->green < channel_statistics[GreenChannel].minima)
1336 channel_statistics[GreenChannel].minima=(double) p->green;
1337 if ((double) p->green > channel_statistics[GreenChannel].maxima)
1338 channel_statistics[GreenChannel].maxima=(double) p->green;
1339 channel_statistics[GreenChannel].mean+=p->green;
1340 channel_statistics[GreenChannel].standard_deviation+=(double) p->green*
1342 channel_statistics[GreenChannel].kurtosis+=(double) p->green*p->green*
1344 channel_statistics[GreenChannel].skewness+=(double) p->green*p->green*
1346 if ((double) p->blue < channel_statistics[BlueChannel].minima)
1347 channel_statistics[BlueChannel].minima=(double) p->blue;
1348 if ((double) p->blue > channel_statistics[BlueChannel].maxima)
1349 channel_statistics[BlueChannel].maxima=(double) p->blue;
1350 channel_statistics[BlueChannel].mean+=p->blue;
1351 channel_statistics[BlueChannel].standard_deviation+=(double) p->blue*
1353 channel_statistics[BlueChannel].kurtosis+=(double) p->blue*p->blue*
1355 channel_statistics[BlueChannel].skewness+=(double) p->blue*p->blue*
1357 if (image->matte != MagickFalse)
1359 if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
1360 channel_statistics[OpacityChannel].minima=(double) p->opacity;
1361 if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
1362 channel_statistics[OpacityChannel].maxima=(double) p->opacity;
1363 channel_statistics[OpacityChannel].mean+=p->opacity;
1364 channel_statistics[OpacityChannel].standard_deviation+=(double)
1365 p->opacity*p->opacity;
1366 channel_statistics[OpacityChannel].kurtosis+=(double) p->opacity*
1367 p->opacity*p->opacity*p->opacity;
1368 channel_statistics[OpacityChannel].skewness+=(double) p->opacity*
1369 p->opacity*p->opacity;
1371 if (image->colorspace == CMYKColorspace)
1373 if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
1374 channel_statistics[BlackChannel].minima=(double) indexes[x];
1375 if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
1376 channel_statistics[BlackChannel].maxima=(double) indexes[x];
1377 channel_statistics[BlackChannel].mean+=indexes[x];
1378 channel_statistics[BlackChannel].standard_deviation+=(double)
1379 indexes[x]*indexes[x];
1380 channel_statistics[BlackChannel].kurtosis+=(double) indexes[x]*
1381 indexes[x]*indexes[x]*indexes[x];
1382 channel_statistics[BlackChannel].skewness+=(double) indexes[x]*
1383 indexes[x]*indexes[x];
1389 area=(double) image->columns*image->rows;
1390 for (i=0; i < AllChannels; i++)
1392 channel_statistics[i].mean/=area;
1393 channel_statistics[i].standard_deviation/=area;
1394 channel_statistics[i].kurtosis/=area;
1395 channel_statistics[i].skewness/=area;
1397 for (i=0; i < AllChannels; i++)
1399 channel_statistics[AllChannels].depth=(unsigned long) MagickMax((double)
1400 channel_statistics[AllChannels].depth,(double)
1401 channel_statistics[i].depth);
1402 channel_statistics[AllChannels].minima=MagickMin(
1403 channel_statistics[AllChannels].minima,channel_statistics[i].minima);
1404 channel_statistics[AllChannels].maxima=MagickMax(
1405 channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
1406 channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
1407 channel_statistics[AllChannels].standard_deviation+=
1408 channel_statistics[i].standard_deviation;
1409 channel_statistics[AllChannels].kurtosis+=channel_statistics[i].kurtosis;
1410 channel_statistics[AllChannels].skewness+=channel_statistics[i].skewness;
1413 if (image->colorspace == CMYKColorspace)
1415 channel_statistics[AllChannels].mean/=channels;
1416 channel_statistics[AllChannels].standard_deviation/=channels;
1417 channel_statistics[AllChannels].kurtosis/=channels;
1418 channel_statistics[AllChannels].skewness/=channels;
1419 for (i=0; i <= AllChannels; i++)
1422 sum_squares=channel_statistics[i].standard_deviation;
1424 sum_cubes=channel_statistics[i].skewness;
1425 channel_statistics[i].standard_deviation=sqrt(
1426 channel_statistics[i].standard_deviation-
1427 (channel_statistics[i].mean*channel_statistics[i].mean));
1428 if (channel_statistics[i].standard_deviation == 0.0)
1430 channel_statistics[i].kurtosis=0.0;
1431 channel_statistics[i].skewness=0.0;
1435 channel_statistics[i].skewness=(channel_statistics[i].skewness-
1436 3.0*channel_statistics[i].mean*sum_squares+
1437 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1438 channel_statistics[i].mean)/
1439 (channel_statistics[i].standard_deviation*
1440 channel_statistics[i].standard_deviation*
1441 channel_statistics[i].standard_deviation);
1442 channel_statistics[i].kurtosis=(channel_statistics[i].kurtosis-
1443 4.0*channel_statistics[i].mean*sum_cubes+
1444 6.0*channel_statistics[i].mean*channel_statistics[i].mean*sum_squares-
1445 3.0*channel_statistics[i].mean*channel_statistics[i].mean*
1446 1.0*channel_statistics[i].mean*channel_statistics[i].mean)/
1447 (channel_statistics[i].standard_deviation*
1448 channel_statistics[i].standard_deviation*
1449 channel_statistics[i].standard_deviation*
1450 channel_statistics[i].standard_deviation)-3.0;
1453 return(channel_statistics);
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461 % G e t I m a g e Q u a n t u m D e p t h %
1465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467 % GetImageQuantumDepth() returns the depth of the image rounded to a legal
1468 % quantum depth: 8, 16, or 32.
1470 % The format of the GetImageQuantumDepth method is:
1472 % unsigned long GetImageQuantumDepth(const Image *image,
1473 % const MagickBooleanType constrain)
1475 % A description of each parameter follows:
1477 % o image: the image.
1479 % o constrain: A value other than MagickFalse, constrains the depth to
1480 % a maximum of MAGICKCORE_QUANTUM_DEPTH.
1483 MagickExport unsigned long GetImageQuantumDepth(const Image *image,
1484 const MagickBooleanType constrain)
1501 if (constrain != MagickFalse)
1502 depth=(unsigned long) MagickMin((double) depth,(double)
1503 MAGICKCORE_QUANTUM_DEPTH);
1508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 % S e t I m a g e C h a n n e l D e p t h %
1516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518 % SetImageChannelDepth() sets the depth of the image.
1520 % The format of the SetImageChannelDepth method is:
1522 % MagickBooleanType SetImageDepth(Image *image,const unsigned long depth)
1523 % MagickBooleanType SetImageChannelDepth(Image *image,
1524 % const ChannelType channel,const unsigned long depth)
1526 % A description of each parameter follows:
1528 % o image: the image.
1530 % o channel: the channel.
1532 % o depth: the image depth.
1536 MagickExport MagickBooleanType SetImageDepth(Image *image,
1537 const unsigned long depth)
1539 return(SetImageChannelDepth(image,AllChannels,depth));
1542 MagickExport MagickBooleanType SetImageChannelDepth(Image *image,
1543 const ChannelType channel,const unsigned long depth)
1560 assert(image != (Image *) NULL);
1561 if (image->debug != MagickFalse)
1562 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1563 assert(image->signature == MagickSignature);
1564 if (GetImageDepth(image,&image->exception) <= (unsigned long)
1565 MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH))
1571 Scale pixels to desired depth.
1574 range=GetQuantumRange(depth);
1575 exception=(&image->exception);
1576 image_view=AcquireCacheView(image);
1577 #if defined(_OPENMP) && (_OPENMP >= 200203)
1578 #pragma omp parallel for schedule(static,1) shared(status)
1580 for (y=0; y < (long) image->rows; y++)
1582 register IndexPacket
1583 *__restrict indexes;
1588 register PixelPacket
1591 if (status == MagickFalse)
1593 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1595 if (q == (PixelPacket *) NULL)
1600 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1601 for (x=0; x < (long) image->columns; x++)
1603 if ((channel & RedChannel) != 0)
1604 q->red=ScaleAnyToQuantum(ScaleQuantumToAny(q->red,range),range);
1605 if ((channel & GreenChannel) != 0)
1606 q->green=ScaleAnyToQuantum(ScaleQuantumToAny(q->green,range),range);
1607 if ((channel & BlueChannel) != 0)
1608 q->blue=ScaleAnyToQuantum(ScaleQuantumToAny(q->blue,range),range);
1609 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1610 q->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(q->opacity,range),range);
1611 if (((channel & IndexChannel) != 0) &&
1612 (image->colorspace == CMYKColorspace))
1613 indexes[x]=ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],range),range);
1616 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1622 image_view=DestroyCacheView(image_view);
1623 if (image->storage_class == PseudoClass)
1631 register PixelPacket
1635 range=GetQuantumRange(depth);
1636 #if defined(_OPENMP) && (_OPENMP >= 200203)
1637 #pragma omp parallel for schedule(static,1) shared(status)
1639 for (i=0; i < (long) image->colors; i++)
1641 if ((channel & RedChannel) != 0)
1642 p->red=ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),range);
1643 if ((channel & GreenChannel) != 0)
1644 p->green=ScaleAnyToQuantum(ScaleQuantumToAny(p->green,range),range);
1645 if ((channel & BlueChannel) != 0)
1646 p->blue=ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),range);
1647 if ((channel & OpacityChannel) != 0)
1648 p->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,range),