mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-19 02:10:25 -05:00
LR-IMP-CAMERA-COVERAGE: measured image area for Nikon bodies without CropArea
Nikon bodies from before ~2016 record no CropArea, so the decoder kept their whole sensor data, less trailing dark columns. Where that data holds masked lines above black or optical black, they were developed as a coloured or dark bar on that edge: the D7000 and D5100's 36 columns at ~600 (#976), the D800's 14 (#914, the top in portrait), the D600 / D610's 8 (#1236), the D3200's 46, and others. MEASURED_BODIES (crates/raw/src/vendor/nef.rs) now gives 44 more model / data size / depth groups the frame of their camera JPEG inside the data, next to the D4, D7100 and D90 entries already there: D7000, D5100, D800, D800E, Df, the D4's 12-bit mode, D3, D3S, D700, D300, D300S, D600, D610, D810, D4S, D5600, Coolpix A, D3000, D40X, D60, D80, D2Xs, D200, D3200 and Nikon 1 V1; and, on best-guess frames short of the evidence rule, each with a comment naming its evidence, the D3100 (3 of 4 clean files agree), D5000 (4 of 5, and the D90's sensor), D40 (2 of 2), D50 and D70 (one file each, agreeing) and D70s (next to them, between pixels). Every best-guess frame keeps the masked lines out by several pixels. An entry matches model, data size and depth exactly. Bodies whose data holds only picture beyond the camera frame get no entry and render as before. `cargo xtask raw-frame FILE...` (crates/engine/examples/raw_frame.rs) measures a body: it aligns each raw's embedded camera JPEG with the sensor data (half-size luminance, gradient correlation, sub-pixel peak; weak, ambiguous or between-pixel peaks are flagged), counts the edge lines that hold no picture and reports what the decoder's crop keeps beyond the camera frame. A masked line is flat and its two CFA phases agree within the noise or within 0.4% of white, so filler with a small fixed offset between them (D90, D5000) counts. It prints entries only with evidence: at least 3 clean files agreeing exactly, of the model (12- and 14-bit pooled) or, with at least one of its own, with sibling models of the same readout (data and JPEG size) that agree on the same frame. On the D7500, which records its CropArea, it finds that area exactly; it declines the Z f, whose JPEG is distortion-corrected. It works for any make whose raw embeds a full-size camera JPEG: on Sony, Canon CR2 / CR3, Pentax and Samsung files it finds the decoder's own crop (relative to the active area). Every Nikon raw on raw.pixls.us without CropArea was surveyed this way (its 138 CC0 samples, plus 124 other publicly posted sample files; only the measurements are committed). Bodies whose data holds only picture beyond the frame need no entry (D750, D5300, D5500, D3300, D2X, D2Hs, D3X, D5200, Coolpix P6000, Nikon 1 AW1 / J3 / V2 / V3, the D800's crop modes); raw-parity.md lists them, and no longer claims every NEF coding but HE decodes. measured_bodies_are_consistent checks every entry lies inside its data and is listed once; measured_older_dx_bodies_image_area covers the D200, D3200, Nikon 1 V1 and best-guess entries. Fixes #976 Fixes #914 Fixes #1236 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
af4c5e102c
commit
2b3b6e7871
7 files changed
+700
-9
No files matched your search
@@ -37,6 +37,11 @@ commands:
|
||||
corpus [--download]
|
||||
show where test corpora live; --download fetches PngSuite and CC0 raw samples (raw.pixls.us) into corpus/ and checks their sha256
|
||||
stats [--exact] count tests and lines per crate (--exact: ask the test harness via `-- --list`)
|
||||
raw-frame [--json] FILE…
|
||||
measure where each raw's embedded camera JPEG sits in its sensor data, which edge bands hold no
|
||||
picture and what the decoder's crop keeps beyond the camera frame (any make with a full-size
|
||||
embedded JPEG); print image-area entries for Nikon bodies that record no crop (MEASURED_BODIES in
|
||||
crates/raw/src/vendor/nef.rs)
|
||||
";
|
||||
|
||||
fn main() -> ExitCode {
|
||||
@@ -54,6 +59,7 @@ fn main() -> ExitCode {
|
||||
Some("ci") => cmd_ci(),
|
||||
Some("corpus") => cmd_corpus(rest.contains(&"--download")),
|
||||
Some("stats") => stats::run(&root(), rest.contains(&"--exact")),
|
||||
Some("raw-frame") => cmd_raw_frame(&rest),
|
||||
Some("-h" | "--help" | "help") | None => {
|
||||
print!("{USAGE}");
|
||||
Ok(())
|
||||
@@ -69,6 +75,20 @@ fn main() -> ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
/// `cargo xtask raw-frame FILE…`: runs the `raw_frame` example of `lightcraft-engine` on the files.
|
||||
fn cmd_raw_frame(files: &[&str]) -> Result<(), String> {
|
||||
if files.is_empty() {
|
||||
return Err("raw-frame needs one or more raw files (several per camera, with detail across the frame)".into());
|
||||
}
|
||||
eprintln!("$ cargo run --release -p lightcraft-engine --example raw_frame -- {}", files.join(" "));
|
||||
let status = cargo()
|
||||
.args(["run", "--release", "-q", "-p", "lightcraft-engine", "--example", "raw_frame", "--"])
|
||||
.args(files)
|
||||
.status()
|
||||
.map_err(|e| format!("raw_frame: {e}"))?;
|
||||
if status.success() { Ok(()) } else { Err("raw_frame failed".into()) }
|
||||
}
|
||||
|
||||
/// Workspace root (parent of the xtask crate).
|
||||
pub fn root() -> PathBuf {
|
||||
// `cargo run` sets it at run time; prefer that over the compile-time value, which goes stale
|
||||
|
||||
Reference in new issue
Block a user