]> granicus.if.org Git - imagemagick/commitdiff
Support -define phash:colorspaces option
authorCristy <urban-warrior@imagemagick.org>
Sat, 3 Sep 2016 01:09:38 +0000 (21:09 -0400)
committerCristy <urban-warrior@imagemagick.org>
Sat, 3 Sep 2016 01:11:55 +0000 (21:11 -0400)
MagickCore/identify.c
MagickCore/statistic.c
MagickCore/statistic.h

index 6e7c888170e62a02f6012ba1eb80e08a27c59f61..1071353411936bf2e22565cd497a29d86f39626d 100644 (file)
@@ -383,8 +383,8 @@ static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel,
   return(n);
 }
 
-static ssize_t PrintChannelPerceptualHash(FILE *file,const PixelChannel channel,
-  const char *name,const ChannelPerceptualHash *channel_phash)
+static ssize_t PrintChannelPerceptualHash(Image *image,FILE *file,
+  const ChannelPerceptualHash *channel_phash)
 {
   register ssize_t
     i;
@@ -392,11 +392,104 @@ static ssize_t PrintChannelPerceptualHash(FILE *file,const PixelChannel channel,
   ssize_t
     n;
 
-  n=FormatLocaleFile(file,"    %s:\n",name);
-  for (i=0; i < MaximumNumberOfPerceptualHashes; i++)
-    n+=FormatLocaleFile(file,"      PH%.20g: %.*g, %.*g\n",i+1.0,
-      GetMagickPrecision(),channel_phash[channel].srgb_hu_phash[i],
-      GetMagickPrecision(),channel_phash[channel].hclp_hu_phash[i]);
+  (void) FormatLocaleFile(file,"  Channel perceptual hash: ");
+  for (i=0; i < (ssize_t) channel_phash[0].number_colorspaces; i++)
+  {
+    (void) FormatLocaleFile(file,"%s",CommandOptionToMnemonic(
+      MagickColorspaceOptions,(ssize_t) channel_phash[0].colorspace[i]));
+    if (i < (ssize_t) (channel_phash[0].number_colorspaces-1))
+      (void) FormatLocaleFile(file,", ");
+  }
+  (void) FormatLocaleFile(file,"\n");
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  {
+    const char
+      *name;
+
+    register ssize_t
+      j;
+
+    PixelChannel channel=GetPixelChannelChannel(image,i);
+    PixelTrait traits=GetPixelChannelTraits(image,channel);
+    if (traits == UndefinedPixelTrait)
+      continue;
+    switch (channel)
+    {
+      case RedPixelChannel:
+      {
+        name="Red";
+        if (image->colorspace == CMYKColorspace)
+          name="Cyan";
+        if (image->colorspace == GRAYColorspace)
+          name="Gray";
+        break;
+      }
+      case GreenPixelChannel:
+      {
+        name="Green";
+        if (image->colorspace == CMYKColorspace)
+          name="Magenta";
+        break;
+      }
+      case BluePixelChannel:
+      {
+        name="Blue";
+        if (image->colorspace == CMYKColorspace)
+          name="Yellow";
+        break;
+      }
+      case BlackPixelChannel:
+      {
+        name="Black";
+        if (image->storage_class == PseudoClass)
+          name="Index";
+        break;
+      }
+      case IndexPixelChannel:
+      {
+        name="Index";
+        break;
+      }
+      case AlphaPixelChannel:
+      {
+        name="Alpha";
+        break;
+      }
+      case ReadMaskPixelChannel:
+      {
+        name="ReadMask";
+        break;
+      }
+      case WriteMaskPixelChannel:
+      {
+        name="WriteMask";
+        break;
+      }
+      case MetaPixelChannel:
+      {
+        name="Meta";
+        break;
+      }
+      default:
+        name="Undefined";
+    }
+    n=FormatLocaleFile(file,"    %s:\n",name);
+    for (j=0; j < MaximumNumberOfPerceptualHashes; j++)
+    {
+      register ssize_t
+        k;
+
+      n+=FormatLocaleFile(file,"      PH%.20g: ",(double) j+1);
+      for (k=0; k < (ssize_t) channel_phash[0].number_colorspaces; k++)
+      {
+        n+=FormatLocaleFile(file,"%.*g",GetMagickPrecision(),
+          channel_phash[channel].phash[k][j]);
+        if (k < (ssize_t) (channel_phash[0].number_colorspaces-1))
+          n+=FormatLocaleFile(file,", ");
+      }
+      n+=FormatLocaleFile(file,"\n");
+    }
+  }
   return(n);
 }
 
@@ -763,8 +856,8 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
           channel_statistics[AlphaPixelChannel].depth);
       scale=1.0;
       if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
