1414from distutils import version
1515import hashlib
1616import math
17- import operator
1817import os
1918import numpy as np
2019import shutil
@@ -251,37 +250,21 @@ def crop_to_same(actual_path, actual_image, expected_path, expected_image):
251250 return actual_image , expected_image
252251
253252def calculate_rms (expectedImage , actualImage ):
254- # compare the resulting image histogram functions
255- expected_version = version . LooseVersion ( "1.6" )
256- found_version = version . LooseVersion ( np . __version__ )
253+ # calculate the per-pixel errors, then compute the root mean square error
254+ num_values = np . prod ( expectedImage . shape )
255+ abs_diff_image = abs ( expectedImage - actualImage )
257256
258257 # On Numpy 1.6, we can use bincount with minlength, which is much faster than
259258 # using histogram
259+ expected_version = version .LooseVersion ("1.6" )
260+ found_version = version .LooseVersion (np .__version__ )
260261 if found_version >= expected_version :
261- rms = 0
262-
263- for i in xrange (0 , 3 ):
264- h1p = expectedImage [:,:,i ]
265- h2p = actualImage [:,:,i ]
266-
267- h1h = np .bincount (h1p .ravel (), minlength = 256 )
268- h2h = np .bincount (h2p .ravel (), minlength = 256 )
269-
270- rms += np .sum (np .power ((h1h - h2h ), 2 ))
262+ histogram = np .bincount (abs_diff_image .ravel (), minlength = 256 )
271263 else :
272- rms = 0
273- bins = np .arange (257 )
274-
275- for i in xrange (0 , 3 ):
276- h1p = expectedImage [:,:,i ]
277- h2p = actualImage [:,:,i ]
264+ histogram = np .histogram (abs_diff_image , bins = np .arange (257 ))[0 ]
278265
279- h1h = np .histogram (h1p , bins = bins )[0 ]
280- h2h = np .histogram (h2p , bins = bins )[0 ]
281-
282- rms += np .sum (np .power ((h1h - h2h ), 2 ))
283-
284- rms = np .sqrt (rms / (256 * 3 ))
266+ sum_of_squares = np .sum (histogram * np .arange (len (histogram ))** 2 )
267+ rms = np .sqrt (float (sum_of_squares ) / num_values )
285268
286269 return rms
287270
@@ -299,8 +282,9 @@ def compare_images( expected, actual, tol, in_decorator=False ):
299282 = INPUT VARIABLES
300283 - expected The filename of the expected image.
301284 - actual The filename of the actual image.
302- - tol The tolerance (a unitless float). This is used to
303- determine the 'fuzziness' to use when comparing images.
285+ - tol The tolerance (a color value difference, where 255 is the
286+ maximal difference). The test fails if the average pixel
287+ difference is greater than this value.
304288 - in_decorator If called from image_comparison decorator, this should be
305289 True. (default=False)
306290 '''
@@ -316,37 +300,25 @@ def compare_images( expected, actual, tol, in_decorator=False ):
316300 # open the image files and remove the alpha channel (if it exists)
317301 expectedImage = _png .read_png_int ( expected )
318302 actualImage = _png .read_png_int ( actual )
303+ expectedImage = expectedImage [:, :, :3 ]
304+ actualImage = actualImage [:, :, :3 ]
319305
320306 actualImage , expectedImage = crop_to_same (actual , actualImage , expected , expectedImage )
321307
322- # compare the resulting image histogram functions
323- expected_version = version .LooseVersion ("1.6" )
324- found_version = version .LooseVersion (np .__version__ )
308+ # convert to signed integers, so that the images can be subtracted without
309+ # overflow
310+ expectedImage = expectedImage .astype (np .int16 )
311+ actualImage = actualImage .astype (np .int16 )
325312
326313 rms = calculate_rms (expectedImage , actualImage )
327314
328315 diff_image = make_test_filename (actual , 'failed-diff' )
329316
330- if ( ( rms / 10000.0 ) <= tol ) :
317+ if rms <= tol :
331318 if os .path .exists (diff_image ):
332319 os .unlink (diff_image )
333320 return None
334321
335- # For Agg-rendered images, we can retry by ignoring pixels with
336- # differences of only 1
337- if extension == 'png' :
338- # Remove differences of only 1
339- diffImage = np .abs (np .asarray (actualImage , dtype = np .int ) -
340- np .asarray (expectedImage , dtype = np .int ))
341- actualImage = np .where (diffImage <= 1 , expectedImage , actualImage )
342-
343- rms = calculate_rms (expectedImage , actualImage )
344-
345- if ( (rms / 10000.0 ) <= tol ):
346- if os .path .exists (diff_image ):
347- os .unlink (diff_image )
348- return None
349-
350322 save_diff_image ( expected , actual , diff_image )
351323
352324 if in_decorator :
@@ -360,7 +332,7 @@ def compare_images( expected, actual, tol, in_decorator=False ):
360332 else :
361333 # old-style call from mplTest directory
362334 msg = " Error: Image files did not match.\n " \
363- " RMS Value: " + str ( rms / 10000.0 ) + "\n " \
335+ " RMS Value: " + str ( rms ) + "\n " \
364336 " Expected:\n " + str ( expected ) + "\n " \
365337 " Actual:\n " + str ( actual ) + "\n " \
366338 " Difference:\n " + str ( diff_image ) + "\n " \
0 commit comments