Repository navigation
Eval: rotation and darkening transforms in the runner - #12
Merged
Merged
Conversation
transforms.py now makes the protocol's rot<degrees> and dark<EV> images: bicubic rotation with mid-grey corners, and darkening in linear light with Poisson-Gaussian sensor noise at the middle of the range Brooks et al. (CVPR 2019) fitted. Both start from the image converted to sRGB by its ICC profile, as Chromium converts it; check_colour.py checks the two agree within 1 for test images with each kind of profile. run_detect.py --transforms makes each copy just before the page asks for it and records the parameters in run_info.json. Part B of the protocol now states the parameters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
darken() turns linear light into 8-bit sRGB by comparing with fixed thresholds rather than calling pow() for each pixel (same pixels on the test image, slightly faster), so reruns don't depend on the platform's pow(). run_info.json records servedSha256 over every image the page was given. Each image is decoded and colour-converted once for all its transforms, so the lines now follow the manifest. upright() refuses image modes check_colour.py has not compared, and check_colour.py answers unknown requests with 404. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 27, 2026
shashwat-deep
marked this pull request as ready for review
October 28, 2026 04:41
06pratyush
approved these changes
Oct 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Next step of the evidence half (
docs/plan.md, "Your half", item 4): the rotation and darkening transforms of protocol part B. The protocol fixes their parameters ineval/transforms.pybefore the first run. Stacked on #10, which is stacked on #9 and #2; merge those first.What is in it
eval/transforms.pymakes the images:rot<degrees>: Pillow'sImage.rotate, counterclockwise, bicubic, on a canvas enlarged to fit, uncovered corners mid-grey (128, 128, 128). 90° and 180° are exact transposes. The geometryscore.pyalready uses matches these images; tests check this against Pillow at seven angles.dark<EV>: linear RGB (IEC 61966-2-1), × 2^−EV, Poisson–Gaussian noise, back to 8-bit sRGB. The noise for a linear value x is a Poisson count with mean x / λ_shot, times λ_shot, plus Gaussian noise of variance λ_read. Its variance is λ_read + λ_shot·x, the model of Brooks et al. (CVPR 2019, Eq. 1). Each image and level gets its own seeded generator.run_detect.py --transforms none,rot15,dark2,…makes each copy just before the page asks for it, as a PNG, and keeps none of them. It checks the decoded size of every copy and records the parameters and the Pillow, numpy and LittleCMS versions inrun_info.json.run_info.jsonalso getsservedSha256, a SHA-256 over every image given to the page. When two runs differ, it shows whether the images did. The lines follow the manifest, each image with its transforms in turn, so each image is decoded and colour-converted once.pow(). On a test image this gives the same pixels as the formula.eval/check_colour.py: see below.none,rot0,rot45,rot90anddark2end to end, scored byscore.py.Colour: what I found
430 of the 1,000 test images carry an ICC profile, about 120 of them wide-gamut (Adobe RGB, camera RGB, ProPhoto). Chromium converts these to sRGB when it decodes them for the untransformed run, so the transformed copies must start from the same pixels.
transforms.upright()converts with LittleCMS (relative colorimetric).check_colour.pydecodes test images in headless Chromium, as the page does, and compares. On 90 images covering all 29 kinds of profile, no pixel differs by more than 1. Getting there turned up one Chromium behaviour: it applies an RGB profile to a greyscale JPEG (14 test images carry one), and it ignores a CMYK profile on an RGB image (1 image).upright()now does the same.For both of us to agree before any run
nonewithrot0shows whether the decoding path itself changes anything.Speed
On 20 test images with all twelve transforms, the stub runner took 41 s. The full report split (800 images × 12 transforms) would take about 27 minutes plus detection time.
🤖 Generated with Claude Code