-        scale=(double) QuantumRange/((size_t) QuantumRange >> ((size_t)
-          MAGICKCORE_QUANTUM_DEPTH-image->depth));
+        scale=(double) (QuantumRange/((size_t) QuantumRange >> ((size_t)
+          MAGICKCORE_QUANTUM_DEPTH-image->depth)));
     }
   if (channel_statistics != (ChannelStatistics *) NULL)
     {
@@ -865,16 +958,7 @@ MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
     }
   if (channel_phash != (ChannelPerceptualHash *) NULL)
     {
-      (void) FormatLocaleFile(file,"  Channel perceptual hash:\n");
-      (void) PrintChannelPerceptualHash(file,RedPixelChannel,"Red, Hue",
-        channel_phash);
-      (void) PrintChannelPerceptualHash(file,GreenPixelChannel,"Green, Chroma",
-        channel_phash);
-      (void) PrintChannelPerceptualHash(file,BluePixelChannel,"Blue, Luma",
-        channel_phash);
-      if (image->alpha_trait != UndefinedPixelTrait)
-        (void) PrintChannelPerceptualHash(file,AlphaPixelChannel,"Alpha, Alpha",
-          channel_phash);
+      (void) PrintChannelPerceptualHash(image,file,channel_phash);
       channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(
         channel_phash);
     }
index 99e9821887bc8d7b00893c70bad118d57c48597f..d74f9c4f70a516670f2d24bd33493931ad5554f5 100644 (file)
@@ -41,9 +41,9 @@
   Include declarations.
 */
 #include "MagickCore/studio.h"
-#include "MagickCore/property.h"
 #include "MagickCore/accelerate-private.h"
 #include "MagickCore/animate.h"
+#include "MagickCore/artifact.h"
 #include "MagickCore/blob.h"
 #include "MagickCore/blob-private.h"
 #include "MagickCore/cache.h"
@@ -78,6 +78,7 @@
 #include "MagickCore/paint.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/profile.h"
+#include "MagickCore/property.h"
 #include "MagickCore/quantize.h"
 #include "MagickCore/quantum-private.h"
 #include "MagickCore/random_.h"
@@ -1772,86 +1773,85 @@ static inline double MagickLog10(const double x)
 {
 #define Log10Epsilon  (1.0e-11)
 
- if (fabs(x) < Log10Epsilon)
-   return(log10(Log10Epsilon));
- return(log10(fabs(x)));
 if (fabs(x) < Log10Epsilon)
+    return(log10(Log10Epsilon));
 return(log10(fabs(x)));
 }
 
