QA: Fix utils.images_are_equal + add basic tests for qa utilities

Note: We allow differences of up to 2 pixel thickness due to erosion operation
This commit is contained in:
Roberto Fernandez Bautista 2023-08-02 00:20:03 +02:00
parent a0d559e884
commit b8a7e378d8
16 changed files with 84 additions and 25 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -70,4 +70,5 @@ def test_pcb_export_svg( kitest: KiTestFixture,
svg_source_path = str( Path( input_file ).with_suffix( "" ) )
svg_source_path += layerNameFixed + ".svg"
assert utils.svgs_are_equivalent( str( generated_svg_path ), svg_source_path, 1200 )
# Comparison DPI = 1270 => 1px == 20um. I.e. allowable error of 60 um after eroding
assert utils.svgs_are_equivalent( str( generated_svg_path ), svg_source_path, 1270 )

View File

@ -0,0 +1,47 @@
#
# This program source code file is part of KiCad, a free EDA CAD application.
#
# Copyright (C) 2023 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
# Copyright (C) 2023 KiCad Developers
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
import pytest
import utils
import os
@pytest.mark.parametrize("image1,image2,expected",
[
("3px_base.png", "3px_mid_blk.png", False),
("3px_base.png", "3px_mid_1px_lines.png", True), # Allow 1 px margin of error
("3px_base.png", "3px_mid_transparent.png", False),
("3px_base.png", "3px_offBy1_blk.png", False),
("3px_base.png", "3px_offBy1_wht.png", False),
("square_base.png", "square_blk.png", False),
("square_base.png", "square_transparent.png", False),
("square_base.png", "square_1px_bigger.png", True), # Allow 1 px margin of error
("irregular_base.png", "irregular_1px_eroded.png", True), # Allow 1 px margin of error
("irregular_base.png", "irregular_2px_eroded.png", False), # 2 px error is too much
]
)
def test_images_are_equal(image1: str, image2: str, expected: bool):
resources_path = os.path.dirname( __file__ )
resources_path = os.path.join( resources_path, "resources" )
image1 = os.path.join( resources_path, image1 )
image2 = os.path.join( resources_path, image2 )
assert utils.images_are_equal( image2, image1 ) == expected
assert utils.images_are_equal( image1, image2 ) == expected

View File

@ -63,12 +63,14 @@ def textdiff_files( golden_filepath: str, new_filepath: str, skip: int = 0 ) ->
return diff_text == ""
def images_are_equal( image1: str, image2: str ) -> bool:
def images_are_equal( image1_path: str, image2_path: str, alpha_colour = (50, 100, 50) ) -> bool:
# Note: if modifying this function - please add new tests for it in test_utils.py
# Increase limit to ~500MB uncompressed
Image.MAX_IMAGE_PIXELS=2 * 1024 * 1024 * 1024 // 4 // 3
image1 = Image.open( image1 )
image2 = Image.open( image2 )
image1 = Image.open( image1_path )
image2 = Image.open( image2_path )
if image1.size != image2.size:
return False
@ -76,30 +78,39 @@ def images_are_equal( image1: str, image2: str ) -> bool:
if image1.mode != image2.mode:
return False
sum = np.sum( ( np.asarray ( image1 ).astype( np.float32 ) - np.asarray( image2 ).astype( np.float32 ) ) ** 2.0 )
diff = ImageChops.difference( image1, image2 )
sum = np.sum( np.asarray( diff ) )
retval = True
if sum != 0.0:
# images are not identical - lets allow 1 pixel error difference (for curved edges)
# Images are not identical - lets allow 1 pixel error difference (for curved edges)
diff_multi_bands = diff.split()
binary_multi_bands = []
diff = ImageChops.difference( image1, image2 )
diffThresholded = diff.point( lambda x: 255 if x > 1 else 0 )
for band_diff in diff_multi_bands:
thresholded_band = band_diff.point( lambda x: x > 0 and 255 )
binary_multi_bands.append( thresholded_band.convert( "1" ) )
# erode binary image by 1 pixel
diffEroded = diffThresholded.filter(ImageFilter.MinFilter(3))
binary_result = binary_multi_bands[0]
erodedSum = np.sum( np.asarray( diffEroded ).astype( np.float32 ) )
for i in range( 1, len( binary_multi_bands ) ):
binary_result = ImageChops.logical_or( binary_result, binary_multi_bands[i] )
retval = erodedSum == 0
eroded_result = binary_result.copy().filter( ImageFilter.MinFilter( 3 ) ) # erode once (trim 1 pixel)
eroded_result_sum = np.sum( np.asarray( eroded_result ) )
retval = eroded_result_sum == 0
# Save images
diff_name = image1.filename + ".diff1.png"
diff.save( diff_name )
diff_name = image1.filename + ".diffthresholded.png"
diffThresholded.save( diff_name )
diffEroded_name = image1.filename + ".diffEroded_erodedsum" + str(erodedSum)+ ".png"
diffEroded.save( diffEroded_name )
#if not retval:
diff_name = image1.filename + ".diff.png"
diff.save( diff_name ) # Note: if the image has alpha, the diff will be mostly transparent
diff_name = image1.filename + ".binary_result.png"
binary_result.save( diff_name )
diff_name = image1.filename + ".eroded_result_" + str( eroded_result_sum )+ ".png"
eroded_result.save( diff_name )
return retval