if ((traits & UpdatePixelTrait) == 0)
continue;
M00[channel]+=QuantumScale*p[i];
+ M00[MaxPixelChannels]+=QuantumScale*p[i];
M10[channel]+=x*QuantumScale*p[i];
+ M10[MaxPixelChannels]+=QuantumScale*p[i];
M01[channel]+=y*QuantumScale*p[i];
+ M01[MaxPixelChannels]+=QuantumScale*p[i];
}
p+=GetPixelChannels(image);
}
continue;
M11[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
QuantumScale*p[i];
+ M11[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
+ QuantumScale*p[i];
M20[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
QuantumScale*p[i];
+ M20[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
+ QuantumScale*p[i];
M02[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
QuantumScale*p[i];
+ M02[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
+ QuantumScale*p[i];
M21[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
(y-centroid[channel].y)*QuantumScale*p[i];
+ M21[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
+ (y-centroid[channel].y)*QuantumScale*p[i];
M12[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
(y-centroid[channel].y)*QuantumScale*p[i];
+ M12[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
+ (y-centroid[channel].y)*QuantumScale*p[i];
M22[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
(y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*p[i];
+ M22[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
+ (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*p[i];
M30[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
(x-centroid[channel].x)*QuantumScale*p[i];
+ M30[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
+ (x-centroid[channel].x)*QuantumScale*p[i];
M03[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
(y-centroid[channel].y)*QuantumScale*p[i];
+ M03[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
+ (y-centroid[channel].y)*QuantumScale*p[i];
}
p+=GetPixelChannels(image);
}
}
+ M00[MaxPixelChannels]/=GetPixelChannels(image);
+ M01[MaxPixelChannels]/=GetPixelChannels(image);
+ M02[MaxPixelChannels]/=GetPixelChannels(image);
+ M03[MaxPixelChannels]/=GetPixelChannels(image);
+ M10[MaxPixelChannels]/=GetPixelChannels(image);
+ M11[MaxPixelChannels]/=GetPixelChannels(image);
+ M12[MaxPixelChannels]/=GetPixelChannels(image);
+ M20[MaxPixelChannels]/=GetPixelChannels(image);
+ M21[MaxPixelChannels]/=GetPixelChannels(image);
+ M22[MaxPixelChannels]/=GetPixelChannels(image);
+ M30[MaxPixelChannels]/=GetPixelChannels(image);
for (channel=0; channel <= MaxPixelChannels; channel++)
{
/*
% %
% %
% %
+% G e t I m a g e C h a n n e l P e r c e p t u a l H a s h %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% GetImagePerceptualHash() returns the perceptual hash of one or more
+% image channels.
+%
+% The format of the GetImagePerceptualHash method is:
+%
+% ChannelPerceptualHash *GetImagePerceptualHash(const Image *image,
+% ExceptionInfo *exception)
+%
+% A description of each parameter follows:
+%
+% o image: the image.
+%
+% o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline double MagickLog10(const double x)
+{
+#define Log10Epsilon (1.0e-11)
+
+ if (fabs(x) < Log10Epsilon)
+ return(log10(Log10Epsilon));
+ return(log10(fabs(x)));
+}
+
+MagickExport ChannelPerceptualHash *GetImagePerceptualHash(
+ const Image *image,ExceptionInfo *exception)
+{
+ ChannelMoments
+ *moments;
+
+ ChannelPerceptualHash
+ *perceptual_hash;
+
+ Image
+ *hash_image;
+
+ MagickBooleanType
+ status;
+
+ register ssize_t
+ i;
+
+ ssize_t
+ channel;
+
+ /*
+ Blur then transform to sRGB colorspace.
+ */
+ hash_image=BlurImage(image,0.0,1.0,exception);
+ if (hash_image == (Image *) NULL)
+ return((ChannelPerceptualHash *) NULL);
+ hash_image->depth=8;
+ status=TransformImageColorspace(hash_image,sRGBColorspace,exception);
+ if (status == MagickFalse)
+ return((ChannelPerceptualHash *) NULL);
+ moments=GetImageMoments(hash_image,exception);
+ hash_image=DestroyImage(hash_image);
+ if (moments == (ChannelMoments *) NULL)
+ return((ChannelPerceptualHash *) NULL);
+ perceptual_hash=(ChannelPerceptualHash *) AcquireQuantumMemory(
+ CompositeChannels+1UL,sizeof(*perceptual_hash));
+ if (perceptual_hash == (ChannelPerceptualHash *) NULL)
+ return((ChannelPerceptualHash *) NULL);
+ for (channel=0; channel <= MaxPixelChannels; channel++)
+ for (i=0; i < 7; i++)
+ perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
+ moments=(ChannelMoments *) RelinquishMagickMemory(moments);
+ /*
+ Blur then transform to HCLp colorspace.
+ */
+ hash_image=BlurImage(image,0.0,1.0,exception);
+ if (hash_image == (Image *) NULL)
+ {
+ perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
+ perceptual_hash);
+ return((ChannelPerceptualHash *) NULL);
+ }
+ hash_image->depth=8;
+ status=TransformImageColorspace(hash_image,HCLpColorspace,exception);
+ if (status == MagickFalse)
+ {
+ perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
+ perceptual_hash);
+ return((ChannelPerceptualHash *) NULL);
+ }
+ moments=GetImageMoments(hash_image,exception);
+ hash_image=DestroyImage(hash_image);
+ if (moments == (ChannelMoments *) NULL)
+ {
+ perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
+ perceptual_hash);
+ return((ChannelPerceptualHash *) NULL);
+ }
+ for (channel=0; channel <= MaxPixelChannels; channel++)
+ for (i=0; i < 7; i++)
+ perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
+ moments=(ChannelMoments *) RelinquishMagickMemory(moments);
+ return(perceptual_hash);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
% G e t I m a g e R a n g e %
% %
% %