blob: c86918fdb4257acd5bb2476e49e9a6e1f60b49cc [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% AAA N N AAA L Y Y ZZZZZ EEEEE %
6% A A NN N A A L Y Y ZZ E %
7% AAAAA N N N AAAAA L Y ZZZ EEE %
8% A A N NN A A L Y ZZ E %
9% A A N N A A LLLLL Y ZZZZZ EEEEE %
10% %
cristy76e378e2009-12-21 18:20:04 +000011% Analyze An Image %
cristy3ed852e2009-09-05 21:47:34 +000012% %
13% Software Design %
14% Bill Corbis %
15% December 1998 %
16% %
17% %
cristy4103d562010-12-10 01:38:54 +000018% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000019% dedicated to making software imaging solutions freely available. %
20% %
21% You may not use this file except in compliance with the License. You may %
22% obtain a copy of the License at %
23% %
24% http://www.imagemagick.org/script/license.php %
25% %
26% Unless required by applicable law or agreed to in writing, software %
27% distributed under the License is distributed on an "AS IS" BASIS, %
28% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
29% See the License for the specific language governing permissions and %
30% limitations under the License. %
31% %
32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33%
34*/
35
36/*
37 Include declarations.
38*/
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <time.h>
43#include <assert.h>
44#include <math.h>
45#include "magick/MagickCore.h"
46
47/*
48%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49% %
50% %
51% %
52% a n a l y z e I m a g e %
53% %
54% %
55% %
56%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57%
58% analyzeImage() computes the brightness and saturation mean, standard
59% deviation, kurtosis and skewness and stores these values as attributes
60% of the image.
61%
62% The format of the analyzeImage method is:
63%
cristyc3186d52010-06-04 13:55:23 +000064% size_t analyzeImage(Image *images,const int argc,
cristy3ed852e2009-09-05 21:47:34 +000065% char **argv,ExceptionInfo *exception)
66%
67% A description of each parameter follows:
68%
69% o image: the address of a structure of type Image.
70%
71% o argc: Specifies a pointer to an integer describing the number of
72% elements in the argument vector.
73%
74% o argv: Specifies a pointer to a text array containing the command line
75% arguments.
76%
77% o exception: return any errors or warnings in this structure.
78%
79*/
cristyc3186d52010-06-04 13:55:23 +000080ModuleExport size_t analyzeImage(Image **images,const int argc,
cristy3ed852e2009-09-05 21:47:34 +000081 const char **argv,ExceptionInfo *exception)
82{
cristy3ed852e2009-09-05 21:47:34 +000083 char
84 text[MaxTextExtent];
85
86 double
87 area,
cristy76e378e2009-12-21 18:20:04 +000088 brightness,
cristy3ed852e2009-09-05 21:47:34 +000089 brightness_mean,
90 brightness_standard_deviation,
91 brightness_kurtosis,
92 brightness_skewness,
93 brightness_sum_x,
94 brightness_sum_x2,
95 brightness_sum_x3,
96 brightness_sum_x4,
cristy76e378e2009-12-21 18:20:04 +000097 hue,
98 saturation,
cristy3ed852e2009-09-05 21:47:34 +000099 saturation_mean,
100 saturation_standard_deviation,
101 saturation_kurtosis,
102 saturation_skewness,
103 saturation_sum_x,
104 saturation_sum_x2,
105 saturation_sum_x3,
106 saturation_sum_x4;
107
cristy3ed852e2009-09-05 21:47:34 +0000108 Image
109 *image;
110
cristy3ed852e2009-09-05 21:47:34 +0000111 assert(images != (Image **) NULL);
112 assert(*images != (Image *) NULL);
113 assert((*images)->signature == MagickSignature);
114 (void) argc;
115 (void) argv;
116 image=(*images);
117 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
118 {
cristy76e378e2009-12-21 18:20:04 +0000119 CacheView
120 *image_view;
121
cristy76e378e2009-12-21 18:20:04 +0000122 MagickBooleanType
123 status;
124
cristyc3186d52010-06-04 13:55:23 +0000125 ssize_t
126 y;
127
cristy3ed852e2009-09-05 21:47:34 +0000128 brightness_sum_x=0.0;
129 brightness_sum_x2=0.0;
130 brightness_sum_x3=0.0;
131 brightness_sum_x4=0.0;
132 brightness_mean=0.0;
133 brightness_standard_deviation=0.0;
134 brightness_kurtosis=0.0;
135 brightness_skewness=0.0;
136 saturation_sum_x=0.0;
137 saturation_sum_x2=0.0;
138 saturation_sum_x3=0.0;
139 saturation_sum_x4=0.0;
140 saturation_mean=0.0;
141 saturation_standard_deviation=0.0;
142 saturation_kurtosis=0.0;
143 saturation_skewness=0.0;
144 area=0.0;
cristy76e378e2009-12-21 18:20:04 +0000145 status=MagickTrue;
146 image_view=AcquireCacheView(image);
147#if defined(MAGICKCORE_OPENMP_SUPPORT)
148 #pragma omp parallel for schedule(dynamic,4) shared(status)
149#endif
cristyc3186d52010-06-04 13:55:23 +0000150 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000151 {
cristy76e378e2009-12-21 18:20:04 +0000152 register const PixelPacket
153 *p;
154
cristyc3186d52010-06-04 13:55:23 +0000155 register ssize_t
cristy76e378e2009-12-21 18:20:04 +0000156 x;
157
158 if (status == MagickFalse)
159 continue;
cristy3ed852e2009-09-05 21:47:34 +0000160 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
161 if (p == (const PixelPacket *) NULL)
cristy76e378e2009-12-21 18:20:04 +0000162 {
163 status=MagickFalse;
164 continue;
165 }
cristyc3186d52010-06-04 13:55:23 +0000166 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000167 {
168 ConvertRGBToHSB(p->red,p->green,p->blue,&hue,&saturation,&brightness);
169 brightness*=QuantumRange;
170 brightness_sum_x+=brightness;
171 brightness_sum_x2+=brightness*brightness;
172 brightness_sum_x3+=brightness*brightness*brightness;
173 brightness_sum_x4+=brightness*brightness*brightness*brightness;
174 saturation*=QuantumRange;
175 saturation_sum_x+=saturation;
176 saturation_sum_x2+=saturation*saturation;
177 saturation_sum_x3+=saturation*saturation*saturation;
178 saturation_sum_x4+=saturation*saturation*saturation*saturation;
179 area++;
180 p++;
181 }
182 }
cristy76e378e2009-12-21 18:20:04 +0000183 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +0000184 if (area <= 0.0)
185 break;
186 brightness_mean=brightness_sum_x/area;
187 (void) FormatMagickString(text,MaxTextExtent,"%g",brightness_mean);
188 (void) SetImageProperty(image,"filter:brightness:mean",text);
189 brightness_standard_deviation=sqrt(brightness_sum_x2/area-(brightness_sum_x/
190 area*brightness_sum_x/area));
191 (void) FormatMagickString(text,MaxTextExtent,"%g",
192 brightness_standard_deviation);
193 (void) SetImageProperty(image,"filter:brightness:standard-deviation",text);
194 if (brightness_standard_deviation != 0)
195 brightness_kurtosis=(brightness_sum_x4/area-4.0*brightness_mean*
196 brightness_sum_x3/area+6.0*brightness_mean*brightness_mean*
197 brightness_sum_x2/area-3.0*brightness_mean*brightness_mean*
198 brightness_mean*brightness_mean)/(brightness_standard_deviation*
199 brightness_standard_deviation*brightness_standard_deviation*
200 brightness_standard_deviation)-3.0;
201 (void) FormatMagickString(text,MaxTextExtent,"%g",brightness_kurtosis);
202 (void) SetImageProperty(image,"filter:brightness:kurtosis",text);
203 if (brightness_standard_deviation != 0)
204 brightness_skewness=(brightness_sum_x3/area-3.0*brightness_mean*
205 brightness_sum_x2/area+2.0*brightness_mean*brightness_mean*
206 brightness_mean)/(brightness_standard_deviation*
207 brightness_standard_deviation*brightness_standard_deviation);
208 (void) FormatMagickString(text,MaxTextExtent,"%g",brightness_skewness);
209 (void) SetImageProperty(image,"filter:brightness:skewness",text);
210 saturation_mean=saturation_sum_x/area;
211 (void) FormatMagickString(text,MaxTextExtent,"%g",saturation_mean);
212 (void) SetImageProperty(image,"filter:saturation:mean",text);
213 saturation_standard_deviation=sqrt(saturation_sum_x2/area-(saturation_sum_x/
214 area*saturation_sum_x/area));
215 (void) FormatMagickString(text,MaxTextExtent,"%g",
216 saturation_standard_deviation);
217 (void) SetImageProperty(image,"filter:saturation:standard-deviation",text);
218 if (saturation_standard_deviation != 0)
219 saturation_kurtosis=(saturation_sum_x4/area-4.0*saturation_mean*
220 saturation_sum_x3/area+6.0*saturation_mean*saturation_mean*
221 saturation_sum_x2/area-3.0*saturation_mean*saturation_mean*
222 saturation_mean*saturation_mean)/(saturation_standard_deviation*
223 saturation_standard_deviation*saturation_standard_deviation*
224 saturation_standard_deviation)-3.0;
225 (void) FormatMagickString(text,MaxTextExtent,"%g",saturation_kurtosis);
226 (void) SetImageProperty(image,"filter:saturation:kurtosis",text);
227 if (saturation_standard_deviation != 0)
228 saturation_skewness=(saturation_sum_x3/area-3.0*saturation_mean*
229 saturation_sum_x2/area+2.0*saturation_mean*saturation_mean*
230 saturation_mean)/(saturation_standard_deviation*
231 saturation_standard_deviation*saturation_standard_deviation);
232 (void) FormatMagickString(text,MaxTextExtent,"%g",saturation_skewness);
233 (void) SetImageProperty(image,"filter:saturation:skewness",text);
234 }
235 return(MagickImageFilterSignature);
236}