mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 21:21:17 +01:00
* Rearrange the GLSL in unmultiply() to a configuration that doesn't hang on PowerVR, or cause a compile failure with no message. * Make sure to always either update or preserve the clip & coverage buffers, even if ENABLE_CLIPPING isn't defined for the current draw. * Don't use GL_KHR_debug on PowerVR. It can cause shader compiles to take 30+ seconds. * Support 32-bit android arch in check_golds.sh & deploy_tests.py. * Reverse histogram sorting order so bad matches come up first. * Simple bugfixes. Diffs= 3c322193bf More android tuning for PowerVR (#8747) Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
152 lines
6.6 KiB
Python
152 lines
6.6 KiB
Python
#requires pip install python-opencv-headless
|
|
|
|
import argparse
|
|
import cv2 as cv
|
|
import numpy as np
|
|
import os
|
|
|
|
parser = argparse.ArgumentParser(description=
|
|
"""
|
|
Compares to images by pixels, outputing two different images for the differences.
|
|
|
|
output file {status}
|
|
output file {name}.diff0.png
|
|
The exact abs(A - B) of each pixel
|
|
output file {name}.diff1.png
|
|
A mask which has 1 for difference and 0 for no difference at a given pixel
|
|
""")
|
|
|
|
parser.add_argument("-n", "--name", type=str, required=True, help="name used for output images")
|
|
parser.add_argument("-c", "--candidate", type=str, required=True, help="candidate for image diffing")
|
|
parser.add_argument("-g", "--golden", type=str, required=True, help="golden to compare against")
|
|
parser.add_argument("-s", "--status", type=str, required=True, help="output stats file name and location")
|
|
parser.add_argument("-o", "--outdir", type=str, help="output directory to store image diffs, if not provided then no output image is saved")
|
|
parser.add_argument("-v", "--verbose", action='store_true', help="enable verbose logging")
|
|
parser.add_argument("-l", "--log", action='store_true', help="redirect all verbose logging to a file with --name")
|
|
parser.add_argument("-H", "--histogram", action='store_true', help="compare images using histograms as an additional method for ruling out 'same' images. This should prevent subtle differences in the image that should not be visible from preventing a passing result")
|
|
|
|
args = parser.parse_args()
|
|
|
|
def verbose_log(val):
|
|
if not args.verbose:
|
|
return
|
|
if args.log:
|
|
with open(f"tmp/{args.name}.log", "a") as log_file:
|
|
log_file.write(val+"\n")
|
|
else:
|
|
print(val)
|
|
|
|
def main():
|
|
if args.log:
|
|
os.makedirs("tmp", exist_ok=True)
|
|
|
|
size_match = False
|
|
failed = False
|
|
try:
|
|
verbose_log(f"loading {args.candidate}")
|
|
candidate = cv.imread(args.candidate)
|
|
verbose_log(f"loading {args.golden}")
|
|
golden = cv.imread(args.golden)
|
|
|
|
if candidate is not None and golden is not None:
|
|
size_match = candidate.shape == golden.shape
|
|
# get absolute difference between golden and candidate
|
|
diff = cv.absdiff(golden, candidate)
|
|
#convert diff to grey scale to make calculations easier
|
|
grey_diff = cv.cvtColor(diff, cv.COLOR_BGR2GRAY)
|
|
#convert to rgb for output png
|
|
rgb_diff = cv.cvtColor(diff, cv.COLOR_BGR2RGB)
|
|
# convert the diff to just white where a difference is
|
|
_, mask = cv.threshold(grey_diff, 0, 255, cv.THRESH_BINARY)
|
|
# get the total number of different pixels
|
|
total_diff_count = cv.countNonZero(grey_diff)
|
|
# get the max channel independent difference
|
|
max_diff = int(diff.max())
|
|
# get average pixel diff, this result is slitely different then imageDiff but its very close.
|
|
# the only difference is that we first convert the diff to grey scale rather than adding the max of every channel
|
|
avg = grey_diff.sum() / (grey_diff.shape[0]*grey_diff.shape[1]*255)
|
|
|
|
if args.histogram:
|
|
# convert to HSV
|
|
hsv_candidate = cv.cvtColor(candidate, cv.COLOR_BGR2HSV)
|
|
hsv_golden = cv.cvtColor(golden, cv.COLOR_BGR2HSV)
|
|
|
|
# down sample to 32x32 for the histogram
|
|
h_bins = 32
|
|
s_bins = 32
|
|
histSize = [h_bins, s_bins]
|
|
|
|
# available range for hue and saturation
|
|
h_ranges = [0, 180]
|
|
s_ranges = [0, 256]
|
|
ranges = h_ranges + s_ranges
|
|
|
|
# get our histograms
|
|
hist_candidate = cv.calcHist(hsv_candidate, [0,1], None, histSize, ranges, accumulate=False)
|
|
hist_golden = cv.calcHist(hsv_golden, [0,1], None, histSize, ranges, accumulate=False)
|
|
|
|
# compare using CORREL histogram algorithm. the different options are detailed here
|
|
# https://docs.opencv.org/3.4/d6/dc7/group__imgproc__hist.html#ga994f53817d621e2e4228fc646342d386
|
|
# a hist_result of 1.0 means identical with this method. any variance results in a number less then 1.0
|
|
hist_result = cv.compareHist(hist_candidate, hist_golden, cv.HISTCMP_CORREL)
|
|
|
|
except Exception as E:
|
|
print(f"Failed to load and process images {E}")
|
|
failed = True
|
|
|
|
# make path to stats file if necessary
|
|
if os.path.dirname(args.status):
|
|
verbose_log(f"making status file path {os.path.dirname(args.status)}")
|
|
os.makedirs(os.path.dirname(args.status), exist_ok=True)
|
|
verbose_log(f"making status file {args.status}")
|
|
with open(args.status, "a") as status:
|
|
status.write(args.name + "\t");
|
|
if candidate is None:
|
|
status.write("missing_candidate\n")
|
|
verbose_log("missing golden for " + args.name)
|
|
return
|
|
if golden is None:
|
|
status.write("missing_golden\n")
|
|
verbose_log("missing golden for " + args.name)
|
|
return
|
|
if failed:
|
|
status.write("failed\n")
|
|
verbose_log("failed to load golden or candidate")
|
|
return
|
|
if total_diff_count == 0:
|
|
status.write("identical\n")
|
|
verbose_log("files are identical")
|
|
return
|
|
if not size_match:
|
|
status.write("sizemismatch\n")
|
|
verbose_log("files are not the same size")
|
|
return
|
|
status.write(str(max_diff)+"\t")
|
|
# prevent python from writing out in scientific notation
|
|
status.write(f"{float(avg):.5f}\t")
|
|
status.write(str(total_diff_count)+"\t")
|
|
status.write(str(diff.shape[0]*diff.shape[1]))
|
|
# add our histogram result as the last value of the status file or write a new line to say we are finished with this status
|
|
if args.histogram:
|
|
status.write(f"\t{float(hist_result):.5f}\n")
|
|
else:
|
|
status.write("\n")
|
|
|
|
verbose_log("status file finished")
|
|
# save the output file if location provided
|
|
if args.outdir:
|
|
# color diff file location
|
|
c_diff_path = os.path.join(args.outdir, args.name + ".diff0.png")
|
|
# mask diff file location
|
|
c_mask_path = os.path.join(args.outdir, args.name + ".diff1.png")
|
|
# create output dir if needed
|
|
verbose_log(f"making output directory {args.outdir}")
|
|
os.makedirs(args.outdir, exist_ok=True)
|
|
verbose_log(f"writing images {c_diff_path} and {c_mask_path}")
|
|
cv.imwrite(c_diff_path, rgb_diff)
|
|
cv.imwrite(c_mask_path, mask)
|
|
verbose_log("finished writing output images")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|