1 /*
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 % %
11 % Analyze An Image %
12 % %
13 % Software Design %
14 % Bill Corbis %
15 % December 1998 %
16 % %
17 % %
18 % Copyright 1999-2020 ImageMagick Studio LLC, a non-profit organization %
19 % 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 % https://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 "MagickCore/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 %
64 % size_t analyzeImage(Image *images,const int argc,
65 % 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 */
analyzeImage(Image ** images,const int argc,const char ** argv,ExceptionInfo * exception)80 ModuleExport size_t analyzeImage(Image **images,const int argc,
81 const char **argv,ExceptionInfo *exception)
82 {
83 char
84 text[MagickPathExtent];
85
86 double
87 area,
88 brightness,
89 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,
97 hue,
98 saturation,
99 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
108 Image
109 *image;
110
111 assert(images != (Image **) NULL);
112 assert(*images != (Image *) NULL);
113 assert((*images)->signature == MagickCoreSignature);
114 (void) argc;
115 (void) argv;
116 image=(*images);
117 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
118 {
119 CacheView
120 *image_view;
121
122 ssize_t
123 y;
124
125 MagickBooleanType
126 status;
127
128 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;
145 status=MagickTrue;
146 image_view=AcquireVirtualCacheView(image,exception);
147 for (y=0; y < (ssize_t) image->rows; y++)
148 {
149 register const Quantum
150 *p;
151
152 register ssize_t
153 x;
154
155 if (status == MagickFalse)
156 continue;
157 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
158 if (p == (const Quantum *) NULL)
159 {
160 status=MagickFalse;
161 continue;
162 }
163 for (x=0; x < (ssize_t) image->columns; x++)
164 {
165 ConvertRGBToHSL(GetPixelRed(image,p),GetPixelGreen(image,p),
166 GetPixelBlue(image,p),&hue,&saturation,&brightness);
167 brightness*=QuantumRange;
168 brightness_sum_x+=brightness;
169 brightness_sum_x2+=brightness*brightness;
170 brightness_sum_x3+=brightness*brightness*brightness;
171 brightness_sum_x4+=brightness*brightness*brightness*brightness;
172 saturation*=QuantumRange;
173 saturation_sum_x+=saturation;
174 saturation_sum_x2+=saturation*saturation;
175 saturation_sum_x3+=saturation*saturation*saturation;
176 saturation_sum_x4+=saturation*saturation*saturation*saturation;
177 area++;
178 p+=GetPixelChannels(image);
179 }
180 }
181 image_view=DestroyCacheView(image_view);
182 if (area <= 0.0)
183 break;
184 brightness_mean=brightness_sum_x/area;
185 (void) FormatLocaleString(text,MagickPathExtent,"%g",brightness_mean);
186 (void) SetImageProperty(image,"filter:brightness:mean",text,
187 exception);
188 brightness_standard_deviation=sqrt(brightness_sum_x2/area-(brightness_sum_x/
189 area*brightness_sum_x/area));
190 (void) FormatLocaleString(text,MagickPathExtent,"%g",
191 brightness_standard_deviation);
192 (void) SetImageProperty(image,"filter:brightness:standard-deviation",text,
193 exception);
194 if (fabs(brightness_standard_deviation) >= MagickEpsilon)
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) FormatLocaleString(text,MagickPathExtent,"%g",brightness_kurtosis);
202 (void) SetImageProperty(image,"filter:brightness:kurtosis",text,
203 exception);
204 if (brightness_standard_deviation != 0)
205 brightness_skewness=(brightness_sum_x3/area-3.0*brightness_mean*
206 brightness_sum_x2/area+2.0*brightness_mean*brightness_mean*
207 brightness_mean)/(brightness_standard_deviation*
208 brightness_standard_deviation*brightness_standard_deviation);
209 (void) FormatLocaleString(text,MagickPathExtent,"%g",brightness_skewness);
210 (void) SetImageProperty(image,"filter:brightness:skewness",text,
211 exception);
212 saturation_mean=saturation_sum_x/area;
213 (void) FormatLocaleString(text,MagickPathExtent,"%g",saturation_mean);
214 (void) SetImageProperty(image,"filter:saturation:mean",text,
215 exception);
216 saturation_standard_deviation=sqrt(saturation_sum_x2/area-(saturation_sum_x/
217 area*saturation_sum_x/area));
218 (void) FormatLocaleString(text,MagickPathExtent,"%g",
219 saturation_standard_deviation);
220 (void) SetImageProperty(image,"filter:saturation:standard-deviation",text,
221 exception);
222 if (fabs(saturation_standard_deviation) >= MagickEpsilon)
223 saturation_kurtosis=(saturation_sum_x4/area-4.0*saturation_mean*
224 saturation_sum_x3/area+6.0*saturation_mean*saturation_mean*
225 saturation_sum_x2/area-3.0*saturation_mean*saturation_mean*
226 saturation_mean*saturation_mean)/(saturation_standard_deviation*
227 saturation_standard_deviation*saturation_standard_deviation*
228 saturation_standard_deviation)-3.0;
229 (void) FormatLocaleString(text,MagickPathExtent,"%g",saturation_kurtosis);
230 (void) SetImageProperty(image,"filter:saturation:kurtosis",text,
231 exception);
232 if (fabs(saturation_standard_deviation) >= MagickEpsilon)
233 saturation_skewness=(saturation_sum_x3/area-3.0*saturation_mean*
234 saturation_sum_x2/area+2.0*saturation_mean*saturation_mean*
235 saturation_mean)/(saturation_standard_deviation*
236 saturation_standard_deviation*saturation_standard_deviation);
237 (void) FormatLocaleString(text,MagickPathExtent,"%g",saturation_skewness);
238 (void) SetImageProperty(image,"filter:saturation:skewness",text,
239 exception);
240 }
241 return(MagickImageFilterSignature);
242 }
243