Start a category mask where the photograph can bear it

Clicking "architecture" made a layer whose mask was gone. Every category layer
began at STRICTNESS_DEFAULT, and that constant was fitted on the synthetic sky
the refine tests build — its own note warns that a real photograph's noise
"moves every crossing down together", which turns out to be a considerable
understatement. Measured over seven ordinary frames, half scale removes 76% to
99.5% of `architecture`, 36% to 93% of `ground` and 18% to 91% of
`vegetation`. Only sky, the category the number was calibrated against,
survives it.

An empty mask is indistinguishable from a broken one: the layer is listed, the
adjustment moves, and no pixel changes. So what this looks like from outside
is that the segmentation does not make masks at all.

No smaller constant fixes it either, because a nat of evidence means different
things over a smooth sky and over a stone facade — the useful position is
above 5 on one frame and below 1 on the next. So the frame is asked instead:
`Refinement::gentle` walks down from half scale and takes the first rung whose
gate removes no more than a sixth of the category's weight, and the model's
own outline when none of them does. One `apply` on a friendly photograph and
four on an unfriendly one, paid when a layer is made rather than for eight
categories nobody masked.

The slider's reset went to 4 as well, so taking the control back to its
"default" emptied the mask. It goes to zero now, which is the one position
documented to mean something: exactly what the model weighted.
This commit is contained in:
2026-09-10 20:27:40 +02:00
parent 404fea47a8
commit 193b35a249
5 changed files with 258 additions and 47 deletions
+15 -6
View File
@@ -3228,7 +3228,7 @@ impl DevelopSession {
},
);
layer.name = name.to_string();
// Refined from the start, where there is anything to refine with.
// Refined from the start, by as much as this photograph will bear.
//
// A category's edges are twenty proxy pixels wide before this runs, so
// the unrefined mask is the wrong default for the common case — a
@@ -3236,16 +3236,25 @@ impl DevelopSession {
// chimney in it. Zero is still one drag away, and it is exactly the
// model's own weighting when they get there.
//
// **Asked of the frame rather than taken from a constant**, and that
// is the correction rather than a refinement of the idea. The constant
// was `STRICTNESS_DEFAULT`, fitted on a synthetic sky; on real
// photographs it removes three quarters to all of `architecture`,
// `ground` and `vegetation`, so clicking a category produced an empty
// mask — the failure that reads as the feature not working at all,
// because the adjustment moves and no pixel changes. The measurements
// are on `dr_segment::Refinement::gentle`, which is what picks the
// number now.
//
// Set here rather than in `MaskLayer::new` because the number belongs
// to `dr_segment` and `dr-pipeline` does not depend on it — see
// `dr_pipeline::mask::MAX_REFINE`.
if self
layer.base_mut().refine = self
.segmentation
.as_ref()
.is_some_and(|seg| seg.category_is_refinable(name))
{
layer.base_mut().refine = dr_segment::STRICTNESS_DEFAULT;
}
.map_or(dr_segment::STRICTNESS_OFF, |seg| {
seg.category_default_refine(name)
});
if !self.graph.masks_mut().push(layer) {
return None;
}