Smooth, Sharpen, and CLAHE Filters

The panel is a new View/ViewModel pair, following the same pattern as VizRay/ViewModels/PixelInfoViewModel.cs and the ContentControl in VizRay/Views/ViewerView.xaml. The pixel-processing pipeline lives in VizRay.Imaging/Image.cs, because rendering, measurements, and export already read from SourceMat.

Behavior

A filter takes effect immediately when its button is clicked: both the pixels and the overlay text change, even before the filter is committed. Fix does not apply the filter again; it only marks the current step as committed. Until that step is committed, selecting another filter replaces it and computes the new result from the previous committed snapshot—or from the original image.

Each step is an entry in a single snapshot history, with a flag indicating whether it is committed. The original image is step 0. A single Undo moves back exactly one step: the uncommitted filter is removed from the display, leaving the previous committed filter or the original image. That click does not also remove the previous step. Redo restores the same step in full, including an uncommitted filter and its parameters.

Example: start with the original image, apply Smooth, click Fix, then apply Sharpen without clicking Fix. The overlay reads Smooth (5), Sharpen (1.5). Undo leaves Smooth (5). Redo restores Sharpen and the same overlay text. The next Undo from Smooth returns to the original image; Redo restores the already committed Smooth step.

Changing parameters in the popup recalculates the current step in place if the displayed step is that same uncommitted filter. For a committed filter, neither the pixels nor its label changes: the new value is only saved in the settings and used the next time that filter is selected. That selection adds a new uncommitted step on top of the latest committed snapshot. Each label stores the parameters used when its result was calculated. The overlay lists the step names from the first filter through the current history position, separated by commas; an uncommitted step is included just like any other step.

Selecting a new filter after Undo discards the redo branch. Flip/Rotate operations apply to the entire snapshot chain: the current step, all previous steps, the redo branch, and the separate original-image buffer if it is still retained. Every step retains the same rotation, so Undo/Redo does not change the orientation or dimensions. Annotations are rotated once, as they are now, and remain aligned with every step.

flowchart TD
    original[Original]
    select[SelectFilter] --> step[UnfixedStepOnLastFixed]
    step --> replace[SelectAnotherFilter]
    replace --> step
    step --> fix[Fix]
    fix --> fixed[FixedStep]
    fixed --> select
    step --> undo[UndoOneStep]
    fixed --> undo
    undo --> previous[PreviousFixedOrOriginal]
    previous --> redo[RedoSameStep]
    redo --> step
    redo --> fixed

Algorithms (16-bit Grayscale)

Create VizRay.Imaging/ImageFilters.cs. Write the result to a separate Mat of the same type, CV_16UC1:

Each parameter has a minimum, maximum, and step defined in code. The slider uses those definitions and snaps to the step. As before, only the value is written to Settings.json.

Whenever the displayed buffer changes, recalculate window/level using that buffer’s min/max so the CLAHE effect is visible. SourceMat always points to the current history step, so pixel probing, profiles, and export all use the same content.