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-2013 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 "MagickCore/studio.h"
44 #include "MagickCore/property.h"
45 #include "MagickCore/animate.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/cache-private.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/client.h"
52 #include "MagickCore/color.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colorspace.h"
55 #include "MagickCore/colorspace-private.h"
56 #include "MagickCore/composite.h"
57 #include "MagickCore/composite-private.h"
58 #include "MagickCore/compress.h"
59 #include "MagickCore/constitute.h"
60 #include "MagickCore/display.h"
61 #include "MagickCore/draw.h"
62 #include "MagickCore/enhance.h"
63 #include "MagickCore/exception.h"
64 #include "MagickCore/exception-private.h"
65 #include "MagickCore/feature.h"
66 #include "MagickCore/gem.h"
67 #include "MagickCore/geometry.h"
68 #include "MagickCore/list.h"
69 #include "MagickCore/image-private.h"
70 #include "MagickCore/magic.h"
71 #include "MagickCore/magick.h"
72 #include "MagickCore/memory_.h"
73 #include "MagickCore/module.h"
74 #include "MagickCore/monitor.h"
75 #include "MagickCore/monitor-private.h"
76 #include "MagickCore/option.h"
77 #include "MagickCore/paint.h"
78 #include "MagickCore/pixel-accessor.h"
79 #include "MagickCore/profile.h"
80 #include "MagickCore/quantize.h"
81 #include "MagickCore/quantum-private.h"
82 #include "MagickCore/random_.h"
83 #include "MagickCore/resource_.h"
84 #include "MagickCore/segment.h"
85 #include "MagickCore/semaphore.h"
86 #include "MagickCore/signature-private.h"
87 #include "MagickCore/string_.h"
88 #include "MagickCore/thread-private.h"
89 #include "MagickCore/timer.h"
90 #include "MagickCore/utility.h"
91 #include "MagickCore/version.h"
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 % G e t I m a g e F e a t u r e s %
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104 % GetImageFeatures() returns features for each channel in the image in
105 % each of four directions (horizontal, vertical, left and right diagonals)
106 % for the specified distance. The features include the angular second
107 % moment, contrast, correlation, sum of squares: variance, inverse difference
108 % moment, sum average, sum varience, sum entropy, entropy, difference variance,% difference entropy, information measures of correlation 1, information
109 % measures of correlation 2, and maximum correlation coefficient. You can
110 % access the red channel contrast, for example, like this:
112 % channel_features=GetImageFeatures(image,1,exception);
113 % contrast=channel_features[RedPixelChannel].contrast[0];
115 % Use MagickRelinquishMemory() to free the features buffer.
117 % The format of the GetImageFeatures method is:
119 % ChannelFeatures *GetImageFeatures(const Image *image,
120 % const size_t distance,ExceptionInfo *exception)
122 % A description of each parameter follows:
124 % o image: the image.
126 % o distance: the distance.
128 % o exception: return any errors or warnings in this structure.
132 static inline ssize_t MagickAbsoluteValue(const ssize_t x)
139 MagickExport ChannelFeatures *GetImageFeatures(const Image *image,
140 const size_t distance,ExceptionInfo *exception)
142 typedef struct _ChannelStatistics
145 direction[4]; /* horizontal, vertical, left and right diagonals */
190 assert(image != (Image *) NULL);
191 assert(image->signature == MagickSignature);
192 if (image->debug != MagickFalse)
193 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
194 if ((image->columns < (distance+1)) || (image->rows < (distance+1)))
195 return((ChannelFeatures *) NULL);
196 length=CompositeChannels+1UL;
197 channel_features=(ChannelFeatures *) AcquireQuantumMemory(length,
198 sizeof(*channel_features));
199 if (channel_features == (ChannelFeatures *) NULL)
200 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
201 (void) ResetMagickMemory(channel_features,0,length*
202 sizeof(*channel_features));
206 grays=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*grays));
207 if (grays == (PixelPacket *) NULL)
209 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
211 (void) ThrowMagickException(exception,GetMagickModule(),
212 ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
213 return(channel_features);
215 for (i=0; i <= (ssize_t) MaxMap; i++)
218 grays[i].green=(~0U);
220 grays[i].alpha=(~0U);
221 grays[i].black=(~0U);
224 image_view=AcquireVirtualCacheView(image);
225 #if defined(MAGICKCORE_OPENMP_SUPPORT)
226 #pragma omp parallel for schedule(static,4) shared(status) \
227 dynamic_number_threads(image,image->columns,image->rows,1)
229 for (y=0; y < (ssize_t) image->rows; y++)
231 register const Quantum
237 if (status == MagickFalse)
239 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
240 if (p == (const Quantum *) NULL)
245 for (x=0; x < (ssize_t) image->columns; x++)
247 grays[ScaleQuantumToMap(GetPixelRed(image,p))].red=
248 ScaleQuantumToMap(GetPixelRed(image,p));
249 grays[ScaleQuantumToMap(GetPixelGreen(image,p))].green=
250 ScaleQuantumToMap(GetPixelGreen(image,p));
251 grays[ScaleQuantumToMap(GetPixelBlue(image,p))].blue=
252 ScaleQuantumToMap(GetPixelBlue(image,p));
253 if (image->colorspace == CMYKColorspace)
254 grays[ScaleQuantumToMap(GetPixelBlack(image,p))].black=
255 ScaleQuantumToMap(GetPixelBlack(image,p));
256 if (image->alpha_trait == BlendPixelTrait)
257 grays[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha=
258 ScaleQuantumToMap(GetPixelAlpha(image,p));
259 p+=GetPixelChannels(image);
262 image_view=DestroyCacheView(image_view);
263 if (status == MagickFalse)
265 grays=(PixelPacket *) RelinquishMagickMemory(grays);
266 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
268 return(channel_features);
270 (void) ResetMagickMemory(&gray,0,sizeof(gray));
271 for (i=0; i <= (ssize_t) MaxMap; i++)
273 if (grays[i].red != ~0U)
274 grays[gray.red++].red=grays[i].red;
275 if (grays[i].green != ~0U)
276 grays[gray.green++].green=grays[i].green;
277 if (grays[i].blue != ~0U)
278 grays[gray.blue++].blue=grays[i].blue;
279 if (image->colorspace == CMYKColorspace)
280 if (grays[i].black != ~0U)
281 grays[gray.black++].black=grays[i].black;
282 if (image->alpha_trait == BlendPixelTrait)
283 if (grays[i].alpha != ~0U)
284 grays[gray.alpha++].alpha=grays[i].alpha;
287 Allocate spatial dependence matrix.
289 number_grays=gray.red;
290 if (gray.green > number_grays)
291 number_grays=gray.green;
292 if (gray.blue > number_grays)
293 number_grays=gray.blue;
294 if (image->colorspace == CMYKColorspace)
295 if (gray.black > number_grays)
296 number_grays=gray.black;
297 if (image->alpha_trait == BlendPixelTrait)
298 if (gray.alpha > number_grays)
299 number_grays=gray.alpha;
300 cooccurrence=(ChannelStatistics **) AcquireQuantumMemory(number_grays,
301 sizeof(*cooccurrence));
302 density_x=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
304 density_xy=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
305 sizeof(*density_xy));
306 density_y=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
308 Q=(ChannelStatistics **) AcquireQuantumMemory(number_grays,sizeof(*Q));
309 sum=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(*sum));
310 if ((cooccurrence == (ChannelStatistics **) NULL) ||
311 (density_x == (ChannelStatistics *) NULL) ||
312 (density_xy == (ChannelStatistics *) NULL) ||
313 (density_y == (ChannelStatistics *) NULL) ||
314 (Q == (ChannelStatistics **) NULL) ||
315 (sum == (ChannelStatistics *) NULL))
317 if (Q != (ChannelStatistics **) NULL)
319 for (i=0; i < (ssize_t) number_grays; i++)
320 Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
321 Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
323 if (sum != (ChannelStatistics *) NULL)
324 sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
325 if (density_y != (ChannelStatistics *) NULL)
326 density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
327 if (density_xy != (ChannelStatistics *) NULL)
328 density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
329 if (density_x != (ChannelStatistics *) NULL)
330 density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
331 if (cooccurrence != (ChannelStatistics **) NULL)
333 for (i=0; i < (ssize_t) number_grays; i++)
334 cooccurrence[i]=(ChannelStatistics *)
335 RelinquishMagickMemory(cooccurrence[i]);
336 cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(
339 grays=(PixelPacket *) RelinquishMagickMemory(grays);
340 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
342 (void) ThrowMagickException(exception,GetMagickModule(),
343 ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
344 return(channel_features);
346 (void) ResetMagickMemory(&correlation,0,sizeof(correlation));
347 (void) ResetMagickMemory(density_x,0,2*(number_grays+1)*sizeof(*density_x));
348 (void) ResetMagickMemory(density_xy,0,2*(number_grays+1)*sizeof(*density_xy));
349 (void) ResetMagickMemory(density_y,0,2*(number_grays+1)*sizeof(*density_y));
350 (void) ResetMagickMemory(&mean,0,sizeof(mean));
351 (void) ResetMagickMemory(sum,0,number_grays*sizeof(*sum));
352 (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares));
353 (void) ResetMagickMemory(density_xy,0,2*number_grays*sizeof(*density_xy));
354 (void) ResetMagickMemory(&entropy_x,0,sizeof(entropy_x));
355 (void) ResetMagickMemory(&entropy_xy,0,sizeof(entropy_xy));
356 (void) ResetMagickMemory(&entropy_xy1,0,sizeof(entropy_xy1));
357 (void) ResetMagickMemory(&entropy_xy2,0,sizeof(entropy_xy2));
358 (void) ResetMagickMemory(&entropy_y,0,sizeof(entropy_y));
359 (void) ResetMagickMemory(&variance,0,sizeof(variance));
360 for (i=0; i < (ssize_t) number_grays; i++)
362 cooccurrence[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays,
363 sizeof(**cooccurrence));
364 Q[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(**Q));
365 if ((cooccurrence[i] == (ChannelStatistics *) NULL) ||
366 (Q[i] == (ChannelStatistics *) NULL))
368 (void) ResetMagickMemory(cooccurrence[i],0,number_grays*
369 sizeof(**cooccurrence));
370 (void) ResetMagickMemory(Q[i],0,number_grays*sizeof(**Q));
372 if (i < (ssize_t) number_grays)
374 for (i--; i >= 0; i--)
376 if (Q[i] != (ChannelStatistics *) NULL)
377 Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
378 if (cooccurrence[i] != (ChannelStatistics *) NULL)
379 cooccurrence[i]=(ChannelStatistics *)
380 RelinquishMagickMemory(cooccurrence[i]);
382 Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
383 cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
384 sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
385 density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
386 density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
387 density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
388 grays=(PixelPacket *) RelinquishMagickMemory(grays);
389 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
391 (void) ThrowMagickException(exception,GetMagickModule(),
392 ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
393 return(channel_features);
396 Initialize spatial dependence matrix.
399 image_view=AcquireVirtualCacheView(image);
400 for (y=0; y < (ssize_t) image->rows; y++)
402 register const Quantum
414 if (status == MagickFalse)
416 p=GetCacheViewVirtualPixels(image_view,-(ssize_t) distance,y,image->columns+
417 2*distance,distance+2,exception);
418 if (p == (const Quantum *) NULL)
423 p+=distance*GetPixelChannels(image);;
424 for (x=0; x < (ssize_t) image->columns; x++)
426 for (i=0; i < 4; i++)
434 Horizontal adjacency.
436 offset=(ssize_t) distance;
444 offset=(ssize_t) (image->columns+2*distance);
450 Right diagonal adjacency.
452 offset=(ssize_t) ((image->columns+2*distance)-distance);
458 Left diagonal adjacency.
460 offset=(ssize_t) ((image->columns+2*distance)+distance);
466 while (grays[u].red != ScaleQuantumToMap(GetPixelRed(image,p)))
468 while (grays[v].red != ScaleQuantumToMap(GetPixelRed(image,p+offset*GetPixelChannels(image))))
470 cooccurrence[u][v].direction[i].red++;
471 cooccurrence[v][u].direction[i].red++;
474 while (grays[u].green != ScaleQuantumToMap(GetPixelGreen(image,p)))
476 while (grays[v].green != ScaleQuantumToMap(GetPixelGreen(image,p+offset*GetPixelChannels(image))))
478 cooccurrence[u][v].direction[i].green++;
479 cooccurrence[v][u].direction[i].green++;
482 while (grays[u].blue != ScaleQuantumToMap(GetPixelBlue(image,p)))
484 while (grays[v].blue != ScaleQuantumToMap(GetPixelBlue(image,p+offset*GetPixelChannels(image))))
486 cooccurrence[u][v].direction[i].blue++;
487 cooccurrence[v][u].direction[i].blue++;
488 if (image->colorspace == CMYKColorspace)
492 while (grays[u].black != ScaleQuantumToMap(GetPixelBlack(image,p)))
494 while (grays[v].black != ScaleQuantumToMap(GetPixelBlack(image,p+offset*GetPixelChannels(image))))
496 cooccurrence[u][v].direction[i].black++;
497 cooccurrence[v][u].direction[i].black++;
499 if (image->alpha_trait == BlendPixelTrait)
503 while (grays[u].alpha != ScaleQuantumToMap(GetPixelAlpha(image,p)))
505 while (grays[v].alpha != ScaleQuantumToMap(GetPixelAlpha(image,p+offset*GetPixelChannels(image))))
507 cooccurrence[u][v].direction[i].alpha++;
508 cooccurrence[v][u].direction[i].alpha++;
511 p+=GetPixelChannels(image);
514 grays=(PixelPacket *) RelinquishMagickMemory(grays);
515 image_view=DestroyCacheView(image_view);
516 if (status == MagickFalse)
518 for (i=0; i < (ssize_t) number_grays; i++)
519 cooccurrence[i]=(ChannelStatistics *)
520 RelinquishMagickMemory(cooccurrence[i]);
521 cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
522 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
524 (void) ThrowMagickException(exception,GetMagickModule(),
525 ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
526 return(channel_features);
529 Normalize spatial dependence matrix.
531 for (i=0; i < 4; i++)
545 Horizontal adjacency.
547 normalize=2.0*image->rows*(image->columns-distance);
555 normalize=2.0*(image->rows-distance)*image->columns;
561 Right diagonal adjacency.
563 normalize=2.0*(image->rows-distance)*(image->columns-distance);
569 Left diagonal adjacency.
571 normalize=2.0*(image->rows-distance)*(image->columns-distance);
575 normalize=PerceptibleReciprocal(normalize);
576 for (y=0; y < (ssize_t) number_grays; y++)
581 for (x=0; x < (ssize_t) number_grays; x++)
583 cooccurrence[x][y].direction[i].red*=normalize;
584 cooccurrence[x][y].direction[i].green*=normalize;
585 cooccurrence[x][y].direction[i].blue*=normalize;
586 if (image->colorspace == CMYKColorspace)
587 cooccurrence[x][y].direction[i].black*=normalize;
588 if (image->alpha_trait == BlendPixelTrait)
589 cooccurrence[x][y].direction[i].alpha*=normalize;
594 Compute texture features.
596 #if defined(MAGICKCORE_OPENMP_SUPPORT)
597 #pragma omp parallel for schedule(static,4) shared(status) \
598 dynamic_number_threads(image,number_grays,number_grays,1)
600 for (i=0; i < 4; i++)
605 for (y=0; y < (ssize_t) number_grays; y++)
610 for (x=0; x < (ssize_t) number_grays; x++)
613 Angular second moment: measure of homogeneity of the image.
615 channel_features[RedPixelChannel].angular_second_moment[i]+=
616 cooccurrence[x][y].direction[i].red*
617 cooccurrence[x][y].direction[i].red;
618 channel_features[GreenPixelChannel].angular_second_moment[i]+=
619 cooccurrence[x][y].direction[i].green*
620 cooccurrence[x][y].direction[i].green;
621 channel_features[BluePixelChannel].angular_second_moment[i]+=
622 cooccurrence[x][y].direction[i].blue*
623 cooccurrence[x][y].direction[i].blue;
624 if (image->colorspace == CMYKColorspace)
625 channel_features[BlackPixelChannel].angular_second_moment[i]+=
626 cooccurrence[x][y].direction[i].black*
627 cooccurrence[x][y].direction[i].black;
628 if (image->alpha_trait == BlendPixelTrait)
629 channel_features[AlphaPixelChannel].angular_second_moment[i]+=
630 cooccurrence[x][y].direction[i].alpha*
631 cooccurrence[x][y].direction[i].alpha;
633 Correlation: measure of linear-dependencies in the image.
635 sum[y].direction[i].red+=cooccurrence[x][y].direction[i].red;
636 sum[y].direction[i].green+=cooccurrence[x][y].direction[i].green;
637 sum[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
638 if (image->colorspace == CMYKColorspace)
639 sum[y].direction[i].black+=cooccurrence[x][y].direction[i].black;
640 if (image->alpha_trait == BlendPixelTrait)
641 sum[y].direction[i].alpha+=cooccurrence[x][y].direction[i].alpha;
642 correlation.direction[i].red+=x*y*cooccurrence[x][y].direction[i].red;
643 correlation.direction[i].green+=x*y*
644 cooccurrence[x][y].direction[i].green;
645 correlation.direction[i].blue+=x*y*
646 cooccurrence[x][y].direction[i].blue;
647 if (image->colorspace == CMYKColorspace)
648 correlation.direction[i].black+=x*y*
649 cooccurrence[x][y].direction[i].black;
650 if (image->alpha_trait == BlendPixelTrait)
651 correlation.direction[i].alpha+=x*y*
652 cooccurrence[x][y].direction[i].alpha;
654 Inverse Difference Moment.
656 channel_features[RedPixelChannel].inverse_difference_moment[i]+=
657 cooccurrence[x][y].direction[i].red/((y-x)*(y-x)+1);
658 channel_features[GreenPixelChannel].inverse_difference_moment[i]+=
659 cooccurrence[x][y].direction[i].green/((y-x)*(y-x)+1);
660 channel_features[BluePixelChannel].inverse_difference_moment[i]+=
661 cooccurrence[x][y].direction[i].blue/((y-x)*(y-x)+1);
662 if (image->colorspace == CMYKColorspace)
663 channel_features[BlackPixelChannel].inverse_difference_moment[i]+=
664 cooccurrence[x][y].direction[i].black/((y-x)*(y-x)+1);
665 if (image->alpha_trait == BlendPixelTrait)
666 channel_features[AlphaPixelChannel].inverse_difference_moment[i]+=
667 cooccurrence[x][y].direction[i].alpha/((y-x)*(y-x)+1);
671 density_xy[y+x+2].direction[i].red+=
672 cooccurrence[x][y].direction[i].red;
673 density_xy[y+x+2].direction[i].green+=
674 cooccurrence[x][y].direction[i].green;
675 density_xy[y+x+2].direction[i].blue+=
676 cooccurrence[x][y].direction[i].blue;
677 if (image->colorspace == CMYKColorspace)
678 density_xy[y+x+2].direction[i].black+=
679 cooccurrence[x][y].direction[i].black;
680 if (image->alpha_trait == BlendPixelTrait)
681 density_xy[y+x+2].direction[i].alpha+=
682 cooccurrence[x][y].direction[i].alpha;
686 channel_features[RedPixelChannel].entropy[i]-=
687 cooccurrence[x][y].direction[i].red*
688 log10(cooccurrence[x][y].direction[i].red+MagickEpsilon);
689 channel_features[GreenPixelChannel].entropy[i]-=
690 cooccurrence[x][y].direction[i].green*
691 log10(cooccurrence[x][y].direction[i].green+MagickEpsilon);
692 channel_features[BluePixelChannel].entropy[i]-=
693 cooccurrence[x][y].direction[i].blue*
694 log10(cooccurrence[x][y].direction[i].blue+MagickEpsilon);
695 if (image->colorspace == CMYKColorspace)
696 channel_features[BlackPixelChannel].entropy[i]-=
697 cooccurrence[x][y].direction[i].black*
698 log10(cooccurrence[x][y].direction[i].black+MagickEpsilon);
699 if (image->alpha_trait == BlendPixelTrait)
700 channel_features[AlphaPixelChannel].entropy[i]-=
701 cooccurrence[x][y].direction[i].alpha*
702 log10(cooccurrence[x][y].direction[i].alpha+MagickEpsilon);
704 Information Measures of Correlation.
706 density_x[x].direction[i].red+=cooccurrence[x][y].direction[i].red;
707 density_x[x].direction[i].green+=cooccurrence[x][y].direction[i].green;
708 density_x[x].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
709 if (image->alpha_trait == BlendPixelTrait)
710 density_x[x].direction[i].alpha+=
711 cooccurrence[x][y].direction[i].alpha;
712 if (image->colorspace == CMYKColorspace)
713 density_x[x].direction[i].black+=
714 cooccurrence[x][y].direction[i].black;
715 density_y[y].direction[i].red+=cooccurrence[x][y].direction[i].red;
716 density_y[y].direction[i].green+=cooccurrence[x][y].direction[i].green;
717 density_y[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
718 if (image->colorspace == CMYKColorspace)
719 density_y[y].direction[i].black+=
720 cooccurrence[x][y].direction[i].black;
721 if (image->alpha_trait == BlendPixelTrait)
722 density_y[y].direction[i].alpha+=
723 cooccurrence[x][y].direction[i].alpha;
725 mean.direction[i].red+=y*sum[y].direction[i].red;
726 sum_squares.direction[i].red+=y*y*sum[y].direction[i].red;
727 mean.direction[i].green+=y*sum[y].direction[i].green;
728 sum_squares.direction[i].green+=y*y*sum[y].direction[i].green;
729 mean.direction[i].blue+=y*sum[y].direction[i].blue;
730 sum_squares.direction[i].blue+=y*y*sum[y].direction[i].blue;
731 if (image->colorspace == CMYKColorspace)
733 mean.direction[i].black+=y*sum[y].direction[i].black;
734 sum_squares.direction[i].black+=y*y*sum[y].direction[i].black;
736 if (image->alpha_trait == BlendPixelTrait)
738 mean.direction[i].alpha+=y*sum[y].direction[i].alpha;
739 sum_squares.direction[i].alpha+=y*y*sum[y].direction[i].alpha;
743 Correlation: measure of linear-dependencies in the image.
745 channel_features[RedPixelChannel].correlation[i]=
746 (correlation.direction[i].red-mean.direction[i].red*
747 mean.direction[i].red)/(sqrt(sum_squares.direction[i].red-
748 (mean.direction[i].red*mean.direction[i].red))*sqrt(
749 sum_squares.direction[i].red-(mean.direction[i].red*
750 mean.direction[i].red)));
751 channel_features[GreenPixelChannel].correlation[i]=
752 (correlation.direction[i].green-mean.direction[i].green*
753 mean.direction[i].green)/(sqrt(sum_squares.direction[i].green-
754 (mean.direction[i].green*mean.direction[i].green))*sqrt(
755 sum_squares.direction[i].green-(mean.direction[i].green*
756 mean.direction[i].green)));
757 channel_features[BluePixelChannel].correlation[i]=
758 (correlation.direction[i].blue-mean.direction[i].blue*
759 mean.direction[i].blue)/(sqrt(sum_squares.direction[i].blue-
760 (mean.direction[i].blue*mean.direction[i].blue))*sqrt(
761 sum_squares.direction[i].blue-(mean.direction[i].blue*
762 mean.direction[i].blue)));
763 if (image->colorspace == CMYKColorspace)
764 channel_features[BlackPixelChannel].correlation[i]=
765 (correlation.direction[i].black-mean.direction[i].black*
766 mean.direction[i].black)/(sqrt(sum_squares.direction[i].black-
767 (mean.direction[i].black*mean.direction[i].black))*sqrt(
768 sum_squares.direction[i].black-(mean.direction[i].black*
769 mean.direction[i].black)));
770 if (image->alpha_trait == BlendPixelTrait)
771 channel_features[AlphaPixelChannel].correlation[i]=
772 (correlation.direction[i].alpha-mean.direction[i].alpha*
773 mean.direction[i].alpha)/(sqrt(sum_squares.direction[i].alpha-
774 (mean.direction[i].alpha*mean.direction[i].alpha))*sqrt(
775 sum_squares.direction[i].alpha-(mean.direction[i].alpha*
776 mean.direction[i].alpha)));
779 Compute more texture features.
781 #if defined(MAGICKCORE_OPENMP_SUPPORT)
782 #pragma omp parallel for schedule(static,4) shared(status) \
783 dynamic_number_threads(image,number_grays,number_grays,1)
785 for (i=0; i < 4; i++)
790 for (x=2; x < (ssize_t) (2*number_grays); x++)
795 channel_features[RedPixelChannel].sum_average[i]+=
796 x*density_xy[x].direction[i].red;
797 channel_features[GreenPixelChannel].sum_average[i]+=
798 x*density_xy[x].direction[i].green;
799 channel_features[BluePixelChannel].sum_average[i]+=
800 x*density_xy[x].direction[i].blue;
801 if (image->colorspace == CMYKColorspace)
802 channel_features[BlackPixelChannel].sum_average[i]+=
803 x*density_xy[x].direction[i].black;
804 if (image->alpha_trait == BlendPixelTrait)
805 channel_features[AlphaPixelChannel].sum_average[i]+=
806 x*density_xy[x].direction[i].alpha;
810 channel_features[RedPixelChannel].sum_entropy[i]-=
811 density_xy[x].direction[i].red*
812 log10(density_xy[x].direction[i].red+MagickEpsilon);
813 channel_features[GreenPixelChannel].sum_entropy[i]-=
814 density_xy[x].direction[i].green*
815 log10(density_xy[x].direction[i].green+MagickEpsilon);
816 channel_features[BluePixelChannel].sum_entropy[i]-=
817 density_xy[x].direction[i].blue*
818 log10(density_xy[x].direction[i].blue+MagickEpsilon);
819 if (image->colorspace == CMYKColorspace)
820 channel_features[BlackPixelChannel].sum_entropy[i]-=
821 density_xy[x].direction[i].black*
822 log10(density_xy[x].direction[i].black+MagickEpsilon);
823 if (image->alpha_trait == BlendPixelTrait)
824 channel_features[AlphaPixelChannel].sum_entropy[i]-=
825 density_xy[x].direction[i].alpha*
826 log10(density_xy[x].direction[i].alpha+MagickEpsilon);
830 channel_features[RedPixelChannel].sum_variance[i]+=
831 (x-channel_features[RedPixelChannel].sum_entropy[i])*
832 (x-channel_features[RedPixelChannel].sum_entropy[i])*
833 density_xy[x].direction[i].red;
834 channel_features[GreenPixelChannel].sum_variance[i]+=
835 (x-channel_features[GreenPixelChannel].sum_entropy[i])*
836 (x-channel_features[GreenPixelChannel].sum_entropy[i])*
837 density_xy[x].direction[i].green;
838 channel_features[BluePixelChannel].sum_variance[i]+=
839 (x-channel_features[BluePixelChannel].sum_entropy[i])*
840 (x-channel_features[BluePixelChannel].sum_entropy[i])*
841 density_xy[x].direction[i].blue;
842 if (image->colorspace == CMYKColorspace)
843 channel_features[BlackPixelChannel].sum_variance[i]+=
844 (x-channel_features[BlackPixelChannel].sum_entropy[i])*
845 (x-channel_features[BlackPixelChannel].sum_entropy[i])*
846 density_xy[x].direction[i].black;
847 if (image->alpha_trait == BlendPixelTrait)
848 channel_features[AlphaPixelChannel].sum_variance[i]+=
849 (x-channel_features[AlphaPixelChannel].sum_entropy[i])*
850 (x-channel_features[AlphaPixelChannel].sum_entropy[i])*
851 density_xy[x].direction[i].alpha;
855 Compute more texture features.
857 #if defined(MAGICKCORE_OPENMP_SUPPORT)
858 #pragma omp parallel for schedule(static,4) shared(status) \
859 dynamic_number_threads(image,number_grays,number_grays,1)
861 for (i=0; i < 4; i++)
866 for (y=0; y < (ssize_t) number_grays; y++)
871 for (x=0; x < (ssize_t) number_grays; x++)
874 Sum of Squares: Variance
876 variance.direction[i].red+=(y-mean.direction[i].red+1)*
877 (y-mean.direction[i].red+1)*cooccurrence[x][y].direction[i].red;
878 variance.direction[i].green+=(y-mean.direction[i].green+1)*
879 (y-mean.direction[i].green+1)*cooccurrence[x][y].direction[i].green;
880 variance.direction[i].blue+=(y-mean.direction[i].blue+1)*
881 (y-mean.direction[i].blue+1)*cooccurrence[x][y].direction[i].blue;
882 if (image->colorspace == CMYKColorspace)
883 variance.direction[i].black+=(y-mean.direction[i].black+1)*
884 (y-mean.direction[i].black+1)*cooccurrence[x][y].direction[i].black;
885 if (image->alpha_trait == BlendPixelTrait)
886 variance.direction[i].alpha+=(y-mean.direction[i].alpha+1)*
887 (y-mean.direction[i].alpha+1)*
888 cooccurrence[x][y].direction[i].alpha;
890 Sum average / Difference Variance.
892 density_xy[MagickAbsoluteValue(y-x)].direction[i].red+=
893 cooccurrence[x][y].direction[i].red;
894 density_xy[MagickAbsoluteValue(y-x)].direction[i].green+=
895 cooccurrence[x][y].direction[i].green;
896 density_xy[MagickAbsoluteValue(y-x)].direction[i].blue+=
897 cooccurrence[x][y].direction[i].blue;
898 if (image->colorspace == CMYKColorspace)
899 density_xy[MagickAbsoluteValue(y-x)].direction[i].black+=
900 cooccurrence[x][y].direction[i].black;
901 if (image->alpha_trait == BlendPixelTrait)
902 density_xy[MagickAbsoluteValue(y-x)].direction[i].alpha+=
903 cooccurrence[x][y].direction[i].alpha;
905 Information Measures of Correlation.
907 entropy_xy.direction[i].red-=cooccurrence[x][y].direction[i].red*
908 log10(cooccurrence[x][y].direction[i].red+MagickEpsilon);
909 entropy_xy.direction[i].green-=cooccurrence[x][y].direction[i].green*
910 log10(cooccurrence[x][y].direction[i].green+MagickEpsilon);
911 entropy_xy.direction[i].blue-=cooccurrence[x][y].direction[i].blue*
912 log10(cooccurrence[x][y].direction[i].blue+MagickEpsilon);
913 if (image->colorspace == CMYKColorspace)
914 entropy_xy.direction[i].black-=cooccurrence[x][y].direction[i].black*
915 log10(cooccurrence[x][y].direction[i].black+MagickEpsilon);
916 if (image->alpha_trait == BlendPixelTrait)
917 entropy_xy.direction[i].alpha-=
918 cooccurrence[x][y].direction[i].alpha*log10(
919 cooccurrence[x][y].direction[i].alpha+MagickEpsilon);
920 entropy_xy1.direction[i].red-=(cooccurrence[x][y].direction[i].red*
921 log10(density_x[x].direction[i].red*density_y[y].direction[i].red+
923 entropy_xy1.direction[i].green-=(cooccurrence[x][y].direction[i].green*
924 log10(density_x[x].direction[i].green*density_y[y].direction[i].green+
926 entropy_xy1.direction[i].blue-=(cooccurrence[x][y].direction[i].blue*
927 log10(density_x[x].direction[i].blue*density_y[y].direction[i].blue+
929 if (image->colorspace == CMYKColorspace)
930 entropy_xy1.direction[i].black-=(
931 cooccurrence[x][y].direction[i].black*log10(
932 density_x[x].direction[i].black*density_y[y].direction[i].black+
934 if (image->alpha_trait == BlendPixelTrait)
935 entropy_xy1.direction[i].alpha-=(
936 cooccurrence[x][y].direction[i].alpha*log10(
937 density_x[x].direction[i].alpha*density_y[y].direction[i].alpha+
939 entropy_xy2.direction[i].red-=(density_x[x].direction[i].red*
940 density_y[y].direction[i].red*log10(density_x[x].direction[i].red*
941 density_y[y].direction[i].red+MagickEpsilon));
942 entropy_xy2.direction[i].green-=(density_x[x].direction[i].green*
943 density_y[y].direction[i].green*log10(density_x[x].direction[i].green*
944 density_y[y].direction[i].green+MagickEpsilon));
945 entropy_xy2.direction[i].blue-=(density_x[x].direction[i].blue*
946 density_y[y].direction[i].blue*log10(density_x[x].direction[i].blue*
947 density_y[y].direction[i].blue+MagickEpsilon));
948 if (image->colorspace == CMYKColorspace)
949 entropy_xy2.direction[i].black-=(density_x[x].direction[i].black*
950 density_y[y].direction[i].black*log10(
951 density_x[x].direction[i].black*density_y[y].direction[i].black+
953 if (image->alpha_trait == BlendPixelTrait)
954 entropy_xy2.direction[i].alpha-=(density_x[x].direction[i].alpha*
955 density_y[y].direction[i].alpha*log10(
956 density_x[x].direction[i].alpha*density_y[y].direction[i].alpha+
960 channel_features[RedPixelChannel].variance_sum_of_squares[i]=
961 variance.direction[i].red;
962 channel_features[GreenPixelChannel].variance_sum_of_squares[i]=
963 variance.direction[i].green;
964 channel_features[BluePixelChannel].variance_sum_of_squares[i]=
965 variance.direction[i].blue;
966 if (image->colorspace == CMYKColorspace)
967 channel_features[BlackPixelChannel].variance_sum_of_squares[i]=
968 variance.direction[i].black;
969 if (image->alpha_trait == BlendPixelTrait)
970 channel_features[AlphaPixelChannel].variance_sum_of_squares[i]=
971 variance.direction[i].alpha;
974 Compute more texture features.
976 (void) ResetMagickMemory(&variance,0,sizeof(variance));
977 (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares));
978 #if defined(MAGICKCORE_OPENMP_SUPPORT)
979 #pragma omp parallel for schedule(static,4) shared(status) \
980 dynamic_number_threads(image,number_grays,number_grays,1)
982 for (i=0; i < 4; i++)
987 for (x=0; x < (ssize_t) number_grays; x++)
992 variance.direction[i].red+=density_xy[x].direction[i].red;
993 variance.direction[i].green+=density_xy[x].direction[i].green;
994 variance.direction[i].blue+=density_xy[x].direction[i].blue;
995 if (image->colorspace == CMYKColorspace)
996 variance.direction[i].black+=density_xy[x].direction[i].black;
997 if (image->alpha_trait == BlendPixelTrait)
998 variance.direction[i].alpha+=density_xy[x].direction[i].alpha;
999 sum_squares.direction[i].red+=density_xy[x].direction[i].red*
1000 density_xy[x].direction[i].red;
1001 sum_squares.direction[i].green+=density_xy[x].direction[i].green*
1002 density_xy[x].direction[i].green;
1003 sum_squares.direction[i].blue+=density_xy[x].direction[i].blue*
1004 density_xy[x].direction[i].blue;
1005 if (image->colorspace == CMYKColorspace)
1006 sum_squares.direction[i].black+=density_xy[x].direction[i].black*
1007 density_xy[x].direction[i].black;
1008 if (image->alpha_trait == BlendPixelTrait)
1009 sum_squares.direction[i].alpha+=density_xy[x].direction[i].alpha*
1010 density_xy[x].direction[i].alpha;
1014 channel_features[RedPixelChannel].difference_entropy[i]-=
1015 density_xy[x].direction[i].red*
1016 log10(density_xy[x].direction[i].red+MagickEpsilon);
1017 channel_features[GreenPixelChannel].difference_entropy[i]-=
1018 density_xy[x].direction[i].green*
1019 log10(density_xy[x].direction[i].green+MagickEpsilon);
1020 channel_features[BluePixelChannel].difference_entropy[i]-=
1021 density_xy[x].direction[i].blue*
1022 log10(density_xy[x].direction[i].blue+MagickEpsilon);
1023 if (image->colorspace == CMYKColorspace)
1024 channel_features[BlackPixelChannel].difference_entropy[i]-=
1025 density_xy[x].direction[i].black*
1026 log10(density_xy[x].direction[i].black+MagickEpsilon);
1027 if (image->alpha_trait == BlendPixelTrait)
1028 channel_features[AlphaPixelChannel].difference_entropy[i]-=
1029 density_xy[x].direction[i].alpha*
1030 log10(density_xy[x].direction[i].alpha+MagickEpsilon);
1032 Information Measures of Correlation.
1034 entropy_x.direction[i].red-=(density_x[x].direction[i].red*
1035 log10(density_x[x].direction[i].red+MagickEpsilon));
1036 entropy_x.direction[i].green-=(density_x[x].direction[i].green*
1037 log10(density_x[x].direction[i].green+MagickEpsilon));
1038 entropy_x.direction[i].blue-=(density_x[x].direction[i].blue*
1039 log10(density_x[x].direction[i].blue+MagickEpsilon));
1040 if (image->colorspace == CMYKColorspace)
1041 entropy_x.direction[i].black-=(density_x[x].direction[i].black*
1042 log10(density_x[x].direction[i].black+MagickEpsilon));
1043 if (image->alpha_trait == BlendPixelTrait)
1044 entropy_x.direction[i].alpha-=(density_x[x].direction[i].alpha*
1045 log10(density_x[x].direction[i].alpha+MagickEpsilon));
1046 entropy_y.direction[i].red-=(density_y[x].direction[i].red*
1047 log10(density_y[x].direction[i].red+MagickEpsilon));
1048 entropy_y.direction[i].green-=(density_y[x].direction[i].green*
1049 log10(density_y[x].direction[i].green+MagickEpsilon));
1050 entropy_y.direction[i].blue-=(density_y[x].direction[i].blue*
1051 log10(density_y[x].direction[i].blue+MagickEpsilon));
1052 if (image->colorspace == CMYKColorspace)
1053 entropy_y.direction[i].black-=(density_y[x].direction[i].black*
1054 log10(density_y[x].direction[i].black+MagickEpsilon));
1055 if (image->alpha_trait == BlendPixelTrait)
1056 entropy_y.direction[i].alpha-=(density_y[x].direction[i].alpha*
1057 log10(density_y[x].direction[i].alpha+MagickEpsilon));
1060 Difference variance.
1062 channel_features[RedPixelChannel].difference_variance[i]=
1063 (((double) number_grays*number_grays*sum_squares.direction[i].red)-
1064 (variance.direction[i].red*variance.direction[i].red))/
1065 ((double) number_grays*number_grays*number_grays*number_grays);
1066 channel_features[GreenPixelChannel].difference_variance[i]=
1067 (((double) number_grays*number_grays*sum_squares.direction[i].green)-
1068 (variance.direction[i].green*variance.direction[i].green))/
1069 ((double) number_grays*number_grays*number_grays*number_grays);
1070 channel_features[BluePixelChannel].difference_variance[i]=
1071 (((double) number_grays*number_grays*sum_squares.direction[i].blue)-
1072 (variance.direction[i].blue*variance.direction[i].blue))/
1073 ((double) number_grays*number_grays*number_grays*number_grays);
1074 if (image->colorspace == CMYKColorspace)
1075 channel_features[BlackPixelChannel].difference_variance[i]=
1076 (((double) number_grays*number_grays*sum_squares.direction[i].black)-
1077 (variance.direction[i].black*variance.direction[i].black))/
1078 ((double) number_grays*number_grays*number_grays*number_grays);
1079 if (image->alpha_trait == BlendPixelTrait)
1080 channel_features[AlphaPixelChannel].difference_variance[i]=
1081 (((double) number_grays*number_grays*sum_squares.direction[i].alpha)-
1082 (variance.direction[i].alpha*variance.direction[i].alpha))/
1083 ((double) number_grays*number_grays*number_grays*number_grays);
1085 Information Measures of Correlation.
1087 channel_features[RedPixelChannel].measure_of_correlation_1[i]=
1088 (entropy_xy.direction[i].red-entropy_xy1.direction[i].red)/
1089 (entropy_x.direction[i].red > entropy_y.direction[i].red ?
1090 entropy_x.direction[i].red : entropy_y.direction[i].red);
1091 channel_features[GreenPixelChannel].measure_of_correlation_1[i]=
1092 (entropy_xy.direction[i].green-entropy_xy1.direction[i].green)/
1093 (entropy_x.direction[i].green > entropy_y.direction[i].green ?
1094 entropy_x.direction[i].green : entropy_y.direction[i].green);
1095 channel_features[BluePixelChannel].measure_of_correlation_1[i]=
1096 (entropy_xy.direction[i].blue-entropy_xy1.direction[i].blue)/
1097 (entropy_x.direction[i].blue > entropy_y.direction[i].blue ?
1098 entropy_x.direction[i].blue : entropy_y.direction[i].blue);
1099 if (image->colorspace == CMYKColorspace)
1100 channel_features[BlackPixelChannel].measure_of_correlation_1[i]=
1101 (entropy_xy.direction[i].black-entropy_xy1.direction[i].black)/
1102 (entropy_x.direction[i].black > entropy_y.direction[i].black ?
1103 entropy_x.direction[i].black : entropy_y.direction[i].black);
1104 if (image->alpha_trait == BlendPixelTrait)
1105 channel_features[AlphaPixelChannel].measure_of_correlation_1[i]=
1106 (entropy_xy.direction[i].alpha-entropy_xy1.direction[i].alpha)/
1107 (entropy_x.direction[i].alpha > entropy_y.direction[i].alpha ?
1108 entropy_x.direction[i].alpha : entropy_y.direction[i].alpha);
1109 channel_features[RedPixelChannel].measure_of_correlation_2[i]=
1110 (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].red-
1111 entropy_xy.direction[i].red)))));
1112 channel_features[GreenPixelChannel].measure_of_correlation_2[i]=
1113 (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].green-
1114 entropy_xy.direction[i].green)))));
1115 channel_features[BluePixelChannel].measure_of_correlation_2[i]=
1116 (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].blue-
1117 entropy_xy.direction[i].blue)))));
1118 if (image->colorspace == CMYKColorspace)
1119 channel_features[BlackPixelChannel].measure_of_correlation_2[i]=
1120 (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].black-
1121 entropy_xy.direction[i].black)))));
1122 if (image->alpha_trait == BlendPixelTrait)
1123 channel_features[AlphaPixelChannel].measure_of_correlation_2[i]=
1124 (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].alpha-
1125 entropy_xy.direction[i].alpha)))));
1128 Compute more texture features.
1130 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1131 #pragma omp parallel for schedule(static,4) shared(status) \
1132 dynamic_number_threads(image,number_grays,number_grays,1)
1134 for (i=0; i < 4; i++)
1139 for (z=0; z < (ssize_t) number_grays; z++)
1147 (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
1148 for (y=0; y < (ssize_t) number_grays; y++)
1153 for (x=0; x < (ssize_t) number_grays; x++)
1156 Contrast: amount of local variations present in an image.
1158 if (((y-x) == z) || ((x-y) == z))
1160 pixel.direction[i].red+=cooccurrence[x][y].direction[i].red;
1161 pixel.direction[i].green+=cooccurrence[x][y].direction[i].green;
1162 pixel.direction[i].blue+=cooccurrence[x][y].direction[i].blue;
1163 if (image->colorspace == CMYKColorspace)
1164 pixel.direction[i].black+=cooccurrence[x][y].direction[i].black;
1165 if (image->alpha_trait == BlendPixelTrait)
1166 pixel.direction[i].alpha+=
1167 cooccurrence[x][y].direction[i].alpha;
1170 Maximum Correlation Coefficient.
1172 Q[z][y].direction[i].red+=cooccurrence[z][x].direction[i].red*
1173 cooccurrence[y][x].direction[i].red/density_x[z].direction[i].red/
1174 density_y[x].direction[i].red;
1175 Q[z][y].direction[i].green+=cooccurrence[z][x].direction[i].green*
1176 cooccurrence[y][x].direction[i].green/
1177 density_x[z].direction[i].green/density_y[x].direction[i].red;
1178 Q[z][y].direction[i].blue+=cooccurrence[z][x].direction[i].blue*
1179 cooccurrence[y][x].direction[i].blue/density_x[z].direction[i].blue/
1180 density_y[x].direction[i].blue;
1181 if (image->colorspace == CMYKColorspace)
1182 Q[z][y].direction[i].black+=cooccurrence[z][x].direction[i].black*
1183 cooccurrence[y][x].direction[i].black/
1184 density_x[z].direction[i].black/density_y[x].direction[i].black;
1185 if (image->alpha_trait == BlendPixelTrait)
1186 Q[z][y].direction[i].alpha+=
1187 cooccurrence[z][x].direction[i].alpha*
1188 cooccurrence[y][x].direction[i].alpha/
1189 density_x[z].direction[i].alpha/
1190 density_y[x].direction[i].alpha;
1193 channel_features[RedPixelChannel].contrast[i]+=z*z*
1194 pixel.direction[i].red;
1195 channel_features[GreenPixelChannel].contrast[i]+=z*z*
1196 pixel.direction[i].green;
1197 channel_features[BluePixelChannel].contrast[i]+=z*z*
1198 pixel.direction[i].blue;
1199 if (image->colorspace == CMYKColorspace)
1200 channel_features[BlackPixelChannel].contrast[i]+=z*z*
1201 pixel.direction[i].black;
1202 if (image->alpha_trait == BlendPixelTrait)
1203 channel_features[AlphaPixelChannel].contrast[i]+=z*z*
1204 pixel.direction[i].alpha;
1207 Maximum Correlation Coefficient.
1208 Future: return second largest eigenvalue of Q.
1210 channel_features[RedPixelChannel].maximum_correlation_coefficient[i]=
1211 sqrt((double) -1.0);
1212 channel_features[GreenPixelChannel].maximum_correlation_coefficient[i]=
1213 sqrt((double) -1.0);
1214 channel_features[BluePixelChannel].maximum_correlation_coefficient[i]=
1215 sqrt((double) -1.0);
1216 if (image->colorspace == CMYKColorspace)
1217 channel_features[BlackPixelChannel].maximum_correlation_coefficient[i]=
1218 sqrt((double) -1.0);
1219 if (image->alpha_trait == BlendPixelTrait)
1220 channel_features[AlphaPixelChannel].maximum_correlation_coefficient[i]=
1221 sqrt((double) -1.0);
1224 Relinquish resources.
1226 sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
1227 for (i=0; i < (ssize_t) number_grays; i++)
1228 Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
1229 Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
1230 density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
1231 density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
1232 density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
1233 for (i=0; i < (ssize_t) number_grays; i++)
1234 cooccurrence[i]=(ChannelStatistics *)
1235 RelinquishMagickMemory(cooccurrence[i]);
1236 cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
1237 return(channel_features);