/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t I m a g e D i s t o r t i o n % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetImageDistortion() updates a distortion parameter with the distortion % (error) computed according to the specified comparison metric. The value % returned reflects all enabled channels. % % The format of the GetImageDistortion method is: % % MagickPassFail GetImageDistortion(const Image *reference_image, % const Image *compare_image, % const MetricType metric, % double *distortion, % ExceptionInfo *exception) % % A description of each parameter follows: % % o reference_image: the reference image. % % o compare_image: the comparison image. % % o channel: the channel to obtain error data for. % % o metric: metric to use when differencing. % % o distortion: updated with the computed distortion. % % o exception: Return any errors or warnings in this structure. % */ MagickExport MagickPassFail GetImageDistortion(const Image *reference_image, const Image *compare_image, const MetricType metric, double *distortion, ExceptionInfo *exception) { return GetImageChannelDistortion(reference_image,compare_image,AllChannels, metric,distortion,exception); }
MagickExport MagickBooleanType GetImageDistortion(Image *image, const Image *reconstruct_image,const MetricType metric,double *distortion, ExceptionInfo *exception) { MagickBooleanType status; status=GetImageChannelDistortion(image,reconstruct_image,AllChannels, metric,distortion,exception); return(status); }
MagickExport Image *CompareImageChannels(Image *image, const Image *reconstruct_image,const ChannelType channel, const MetricType metric,double *distortion,ExceptionInfo *exception) { Image *difference_image; long y; MagickPixelPacket composite, red, source, white; MagickStatusType difference; register const IndexPacket *indexes, *reconstruct_indexes; register const PixelPacket *p, *q; register IndexPacket *difference_indexes; register long x; register PixelPacket *r; ViewInfo *difference_view, *image_view, *reconstruct_view; assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(reconstruct_image != (const Image *) NULL); assert(reconstruct_image->signature == MagickSignature); assert(distortion != (double *) NULL); *distortion=0.0; if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); if ((reconstruct_image->columns != image->columns) || (reconstruct_image->rows != image->rows)) ThrowImageException(ImageError,"ImageSizeDiffers"); difference_image=CloneImage(image,image->columns,image->rows,MagickTrue, exception); if (difference_image == (Image *) NULL) return((Image *) NULL); if (SetImageStorageClass(difference_image,DirectClass) == MagickFalse) { InheritException(exception,&difference_image->exception); difference_image=DestroyImage(difference_image); return((Image *) NULL); } (void) QueryMagickColor("#f1001e",&red,exception); (void) QueryMagickColor("#ffffff",&white,exception); if (difference_image->colorspace == CMYKColorspace) { ConvertRGBToCMYK(&red); ConvertRGBToCMYK(&white); } /* Generate difference image. */ GetMagickPixelPacket(reconstruct_image,&source); GetMagickPixelPacket(difference_image,&composite); image_view=OpenCacheView(image); reconstruct_view=OpenCacheView(reconstruct_image); difference_view=OpenCacheView(difference_image); for (y=0; y < (long) image->rows; y++) { p=AcquireCacheViewPixels(image_view,0,y,image->columns,1,exception); q=AcquireCacheViewPixels(reconstruct_view,0,y,reconstruct_image->columns,1, exception); r=SetCacheView(difference_view,0,y,difference_image->columns,1); if ((p == (const PixelPacket *) NULL) || (q == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL)) break; indexes=AcquireCacheViewIndexes(image_view); reconstruct_indexes=AcquireCacheViewIndexes(reconstruct_view); difference_indexes=GetCacheViewIndexes(difference_view); for (x=0; x < (long) image->columns; x++) { difference=MagickFalse; if ((channel & RedChannel) != 0) if (p->red != q->red) difference=MagickTrue; if ((channel & GreenChannel) != 0) if (p->green != q->green) difference=MagickTrue; if ((channel & BlueChannel) != 0) if (p->blue != q->blue) difference=MagickTrue; if ((channel & OpacityChannel) != 0) if (p->opacity != q->opacity) difference=MagickTrue; if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace) && (reconstruct_image->colorspace == CMYKColorspace)) if (indexes[x] != reconstruct_indexes[x]) difference=MagickTrue; SetMagickPixelPacket(reconstruct_image,q,reconstruct_indexes+x,&source); if (difference != MagickFalse) MagickPixelCompositeOver(&source,7.5*QuantumRange/10.0,&red, (MagickRealType) red.opacity,&composite); else MagickPixelCompositeOver(&source,7.5*QuantumRange/10.0,&white, (MagickRealType) white.opacity,&composite); SetPixelPacket(difference_image,&composite,r,difference_indexes+x); p++; q++; r++; } if (SyncCacheView(difference_view) == MagickFalse) break; } difference_view=CloseCacheView(difference_view); reconstruct_view=CloseCacheView(reconstruct_view); image_view=CloseCacheView(image_view); (void) GetImageChannelDistortion(image,reconstruct_image,channel,metric, distortion,exception); return(difference_image); }