diff --git a/docs/dev/panorama.md b/docs/dev/panorama.md index 458daa7..4dbfe4d 100644 --- a/docs/dev/panorama.md +++ b/docs/dev/panorama.md @@ -244,7 +244,9 @@ first source with a `-pano` suffix, beside it. Three samples per pixel rather than a CFA: the warp resamples, and there is no sensor grid to mosaic back onto. Nothing else about being a RAW is lost — no white balance, no curve, no matrix, no clip has been applied — and the -photographer develops the panorama afterwards as one photograph. +photographer develops the panorama afterwards as one photograph. One sample +is rewritten: a blown one, which is written as the camera value the +composite's balance calls grey rather than as the sensor's (1, 1, 1) — §15. The sources are portrait frames in the 6D set: `Orientation` is applied before alignment (learned features are not rotation-invariant) and the @@ -285,7 +287,9 @@ carrying the first source's EXIF in a sub-IFD as `dr-export` already does. - The dialog shows the aligned proxies in the chosen projection, with the projection, horizon and crop controls of FR-MRG-4, and the per-frame residuals. A frame that failed to align is named there (FR-MRG-5), and the - merge cannot be confirmed with it in the set. + merge cannot be confirmed with it in the set. *(Since 2026-09-27 each row + has a box: an unticked frame is left out and the rest are solved again from + what the first pass measured — §15.)* - Confirm starts the FR-MRG-7 job. The composite appears in the grid when the file is written and catalogued, beside its sources, with the merge as the first entry in its history. @@ -565,3 +569,40 @@ gaps between cells — built and measured in `darkroom-infill` and the next thing to port into `dr_pano::fill` (it needs the discriminator as a second model, ~80 MB fp16). FR-MRG-4's *experimental* stays. + +## 15. Leaving a frame out, and white clouds — 2026-09-27 + +**A frame is left out from its row, not by starting again.** Until now a +frame that did not fit ended the job with its name, and the only way on was +Back, a smaller selection, and every frame read, demosaiced and searched for +keypoints again. Each row of the Frames table on the merge page now has a +box, ticked by default. Unticking one leaves the frame out and the rest are +solved again at once; ticking it brings it back. + +What makes that cheap is a split in `dr_pano::align`. `match_pairs` does +the matching and the pairwise RANSAC once over every frame — about 5 s for +the twelve-frame fixture — and `solve` takes a subset and uses only the +links among the frames in it, about 0.1 s. Solving a subset by re-aligning +it from scratch was tried and is wrong: the RANSAC seeds are keyed on frame +position, so dropping a frame moved every seed after it, and on the fixture +that was enough to lose a marginal link and strand a neighbour of the frame +left out. A frame whose only overlap was with one left out is reported +unaligned, exactly as it would be had it never been measured with it. + +**A frame that cannot be placed no longer ends the job either** (FR-MRG-5). +Its row names it and says why, and `Merge` stays off until it is unticked — +still never a silent drop. The headless example leaves such frames out the +same way, and takes `--leave-out N` to untick frame `N` once the first +alignment is in. + +**Blown highlights stay white.** A clipped photosite reaches the merge as +camera (1, 1, 1), which the as-shot balance turns magenta. The alignment +preview balanced it with no highlight rule, so every blown cloud was pink +on the page. The DNG had a quieter form of the same fault: a frame's gain +below one moved a blown sample off the white level, and the feather mixed +it into a neighbour's real sky, after which the develop's own highlight +desaturation no longer recognised it. The merge shader (`merge.wgsl`) and +the preview (`grey_if_blown` in `dr_ui::merge`) now write a blown sample, +before the gain, as the camera value the composite's balance maps to grey — +the develop pipeline's neutral, fading in from `CLIP_ONSET` exactly as the +develop's does. diff --git a/docs/dev/requirements.md b/docs/dev/requirements.md index 488f23c..f906923 100644 --- a/docs/dev/requirements.md +++ b/docs/dev/requirements.md @@ -1979,6 +1979,11 @@ The same rule as `spot-removal.md`'s and D17's: a tool that quietly alters or om photograph is the failure this application must not have, and here the omission would be an entire frame. +*Amended 2026-09-27:* the job no longer stops. The frame is named on its row, with why, and the +merge cannot be confirmed until the photographer unticks it; the rest are then solved again from +the pairs already measured (panorama.md §15). The omission is the photographer's, made in view, +which is what this clause asks — never a silent drop. + **FR-MRG-6 — Provenance.** *(general to any merge)* The composite's sidecar carries `derived_from`: the content hashes of its sources in order, and the merge parameters. The history records the merge as the first entry, and export metadata declares the composite as one. Sources diff --git a/docs/manual/README.md b/docs/manual/README.md index 767b7bf..f6e532d 100644 --- a/docs/manual/README.md +++ b/docs/manual/README.md @@ -345,6 +345,12 @@ the border to be filled rather than cropped, then `Merge`. The composite is written beside its sources as a DNG and appears in the grid with the merge as the first step in its history. +Each frame has a box in the `Frames` list. Untick one to leave it out, and +the rest are aligned again at once, without reading the frames again; tick +it to bring it back. A frame that cannot be placed is named there with why, +and `Merge` stays off until it is unticked. Blown sky stays white in the +preview and in the composite. + ![Twelve frames aligned, the projections tried, and the border filled](media/panorama.gif) ![The alignment on a cylinder, each frame outlined where it landed](media/panorama-aligned.png)