mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-01 05:57:09 -06:00
LR-IMP-FORMATS: AHD's blend leaves out a candidate that isn't finite (#2698 review)
The outright pick never let the losing candidate's NaN (beside a float raw's NaN sample) into the output; the blend did, as 0 · NaN. A candidate taken alone is now copied, and one that isn't finite is left out while the other is. A NaN sample reaches as many pixels as before the blend (9 in the new test; the blend made it 33).
This commit is contained in:
@@ -159,7 +159,16 @@ fn tile(m: &Mosaic, x0: usize, y0: usize, tw: usize, th: usize) -> Vec<[f32; 3]>
|
||||
sv += hv[j] as u32;
|
||||
}
|
||||
let wh = (0.5 + (sh as f32 - sv as f32) / (2.0 * BLEND)).clamp(0.0, 1.0);
|
||||
out.push([0, 1, 2].map(|c| rh[i][c] * wh + rv[i][c] * (1.0 - wh)));
|
||||
// a candidate taken alone is copied, and one that isn't finite (beside a float raw's NaN sample) is left out,
|
||||
// so the other's value doesn't become 0 · NaN
|
||||
let finite = |p: &[f32; 3]| p.iter().all(|v| v.is_finite());
|
||||
out.push(if wh >= 1.0 || !finite(&rv[i]) {
|
||||
rh[i]
|
||||
} else if wh <= 0.0 || !finite(&rh[i]) {
|
||||
rv[i]
|
||||
} else {
|
||||
[0, 1, 2].map(|c| rh[i][c] * wh + rv[i][c] * (1.0 - wh))
|
||||
});
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
@@ -290,6 +290,20 @@ mod tests {
|
||||
assert_eq!(demosaic(&n, Method::Ahd).data, vec![[0.1, 0.2, 0.3]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_nan_sample_spreads_no_further_than_the_chosen_candidate_takes_it() {
|
||||
// vertical stripes: the vertical candidate wins outright beside them, and the horizontal one, which reads two
|
||||
// samples to each side, is the only one that sees a NaN two columns away
|
||||
let img = Rgb32f::from_fn(32, 24, |x, _| if (x / 2) % 2 == 0 { [0.2, 0.3, 0.25] } else { [0.7, 0.8, 0.6] });
|
||||
let cfa = Cfa::bayer("RGGB").unwrap();
|
||||
let mut n = mosaic_from_rgb(&img, &cfa);
|
||||
n.data[12 * 32 + 16] = f32::NAN;
|
||||
let out = demosaic(&n, Method::Ahd);
|
||||
let bad = out.data.iter().filter(|p| p.iter().any(|v| !v.is_finite())).count();
|
||||
// the pixels that read the NaN sample themselves, as many as the outright pick gave; the blend made it 33
|
||||
assert!(bad <= 9, "{bad} pixels not finite");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_finite_samples_do_not_panic() {
|
||||
// regression: NaN samples (a float DNG) gave AHD and PPG NaN bounds for `f32::clamp`, which panics
|
||||
|
||||
Reference in New Issue
Block a user