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-2016 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 % 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 /* 38 Include declarations. 39 */ 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <time.h> 44 #include <assert.h> 45 #include <math.h> 46 #include "MagickCore/MagickCore.h" 47 48 /* 50 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 51 % % 52 % % 53 % % 54 % a n a l y z e I m a g e % 55 % % 56 % % 57 % % 58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 59 % 60 % analyzeImage() computes the brightness and saturation mean, standard 61 % deviation, kurtosis and skewness and stores these values as attributes 62 % of the image. 63 % 64 % The format of the analyzeImage method is: 65 % 66 % size_t analyzeImage(Image *images,const int argc, 67 % char **argv,ExceptionInfo *exception) 68 % 69 % A description of each parameter follows: 70 % 71 % o image: the address of a structure of type Image. 72 % 73 % o argc: Specifies a pointer to an integer describing the number of 74 % elements in the argument vector. 75 % 76 % o argv: Specifies a pointer to a text array containing the command line 77 % arguments. 78 % 79 % o exception: return any errors or warnings in this structure. 80 % 81 */ 82 ModuleExport size_t analyzeImage(Image **images,const int argc, 83 const char **argv,ExceptionInfo *exception) 84 { 85 char 86 text[MagickPathExtent]; 87 88 double 89 area, 90 brightness, 91 brightness_mean, 92 brightness_standard_deviation, 93 brightness_kurtosis, 94 brightness_skewness, 95 brightness_sum_x, 96 brightness_sum_x2, 97 brightness_sum_x3, 98 brightness_sum_x4, 99 hue, 100 saturation, 101 saturation_mean, 102 saturation_standard_deviation, 103 saturation_kurtosis, 104 saturation_skewness, 105 saturation_sum_x, 106 saturation_sum_x2, 107 saturation_sum_x3, 108 saturation_sum_x4; 109 110 Image 111 *image; 112 113 assert(images != (Image **) NULL); 114 assert(*images != (Image *) NULL); 115 assert((*images)->signature == MagickCoreSignature); 116 (void) argc; 117 (void) argv; 118 image=(*images); 119 for ( ; image != (Image *) NULL; image=GetNextImageInList(image)) 120 { 121 CacheView 122 *image_view; 123 124 ssize_t 125 y; 126 127 MagickBooleanType 128 status; 129 130 brightness_sum_x=0.0; 131 brightness_sum_x2=0.0; 132 brightness_sum_x3=0.0; 133 brightness_sum_x4=0.0; 134 brightness_mean=0.0; 135 brightness_standard_deviation=0.0; 136 brightness_kurtosis=0.0; 137 brightness_skewness=0.0; 138 saturation_sum_x=0.0; 139 saturation_sum_x2=0.0; 140 saturation_sum_x3=0.0; 141 saturation_sum_x4=0.0; 142 saturation_mean=0.0; 143 saturation_standard_deviation=0.0; 144 saturation_kurtosis=0.0; 145 saturation_skewness=0.0; 146 area=0.0; 147 status=MagickTrue; 148 image_view=AcquireVirtualCacheView(image,exception); 149 #if defined(MAGICKCORE_OPENMP_SUPPORT) 150 #pragma omp parallel for schedule(static,4) shared(status) \ 151 magick_threads(image,image,image->rows,1) 152 #endif 153 for (y=0; y < (ssize_t) image->rows; y++) 154 { 155 register const Quantum 156 *p; 157 158 register ssize_t 159 x; 160 161 if (status == MagickFalse) 162 continue; 163 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 164 if (p == (const Quantum *) NULL) 165 { 166 status=MagickFalse; 167 continue; 168 } 169 for (x=0; x < (ssize_t) image->columns; x++) 170 { 171 ConvertRGBToHSL(GetPixelRed(image,p),GetPixelGreen(image,p), 172 GetPixelBlue(image,p),&hue,&saturation,&brightness); 173 brightness*=QuantumRange; 174 brightness_sum_x+=brightness; 175 brightness_sum_x2+=brightness*brightness; 176 brightness_sum_x3+=brightness*brightness*brightness; 177 brightness_sum_x4+=brightness*brightness*brightness*brightness; 178 saturation*=QuantumRange; 179 saturation_sum_x+=saturation; 180 saturation_sum_x2+=saturation*saturation; 181 saturation_sum_x3+=saturation*saturation*saturation; 182 saturation_sum_x4+=saturation*saturation*saturation*saturation; 183 area++; 184 p+=GetPixelChannels(image); 185 } 186 } 187 image_view=DestroyCacheView(image_view); 188 if (area <= 0.0) 189 break; 190 brightness_mean=brightness_sum_x/area; 191 (void) FormatLocaleString(text,MagickPathExtent,"%g",brightness_mean); 192 (void) SetImageProperty(image,"filter:brightness:mean",text, 193 exception); 194 brightness_standard_deviation=sqrt(brightness_sum_x2/area-(brightness_sum_x/ 195 area*brightness_sum_x/area)); 196 (void) FormatLocaleString(text,MagickPathExtent,"%g", 197 brightness_standard_deviation); 198 (void) SetImageProperty(image,"filter:brightness:standard-deviation",text, 199 exception); 200 if (fabs(brightness_standard_deviation) >= MagickEpsilon) 201 brightness_kurtosis=(brightness_sum_x4/area-4.0*brightness_mean* 202 brightness_sum_x3/area+6.0*brightness_mean*brightness_mean* 203 brightness_sum_x2/area-3.0*brightness_mean*brightness_mean* 204 brightness_mean*brightness_mean)/(brightness_standard_deviation* 205 brightness_standard_deviation*brightness_standard_deviation* 206 brightness_standard_deviation)-3.0; 207 (void) FormatLocaleString(text,MagickPathExtent,"%g",brightness_kurtosis); 208 (void) SetImageProperty(image,"filter:brightness:kurtosis",text, 209 exception); 210 if (brightness_standard_deviation != 0) 211 brightness_skewness=(brightness_sum_x3/area-3.0*brightness_mean* 212 brightness_sum_x2/area+2.0*brightness_mean*brightness_mean* 213 brightness_mean)/(brightness_standard_deviation* 214 brightness_standard_deviation*brightness_standard_deviation); 215 (void) FormatLocaleString(text,MagickPathExtent,"%g",brightness_skewness); 216 (void) SetImageProperty(image,"filter:brightness:skewness",text, 217 exception); 218 saturation_mean=saturation_sum_x/area; 219 (void) FormatLocaleString(text,MagickPathExtent,"%g",saturation_mean); 220 (void) SetImageProperty(image,"filter:saturation:mean",text, 221 exception); 222 saturation_standard_deviation=sqrt(saturation_sum_x2/area-(saturation_sum_x/ 223 area*saturation_sum_x/area)); 224 (void) FormatLocaleString(text,MagickPathExtent,"%g", 225 saturation_standard_deviation); 226 (void) SetImageProperty(image,"filter:saturation:standard-deviation",text, 227 exception); 228 if (fabs(saturation_standard_deviation) >= MagickEpsilon) 229 saturation_kurtosis=(saturation_sum_x4/area-4.0*saturation_mean* 230 saturation_sum_x3/area+6.0*saturation_mean*saturation_mean* 231 saturation_sum_x2/area-3.0*saturation_mean*saturation_mean* 232 saturation_mean*saturation_mean)/(saturation_standard_deviation* 233 saturation_standard_deviation*saturation_standard_deviation* 234 saturation_standard_deviation)-3.0; 235 (void) FormatLocaleString(text,MagickPathExtent,"%g",saturation_kurtosis); 236 (void) SetImageProperty(image,"filter:saturation:kurtosis",text, 237 exception); 238 if (fabs(saturation_standard_deviation) >= MagickEpsilon) 239 saturation_skewness=(saturation_sum_x3/area-3.0*saturation_mean* 240 saturation_sum_x2/area+2.0*saturation_mean*saturation_mean* 241 saturation_mean)/(saturation_standard_deviation* 242 saturation_standard_deviation*saturation_standard_deviation); 243 (void) FormatLocaleString(text,MagickPathExtent,"%g",saturation_skewness); 244 (void) SetImageProperty(image,"filter:saturation:skewness",text, 245 exception); 246 } 247 return(MagickImageFilterSignature); 248 } 249