blob: 3c74824a4f7d2b74f118f4506d2c09c69177abf7 [file] [log] [blame]
cristy3e2860c2010-01-24 01:36:30 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
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 %
11% %
12% %
13% MagickCore Image Feature Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
20% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
21% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
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. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
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"
91
92/*
93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94% %
95% %
96% %
97% G e t I m a g e C h a n n e l F e a t u r e s %
98% %
99% %
100% %
101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102%
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:
110%
111% channel_features=GetImageChannelFeatures(image,excepton);
112% contrast=channel_features[RedChannel].contrast;
113%
114% Use MagickRelinquishMemory() to free the features buffer.
115%
116% The format of the GetImageChannelFeatures method is:
117%
118% ChannelFeatures *GetImageChannelFeatures(const Image *image,
119% ExceptionInfo *exception)
120%
121% A description of each parameter follows:
122%
123% o image: the image.
124%
125% o exception: return any errors or warnings in this structure.
126%
127*/
128MagickExport ChannelFeatures *GetImageChannelFeatures(const Image *image,
129 ExceptionInfo *exception)
130{
cristyf2bf2c72010-01-25 19:54:15 +0000131 typedef struct _SpatialDependenceMatrix
132 {
133 LongPixelPacket
134 tone[4];
135 } SpatialDependenceMatrix;
136
cristy2070fa52010-01-24 03:17:57 +0000137 CacheView
138 *image_view;
139
cristy3e2860c2010-01-24 01:36:30 +0000140 ChannelFeatures
141 *channel_features;
142
cristy2070fa52010-01-24 03:17:57 +0000143 LongPixelPacket
cristyf2bf2c72010-01-25 19:54:15 +0000144 tone,
145 *tones;
cristy2070fa52010-01-24 03:17:57 +0000146
cristy3e2860c2010-01-24 01:36:30 +0000147 long
148 y;
149
cristy2070fa52010-01-24 03:17:57 +0000150 MagickBooleanType
151 status;
152
153 register long
154 i;
155
cristy3e2860c2010-01-24 01:36:30 +0000156 size_t
157 length;
158
cristyf2bf2c72010-01-25 19:54:15 +0000159 SpatialDependenceMatrix
160 **pixels;
161
162 unsigned long
163 number_tones;
164
cristy3e2860c2010-01-24 01:36:30 +0000165 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));
cristy2070fa52010-01-24 03:17:57 +0000176 /*
cristyf2bf2c72010-01-25 19:54:15 +0000177 Form tones.
cristy2070fa52010-01-24 03:17:57 +0000178 */
cristyf2bf2c72010-01-25 19:54:15 +0000179 tones=(LongPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*tones));
180 if (tones == (LongPixelPacket *) NULL)
cristy2070fa52010-01-24 03:17:57 +0000181 {
182 (void) ThrowMagickException(exception,GetMagickModule(),
183 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
184 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
185 channel_features);
186 return(channel_features);
187 }
188 for (i=0; i <= (long) MaxMap; i++)
189 {
cristyf2bf2c72010-01-25 19:54:15 +0000190 tones[i].red=(~0UL);
191 tones[i].green=(~0UL);
192 tones[i].blue=(~0UL);
193 tones[i].opacity=(~0UL);
194 tones[i].index=(~0UL);
cristy2070fa52010-01-24 03:17:57 +0000195 }
196 status=MagickTrue;
197 image_view=AcquireCacheView(image);
198#if defined(MAGICKCORE_OPENMP_SUPPORT)
199 #pragma omp parallel for schedule(dynamic,4) shared(status)
200#endif
cristy3e2860c2010-01-24 01:36:30 +0000201 for (y=0; y < (long) image->rows; y++)
202 {
203 register const IndexPacket
204 *restrict indexes;
205
206 register const PixelPacket
207 *restrict p;
208
209 register long
210 x;
211
cristy2070fa52010-01-24 03:17:57 +0000212 if (status == MagickFalse)
213 continue;
214 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy3e2860c2010-01-24 01:36:30 +0000215 if (p == (const PixelPacket *) NULL)
cristy2070fa52010-01-24 03:17:57 +0000216 {
217 status=MagickFalse;
218 continue;
219 }
220 indexes=GetCacheViewVirtualIndexQueue(image_view);
cristy3e2860c2010-01-24 01:36:30 +0000221 for (x=0; x < (long) image->columns; x++)
222 {
cristyf2bf2c72010-01-25 19:54:15 +0000223 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);
cristy2070fa52010-01-24 03:17:57 +0000226 if (image->matte != MagickFalse)
cristyf2bf2c72010-01-25 19:54:15 +0000227 tones[ScaleQuantumToMap(p->opacity)].opacity=
cristy2070fa52010-01-24 03:17:57 +0000228 ScaleQuantumToMap(p->opacity);
229 if (image->colorspace == CMYKColorspace)
cristyf2bf2c72010-01-25 19:54:15 +0000230 tones[ScaleQuantumToMap(indexes[x])].index=
cristy2070fa52010-01-24 03:17:57 +0000231 ScaleQuantumToMap(indexes[x]);
cristy3e2860c2010-01-24 01:36:30 +0000232 p++;
233 }
234 }
cristy30c510a2010-01-24 03:43:00 +0000235 image_view=DestroyCacheView(image_view);
236 if (status == MagickFalse)
237 {
cristyf2bf2c72010-01-25 19:54:15 +0000238 tones=(LongPixelPacket *) RelinquishMagickMemory(tones);
cristy30c510a2010-01-24 03:43:00 +0000239 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
240 channel_features);
241 return(channel_features);
242 }
cristyf2bf2c72010-01-25 19:54:15 +0000243 (void) ResetMagickMemory(&tone,0,sizeof(tone));
cristy2070fa52010-01-24 03:17:57 +0000244 for (i=0; i <= (long) MaxMap; i++)
245 {
cristyf2bf2c72010-01-25 19:54:15 +0000246 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;
cristy2070fa52010-01-24 03:17:57 +0000252 if (image->matte != MagickFalse)
cristyf2bf2c72010-01-25 19:54:15 +0000253 if (tones[i].opacity != ~0UL)
254 tones[tone.opacity++].opacity=tones[i].opacity;
cristy2070fa52010-01-24 03:17:57 +0000255 if (image->colorspace == CMYKColorspace)
cristyf2bf2c72010-01-25 19:54:15 +0000256 if (tones[i].index != ~0UL)
257 tones[tone.index++].index=tones[i].index;
cristy2070fa52010-01-24 03:17:57 +0000258 }
cristyf2bf2c72010-01-25 19:54:15 +0000259 /*
260 Allocate spatial dependence matrix.
261 */
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,
274 sizeof(**pixels));
275 if (pixels == (SpatialDependenceMatrix **) NULL)
276 {
277 (void) ThrowMagickException(exception,GetMagickModule(),
278 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
279 tones=(LongPixelPacket *) RelinquishMagickMemory(tones);
280 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
281 channel_features);
282 return(channel_features);
283 }
284 for (i=0; i <= (long) number_tones; i++)
285 {
286 pixels[i]=(SpatialDependenceMatrix *) AcquireQuantumMemory(number_tones,
287 sizeof(*pixels));
288 if (pixels[i] == (SpatialDependenceMatrix *) NULL)
289 break;
290 (void) ResetMagickMemory(pixels[i],0,number_tones*sizeof(*pixels));
291 }
292 if (i <= (long) number_tones)
293 {
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(
301 channel_features);
302 return(channel_features);
303 }
304 /*
305 Initialize spatial dependence matrix.
306 */
307 status=MagickTrue;
308 image_view=AcquireCacheView(image);
309#if defined(MAGICKCORE_OPENMP_SUPPORT)
310 #pragma omp parallel for schedule(dynamic,4) shared(status)
311#endif
312 for (y=0; y < (long) image->rows; y++)
313 {
314 long
315 u,
316 v;
317
318 register const IndexPacket
319 *restrict indexes;
320
321 register const PixelPacket
322 *restrict p;
323
324 register long
325 x;
326
327 if (status == MagickFalse)
328 continue;
329 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
330 if (p == (const PixelPacket *) NULL)
331 {
332 status=MagickFalse;
333 continue;
334 }
335 indexes=GetCacheViewVirtualIndexQueue(image_view);
336 for (x=0; x < (long) image->columns; x++)
337 {
338 for (i=0; i < 4; i++)
339 {
340 }
341 }
342 }
343 image_view=DestroyCacheView(image_view);
344 if (status == MagickFalse)
345 {
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(
353 channel_features);
354 return(channel_features);
355 }
356 /*
357 Relinquish resources.
358 */
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);
cristy3e2860c2010-01-24 01:36:30 +0000363 return(channel_features);
364}