1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
from __future__ import annotations
import os
from shutil import copyfile
from typing import TYPE_CHECKING
import numpy as np
if TYPE_CHECKING:
import io
def compare_images(
test_buffer: io.BytesIO,
baseline_filename: str,
test_filename_suffix: str | None = None,
max_threshold: int | None = None,
mean_threshold: float | None = None,
) -> None:
from PIL import Image
from .conftest import image_diffs_log
if max_threshold is None:
max_threshold = 100
if mean_threshold is None:
mean_threshold = 0.02
if test_filename_suffix:
basename, extension = os.path.splitext(baseline_filename)
test_filename = f"{basename}_{test_filename_suffix}{extension}"
else:
test_filename = baseline_filename
max_diff = None
mean_diff = None
try:
test_image = np.asarray(Image.open(test_buffer).convert("RGB"))
test_image = test_image.astype(np.int16)
full_baseline_filename = os.path.join("tests", "baseline_images", baseline_filename)
assert os.path.isfile(full_baseline_filename)
baseline_image = np.asarray(Image.open(full_baseline_filename).convert("RGB"))
baseline_image = baseline_image.astype(np.int16)
diff = np.abs(test_image - baseline_image)
if np.dtype(np.intp).itemsize == 4:
# 32-bit Matplotlib agg backend RGB components can be 1 out compared to 64-bit due to
# slightly different rounding. So ignore differences of 1 on 32-bit.
diff[diff == 1] = 0
max_diff = diff.max()
mean_diff = diff.mean()
log = f"{max_diff},{max_threshold},{mean_diff:g},{mean_threshold},{test_filename}"
image_diffs_log.append(log)
assert max_diff < max_threshold and mean_diff < mean_threshold
except AssertionError:
# Write test image.
result_directory = "result_images"
if not os.path.exists(result_directory):
os.makedirs(result_directory)
full_test_filename = os.path.join(result_directory, test_filename)
with open(full_test_filename, "wb") as f:
f.write(test_buffer.getbuffer())
if max_diff is not None and mean_diff is not None:
basename, extension = os.path.splitext(test_filename)
# Copy expected file.
expected_filename = f"{basename}-expected{extension}"
expected_filename = os.path.join(result_directory, expected_filename)
copyfile(full_baseline_filename, expected_filename)
print(f"diffs: max {max_diff}, mean {mean_diff:.4f} "
f"(thresholds max {max_threshold}, mean {mean_threshold})")
# Write difference image.
difference_filename = f"{basename}-diff{extension}"
difference_filename = os.path.join(result_directory, difference_filename)
diff = diff.astype(np.float64)*10
diff = np.clip(diff, 0, 255).astype(np.uint8)
Image.fromarray(diff).save(difference_filename, format="png")
raise
|