imazen / imazen/codec-corpus

Structural-corruption distortion corpus for zensim negative-tail validation

Open
#7 0 comments 0 reactions 1 assignee Claimed by @lilith View on GitHub
Dominant language
Rust
Stars
13
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Purpose

Build a held-out **structural-corruption distortion corpus** to validate and calibrate zensim's intentional *negative tail*. A faithful similarity metric must rank a localized, catastrophic decode/render defect (channel swap, off-by-one edge, dropped MCU) **below** an honest uniform low-quality encode of the same reference. This corpus is the ground truth for the regression-test use case: a broken decode must score worse than a legitimately-lossy one, so a test catches the bug instead of passing it.

**Spec:** `zensim/docs/structural_corruption_corpus_spec_2026-05-27.md` (in the zensim repo). The gate every entry asserts:

```
score(ref, corruption) < score(ref, honest_lq_anchor)
```

where `honest_lq_anchor` = a uniform JPEG q20 (and q10) encode of the reference. For egregious corruptions (large region, opaque channel swap), the calibrated score should be `< 0`. Subtle ones (8x8 block, 1px 20%-opacity border) need only rank below the lq anchor — they are the hard cases and the research signal for the negative-tail calibration.

## Synthetic distortion families (10, from the spec)

Each family is parameterized by **region size** (sweep: whole-image -> 1/4 -> 1/16 -> 64x64 -> 16x16 -> 8x8 -> single-pixel where meaningful) and **severity** (opacity/magnitude). Generate deterministically (seeded) on a content-varied reference set.

1. **Channel corruption** — within a rectangle: invert (255-v), channel swap (RGB->BGR, R<->G, R<->B, G<->B), single-channel zero/max.
2. **Block corruption** — N×N block: zero-fill, mid-gray fill, garbage, copy-from-wrong-location (MCU mispredict), repeat-neighbor.
3. **Edge / border artifacts** — k-px border (k in {1,2,4}) at p% opacity (p in {20,50,100}); 1px interior shift (off-by-one crop/pad); duplicated/dropped edge row.
4. **Salt-and-pepper / bit errors** — k random pixels (1 .. 0.1%) to black/white/random; single-bit channel flips.
5. **Local tone / gamma** — within a block: wrong transfer function (apply/undo sRGB), local contrast boost ×1.5, brightness offset.
6. **Low-opacity overlay** — shape (rect/line/glyph) at 5-30% opacity (render leak / watermark bleed).
7. **Chroma-boundary mismatch** — upsample chroma with wrong phase / different kernel than luma at block boundaries.
8. **Aliasing / moiré** — NN downscale->upscale, or HF pattern downsampled without prefilter.
9. **Geometric** — 1px translation / sub-pixel shift / small rotation / flip / 1px skew of a region.
10. **Wrong-background compositing** — premultiplied-as-straight (and vice-versa); composite onto wrong bg (black/white/gray).

## Gold-standard members: MINED real historical decoder/renderer bugs (MANDATORY)

These are reproductions of real shipped wrong-pixel bugs from imageflow + the zensim-regress codec users. Each must appear as a corpus entry: the reference + the buggy output (recovered from the fixed test/fixture) OR a synthetic repro of the bug's exact pixel pattern. `source: "real-bug:#"` in the manifest.

