Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/vectrify/vector/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,14 @@ def run_vector_search(

scoring_img = resize_long_side(original_img, DEFAULT_CONFIG.target_long_side)
pixel_ref = prepare(scoring_img)
# The target's own detail, measured once. Candidates are charged for the
# distance from it, so this has to come from the same render size they do.
_ref_buf = io.BytesIO()
scoring_img.save(_ref_buf, format="PNG")
reference_detail = detail(_ref_buf.getvalue())
# The target's own detail, measured once, at the size candidates are
# rasterized at -- original_png_bytes, not the smaller image the pixel
# comparison resizes to. Compressed size grows with pixel count, so reading
# the reference at scoring resolution and candidates at render resolution
# charges every candidate for the difference between the two: measured on
# the duck, the same image reads 7,607 at 256 and 41,602 at 700, and every
# candidate in a run came out 58-142% "busier" than a target it matched.
reference_detail = detail(original_png_bytes)
log.info(
"Round scoring: edge overlap, colour distance and a detail budget, no model. "
f"Front evaluator: {ScorerType(scorer_type).value} ({vision_model})."
Expand Down
29 changes: 29 additions & 0 deletions tests/score/test_complexity.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,32 @@ def test_an_empty_candidate_wins_this_axis_and_loses_the_rest():

def test_survives_a_blank_reference():
assert detail_excess(0.0, _noisy()) == 0.0


def test_detail_grows_with_pixel_count_at_equal_busyness():
"""Why the reference has to be measured at the size candidates render at.
Compressed size counts bytes, so the same picture reads larger when there
is more of it -- reading the reference at scoring resolution and candidates
at render resolution charges every candidate for the gap between the two.
"""
from vectrify.image_utils import resize_long_side

rng = random.Random(5)
big = Image.new("RGB", (256, 256))
big.putdata(
[
(rng.randrange(256), rng.randrange(256), rng.randrange(256))
for _ in range(256 * 256)
]
)
small = resize_long_side(big, 96)

def as_png(img):
buf = io.BytesIO()
img.save(buf, format="PNG")
return buf.getvalue()

assert detail(as_png(big)) > detail(as_png(small)) * 2
# Which is exactly the false charge: the same image against itself at the
# wrong scale reads as substantially busier than the reference.
assert detail_excess(detail(as_png(small)), as_png(big)) > 1.0
Loading