2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % FFFFF EEEEE AAA TTTTT U U RRRR EEEEE %
7 % F E A A T U U R R E %
8 % FFF EEE AAAAA T U U RRRR EEE %
9 % F E A A T U U R R E %
10 % F EEEEE A A T UUU R R EEEEE %
13 % MagickCore Image Feature Methods %
20 % Copyright 1999-2010 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/feature.h"
67 #include "magick/gem.h"
68 #include "magick/geometry.h"
69 #include "magick/list.h"
70 #include "magick/image-private.h"
71 #include "magick/magic.h"
72 #include "magick/magick.h"
73 #include "magick/memory_.h"
74 #include "magick/module.h"
75 #include "magick/monitor.h"
76 #include "magick/monitor-private.h"
77 #include "magick/option.h"
78 #include "magick/paint.h"
79 #include "magick/pixel-private.h"
80 #include "magick/profile.h"
81 #include "magick/quantize.h"
82 #include "magick/random_.h"
83 #include "magick/segment.h"
84 #include "magick/semaphore.h"
85 #include "magick/signature-private.h"
86 #include "magick/string_.h"
87 #include "magick/thread-private.h"
88 #include "magick/timer.h"
89 #include "magick/utility.h"
90 #include "magick/version.h"
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 % G e t I m a g e C h a n n e l F e a t u r e s %
101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 % GetImageChannelFeatures() returns features for each channel in the
104 % image. The features include the angular second momentum, contrast,
105 % correlation, sum of squares: variance, inverse difference moment, sum
106 % average, sum varience, sum entropy, entropy, difference variance, difference
107 % entropy, information measures of correlation 1, information measures of
108 % correlation 2, and maximum correlation coefficient. You can access the red
109 % channel contrast, for example, like this:
111 % channel_features=GetImageChannelFeatures(image,excepton);
112 % contrast=channel_features[RedChannel].contrast;
114 % Use MagickRelinquishMemory() to free the features buffer.
116 % The format of the GetImageChannelFeatures method is:
118 % ChannelFeatures *GetImageChannelFeatures(const Image *image,
119 % ExceptionInfo *exception)
121 % A description of each parameter follows:
123 % o image: the image.
125 % o exception: return any errors or warnings in this structure.
128 MagickExport ChannelFeatures *GetImageChannelFeatures(const Image *image,
129 ExceptionInfo *exception)
131 typedef struct _SpatialDependenceMatrix
135 } SpatialDependenceMatrix;
159 SpatialDependenceMatrix
165 assert(image != (Image *) NULL);
166 assert(image->signature == MagickSignature);
167 if (image->debug != MagickFalse)
168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
169 length=AllChannels+1UL;
170 channel_features=(ChannelFeatures *) AcquireQuantumMemory(length,
171 sizeof(*channel_features));
172 if (channel_features == (ChannelFeatures *) NULL)
173 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
174 (void) ResetMagickMemory(channel_features,0,length*
175 sizeof(*channel_features));
179 tones=(LongPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*tones));
180 if (tones == (LongPixelPacket *) NULL)
182 (void) ThrowMagickException(exception,GetMagickModule(),
183 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
184 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
186 return(channel_features);
188 for (i=0; i <= (long) MaxMap; i++)
191 tones[i].green=(~0UL);
192 tones[i].blue=(~0UL);
193 tones[i].opacity=(~0UL);
194 tones[i].index=(~0UL);
197 image_view=AcquireCacheView(image);
198 #if defined(MAGICKCORE_OPENMP_SUPPORT)
199 #pragma omp parallel for schedule(dynamic,4) shared(status)
201 for (y=0; y < (long) image->rows; y++)
203 register const IndexPacket
206 register const PixelPacket
212 if (status == MagickFalse)
214 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
215 if (p == (const PixelPacket *) NULL)
220 indexes=GetCacheViewVirtualIndexQueue(image_view);
221 for (x=0; x < (long) image->columns; x++)
223 tones[ScaleQuantumToMap(p->red)].red=ScaleQuantumToMap(p->red);
224 tones[ScaleQuantumToMap(p->green)].green=ScaleQuantumToMap(p->green);
225 tones[ScaleQuantumToMap(p->blue)].blue=ScaleQuantumToMap(p->blue);
226 if (image->matte != MagickFalse)
227 tones[ScaleQuantumToMap(p->opacity)].opacity=
228 ScaleQuantumToMap(p->opacity);
229 if (image->colorspace == CMYKColorspace)
230 tones[ScaleQuantumToMap(indexes[x])].index=
231 ScaleQuantumToMap(indexes[x]);
235 image_view=DestroyCacheView(image_view);
236 if (status == MagickFalse)
238 tones=(LongPixelPacket *) RelinquishMagickMemory(tones);
239 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
241 return(channel_features);
243 (void) ResetMagickMemory(&tone,0,sizeof(tone));
244 for (i=0; i <= (long) MaxMap; i++)
246 if (tones[i].red != ~0UL)
247 tones[tone.red++].red=tones[i].red;
248 if (tones[i].green != ~0UL)
249 tones[tone.green++].green=tones[i].green;
250 if (tones[i].blue != ~0UL)
251 tones[tone.blue++].blue=tones[i].blue;
252 if (image->matte != MagickFalse)
253 if (tones[i].opacity != ~0UL)
254 tones[tone.opacity++].opacity=tones[i].opacity;
255 if (image->colorspace == CMYKColorspace)
256 if (tones[i].index != ~0UL)
257 tones[tone.index++].index=tones[i].index;
260 Allocate spatial dependence matrix.
262 number_tones=tone.red;
263 if (tone.green > number_tones)
264 number_tones=tone.green;
265 if (tone.blue > number_tones)
266 number_tones=tone.blue;
267 if (image->matte != MagickFalse)
268 if (tone.opacity > number_tones)
269 number_tones=tone.opacity;
270 if (image->colorspace == CMYKColorspace)
271 if (tone.index > number_tones)
272 number_tones=tone.index;
273 pixels=(SpatialDependenceMatrix **) AcquireQuantumMemory(number_tones,
275 if (pixels == (SpatialDependenceMatrix **) NULL)
277 (void) ThrowMagickException(exception,GetMagickModule(),
278 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
279 tones=(LongPixelPacket *) RelinquishMagickMemory(tones);
280 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
282 return(channel_features);
284 for (i=0; i <= (long) number_tones; i++)
286 pixels[i]=(SpatialDependenceMatrix *) AcquireQuantumMemory(number_tones,
288 if (pixels[i] == (SpatialDependenceMatrix *) NULL)
290 (void) ResetMagickMemory(pixels[i],0,number_tones*sizeof(*pixels));
292 if (i <= (long) number_tones)
294 (void) ThrowMagickException(exception,GetMagickModule(),
295 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
296 for (i--; i >= 0; i--)
297 pixels[i]=(SpatialDependenceMatrix *) RelinquishMagickMemory(pixels[i]);
298 pixels=(SpatialDependenceMatrix **) RelinquishMagickMemory(pixels);
299 tones=(LongPixelPacket *) RelinquishMagickMemory(tones);
300 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
302 return(channel_features);
305 Initialize spatial dependence matrix.
308 image_view=AcquireCacheView(image);
309 #if defined(MAGICKCORE_OPENMP_SUPPORT)
310 #pragma omp parallel for schedule(dynamic,4) shared(status)
312 for (y=0; y < (long) image->rows; y++)
318 register const IndexPacket
321 register const PixelPacket
327 if (status == MagickFalse)
329 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
330 if (p == (const PixelPacket *) NULL)
335 indexes=GetCacheViewVirtualIndexQueue(image_view);
336 for (x=0; x < (long) image->columns; x++)
338 for (i=0; i < 4; i++)
343 image_view=DestroyCacheView(image_view);
344 if (status == MagickFalse)
346 (void) ThrowMagickException(exception,GetMagickModule(),
347 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
348 for (i=0; i <= (long) number_tones; i++)
349 pixels[i]=(SpatialDependenceMatrix *) RelinquishMagickMemory(pixels[i]);
350 pixels=(SpatialDependenceMatrix **) RelinquishMagickMemory(pixels);
351 tones=(LongPixelPacket *) RelinquishMagickMemory(tones);
352 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
354 return(channel_features);
357 Relinquish resources.
359 for (i=0; i <= (long) number_tones; i++)
360 pixels[i]=(SpatialDependenceMatrix *) RelinquishMagickMemory(pixels[i]);
361 pixels=(SpatialDependenceMatrix **) RelinquishMagickMemory(pixels);
362 tones=(LongPixelPacket *) RelinquishMagickMemory(tones);
363 return(channel_features);