| repo | bug (1 line) | pixel-defect pattern | commit / issue ref | repro available? |
|---|---|---|---|---|
| zenjpeg | Progressive decoder truncated AC coeffs near restart markers | Trailing blocks zeroed -> blocky/desaturated trailing MCUs | commit `08ef601` (Q91-93, DRI=216, 576x576) | fixed-test repro: `quality_regression diagnostic_coefficient_comparison` |
| zenjpeg | Progressive MCU-padded storage stride mismatch (4:2:0 non-MCU-aligned width) | 1-block-per-row horizontal shift accumulating to max_diff=255 | commit `29d6d81` (~20/543 corpus files) | yes (fixed regression) |
| zenjpeg | Progressive interleaved DC scan padding desynced Huffman decoder | "invalid Huffman code" / wrong block decode on 80/543 4:2:0 files | commit `759a4a7` | yes |
| zenjpeg | 4:2:0 scanline chroma upsampling used edge-replication at MCU **bottom** boundary | Horizontal chroma band at MCU row edges (max ~43-57 px err) | commit `bd0f8d7` | yes — this IS family #7 (chroma-boundary mismatch) |
| zenjpeg | XYB Full mode emitted BQuarter MCU block ordering | Every component read as wrong plane -> catastrophic color (red->green) | commit `daf52508` | yes (4-quadrant test image) |
| zenjpeg | XYB linear-input path double-scaled -> Y~1600 saturates every MCU | Decodes to **solid white** | commits `28658af6`+`9e2348fe` (Known Bug #7) | yes (`xyb_roundtrip.rs`) |
| zenjpeg | XYB 4:2:0 DC category clamped to 11 but encoder wrote unclamped | Huffman code=0,len=0 -> **corrupted bitstream**, undecodable | commit `b0cafce` | partial (files in `testdata/decode_failures/`) |
| zenjpeg | False XYB-ICC detection on cjpegli JPEGs ("jxl " CMM) | Wrong XYB->RGB path -> completely wrong colors (max_diff=252) | commit `744d38a` | yes |
| zenjpeg | grayscale Hi/Vi>1 + Bgr -> wrong bytes (IDCT strip overflow) | Garbled grayscale output | commit `4af35564` | yes (`grayscale_*_sampling2x2.jpg`) |
| zenjpeg | h2v2 boundary fixup overflow / sharp-YUV y_offset sign error | green color shift (Cb/Cr pushed low) | `1c9631a8` (closes zenwebp#17) | yes |
| zenwebp | Multi-pass probability signaling bug | encoder signals 0 prob updates, decoder expects ~125 -> 99.9% pixels garbage | commit `d58fc25` | yes |
| zenwebp | Chroma error-diffusion applied in encode but not in reconstruction | encoder recon != bitstream -> decoder produces different pixels | commit `eaa7afe` | yes |
| zenwebp | Missing U/V chroma-conversion rounding | 99% of U/V off-by-1 vs reference | commit `11465dd` | yes |
| zenwebp | sharp_yuv used non-gamma-corrected BT.601 forward matrix | systematic **green shift** (Cb/Cr ~12 low) | commit `7a23ffa` | yes |
| zenwebp | fused-scalar fancy-upsampling collapsed to single chroma sample | chroma blockiness (no neighbor blend) | commit `c63d898` | yes |
| zenwebp | NEON `sse_8x8_chroma` chroma-width stride bug | wrong chroma SSE -> mode mis-selection | commit `167ad48` | yes (parity tests) |
| zenwebp | animation dispose-to-background used 3-byte stride on RGBA canvas | misaligned writes -> **canvas corruption** of cleared rect | commit `a8df324` | yes |
| zenwebp | lossless + alpha + padded-stride corruption | alpha plane corruption | PR #18 / issue #10 (`8c29215`) | yes (regression tests) |
| zenwebp | color-indexing transform decode bug | wrong indexed colors | commit `cfd582c` (#28) | upstream-fixed |
| zenwebp | lossless color-cache update missing in fast path | wrong pixels in lossless decode | commit `7b2bbbc` (#114) | upstream-fixed |
| zenwebp | systematic quality drops at q75->80 and q87->90 (mode switches) | non-monotonic quality cliff at codec mode boundaries | zensim MEMORY.md (Known Issues) | needs synthetic repro |
| zengif | transparent pixels mapped to nearest palette color (shared-palette mode) | transparent regions render as dark gray (SSIM2 down to 41) | commit `93b6da2` | yes |
| zengif | quantize_frame returned raw indices w/o alpha->transparent-index post-process | transparent pixels render opaque | commit `0d9f031` | yes |
| zenpng | U16->U8 depth reduction used `>>8` truncation not rounding | per-channel off-by-up-to-1 banding on 16-bit PNG | commit `d88325c` | yes |
| zenpng | 16-bit PNG decode truncated to u8 before f32 (precision loss) | lost 16-bit precision -> banding | commit `838cad7` | yes |
| zenpng | Adam7 interlaced decode buffer too small for wide images | infinite loop / failed decode on wide interlaced PNG | commit `3cbed35` | yes (`8625x8625`) |
| zenavif | `unpremultiply8` truncated `(c*255/a)` instead of rounding | off-by-1 on un-premultiplied (alpha) pixels | commit `4509713` | yes |
| zenavif | `scale_from_u16` half-up rounding fought LSB replication | 50% (511/1024) of 10-bit values shifted +1 on roundtrip | commit `42d06a7` | yes |
| zenavif | bilinear chroma interp negative weights at image edges | broken edge chroma interpolation | commit `cb366c5` | yes |
| zenavif | f32 PQ/HLG routed through `linear_to_srgb_u8` | HDR signal destroyed (tone-clipped) | commit `37d2073` | yes |
| heic | chroma MC shift 4 instead of 6 (uni-pred) | **chroma scaled 4x** -> wildly wrong color | commit `c20861e` | yes (conformance) |
| heic | chroma MC wrong intermediate precision (bi-pred) | wrong chroma in B-slices | commit `b24c111` | yes |
| heic | spurious rounding offset in bi-pred MC vertical pass | luma off-by small amount in bi-pred | commit `9e9b1c5` | yes |
| heic | deblocking boundary strength wrong (inter) / SAO corruption | edge artifacts / SAO corruption | commits `251968b`, `754a029` | yes (conformance) |
| heic | tile-boundary CABAC/QP/MPM errors | wrong pixels across tile boundaries (grid HEIC) | commits `dafa255`, `5d035ec` | yes |
| imageflow | transparent PNG->JPEG loses color (bgcolor=transparent matte) | desaturated / wrong matte on flatten | issue #669 | repro inputs in issue |
| imageflow | "within" constraint rounding -> 1px transparent border | 99x33 content in a 100x33 canvas (off-by-one edge) | issue #656 | yes — this IS family #3 (edge off-by-one) |
| imageflow | transparent PNG shows black background on JPEG convert | wrong-bg composite (black not white) | issues #158, #190, #175 | yes — family #10 (wrong-bg) |
| imageflow | swapped width/height in `enable_transparency` canvas creation | misaligned transparent canvas | CHANGELOG security-audit (`0e7c0385`) | needs synthetic repro |
| imageflow | EXIF-orientated image cropped in wrong region | crop applied pre-orientation -> wrong content | issue #553 | yes (orientation samples) |
| imageflow | WebPLossy desaturated color | systematic desaturation vs mozjpeg | issue #588 | repro inputs in issue |

**Family coverage check:** families #3 (edge off-by-one), #7 (chroma-boundary), #10 (wrong-bg composite) have **direct real-bug analogues** above (imageflow #656; zenjpeg `bd0f8d7`; imageflow #158/#190). Family #1 (channel corruption) maps to zenjpeg `daf52508` (wrong-plane). Family #2 (block corruption) maps to zenjpeg progressive-truncation/stride bugs. Family #5 (local gamma) maps to zenjpeg cjpegli-ICC + zenavif PQ/HLG. Families with **no exact real-bug analogue found** (synthetic-only): **#4 salt-and-pepper / single-bit errors**, **#6 low-opacity overlay / watermark bleed**, **#8 aliasing / moiré (resampler)**, **#9 geometric (rotation/flip/skew)**. These remain synthetic; flag in the manifest as `source: "synthetic"`.

**Bug class the spec under-weights:** *off-by-one rounding in bit-depth/range conversion* (zenpng `d88325c` U16->U8, zenavif `42d06a7` 10-bit roundtrip, zenwebp `11465dd` U/V rounding, zenavif `4509713` unpremul). These are extremely subtle (max_diff=1) but systematic across the whole image — a worst case for a saturating metric. Worth a dedicated "global off-by-one rounding" sub-family beyond the localized families.

## Corpus deliverables checklist

- [ ] `corruptions/` module with deterministic seeded Rust generators, one fn per family, parameterized by region + severity.
- [ ] `_MANIFEST.json` per entry: `{ ref_id, family, params, expected_below_lq: true, expected_negative: bool, source: "synthetic" | "real-bug:#" }`.
- [ ] Reuse codec-corpus curated references; do NOT commit large generated images — prefer on-demand generation from seed + ref_id (reproducible without committing bytes).
- [ ] Region-size sweep dense from whole-image down to 8x8 (and 1px for edge/geometric); severity from subtle (20% opacity, 8x8) to obvious (opaque, whole-image).
- [ ] >= 5 content classes (photo, screen/UI, line-art, text, gradient) x >= 10 references each.
- [ ] Real-bug gold-standard members (every row in the table above), with recovered buggy output where the fixed test/fixture provides it, else a synthetic pixel-pattern repro.
- [ ] zensim-gate driver: given a reference, emits `(ref, corruption, q20-anchor, q10-anchor)` so the gate runs directly.
- [ ] zensim eval reporting per family x region x severity: `score(corruption)`, `score(q20)`, `score(q10)`, gate pass/fail `score(corruption) < score(q20)` (measured, not asserted, on the subtle end).

## Note

The corpus **build is being done in parallel** (another agent). This issue is the tracking + the real-bug requirements: the mined gold-standard members above are mandatory members, not optional.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.