blob: 99ad3fe5a48f9700a94c6199768aca2f89640440 [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{
cristy2070fa52010-01-24 03:17:57 +0000131 CacheView
132 *image_view;
133
cristy3e2860c2010-01-24 01:36:30 +0000134 ChannelFeatures
135 *channel_features;
136
cristy2070fa52010-01-24 03:17:57 +0000137 LongPixelPacket
cristy30c510a2010-01-24 03:43:00 +0000138 pixel,
139 *pixels;
cristy2070fa52010-01-24 03:17:57 +0000140
cristy3e2860c2010-01-24 01:36:30 +0000141 long
142 y;
143
cristy2070fa52010-01-24 03:17:57 +0000144 MagickBooleanType
145 status;
146
147 register long
148 i;
149
cristy3e2860c2010-01-24 01:36:30 +0000150 size_t
151 length;
152
153 assert(image != (Image *) NULL);
154 assert(image->signature == MagickSignature);
155 if (image->debug != MagickFalse)
156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
157 length=AllChannels+1UL;
158 channel_features=(ChannelFeatures *) AcquireQuantumMemory(length,
159 sizeof(*channel_features));
160 if (channel_features == (ChannelFeatures *) NULL)
161 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
162 (void) ResetMagickMemory(channel_features,0,length*
163 sizeof(*channel_features));
cristy2070fa52010-01-24 03:17:57 +0000164 /*
cristy30c510a2010-01-24 03:43:00 +0000165 Form pixels.
cristy2070fa52010-01-24 03:17:57 +0000166 */
cristy30c510a2010-01-24 03:43:00 +0000167 pixels=(LongPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*pixels));
168 if (pixels == (LongPixelPacket *) NULL)
cristy2070fa52010-01-24 03:17:57 +0000169 {
170 (void) ThrowMagickException(exception,GetMagickModule(),
171 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
172 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
173 channel_features);
174 return(channel_features);
175 }
176 for (i=0; i <= (long) MaxMap; i++)
177 {
cristy30c510a2010-01-24 03:43:00 +0000178 pixels[i].red=(~0UL);
179 pixels[i].green=(~0UL);
180 pixels[i].blue=(~0UL);
181 pixels[i].opacity=(~0UL);
182 pixels[i].index=(~0UL);
cristy2070fa52010-01-24 03:17:57 +0000183 }
184 status=MagickTrue;
185 image_view=AcquireCacheView(image);
186#if defined(MAGICKCORE_OPENMP_SUPPORT)
187 #pragma omp parallel for schedule(dynamic,4) shared(status)
188#endif
cristy3e2860c2010-01-24 01:36:30 +0000189 for (y=0; y < (long) image->rows; y++)
190 {
191 register const IndexPacket
192 *restrict indexes;
193
194 register const PixelPacket
195 *restrict p;
196
197 register long
198 x;
199
cristy2070fa52010-01-24 03:17:57 +0000200 if (status == MagickFalse)
201 continue;
202 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy3e2860c2010-01-24 01:36:30 +0000203 if (p == (const PixelPacket *) NULL)
cristy2070fa52010-01-24 03:17:57 +0000204 {
205 status=MagickFalse;
206 continue;
207 }
208 indexes=GetCacheViewVirtualIndexQueue(image_view);
cristy3e2860c2010-01-24 01:36:30 +0000209 for (x=0; x < (long) image->columns; x++)
210 {
cristy30c510a2010-01-24 03:43:00 +0000211 pixels[ScaleQuantumToMap(p->red)].red=ScaleQuantumToMap(p->red);
212 pixels[ScaleQuantumToMap(p->green)].green=ScaleQuantumToMap(p->green);
213 pixels[ScaleQuantumToMap(p->blue)].blue=ScaleQuantumToMap(p->blue);
cristy2070fa52010-01-24 03:17:57 +0000214 if (image->matte != MagickFalse)
cristy30c510a2010-01-24 03:43:00 +0000215 pixels[ScaleQuantumToMap(p->opacity)].opacity=
cristy2070fa52010-01-24 03:17:57 +0000216 ScaleQuantumToMap(p->opacity);
217 if (image->colorspace == CMYKColorspace)
cristy30c510a2010-01-24 03:43:00 +0000218 pixels[ScaleQuantumToMap(indexes[x])].index=
cristy2070fa52010-01-24 03:17:57 +0000219 ScaleQuantumToMap(indexes[x]);
cristy3e2860c2010-01-24 01:36:30 +0000220 p++;
221 }
222 }
cristy30c510a2010-01-24 03:43:00 +0000223 image_view=DestroyCacheView(image_view);
224 if (status == MagickFalse)
225 {
226 pixels=(LongPixelPacket *) RelinquishMagickMemory(pixels);
227 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
228 channel_features);
229 return(channel_features);
230 }
231 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
cristy2070fa52010-01-24 03:17:57 +0000232 for (i=0; i <= (long) MaxMap; i++)
233 {
cristy30c510a2010-01-24 03:43:00 +0000234 if (pixels[i].red != ~0UL)
235 pixels[pixel.red++].red=pixels[i].red;
236 if (pixels[i].green != ~0UL)
237 pixels[pixel.green++].green=pixels[i].green;
238 if (pixels[i].blue != ~0UL)
239 pixels[pixel.blue++].blue=pixels[i].blue;
cristy2070fa52010-01-24 03:17:57 +0000240 if (image->matte != MagickFalse)
cristy30c510a2010-01-24 03:43:00 +0000241 if (pixels[i].opacity != ~0UL)
242 pixels[pixel.opacity++].opacity=pixels[i].opacity;
cristy2070fa52010-01-24 03:17:57 +0000243 if (image->colorspace == CMYKColorspace)
cristy30c510a2010-01-24 03:43:00 +0000244 if (pixels[i].index != ~0UL)
245 pixels[pixel.index++].index=pixels[i].index;
cristy2070fa52010-01-24 03:17:57 +0000246 }
cristy30c510a2010-01-24 03:43:00 +0000247 pixels=(LongPixelPacket *) RelinquishMagickMemory(pixels);
cristy3e2860c2010-01-24 01:36:30 +0000248 return(channel_features);
249}