LR-PROF-CAMERACOLOR: match the camera JPEG proxy to the sensor proxy size exactly
proxies() fitted the decoded camera JPEG into the sensor proxy's box, which keeps the JPEG's own aspect and can round a pixel short: an ILCE-7RM4's 1616x1080 preview, decoded at 384x257, fits a 192x128 profile proxy as 191x128, and collect_pairs rejected the mismatch. So `lightcraft-cli calibrate` skipped every file from this camera and no profile could be written. Resize the JPEG to exactly the sensor proxy's size instead; proxies() has already rejected references whose aspect differs by more than 2%. Where fitting already landed on the proxy's size the result is identical (fit is resize at a rounded size), so working renders don't change: 34 real ILCE-7RM4 ARWs render bit-identically. On 923 files from one trip calibrate goes from 0 to 843 accepted. Refs #515 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
65ad290e89
commit
fba436a93b
|
|
@ -8,7 +8,7 @@ use lightcraft_color::{D50, D65, Mat3, PROPHOTO, REC2020, bradford, luminance_20
|
|||
use lightcraft_pipeline::tone::{CameraTone, ToneMap};
|
||||
use lightcraft_raster::{
|
||||
Rgb32f,
|
||||
resample::{Filter, fit},
|
||||
resample::{Filter, fit, resize},
|
||||
};
|
||||
use lightcraft_raw::{RawFormat, RawImage, color::CameraTransform, profile::HsvTable};
|
||||
|
||||
|
|
@ -99,13 +99,22 @@ fn proxies(raw: &RawImage, bytes: &[u8], transform: &CameraTransform, size: usiz
|
|||
sensor = align_cr3_framing(sensor, &reference);
|
||||
}
|
||||
let mut sensor = fit(&sensor, size, size, Filter::Box);
|
||||
let reference = fit(&reference, sensor.width, sensor.height, Filter::Box);
|
||||
let reference = reference_at(&reference, &sensor);
|
||||
if raw.format != RawFormat::Cr3 {
|
||||
sensor.map_in_place(to_working);
|
||||
}
|
||||
Some((sensor, reference))
|
||||
}
|
||||
|
||||
/// The camera JPEG at exactly the sensor proxy's size, so the two pair pixel for pixel. Fitting it
|
||||
/// into the proxy's box instead keeps its own aspect, which can round a pixel short: an ILCE-7RM4's
|
||||
/// 1616×1080 preview, decoded at 384×257, fits a 192×128 proxy as 191×128, and `collect_pairs`
|
||||
/// then rejected every file `lightcraft-cli calibrate` was given. `proxies` has already checked
|
||||
/// that the aspects agree within 2 %.
|
||||
fn reference_at(reference: &Rgb32f, sensor: &Rgb32f) -> Rgb32f {
|
||||
resize(reference, sensor.width, sensor.height, Filter::Box)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Cr3Framing {
|
||||
scale: f32,
|
||||
|
|
@ -729,6 +738,23 @@ fn fit_tone(mut pairs: Vec<(f64, f64)>) -> Option<CameraTone> {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn camera_jpeg_matches_the_sensor_proxy_size_exactly() {
|
||||
// An ILCE-7RM4 ARW (9504×6336 crop) embeds a 1616×1080 preview; for the camera-profile proxy
|
||||
// it is decoded at 384×257 (`proxies`: twice the proxy edge) next to a 192×128 sensor proxy.
|
||||
let sensor = fit(&Rgb32f::new(9504, 6336), PROFILE_PROXY, PROFILE_PROXY, Filter::Box);
|
||||
assert_eq!((sensor.width, sensor.height), (192, 128));
|
||||
let jpeg = Rgb32f::new(384, 257);
|
||||
// what fitting gave before: a pixel short, so every pair was rejected
|
||||
assert_eq!(fit(&jpeg, sensor.width, sensor.height, Filter::Box).width, 191);
|
||||
let r = reference_at(&jpeg, &sensor);
|
||||
assert_eq!((r.width, r.height), (192, 128));
|
||||
// and at the single-photo proxy size, where fitting happened to land on the same size
|
||||
let sensor = fit(&Rgb32f::new(9504, 6336), PROXY, PROXY, Filter::Box);
|
||||
let r = reference_at(&Rgb32f::new(192, 129), &sensor);
|
||||
assert_eq!((r.width, r.height), (sensor.width, sensor.height));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linear_arw_gets_a_sensor_proxy_without_demosaicing() {
|
||||
use lightcraft_raw::{BlackLevel, ColorData, OpcodeLists, Orientation, RawData, RawFormat, Rect};
|
||||
|
|
|
|||
Loading…
Reference in New Issue