From 4c929a72206e38c57b9c452f0e5f302223ed089f Mon Sep 17 00:00:00 2001 From: cristy Date: Wed, 24 Nov 2010 18:54:42 +0000 Subject: [PATCH] --- magick/compare.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++ magick/compare.h | 3 +- magick/option.c | 1 + wand/compare.c | 2 + 4 files changed, 125 insertions(+), 1 deletion(-) diff --git a/magick/compare.c b/magick/compare.c index 24e701614..651beb17c 100644 --- a/magick/compare.c +++ b/magick/compare.c @@ -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: { diff --git a/magick/compare.h b/magick/compare.h index e7486dc35..aa8070e28 100644 --- a/magick/compare.h +++ b/magick/compare.h @@ -33,7 +33,8 @@ typedef enum MeanSquaredErrorMetric, PeakAbsoluteErrorMetric, PeakSignalToNoiseRatioMetric, - RootMeanSquaredErrorMetric + RootMeanSquaredErrorMetric, + NormalizedCrossCorrelationErrorMetric } MetricType; extern MagickExport double diff --git a/magick/option.c b/magick/option.c index b16b9d1fc..62f30d37c 100644 --- a/magick/option.c +++ b/magick/option.c @@ -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 }, diff --git a/wand/compare.c b/wand/compare.c index cb1064052..04981976c 100644 --- a/wand/compare.c +++ b/wand/compare.c @@ -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) -- 2.50.1