@@ -2092,45 +2092,133 @@ MagickExport MagickBooleanType IsImagesEqual(Image *image,
2092
2092
%
2093
2093
*/
2094
2094
2095
- static double GetSimilarityMetric (const Image * image ,const Image * reference ,
2096
- const MetricType metric ,const ssize_t x_offset , const ssize_t y_offset ,
2097
- ExceptionInfo * exception )
2095
+ static double GetSimilarityMetric (const Image * image ,
2096
+ const Image * reconstruct_image ,const MetricType metric ,
2097
+ const ssize_t x_offset , const ssize_t y_offset , ExceptionInfo * exception )
2098
2098
{
2099
2099
double
2100
- distortion ,
2101
- similarity ;
2100
+ * channel_similarity ,
2101
+ similarity = 0.0 ;
2102
+
2103
+ ExceptionInfo
2104
+ * sans_exception = AcquireExceptionInfo ();
2102
2105
2103
2106
Image
2104
2107
* similarity_image ;
2105
2108
2106
2109
MagickBooleanType
2107
- status ;
2110
+ status = MagickTrue ;
2108
2111
2109
2112
RectangleInfo
2110
2113
geometry ;
2111
2114
2112
- SetGeometry (reference ,& geometry );
2115
+ size_t
2116
+ length = MaxPixelChannels + 1UL ;
2117
+
2118
+ SetGeometry (reconstruct_image ,& geometry );
2113
2119
geometry .x = x_offset ;
2114
2120
geometry .y = y_offset ;
2115
- similarity_image = CropImage (image ,& geometry ,exception );
2121
+ similarity_image = CropImage (image ,& geometry ,sans_exception );
2122
+ sans_exception = DestroyExceptionInfo (sans_exception );
2116
2123
if (similarity_image == (Image * ) NULL )
2117
2124
return (NAN );
2118
- distortion = 0.0 ;
2119
- status = GetImageDistortion (similarity_image ,reference ,metric ,& distortion ,
2120
- exception );
2121
- similarity_image = DestroyImage (similarity_image );
2122
- if (status == MagickFalse )
2123
- return (NAN );
2124
- similarity = distortion ;
2125
+ /*
2126
+ Get image distortion.
2127
+ */
2128
+ channel_similarity = (double * ) AcquireQuantumMemory (length ,
2129
+ sizeof (* channel_similarity ));
2130
+ if (channel_similarity == (double * ) NULL )
2131
+ ThrowFatalException (ResourceLimitFatalError ,"MemoryAllocationFailed" );
2132
+ (void ) memset (channel_similarity ,0 ,length * sizeof (* channel_similarity ));
2125
2133
switch (metric )
2126
2134
{
2135
+ case AbsoluteErrorMetric :
2136
+ {
2137
+ status = GetAESimilarity (similarity_image ,reconstruct_image ,
2138
+ channel_similarity ,exception );
2139
+ break ;
2140
+ }
2141
+ case DotProductCorrelationErrorMetric :
2142
+ case PhaseCorrelationErrorMetric :
2143
+ {
2144
+ status = GetMSESimilarity (similarity_image ,reconstruct_image ,
2145
+ channel_similarity ,exception );
2146
+ break ;
2147
+ }
2148
+ case FuzzErrorMetric :
2149
+ {
2150
+ status = GetFUZZSimilarity (similarity_image ,reconstruct_image ,
2151
+ channel_similarity ,exception );
2152
+ break ;
2153
+ }
2154
+ case MeanAbsoluteErrorMetric :
2155
+ {
2156
+ status = GetMAESimilarity (similarity_image ,reconstruct_image ,
2157
+ channel_similarity ,exception );
2158
+ break ;
2159
+ }
2160
+ case MeanErrorPerPixelErrorMetric :
2161
+ {
2162
+ status = GetMEPPSimilarity (similarity_image ,reconstruct_image ,
2163
+ channel_similarity ,exception );
2164
+ break ;
2165
+ }
2166
+ case MeanSquaredErrorMetric :
2167
+ {
2168
+ status = GetMSESimilarity (similarity_image ,reconstruct_image ,
2169
+ channel_similarity ,exception );
2170
+ break ;
2171
+ }
2127
2172
case NormalizedCrossCorrelationErrorMetric :
2128
2173
{
2129
- similarity = 1.0 - similarity ;
2174
+ status = GetNCCSimilarity (similarity_image ,reconstruct_image ,
2175
+ channel_similarity ,exception );
2176
+ break ;
2177
+ }
2178
+ case PeakAbsoluteErrorMetric :
2179
+ {
2180
+ status = GetPASimilarity (similarity_image ,reconstruct_image ,
2181
+ channel_similarity ,exception );
2182
+ break ;
2183
+ }
2184
+ case PeakSignalToNoiseRatioErrorMetric :
2185
+ {
2186
+ status = GetPSNRSimilarity (similarity_image ,reconstruct_image ,
2187
+ channel_similarity ,exception );
2188
+ break ;
2189
+ }
2190
+ case PerceptualHashErrorMetric :
2191
+ {
2192
+ status = GetPHASHSimilarity (similarity_image ,reconstruct_image ,
2193
+ channel_similarity ,exception );
2194
+ break ;
2195
+ }
2196
+ case RootMeanSquaredErrorMetric :
2197
+ case UndefinedErrorMetric :
2198
+ default :
2199
+ {
2200
+ status = GetRMSESimilarity (similarity_image ,reconstruct_image ,
2201
+ channel_similarity ,exception );
2202
+ break ;
2203
+ }
2204
+ case StructuralDissimilarityErrorMetric :
2205
+ {
2206
+ status = GetDSSIMSimilarity (similarity_image ,reconstruct_image ,
2207
+ channel_similarity ,exception );
2208
+ break ;
2209
+ }
2210
+ case StructuralSimilarityErrorMetric :
2211
+ {
2212
+ status = GetSSIMSimularity (similarity_image ,reconstruct_image ,
2213
+ channel_similarity ,exception );
2130
2214
break ;
2131
2215
}
2132
- default : break ;
2133
2216
}
2217
+ similarity_image = DestroyImage (similarity_image );
2218
+ similarity = channel_similarity [CompositePixelChannel ];
2219
+ channel_similarity = (double * ) RelinquishMagickMemory (channel_similarity );
2220
+ if (status == MagickFalse )
2221
+ return (NAN );
2134
2222
return (similarity );
2135
2223
}
2136
2224
@@ -2350,7 +2438,15 @@ MagickExport Image *SimilarityMetricImage(Image *image,const Image *reconstruct,
2350
2438
if (status == MagickFalse )
2351
2439
similarity_image = DestroyImage (similarity_image );
2352
2440
* similarity_metric = similarity_info .similarity ;
2441
+ if (fabs (* similarity_metric ) < MagickEpsilon )
2442
+ * similarity_metric = 0.0 ;
2353
2443
offset -> x = similarity_info .x ;
2354
2444
offset -> y = similarity_info .y ;
2445
+ (void ) FormatImageProperty ((Image * ) image ,"similarity" ,"%.*g" ,
2446
+ GetMagickPrecision (),* similarity_metric );
2447
+ (void ) FormatImageProperty ((Image * ) image ,"similarity.offset.x" ,"%.*g" ,
2448
+ GetMagickPrecision (),(double ) offset -> x );
2449
+ (void ) FormatImageProperty ((Image * ) image ,"similarity.offset.y" ,"%.*g" ,
2450
+ GetMagickPrecision (),(double ) offset -> y );
2355
2451
return (similarity_image );
2356
2452
}
0 commit comments