An interactive visualization of inverse image filter recovery using gradient descent. Given a target image produced by an unknown filter, the program recovers the filter parameters by minimizing the mean squared error between the filtered output and the target, for both color grading pipelines and convolutional kernels.
The program runs two simultaneous optimization problems side by side:
Color filter recovery recovers five scalar parameters (brightness, contrast, tint R/G/B) that reproduce a target color-graded image from the original input. Three filter types are supported: Filter (neutral), WarmFilter (boosts reds, cuts blues), and CoolFilter (boosts blues, cuts reds).
Convolution kernel recovery independently recovers the 3x3 kernel weights for three classical image processing kernels (Emboss, Sobel, Edge Detection) by minimizing the difference between the output of the unknown target kernel and the current learned kernel applied to a grayscale version of the input image.
Both optimizations run via vanilla gradient descent with analytically derived gradients (hand-computed chain rule, verified against finite differences). Five post-processing activation functions can be applied on top of the filter output: identity, swish, softplus, tanh, and square.
pipeline.py- filter math:Filter/WarmFilter/CoolFilterclasses, activation functions and their gradients, forward passes (apply_filter_raw,apply_conv_filter_raw), gradient descent steps (color_grad_step,conv_grad_step), and finite-difference gradient verification. Depends only on NumPy.main.py- interactive matplotlib UI (FilterApp): scene/activation/filter-type selectors, play/pause/reset controls per optimizer, live loss plots.
numpy
matplotlib
pillow
Install with:
pip install numpy matplotlib pillowPlace the three scene images inside an images/ folder in the same directory as the scripts, then run:
python main.pyScene images (images/):
beach.pngcar.pngsoap_bubble.png
On startup the program runs gradient verification for all activations and prints results to the terminal, then opens the interactive window.
The right panel has three radio selectors:
- Scene - switch between the three input images (resets all optimizers)
- Activation - switch the post-processing activation function (resets all optimizers)
- Filter type - switch between Filter, WarmFilter, CoolFilter (resets all optimizers)
Each optimizer (Color Filter, Emboss, Sobel, Edge) has its own play/pause button and reset button. All optimizers can run simultaneously.
The forward pass for the color filter is:
pre_tint = (input * brightness - 0.5) * contrast + 0.5
raw = pre_tint * tint
activated = act(raw)
loss = mean((activated - target)^2)
Gradients are derived analytically via the chain rule and applied directly, with no automatic differentiation library. The convolution kernel gradient follows the same structure: d(loss)/d(kernel) = draw * patch, summed over all sampled pixels.
Gradients are verified at startup against central finite differences for all five activations.