Commit 2f98f7d20 for imagemagick.org

commit 2f98f7d2080f49c7a346ea131d43aec8320ee93b
Author: Cristy <urban-warrior@imagemagick.org>
Date:   Fri May 30 22:21:34 2025 -0400

    correct MSE metric

diff --git a/MagickCore/compare.c b/MagickCore/compare.c
index 9b4808f5d..1d338b3f7 100644
--- a/MagickCore/compare.c
+++ b/MagickCore/compare.c
@@ -1728,7 +1728,7 @@ static MagickBooleanType GetStructuralSimilarityDistortion(const Image *image,
         x_pixel_mu_squared=x_pixel_mu[i]*x_pixel_mu[i];
         y_pixel_mu_squared=y_pixel_mu[i]*y_pixel_mu[i];
         xy_mu=x_pixel_mu[i]*y_pixel_mu[i];
-        xy_sigmas=fabs(xy_sigma[i]-xy_mu);
+        xy_sigmas=xy_sigma[i]-xy_mu;
         x_pixel_sigmas_squared=x_pixel_sigma_squared[i]-x_pixel_mu_squared;
         y_pixel_sigmas_squared=y_pixel_sigma_squared[i]-y_pixel_mu_squared;
         ssim=((2.0*xy_mu+c1)*(2.0*xy_sigmas+c2))/
@@ -1784,8 +1784,9 @@ static MagickBooleanType GetStructuralSimilarityDistortion(const Image *image,
   return(status);
 }

-static MagickBooleanType GetStructuralDisimilarityDistortion(const Image *image,
-  const Image *reconstruct_image,double *distortion,ExceptionInfo *exception)
+static MagickBooleanType GetStructuralDissimilarityDistortion(
+  const Image *image,const Image *reconstruct_image,double *distortion,
+  ExceptionInfo *exception)
 {
   MagickBooleanType
     status;
@@ -1933,7 +1934,7 @@ MagickExport MagickBooleanType GetImageDistortion(Image *image,
     }
     case StructuralDissimilarityErrorMetric:
     {
-      status=GetStructuralDisimilarityDistortion(image,reconstruct_image,
+      status=GetStructuralDissimilarityDistortion(image,reconstruct_image,
         channel_distortion,exception);
       break;
     }
@@ -2095,7 +2096,7 @@ MagickExport double *GetImageDistortions(Image *image,
     }
     case StructuralDissimilarityErrorMetric:
     {
-      status=GetStructuralDisimilarityDistortion(image,reconstruct_image,
+      status=GetStructuralDissimilarityDistortion(image,reconstruct_image,
         distortion,exception);
       break;
     }
@@ -2264,10 +2265,10 @@ MagickExport MagickBooleanType SetImageColorMetric(Image *image,
     *reconstruct_view;

   double
-    area,
-    maximum_error,
-    mean_error,
-    mean_error_per_pixel;
+    area = 0.0,
+    maximum_error = (-MagickMaximumValue),
+    mean_error = 0.0,
+    mean_error_per_pixel = 0.0;

   MagickBooleanType
     status;
@@ -2283,10 +2284,6 @@ MagickExport MagickBooleanType SetImageColorMetric(Image *image,
   assert(image->signature == MagickCoreSignature);
   assert(reconstruct_image != (const Image *) NULL);
   assert(reconstruct_image->signature == MagickCoreSignature);
-  area=0.0;
-  maximum_error=0.0;
-  mean_error_per_pixel=0.0;
-  mean_error=0.0;
   SetImageDistortionBounds(image,reconstruct_image,&columns,&rows);
   image_view=AcquireVirtualCacheView(image,exception);
   reconstruct_view=AcquireVirtualCacheView(reconstruct_image,exception);
@@ -2320,8 +2317,8 @@ MagickExport MagickBooleanType SetImageColorMetric(Image *image,
         if (((traits & UpdatePixelTrait) == 0) ||
             ((reconstruct_traits & UpdatePixelTrait) == 0))
           continue;
-        distance=fabs((double) p[i]-(double) GetPixelChannel(reconstruct_image,
-          channel,q));
+        distance=QuantumScale*fabs((double) p[i]-(double)
+          GetPixelChannel(reconstruct_image,channel,q));
         if (distance >= MagickEpsilon)
           {
             mean_error_per_pixel+=distance;
@@ -2329,19 +2326,21 @@ MagickExport MagickBooleanType SetImageColorMetric(Image *image,
             if (distance > maximum_error)
               maximum_error=distance;
           }
-        area++;
       }
+      area++;
       p+=(ptrdiff_t) GetPixelChannels(image);
       q+=(ptrdiff_t) GetPixelChannels(reconstruct_image);
     }
   }
   reconstruct_view=DestroyCacheView(reconstruct_view);
   image_view=DestroyCacheView(image_view);
-  image->error.mean_error_per_pixel=(double) (mean_error_per_pixel/area);
-  image->error.normalized_mean_error=(double) (QuantumScale*QuantumScale*
-    mean_error/area);
-  image->error.normalized_maximum_error=(double) (QuantumScale*maximum_error);
-  status=image->error.mean_error_per_pixel == 0.0 ? MagickTrue : MagickFalse;
+  area=PerceptibleReciprocal(area);
+  image->error.mean_error_per_pixel=(double) QuantumRange*
+    (mean_error_per_pixel*area);
+  image->error.normalized_mean_error=mean_error*area;
+  image->error.normalized_maximum_error=maximum_error;
+  status=fabs(image->error.mean_error_per_pixel) < MagickEpsilon ?
+    MagickTrue : MagickFalse;
   return(status);
 }