FR-DEV-20 — Perspective correction #13

Closed
opened 2026-09-05 16:09:21 +00:00 by dtourolle · 2 comments
Owner

Framing shall include perspective correction — vertical and horizontal keystone — applied before the crop.

Why

The one corrective operation with no implementation anywhere in the tree. framing.rs offers ±45° straighten, quarter turns and flips; there is no perspective transform.

Converging verticals are the commonest geometric fault in architectural and interior work, and correcting them reframes the image, which is why the order relative to the crop is not a preference. framing.rs already documents and enforces the coordinate order this has to slot into.

Acceptance

  • Runs in the coordinate chain between framing and the lens warp, preserving the documented space: output pixel → framing → warp (lens) → sample → colour ops → output.
  • Carries Attribute::Compose, so it is withheld from a settings paste by default alongside the crop — for the same reason.
  • Interacts correctly with max_inscribed_crop, which must account for the transform.

Priority

Low, and genre-bound. Listed so its absence is a decision rather than an oversight.


Part of the Develop Ergonomics spec (FR-DEV series proposal), 2026-09-05.

Framing shall include **perspective correction** — vertical and horizontal keystone — applied before the crop. ## Why The one corrective operation with no implementation anywhere in the tree. `framing.rs` offers ±45° straighten, quarter turns and flips; there is no perspective transform. Converging verticals are the commonest geometric fault in architectural and interior work, and correcting them **reframes the image**, which is why the order relative to the crop is not a preference. `framing.rs` already documents and enforces the coordinate order this has to slot into. ## Acceptance - [ ] Runs in the coordinate chain between framing and the lens warp, preserving the documented space: `output pixel → framing → warp (lens) → sample → colour ops → output`. - [ ] Carries `Attribute::Compose`, so it is withheld from a settings paste by default alongside the crop — for the same reason. - [ ] Interacts correctly with `max_inscribed_crop`, which must account for the transform. ## Priority Low, and genre-bound. Listed so its absence is a decision rather than an oversight. --- Part of the Develop Ergonomics spec (FR-DEV series proposal), 2026-09-05.
dtourolle added the developpipelinesize:S labels 2026-09-05 16:09:21 +00:00
dtourolle changed title from FR-DEV-19 — Perspective correction to FR-DEV-20 — Perspective correction 2026-09-19 10:19:43 +00:00
Author
Owner

Renumbered from FR-DEV-19, which the spec assigned to mask editing on 2026-09-06. The clause enters the spec as FR-DEV-20 when it is built; per the 2026-09-19 audit the spec's numbering wins over a number reserved in a title.

Renumbered from FR-DEV-19, which the spec assigned to mask editing on 2026-09-06. The clause enters the spec as FR-DEV-20 when it is built; per the 2026-09-19 audit the spec's numbering wins over a number reserved in a title.
Author
Owner

Merged to master: ff89a4f, 5a50011, 114d979. FR-DEV-20 is now in requirements.md.

  • The keystone is two framing parameters, keystone_v and keystone_h (-100..100), so it inherits framing's Compose attribute, sidecar storage, paste scoping, history and reset. Sidecars written before this read as no correction.
  • The shader's coordinate chain is output → crop → straighten → perspective → orientation → lens warp → sample, so "vertical" means vertical as the photo is shown. The CPU copies of the map apply the same step, so masks, gradients and spot handles follow it. The output frame maps onto a trapezoid inside the source, so a keystone alone never leaves black corners.
  • max_inscribed_crop searches numerically when a keystone is set, and every rect it returns is tested corner by corner. Without a keystone the closed form is unchanged.
  • UI: Vertical and Horizontal sliders under Straighten in Compose. Releasing one refits the crop, each move is an undoable step, and the Compose reset clears them.
  • Sign: positive Vertical spreads the top, which fixes a building shot from below. Positive Horizontal spreads the right side. This deliberately does not follow Lightroom's sign.
  • Tests: the pipeline maths (no sampling outside the source, converging lines come out parallel, sideways-stored files, the crop search), a GPU render check, and a develop session test. Also checked in the app.

Not covered: the segmentation region overlay does not follow the keystone (it already ignored quarter turns; noted in masks.rs). There is no Aspect or Scale slider. Saving from the running app was not exercised; the sidecar round trip is covered by a unit test.

Merged to master: ff89a4f, 5a50011, 114d979. FR-DEV-20 is now in requirements.md. - The keystone is two framing parameters, `keystone_v` and `keystone_h` (-100..100), so it inherits framing's `Compose` attribute, sidecar storage, paste scoping, history and reset. Sidecars written before this read as no correction. - The shader's coordinate chain is output → crop → straighten → perspective → orientation → lens warp → sample, so "vertical" means vertical as the photo is shown. The CPU copies of the map apply the same step, so masks, gradients and spot handles follow it. The output frame maps onto a trapezoid inside the source, so a keystone alone never leaves black corners. - `max_inscribed_crop` searches numerically when a keystone is set, and every rect it returns is tested corner by corner. Without a keystone the closed form is unchanged. - UI: Vertical and Horizontal sliders under Straighten in Compose. Releasing one refits the crop, each move is an undoable step, and the Compose reset clears them. - Sign: positive Vertical spreads the top, which fixes a building shot from below. Positive Horizontal spreads the right side. This deliberately does not follow Lightroom's sign. - Tests: the pipeline maths (no sampling outside the source, converging lines come out parallel, sideways-stored files, the crop search), a GPU render check, and a develop session test. Also checked in the app. Not covered: the segmentation region overlay does not follow the keystone (it already ignored quarter turns; noted in `masks.rs`). There is no Aspect or Scale slider. Saving from the running app was not exercised; the sidecar round trip is covered by a unit test.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dtourolle/DarkRoom#13