-MagickExport ChannelPerceptualHash *GetImagePerceptualHash(
-  const Image *image,ExceptionInfo *exception)
+MagickExport ChannelPerceptualHash *GetImagePerceptualHash(const Image *image,
+  ExceptionInfo *exception)
 {
-  ChannelMoments
-    *moments;
-
   ChannelPerceptualHash
     *perceptual_hash;
 
-  Image
-    *hash_image;
+  char
+    *colorspaces,
+    *q;
+
+  const char
+    *artifact;
 
   MagickBooleanType
     status;
 
+  register char
+    *p;
+
   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(
     MaxPixelChannels+1UL,sizeof(*perceptual_hash));
   if (perceptual_hash == (ChannelPerceptualHash *) NULL)
     return((ChannelPerceptualHash *) NULL);
-  for (channel=0; channel <= MaxPixelChannels; channel++)
-    for (i=0; i < MaximumNumberOfImageMoments; i++)
-      perceptual_hash[channel].srgb_hu_phash[i]=
-        (-MagickLog10(moments[channel].invariant[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 < MaximumNumberOfImageMoments; i++)
-      perceptual_hash[channel].hclp_hu_phash[i]=
-        (-MagickLog10(moments[channel].invariant[i]));
-  moments=(ChannelMoments *) RelinquishMagickMemory(moments);
+  artifact=GetImageArtifact(image,"phash:colorspaces");
+  if (artifact != NULL)
+    colorspaces=AcquireString(artifact);
+  else
+    colorspaces=AcquireString("sRGB,HCLp");
+  q=colorspaces;
+  for (i=0; (p=StringToken(",",&q)) != (char *) NULL; i++)
+  {
+    ChannelMoments
+      *moments;
+
+    Image
+      *hash_image;
+
+
+    size_t
+      j;
+
+    ssize_t
+      channel,
+      colorspace;
+
+    if (i >= MaximumNumberOfPerceptualColorspaces)
+      break;
+    colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,p);
+    if (colorspace < 0)
+      break;
+    perceptual_hash[0].colorspace[i]=(ColorspaceType) colorspace;
+    hash_image=BlurImage(image,0.0,1.0,exception);
+    if (hash_image == (Image *) NULL)
+      break;
+    hash_image->depth=8;
+    status=TransformImageColorspace(hash_image,(ColorspaceType) colorspace,
+      exception);
+    if (status == MagickFalse)
+      break;
+    moments=GetImageMoments(hash_image,exception);
+    hash_image=DestroyImage(hash_image);
+    if (moments == (ChannelMoments *) NULL)
+      break;
+    for (channel=0; channel <= MaxPixelChannels; channel++)
+      for (j=0; j < MaximumNumberOfImageMoments; j++)
+        perceptual_hash[channel].phash[i][j]=
+          (-MagickLog10(moments[channel].invariant[j]));
+    moments=(ChannelMoments *) RelinquishMagickMemory(moments);
+  }
+  perceptual_hash[0].number_colorspaces=(size_t) i;
+  colorspaces=DestroyString(colorspaces);
   return(perceptual_hash);
 }
 \f
index 2bf63ae5bbc8f579b5c398a25ffdb4832164cecb..23fa9457155346d96813ab4da9ce787b1fe57293 100644 (file)
@@ -23,6 +23,7 @@ extern "C" {
 #endif
 
 #define MaximumNumberOfImageMoments  8
+#define MaximumNumberOfPerceptualColorspaces  6
 #define MaximumNumberOfPerceptualHashes  7
 
 typedef struct _ChannelStatistics
@@ -49,7 +50,7 @@ typedef struct _ChannelStatistics
 typedef struct _ChannelMoments
 {
   double
-     invariant[MaximumNumberOfImageMoments+1];
+    invariant[MaximumNumberOfImageMoments+1];
 
   PointInfo
     centroid,
@@ -66,6 +67,15 @@ typedef struct _ChannelPerceptualHash
   double
     srgb_hu_phash[MaximumNumberOfImageMoments+1],
     hclp_hu_phash[MaximumNumberOfImageMoments+1];
+
+  size_t
+    number_colorspaces;
+
+  ColorspaceType
+    colorspace[MaximumNumberOfPerceptualColorspaces+1];
+
+  double
+    phash[MaximumNumberOfPerceptualColorspaces+1][MaximumNumberOfImageMoments+1];
 } ChannelPerceptualHash;
 
 typedef enum