Let the fill show the model an open void: mirror depth 0 means no ring and nothing known beyond the band
This commit is contained in:
+86
-14
@@ -89,12 +89,19 @@ pub struct Params {
|
||||
pub coarse: usize,
|
||||
/// The fine passes' band width.
|
||||
pub band: usize,
|
||||
/// How deep into the picture the mirrored context reaches. A plain
|
||||
/// reflection of a deep hole pulls in whatever is that far from the
|
||||
/// edge — a ridge, a peak — and the model, told that is what lies
|
||||
/// beyond, paints it upside down. Folding the reflection within this
|
||||
/// band keeps the ring looking like the edge it continues (sky beside
|
||||
/// sky, grass beside grass) and nothing further away.
|
||||
/// How deep into the picture the mirrored context reaches, or **zero
|
||||
/// for no mirrored context at all**: the void is then shown to the
|
||||
/// model as it is — reaching the picture's edge with nothing beyond,
|
||||
/// and, beyond the band being filled, still unknown. That is what the
|
||||
/// shipped model was trained on (a fine-tune of MI-GAN on voids cut
|
||||
/// from photographs the way a cylindrical merge cuts them, see
|
||||
/// `docs/panorama.md` §14); a ring would give it a fold to continue.
|
||||
///
|
||||
/// Non-zero is the stock model's crutch: a plain reflection of a deep
|
||||
/// hole pulls in whatever is that far from the edge — a ridge, a peak —
|
||||
/// and the model, told that is what lies beyond, paints it upside down.
|
||||
/// Folding the reflection within this band keeps the ring looking like
|
||||
/// the edge it continues and nothing further away.
|
||||
pub mirror_depth: usize,
|
||||
/// How far inside the real edge the fill also regenerates, the two
|
||||
/// blended by distance. A hard cut between real pixels and invented
|
||||
@@ -108,9 +115,9 @@ pub struct Params {
|
||||
impl Default for Params {
|
||||
fn default() -> Self {
|
||||
Params {
|
||||
coarse: 4,
|
||||
band: 96,
|
||||
mirror_depth: 48,
|
||||
coarse: 1,
|
||||
band: 192,
|
||||
mirror_depth: 0,
|
||||
feather: 24,
|
||||
stride: 384,
|
||||
}
|
||||
@@ -141,7 +148,10 @@ pub fn fill_border(
|
||||
} = params;
|
||||
let q = q.max(1);
|
||||
let band = band.max(8);
|
||||
let mirror_depth = mirror_depth.max(1);
|
||||
// No ring: the void beyond the band stays unknown, as in the model's
|
||||
// training; with a ring the far side is the coarse fill, presented as
|
||||
// known, which the stock model needed to see something there.
|
||||
let open = mirror_depth == 0;
|
||||
if width == 0 || height == 0 || rgb.len() != width * height * 3 || known.len() != width * height
|
||||
{
|
||||
return Err(PanoError::Input("fill: buffer sizes disagree".into()));
|
||||
@@ -227,7 +237,11 @@ pub fn fill_border(
|
||||
let mut any = false;
|
||||
for i in 0..width * height {
|
||||
let in_band = !known[i] && dist[i] > lo && dist[i] <= hi;
|
||||
band_known[i] = !in_band;
|
||||
band_known[i] = if open {
|
||||
known[i] || dist[i] <= lo
|
||||
} else {
|
||||
!in_band
|
||||
};
|
||||
any |= in_band;
|
||||
}
|
||||
if !any {
|
||||
@@ -369,7 +383,7 @@ fn fill_once(
|
||||
if known[i] {
|
||||
continue;
|
||||
}
|
||||
let p = (yy + RING) * pw + (xx + RING);
|
||||
let p = (yy + ctx.ring) * pw + (xx + ctx.ring);
|
||||
if wsum[p] > 0.0 {
|
||||
for ch in 0..3 {
|
||||
rgb[i * 3 + ch] = (acc[p * 3 + ch] / wsum[p]).clamp(0.0, 1.0);
|
||||
@@ -478,12 +492,25 @@ fn fold(d: usize, depth: usize) -> usize {
|
||||
struct MirroredContext {
|
||||
width: usize,
|
||||
height: usize,
|
||||
/// The padding on every side: `RING` with mirrored context, 0 without.
|
||||
ring: usize,
|
||||
rgb: Vec<f32>,
|
||||
hole: Vec<bool>,
|
||||
}
|
||||
|
||||
impl MirroredContext {
|
||||
fn build(rgb: &[f32], width: usize, height: usize, known: &[bool], depth: usize) -> Self {
|
||||
if depth == 0 {
|
||||
// Open: the picture as it is, the hole as it is. What the hole
|
||||
// holds does not matter — the model masks it out.
|
||||
return MirroredContext {
|
||||
width,
|
||||
height,
|
||||
ring: 0,
|
||||
rgb: rgb.to_vec(),
|
||||
hole: known.iter().map(|&k| !k).collect(),
|
||||
};
|
||||
}
|
||||
let fold = |d: usize| fold(d, depth);
|
||||
let (pw, ph) = (width + 2 * RING, height + 2 * RING);
|
||||
let mut canvas = vec![0.0f32; pw * ph * 3];
|
||||
@@ -534,6 +561,7 @@ impl MirroredContext {
|
||||
MirroredContext {
|
||||
width: pw,
|
||||
height: ph,
|
||||
ring: RING,
|
||||
rgb: canvas,
|
||||
hole,
|
||||
}
|
||||
@@ -634,7 +662,10 @@ mod tests {
|
||||
200,
|
||||
&known,
|
||||
&mut model,
|
||||
test_params(0),
|
||||
Params {
|
||||
mirror_depth: 48,
|
||||
..test_params(0)
|
||||
},
|
||||
&mut |_, _| {},
|
||||
)
|
||||
.unwrap();
|
||||
@@ -648,6 +679,42 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_open_void_reaches_the_tile_edge_and_stays_unknown_beyond_the_band() {
|
||||
// A 150-tall hole above and below; bands of 96. With no ring the
|
||||
// first band's tiles sit at the picture's edge, so a tile's top
|
||||
// row is unknown, and the rows deeper than the band are unknown
|
||||
// too — not "known" coarse fill — exactly as the model was trained.
|
||||
let (mut rgb, known) = picture(200, 500, 150);
|
||||
let mut model = Flat {
|
||||
tile: 64,
|
||||
seen: Vec::new(),
|
||||
};
|
||||
fill_border(
|
||||
&mut rgb,
|
||||
200,
|
||||
500,
|
||||
&known,
|
||||
&mut model,
|
||||
Params {
|
||||
band: 96,
|
||||
..test_params(0)
|
||||
},
|
||||
&mut |_, _| {},
|
||||
)
|
||||
.unwrap();
|
||||
// The first pass's tile at the picture's top edge is unknown
|
||||
// through and through: the hole is 150 deep, the tile 64, and
|
||||
// nothing beyond the band was presented as known. With a ring, or
|
||||
// with the far side shown as coarse fill, no tile is ever all hole.
|
||||
assert!(model.seen.iter().any(|(_, k)| k.iter().all(|&v| !v)));
|
||||
for i in 0..200 * 500 {
|
||||
if !known[i] {
|
||||
assert!((rgb[i * 3] - 0.5).abs() < 1e-4, "pixel {i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_fine_passes_run_in_bands_after_the_coarse_one() {
|
||||
// A 150-tall hole above and below a picture: the coarse pass sees
|
||||
@@ -663,7 +730,12 @@ mod tests {
|
||||
500,
|
||||
&known,
|
||||
&mut model,
|
||||
test_params(0),
|
||||
Params {
|
||||
coarse: 4,
|
||||
band: 96,
|
||||
mirror_depth: 48,
|
||||
..test_params(0)
|
||||
},
|
||||
&mut |_, _| {},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user