Exposure Correction¶
Purpose and expected result¶
Exposure Correction multiplies normalized samples or one selected RGB-derived
component by a scalar and clamps the result to [0,1]. In linear light, a
positive scalar can model a brighter exposure and a scalar below one can model
a darker exposure. The Exposure control is not an adjustment in stops: it
does not use the standard stop equation 2^e, and its tooltip states the factor
it applies.
For entered value e, AfterNight computes the float multiplier m as
Thus +1 means 1.2x, not the 2x of a true +1-stop adjustment; only the
positive endpoint +5 happens to produce 2x. Negative values use an extra
0.02 offset, so the mapping is discontinuous at zero and small negative
values can brighten rather than darken. The guide reports this current behavior
so that results are reproducible; it is not a recommended stop definition.
For unclipped RGB in RGB mode, the common multiplier preserves stored channel ratios. Once one channel clips, color and highlight ratios change. Selecting one stored or converted component changes only that component before RGB reconstruction and is not a physical exposure adjustment.
Every Apply records its result as nonlinear on the processing-state cards, even an unclipped scaling of linear data, and keeps the source's other FITS cards, astrometric solution, and acquisition record; see Inputs, outputs, and metadata.
At a glance¶
| Item | Current behavior |
|---|---|
| Menu path | Process > Adjustments > Exposure |
| Enabled when | An image or sequence is active, the same process is not already attached to it, and no attached process holds exclusive access |
| Inputs | One intended normalized grayscale or RGB still or sequence; an optional active mask must match target geometry |
| Outputs | Destructively replaces a still or, after successful temporary processing, a sequence; Take snapshot creates an auxiliary still without replacing the target; component modes reconstruct RGB; automatic sequence CFA debayer can change frame format/channels; no file is written directly |
| Recommended image state | Linear-light data for exposure-like scaling; on nonlinear data this is only encoded-value brightness scaling; either way the result is recorded as nonlinear |
| Preview support | Asynchronous RT preview of the full image or a selected preview area, using the same multiply-and-clamp operation as Apply, plus a histogram of the mask-aware result; the preview viewer can display Linear values or a display-only Autostretch |
| Sequence support | Supported: each decoded frame is processed exactly as a still image of it would be, into a temporary sequence that replaces the target only after every frame succeeds, with per-frame progress and Cancel; the configured CFA auto-debayer request can produce RGB frames |
| Mask support | Supported for preview, still Apply, and sequence Apply by post-transform blending; white applies, black protects, gray blends, and Invert Mask reverses weights |
| External dependencies | None; bundled engine only; no tool, profile, catalog, or network service |
Before you start¶
- Use linear-light data if the goal is exposure-like scaling. Multiplying gamma-encoded or already stretched samples changes display values, not scene exposure.
- Apply records its result as nonlinear even when no sample clipped. If later steps rely on a recorded linear state, run them before Exposure Correction.
- Treat the control as a project-specific scalar control, not a stop control.
For a true multiplier
2^s, the current positive branch can represent only1..2x, and its label does not identify the equivalent stop value. - Inspect highlights before Apply. Every stored/component value above
1/mis clipped to1; no later operation can recover those distinctions. - RGB preserves ratios only while all channels remain below the clamp. Red/Green/Blue or derived-component processing intentionally changes color.
- Avoid hue/chroma modes for ordinary exposure work. Their normalized encoded coordinates are multiplied and clamped as ordinary scalars; hue is not treated as a circular angle.
- In a converted-component mode only the component is clamped: on a floating
image the reconstructed RGB color is not clamped to
[0,1], and on an integer image it saturates at the type's range. - For a sequence, verify the selected Channel, active mask, and CFA auto-debayer setting before Apply. The same captured Exposure/Channel selection is used for every decoded frame; cancellation discards the temporary output.
Procedure¶
- Select a still or sequence and open Process > Adjustments > Exposure. Confirm Target Image, leave Channel: RGB, and keep Preview selected.
- Change Exposure slowly. Positive values multiply by
1+e/5; negative values multiply by1.02+e/5. The identity value0disables Apply. - Inspect the histogram's white endpoint and bright colored stars at 100%. Reduce the value if one or more channels form a clipped plateau. On a large image, check Preview area on the preview view to tune on one region.
- If choosing a single stored/derived channel, inspect color and gamut. This is component scaling, not exposure.
- If a mask is active, judge the mask-aware preview. Histogram clipping refers to displayed result bins after blending.
- Apply when the result is acceptable. For a sequence, monitor the progress
dialog and use Cancel to preserve the original sequence. Image History holds
one Exposure Correction step that Undo reverses, and the result is
recorded as nonlinear with
exposure-correctionas the operation.
Complete parameter and action reference¶
| UI label/action | Type and unit | Runtime default | Persisted-default exception | Valid values, step, or constraints | Effect of increasing, decreasing, or selecting | Dependencies and enable/visibility rules | Quality, artifact, runtime, memory, or disk trade-off | Scope: preview/apply, channel, mask, still/sequence | Persistence |
|---|---|---|---|---|---|---|---|---|---|
| Histogram plot | Graph, normalized intensity/count | Source or current preview; RGB channels overlaid | None | Binning comes from Plot resolution | Shows source or mask-aware preview distribution and approximate endpoint-bin clipping; never changes samples | Show histogram controls visibility | Recalculation adds work; endpoint counts are resolution-dependent | Display only; shown source/preview channels | Recomputed after source, preview, or resolution changes |
| Left-drag in histogram | Graph gesture | No readout | None | Hold left button and move | Shows normalized coordinate readout | Histogram must be shown | Diagnostic only | Display only | Ends on release |
| Middle-drag in histogram | Graph gesture | Fitted/unpanned | None | Hold middle button and drag | Pans within graph scroll area | Useful only beyond viewport | No output effect | Display only | Until reset/window close |
| Ctrl+mouse wheel in histogram | Graph gesture | Fitted size | None | Up 1.20x; down 0.8x; plain wheel scrolls |
Zooms around cursor | Interactive graph enabled | Rendering area only | Display only | Window lifetime; process Reset does not change it |
| Zoom in | Toolbar action | Fitted size | None | Each action 1.30x |
Enlarges plot | Disabled with hidden histogram | Rendering only | Display only | Window lifetime |
| Zoom out | Toolbar action | Fitted size | None | Each action 0.70x |
Shrinks plot | Disabled with hidden histogram | Rendering only | Display only | Window lifetime |
| Zoom reset | Toolbar action | — | None | One action | Fits plot/resets scrolling | Disabled with hidden histogram | Rendering only | Display only | Immediate |
| Show grid | Toggle | Checked | None | Checked/unchecked | Shows/hides grid | Disabled with hidden histogram | Display-only aid | Display only | Window lifetime; hiding histogram resets grid internally |
| Show clipping info | Toggle | Checked | None | Checked/unchecked | Shows/hides histogram endpoint-bin counts | Disabled with hidden histogram | Binning-dependent estimate, not a count of values clipped specifically by this process | Display only | Window lifetime |
| Absolute scales | Toggle | Unchecked | None | Checked/unchecked | Checked normalizes each visible histogram channel to its own peak | Disabled with hidden histogram | Can conceal relative channel strength; no image normalization | Display only | Window lifetime |
| Draw histogram areas | Toggle | Unchecked | None | Checked/unchecked | Filled-area versus line drawing | Disabled with hidden histogram | Area overlap can obscure channels | Display only | Window lifetime |
| Show histogram | Toggle | Checked | None | Checked/unchecked | Hides/clears graph and disables toolbar, or reloads source/preview | Always available while idle | Hiding saves graph work, not preview processing | Display only | Window lifetime; process Reset does not change it |
| Plot resolution | Combo box, bins | 8-bit (256) | None | 6-bit (64), 7-bit (128), 8-bit (256), 9-bit (512), 10-bit (1024), 12-bit (4096), 14-bit (16K), 16-bit (64K), 100 levels, 1000 levels, 10000 levels | More bins refine the graph/endpoint estimates | Disabled with hidden histogram | Higher bins cost graph memory/rendering; output precision unchanged | Display only | Window lifetime |
| Exposure | Double value plus slider labelled Exposure; its tooltip states the factor below | 0.00 identity |
None | -5.00..+5.00; two decimals; spin step 0.03; slider linear over 1,000 positions |
Positive uses 1+e/5; negative uses 1.02+e/5; -0.10 is another identity and (-0.10,0) brightens despite being negative |
Enabled while idle; Apply disabled only exactly at 0.0 |
Positive values clip samples above 1/m; negative branch reaches 0.02x at -5; displayed value is not a true stop count |
Preview/Apply; selected channel/component; mask post-blend; still/sequence | Captured per execution; Reset/success returns 0.0 |
| Target Image | Image selector | Attached/active target | None | Open eligible image or sequence | Changes source, Channel list, histogram, Preview, Apply | Active image required; duplicate/exclusive gates apply | Wrong target is destructively replaced; sequence writes a temporary result and replaces only after success | Preview/Apply source and active mask | Target lifecycle; Reset does not change it |
| Channel | Combo box | RGB for RGB; disabled Grayscale for mono | None | RGB, Red, Green, Blue, CIE L* (Lightness), CIE a, CIE b, CIE c, CIE h, CIE X, CIE Y (Luminance), CIE Z, HSL Hue, HSL Saturation, HSL Lightness, HSV Hue, HSV Saturation, HSV Value, YCbCr Luma, YCbCr Blue Chroma, YCbCr Red Chroma | RGB/Grayscale multiplies stored samples; Red/Green/Blue multiplies one stored channel; other modes convert, multiply one encoded component, and reconstruct RGB | Component choices require RGB; mono selector disabled | RGB preserves ratios until clipping; other modes add conversion work and gamut risk (a floating reconstructed color is not clamped to [0,1], an integer one saturates at the type's range); source metadata is kept in every mode |
Preview/Apply; selected component; mask post-blend; still/sequence | Captured by current selection; Reset/success returns RGB when target is RGB |
| Preview | Checkbox | Checked | None | Checked/unchecked | Enables/disables the asynchronous multiply/clamp preview and switches histogram result/source | Process idle | Result/histogram buffers cost time/memory; same mathematical transfer as Apply | Preview only; mask-aware; current still/current displayed sequence frame | Window lifetime; Reset does not change it |
| Preview pane | Full-image viewer | Current result | None | Standard viewer zoom/pan/display controls | Shows mask-aware result | Exists only with Preview | Holds result image; component conversions add buffers | Preview only; target unchanged | Window lifetime |
| Display Mode | Preview-toolbar combo box | Inherits the target view's Linear or Autostretch mode when the preview is created | None | Linear, Autostretch | Changes only how the Exposure result is displayed; Autostretch uses cached full-target source statistics without changing process output pixels | Exists only with Preview; Autostretch enables Autostretch Settings | A source-derived display stretch can reveal faint structure or exaggerate noise and must not be mistaken for Exposure output | Preview display only; no effect on Apply, snapshots, masks, or sequences | Preview-view state; process Reset does not change it |
| Autostretch Settings | Preview-toolbar dialog action | Disabled in Linear mode; current target-view settings are inherited | Current shared-view values load when opened | Opens the shared settings for Target Background, Shadows Clipping, linked channels, neutralization/color calibration, saturation/background, brightness, contrast, banner, Reset, and Close | Tunes only the preview viewer's display stretch | Enabled only in Autostretch mode; the action is disabled while its dialog is open; Apply Stretch is hidden in this RT-preview dialog | Aggressive display settings can exaggerate noise/color without changing Exposure output | Preview display only | Viewer-scoped; not captured in Exposure parameters or history |
| Switch image | Preview-toolbar action | Exposure preview shown | None | Click; Space; right-click; Ctrl+Shift+O | Toggles the preview viewer between the current result and original target | Exists only with Preview | Display comparison only; no recomputation or pixel change | Preview display only; still/current displayed sequence frame | Preview-window lifetime |
| Preview area | Preview-toolbar checkbox | Unchecked | None | Checked/unchecked; move/resize the selection overlay | Limits preview and snapshot processing to a selected area and composites that result over the original full image; inside the area the preview is what Apply makes of an image of that area | Exists only with Preview | Reduces multiply/component work while tuning; does not limit final Apply | Preview and Take snapshot only; mask is cropped consistently | Preview-window lifetime; Reset does not change it |
| Take snapshot | Preview-toolbar action | No snapshot | None | Click or Ctrl+Shift+K | Re-executes the current Exposure settings at source depth and opens a new still named <target> - Exposure Correction - SNAPSHOT |
Exists only with Preview | Allocates and processes an auxiliary image; active mask and selected preview area are honored; Display Mode/Autostretch is not baked into the snapshot | New still image; target is unchanged; a snapshot is a preview result and is not recorded as nonlinear | Each action creates a separate image view |
| Apply | Button/action | Disabled at Exposure 0.0 |
None | One action at any other displayed value, including the second identity -0.10 |
Captures Exposure and runs one fused multiply-and-clamp program over the selected channel for a still or each decoded sequence frame | Target must lock; controls disabled during the run | One parallel engine pass; integer samples add a floating working copy; conversions and masks add passes; recording the nonlinear state usually copies the result once more; clipping is irreversible | Destructive still/sequence replacement; active mask applies | Success records one history step, then resets Exposure and Channel |
| Reset | Button/action | Enabled while idle | None | One action | Restores Exposure 0.0 and RGB for an RGB target |
Does not change Target, Preview, or histogram toolbar/zoom | No output cost | UI only | Immediate |
| Close | Button/action | Enabled while idle | None | One action | Closes without Apply | Disabled during commit | Pending preview result is discarded | UI only | No setting persistence |
| Sequence progress / Cancel | Shared modal progress dialog and Cancel action | Created automatically when sequence Apply starts | None | One progress update per frame; cooperative Cancel | Processes decoded frames into a temporary sequence and replaces the target only after success | Sequence target only | Sequence processing adds decode/encode and temporary-disk cost; automatic CFA debayer can produce RGB frames | Sequence Apply; chosen channel and active mask apply to every frame | Cancel or a failed frame discards the temporary sequence; success replaces the sequence, records one history step, and resets settings |
How the algorithm works¶
Transfer, clipping, and channel behavior¶
The standard exposure-stop law is m=2^s: +1 doubles linear-light samples
and -1 halves them. AfterNight instead uses the piecewise linear control map
shown above. On the positive branch, the equivalent stop change is
log2(1+e/5); on the negative branch it is log2(1.02+e/5).
For normalized finite input, multiplication is followed by an unconditional
clamp. Positive values therefore create a hard highlight plateau wherever
x >= 1/m. The negative branch's multiplier remains positive over its allowed
range, reaching 0.02 at -5, so ordinary normalized values do not black-clip
except exact zero. Floating samples outside [0,1] are also clamped after
multiplication; a not-a-number sample stays not-a-number. Samples that the
image's own validity rule or mask marks as invalid are left as they were.
RGB and selected components¶
- RGB uses one multiplier independently on every stored R/G/B value. Ratios are preserved before clipping; they diverge when channels reach white at different input levels.
- Red, Green, or Blue changes only one stored channel.
- CIE, HSL, HSV, and YCbCr modes convert the image's red, green, and blue,
multiply and clamp one component handed over in the unit interval as a
Float32 working plane (Float64 for a 64-bit float image), then reconstruct
RGB. A source whose description says it is linear is read as linear RGB; any
other is read as sRGB-encoded. Reconstruction can leave the gamut or alter
hue/chroma: a floating result is not clamped to
[0,1], and an integer result is rounded to the nearest code and saturated at the type's range. CIE components are reconstructed through the exact inverse of the XYZ matrix, and YCbCr through unrounded luma-chroma coefficients. Hue receives no circular wrap treatment. - Grayscale and one-channel CFA stills are treated as one stored channel. This process does not demosaic a still.
The operation keeps the source pixel type. Integer input is read in normalized units (an unsigned integer as a fraction of its largest value, a signed one counted from its smallest value to its largest), converted to a floating working copy (Float64 for the two 32-bit types, Float32 otherwise), multiplied by the single-precision factor, clamped, and rounded back to the nearest code, ties to even. Float input remains float and double remains double. The multiply and the clamp are one fused engine pass on the operation's threads. Preview and Apply use the same engine operation, although histogram bins remain diagnostic only.
Inputs, outputs, and metadata¶
Image state, metadata, masks, and history¶
Scalar multiplication is exposure-like only in linear light and, before
clipping, preserves linearity. Every Apply nevertheless records its result as
nonlinear on the processing-state cards a saved file carries: ANLIN becomes
nonlinear, ANASRC process, ANOP exposure-correction, and ANBASIS the
basis a stretched image of its kind is in (for example display-rgb for an RGB
image). A linear transfer function the source claimed is no longer claimed, and
the image's lineage gains an entry naming the engine operation with the exposure
and its factor.
- Every other FITS card, the astrometric solution, and the acquisition record are kept, in stored-channel and converted-component modes alike.
- A Take snapshot image is a preview result and is not recorded as nonlinear.
An active mask is blended afterward as
source*(1-mask) + corrected*mask, reversed for an inverted mask. Factor
derivation and clipping happen before this blend. Image History records one step
named Exposure Correction, described as Adjust exposure to <e>, followed
by in channel: <Channel> for an RGB target (for example
Adjust exposure to 1.5 in channel: RGB); it states the displayed control
value, not the actual multiplier/equivalent stops. Undo restores the previous
image. Successful still Apply resets Exposure to zero and Channel to RGB.
A run whose stop is requested (Cancel in a sequence's progress dialog, or the target closing while a run works) is stopped inside the engine operation and publishes nothing; the image and its history stay as they were.
Sequence Apply processes each decoded frame as an Apply processes a still image of it, active mask included, writes the frames to a temporary sequence, supports Cancel from its progress dialog, and replaces the target only after every frame succeeds; a cancelled or failed run leaves no temporary output. The current CFA auto-debayer request is passed to the sequence reader. One history step is recorded.
Parameter interactions and starting points¶
| Combination | Conservative starting point | Too weak looks like | Too strong or defective looks like | Adjustment order |
|---|---|---|---|---|
| Exposure + highlight headroom | Small positive increments around 0.1..0.3 |
Brightness barely changes because multipliers are only 1.02..1.06 |
White plateau and colored-star saturation | Inspect maximum/channel histograms, raise slowly, stop before clipping |
| Negative value + current discontinuity | Use e <= -0.10 only after checking the formula |
-0.10 changes nothing |
Values between -0.10 and 0 brighten; near zero the preview jumps |
Treat the value as scalar control, not stops; verify result numerically |
| RGB + channel clipping | Leave RGB selected | Desired brightening remains modest | One channel clips before others and changes color | Inspect each RGB endpoint, then reduce Exposure |
| Component mode + color | Prefer RGB for physical exposure intent | Selected component has little visible effect | Hue, saturation, or gamut shifts after reconstruction | Choose component only for deliberate color editing; inspect colors |
| Mask + clipping | Use soft transitions and modest positive values | Protected region changes too little | Applied region clips or mask boundary becomes visible | Tune unmasked transfer, then inspect mask-aware result |
Performance¶
The core is one parallel multiply/clamp pass. Integer samples add a floating working copy; stored single-channel modes avoid color conversion; component modes compute a floating working plane and convert back. The run works on a copy of the target, and recording the nonlinear state usually copies the result once more; if the session's memory budget refuses one of these copies, Apply publishes nothing and reports the refusal. An active mask adds another full-image blend, and Preview also retains a result and updates the histogram. Histogram resolution changes diagnostic rendering, not output precision or the multiplier.
Disable Preview while entering several values on a large image, or use Preview area, then re-enable the full preview for the final check. No approved project image was timed, so no production throughput or memory figure is claimed.
Worked example¶
- Evidence mode: Source-, focused-test-, and calculator-derived; not executed on project-owned astronomical data.
- Positive setting: With Exposure
+1, the current multiplier is1.2, not2. Inputs[0.25, 0.50, 0.90]become[0.30, 0.60, 1.00]; the last raw value is1.08and clips. The equivalent unclipped change is aboutlog2(1.2)=+0.263stops. - Negative setting: With Exposure
-1, the multiplier is0.82, so input0.50becomes0.41. This is about-0.286stops, not-1stop (0.25). - Discontinuity checkpoint: Exposure
-0.10produces multiplier1.0even though Apply is enabled. Exposure-0.05produces1.01, so input0.50becomes0.505: a negative displayed value brightens. At exactly0, the multiplier returns to1and Apply is disabled. - Inspect in real use: Check each RGB white endpoint, the brightest star cores, and the recorded history value. Do not translate the displayed value into stops without applying the piecewise equation.
- Limitations: No real-image color fidelity, clipping recovery, metadata round trip, executed sequence output, or production timing was measured.
Warnings and limitations¶
The current control is not calibrated in exposure stops
AfterNight does not compute 2^Exposure. A displayed +1 gives 1.2x, and
-1 gives 0.82x. Use the documented piecewise multiplier when exact
scaling matters.
Small negative values can brighten
The negative branch adds 0.02, creating a discontinuity at zero.
-0.10 is an enabled identity and values between -0.10 and 0 brighten.
- Positive scaling hard-clips every value above
1/m; clipped detail and color ratios cannot be restored later. - Scaling nonlinear/encoded samples is not scene exposure compensation. Work in linear light when that interpretation matters.
- Every Apply is recorded as nonlinear, even an unclipped scaling of linear data. Run steps that rely on a recorded linear state before Exposure Correction.
- Component modes are color-coordinate edits, not exposure changes, and a
floating reconstructed color is not clamped to
[0,1]. - History records the displayed value rather than actual multiplier, so the piecewise formula is required to reproduce the math outside AfterNight.
- Integer results are rounded to the nearest code, ties to even.
- A not-a-number floating sample is not repaired. Use finite normalized data.
Troubleshooting¶
| Symptom or exact error | Verified cause/validation path | Recovery | Evidence source |
|---|---|---|---|
+1 does not look one stop brighter |
Current multiplier is 1+1/5=1.2, not 2^1=2 |
Use the current formula, which the tooltip states, and judge highlights; do not read the value as stops | ExposureCorrectionProcess::exposureFactor; worked calculator reproduction |
| A small negative value brightens | Negative branch is 1.02+e/5; it exceeds one for -0.10<e<0 |
Use e<-0.10 for darkening and verify the actual multiplier |
ExposureCorrectionProcess::exposureFactor |
Exposure -0.10 runs but changes no pixel in [0,1] |
It is a second mathematical identity, while Apply is disabled only at exact 0.0; floating samples outside [0,1] are still clamped, and the result is still recorded as nonlinear with a history step |
Reset to 0; avoid committing -0.10 |
ExposureCorrectionProcess::exposureFactor; ExposureCorrectionProcess::settingsUpdatedImpl |
| Highlights become flat white or change color | Multiply result is clamped to one; RGB channels can reach the clamp at different inputs | Reduce Exposure or create headroom before scaling | buildScaleBiasProgram clamp; ExposureCorrectionProcess::executeTypedProcessIteration |
A floating image has values outside [0,1] after a component mode |
Only the component is clamped; it is converted back to RGB without clamping a floating result | Use a smaller change or a stored-channel mode | applyProcessChannelScope; ChannelScope.h recomposition |
| A later step treats the result as nonlinear | Apply records ANLIN nonlinear and ANOP exposure-correction on the result, even without clipping |
Expected; run steps that need a recorded linear state first, or undo the step in Image History | process_utils::recordNonlinearResult |
| Apply fails with an error naming the memory budget | The session's memory budget cannot hold the run's copy of the target and the recorded result | Close other images, work on a smaller image, or raise the memory limit on the Processing settings page (it takes effect at the next start); the target is unchanged | process_utils::recordNonlinearResult; ImageRTPreviewControl::finishRun |
| A cancelled sequence does not replace the target | The sequence run writes a temporary sequence and publishes it only when every frame succeeded; Cancel stops the run and leaves no output | This is expected; restart Apply when ready | ImageRTPreviewControl::runOverSequence |
| Apply resets the controls | Shared successful-commit path calls Exposure Reset | This is expected; re-enter settings for another still | resetSettingsAsync; ExposureCorrectionProcess::resetSettings |
Related workflow steps¶
Complete calibration and linear color work before using an exposure-like correction. Use Image Statistics and the histogram to measure highlight headroom. Compare Gamma Correction for nonlinear midtone shaping, Histogram Transformation or Statistical Stretch for a main stretch, and Adjust Brightness/Contrast for an encoded-value brightness/contrast control. Monitor Image History after Apply.
References and provenance¶
- AfterNight project source — authoritative for the current piecewise multiplier, clamp, controls, channel conversion, masks, metadata/state behavior, history, display-only execution autostretch, and the temporary replacement-sequence workflow.
- The standard photographic stop relation
m=2^sis used only as the comparison definition needed to interpret the current UI; AfterNight does not implement that equation here.