]> granicus.if.org Git - imagemagick/commitdiff
(no commit message)
authorcristy <urban-warrior@git.imagemagick.org>
Wed, 24 Nov 2010 18:54:42 +0000 (18:54 +0000)
committercristy <urban-warrior@git.imagemagick.org>
Wed, 24 Nov 2010 18:54:42 +0000 (18:54 +0000)
magick/compare.c
magick/compare.h
magick/option.c
wand/compare.c

index 24e7016149f9a633464c080d058ca9bd3ab54aa2..651beb17c2e97a405259130d30221acf99c9367c 100644 (file)
@@ -811,6 +811,114 @@ static MagickBooleanType GetMeanSquaredError(const Image *image,
   return(status);
 }
 
+static MagickBooleanType GetNormalizedCrossCorrelationError(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  ssize_t
+    y;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      channel_distortion[AllChannels+1];
+
+    register const IndexPacket
+      *restrict indexes,
+      *restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,
+      reconstruct_image->columns,1,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->red-(double) q->red);
+          channel_distortion[RedChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->green-(double) q->green);
+          channel_distortion[GreenChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*fabs(p->blue-(double) q->blue);
+          channel_distortion[BlueChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=QuantumScale*fabs(p->opacity-(double) q->opacity);
+          channel_distortion[OpacityChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*fabs(indexes[x]-(double)
+            reconstruct_indexes[x]);
+          channel_distortion[BlackChannel]+=distance;
+          channel_distortion[AllChannels]+=distance;
+        }
+      p++;
+      q++;
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetNormalizedCrossCorrelationError)
+#endif
+    for (i=0; i <= (ssize_t) AllChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  for (i=0; i <= (ssize_t) AllChannels; i++)
+    distortion[i]/=((double) image->columns*image->rows);
+  distortion[AllChannels]/=(double) GetNumberChannels(image,channel);
+  return(status);
+}
+
 static MagickBooleanType GetPeakAbsoluteError(const Image *image,
   const Image *reconstruct_image,const ChannelType channel,
   double *distortion,ExceptionInfo *exception)
@@ -1043,6 +1151,12 @@ MagickExport MagickBooleanType GetImageChannelDistortion(Image *image,
         channel_distortion,exception);
       break;
     }
+    case NormalizedCrossCorrelationErrorMetric:
+    {
+      status=GetNormalizedCrossCorrelationError(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
     case PeakAbsoluteErrorMetric:
     default:
     {
@@ -1164,6 +1278,12 @@ MagickExport double *GetImageChannelDistortions(Image *image,
         channel_distortion,exception);
       break;
     }
+    case NormalizedCrossCorrelationErrorMetric:
+    {
+      status=GetNormalizedCrossCorrelationError(image,reconstruct_image,
+        AllChannels,channel_distortion,exception);
+      break;
+    }
     case PeakAbsoluteErrorMetric:
     default:
     {
index e7486dc357e6fd44bf74bc58ff8445f2efd644f7..aa8070e28e05f0f2226fc7205b239b3fd1f4c812 100644 (file)
@@ -33,7 +33,8 @@ typedef enum
   MeanSquaredErrorMetric,
   PeakAbsoluteErrorMetric,
   PeakSignalToNoiseRatioMetric,
-  RootMeanSquaredErrorMetric
+  RootMeanSquaredErrorMetric,
+  NormalizedCrossCorrelationErrorMetric
 } MetricType;
 
 extern MagickExport double
index b16b9d1fcd73ad2f08f59f2f1e35f142ad81e1f4..62f30d37c2cc6023a8a0f7247341649d8c0e7bda 100644 (file)
@@ -1244,6 +1244,7 @@ static const OptionInfo
     { "MAE", (ssize_t) MeanAbsoluteErrorMetric, MagickFalse },
     { "MEPP", (ssize_t) MeanErrorPerPixelMetric, MagickFalse },
     { "MSE", (ssize_t) MeanSquaredErrorMetric, MagickFalse },
+    { "NCC", (ssize_t) NormalizedCrossCorrelationErrorMetric, MagickFalse },
     { "PAE", (ssize_t) PeakAbsoluteErrorMetric, MagickFalse },
     { "PSNR", (ssize_t) PeakSignalToNoiseRatioMetric, MagickFalse },
     { "RMSE", (ssize_t) RootMeanSquaredErrorMetric, MagickFalse },
index cb106405237391ef3aec3b25b2a141bb6c35f6de..04981976cc23f7503a4c5dc97741f850cb75f4ff 100644 (file)
@@ -1011,6 +1011,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
               break;
             }
             case AbsoluteErrorMetric:
+            case NormalizedCrossCorrelationErrorMetric:
             case PeakSignalToNoiseRatioMetric:
             {
               (void) fprintf(stderr,"%g",distortion);
@@ -1116,6 +1117,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
               break;
             }
             case AbsoluteErrorMetric:
+            case NormalizedCrossCorrelationErrorMetric:
             case PeakSignalToNoiseRatioMetric:
             {
               switch (image->colorspace)