return(status);
}
-static Image *PerceptualImageHash(const Image *image,
- const ColorspaceType colorspace,ExceptionInfo *exception)
-{
- Image
- *phash_image;
-
- MagickBooleanType
- status;
-
- /*
- Transform colorspace then blur perceptual hash image.
- */
- phash_image=BlurImage(image,0.0,1.0,exception);
- if (phash_image == (Image *) NULL)
- return((Image *) NULL);
- phash_image->depth=8;
- status=TransformImageColorspace(phash_image,colorspace,exception);
- if (status == MagickFalse)
- phash_image=DestroyImage(phash_image);
- return(phash_image);
-}
-
static MagickBooleanType GetPerceptualHashDistortion(const Image *image,
const Image *reconstruct_image,double *distortion,ExceptionInfo *exception)
{
- ChannelMoments
- *image_moments,
- *reconstruct_moments;
-
- Image
- *phash_image;
-
- MagickBooleanType
- grayscale;
+ ChannelPerceptualHash
+ *image_phash,
+ *reconstruct_phash;
ssize_t
channel;
/*
- Compute perceptual hash in the native image colorspace.
+ Compute perceptual hash in the sRGB colorspace.
*/
- phash_image=PerceptualImageHash(image,image->colorspace,exception);
- if (phash_image == (Image *) NULL)
+ image_phash=GetImageChannelPerceptualHash(image,exception);
+ if (image_phash == (ChannelPerceptualHash *) NULL)
return(MagickFalse);
- image_moments=GetImageMoments(phash_image,exception);
- phash_image=DestroyImage(phash_image);
- if (image_moments == (ChannelMoments *) NULL)
- return(MagickFalse);
- phash_image=PerceptualImageHash(reconstruct_image,
- reconstruct_image->colorspace,exception);
- if (phash_image == (Image *) NULL)
- {
- image_moments=(ChannelMoments *) RelinquishMagickMemory(image_moments);
- return(MagickFalse);
- }
- reconstruct_moments=GetImageMoments(phash_image,exception);
- phash_image=DestroyImage(phash_image);
- if (reconstruct_moments == (ChannelMoments *) NULL)
+ reconstruct_phash=GetImageChannelPerceptualHash(reconstruct_image,exception);
+ if (image_phash == (ChannelPerceptualHash *) NULL)
{
- image_moments=(ChannelMoments *) RelinquishMagickMemory(image_moments);
+ image_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(image_phash);
return(MagickFalse);
}
- /*
- Compute sum of moment differences squared.
- */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp parallel for schedule(static,4)
#endif
alpha,
beta;
- alpha=MagickLog10(image_moments[channel].I[i]);
- beta=MagickLog10(reconstruct_moments[channel].I[i]);
+ alpha=image_phash[channel].P[i];
+ beta=reconstruct_phash[channel].P[i];
difference+=(beta-alpha)*(beta-alpha);
}
distortion[channel]+=difference;
#endif
distortion[CompositePixelChannel]+=difference;
}
- image_moments=(ChannelMoments *) RelinquishMagickMemory(image_moments);
- reconstruct_moments=(ChannelMoments *) RelinquishMagickMemory(
- reconstruct_moments);
- grayscale=(IsImageGray(image,exception) != MagickFalse) &&
- (IsImageGray(reconstruct_image,exception) != MagickFalse) ? MagickTrue :
- MagickFalse;
- if (grayscale != MagickFalse)
- return(MagickTrue);
/*
Compute perceptual hash in the HCLP colorspace.
*/
- phash_image=PerceptualImageHash(image,HCLpColorspace,exception);
- if (phash_image == (Image *) NULL)
- return(MagickFalse);
- image_moments=GetImageMoments(phash_image,exception);
- phash_image=DestroyImage(phash_image);
- if (image_moments == (ChannelMoments *) NULL)
- return(MagickFalse);
- phash_image=PerceptualImageHash(reconstruct_image,HCLpColorspace,exception);
- if (phash_image == (Image *) NULL)
- {
- image_moments=(ChannelMoments *) RelinquishMagickMemory(image_moments);
- return(MagickFalse);
- }
- reconstruct_moments=GetImageMoments(phash_image,exception);
- phash_image=DestroyImage(phash_image);
- if (reconstruct_moments == (ChannelMoments *) NULL)
- {
- image_moments=(ChannelMoments *) RelinquishMagickMemory(image_moments);
- return(MagickFalse);
- }
- /*
- Compute sum of moment differences squared.
- */
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp parallel for schedule(static,4)
#endif
alpha,
beta;
- alpha=MagickLog10(image_moments[channel].I[i]);
- beta=MagickLog10(reconstruct_moments[channel].I[i]);
+ alpha=image_phash[channel].Q[i];
+ beta=reconstruct_phash[channel].Q[i];
difference+=(beta-alpha)*(beta-alpha);
}
distortion[channel]+=difference;
#endif
distortion[CompositePixelChannel]+=difference;
}
- image_moments=(ChannelMoments *) RelinquishMagickMemory(image_moments);
- reconstruct_moments=(ChannelMoments *) RelinquishMagickMemory(
- reconstruct_moments);
+ /*
+ Free resources.
+ */
+ reconstruct_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(
+ reconstruct_phash);
+ image_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(image_phash);
return(MagickTrue);
}
+
static MagickBooleanType GetRootMeanSquaredDistortion(const Image *image,
const Image *reconstruct_image,double *distortion,ExceptionInfo *exception)
{
% %
% %
% %
+% 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 %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% GetImageChannelPerceptualHash() returns the perceptual hash of one or more
+% image channels.
+%
+% The format of the GetImageChannelPerceptualHash method is:
+%
+% ChannelPerceptualHash *GetImageChannelPerceptualHash(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 *GetImageChannelPerceptualHash(
+ 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 %
% %
% %