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
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 623 B |
After Width: | Height: | Size: 625 B |
After Width: | Height: | Size: 626 B |
After Width: | Height: | Size: 567 B |
After Width: | Height: | Size: 554 B |
After Width: | Height: | Size: 567 B |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.2 KiB |
|
@ -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 )
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|