retinex 0.1.0

Single-scale and multi-scale Retinex image enhancement with color restoration (MSRCR)
Documentation
  • Coverage
  • 100%
    18 out of 18 items documented5 out of 13 items with examples
  • Size
  • Source code size: 701.97 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 4.96 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 1m 15s Average build duration of successful builds.
  • all releases: 1m 15s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • sunsided/retinex-rs
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • sunsided

Retinex

A reference implementation of single-scale and multi-scale Retinex image enhancement with color restoration (MSRCR).

Prerequisites

  • Rust toolchain (rustup recommended)

Build

cargo build --release

Usage

retinex --help

Basic Examples

Single scale with default sigma (produces grayscale reflectance):

cargo run --release -- images/house.jpg output.jpg

Multi scale with custom sigmas:

cargo run --release -- images/house.jpg msr.jpg --mode multi --sigmas 15,80,250

Multi-Scale Retinex with Color Restoration (MSR)

The recommended approach for best results - combines multiple scales with color restoration:

cargo run --release -- images/house.jpg msr.jpg \
  --mode multi \
  --sigmas 15,80,250 \
  --color-restore

This produces natural-looking results with enhanced local details and corrected global illumination.

Color Restoration (MSRCR)

The basic Retinex algorithm produces grayscale output because it processes each color channel independently and normalizes them separately. This destroys the color ratios.

Enable color restoration to preserve colors:

cargo run --release -- images/house.jpg color.jpg --color-restore

Viewing Components Separately

Save the estimated illumination (lighting component):

cargo run --release -- images/house.jpg output.jpg --illumination illumination.jpg

Save the raw reflectance (before color restoration):

cargo run --release -- images/house.jpg output.jpg --reflectance reflectance.jpg

Save all components at once:

cargo run --release -- images/house.jpg result.jpg \
  --mode multi \
  --sigmas 15,80,250 \
  --color-restore \
  --illumination light.jpg \
  --reflectance refl.jpg

Example Results

Original Input

Original

Single-Scale Retinex (Grayscale)

Basic Retinex without color restoration produces high-contrast grayscale:

retinex images/house.jpg readme/house_basic.jpg --mode single --sigmas 15

Basic Retinex

Multi-Scale Retinex with Color Restoration (MSR)

The recommended approach using multiple scales with color restoration:

retinex images/house.jpg readme/house_msr.jpg \
  --mode multi \
  --sigmas 15,80,250 \
  --color-restore

MSR Result

Illumination Component

The estimated lighting (slowly varying, blurred version of input):

retinex images/house.jpg output.jpg --illumination readme/house_illumination.jpg

Illumination

Reflectance Component

The extracted reflectance (high-contrast, object colors without lighting):

retinex images/house.jpg output.jpg --reflectance readme/house_reflectance.jpg

Reflectance

Why Basic Retinex Looks Grayscale

The basic Retinex formula computes:

R = log(I) - log(G_σ * I)

When applied independently to each RGB channel and then normalized per-channel, the relative color ratios are lost. All three channels end up with similar values because:

  1. Each channel's log-response is normalized to [0, 255] independently
  2. The min/max stretching destroys the original color proportions
  3. The result appears bright and desaturated (grayscale)

Color Restoration (MSRCR)

MSRCR (Multi-Scale Retinex with Color Restoration) fixes this by applying a color restoration factor based on the original image's color ratios:

R_final = R_msr × (I_channel / (I_r + I_g + I_b)) × 3

The factor of 3 normalizes the weights (since the three ratios sum to 1). This preserves the original hue while applying the Retinex contrast enhancement.

Algorithm Overview

Given an observed image I:

I(x,y) = R(x,y) × L(x,y)
  • R is the reflectance (desired result - object colors)
  • L is illumination (slowly varying lighting - estimated via Gaussian blur)

Single-scale Retinex:

R = log(I + ε) - log((G_σ × I) + ε)

Multi-scale Retinex averages multiple scales to balance local and global contrast.

Output Files

  • Main output (output.jpg): The processed result

    • Without --color-restore: Normalized reflectance (grayscale, high contrast)
    • With --color-restore: Color-corrected result with preserved hues
  • Illumination (--illumination): The estimated lighting component

    • Shows the slowly-varying illumination that was subtracted
    • Blurred version of the original image
  • Reflectance (--reflectance): The raw reflectance before color restoration

    • Shows what the algorithm extracted as "object colors"
    • High-contrast grayscale image

Parameters

  • --mode: single or multi - use multiple scales for better results
  • --sigmas: Comma-separated Gaussian blur radii (e.g., 15,80,250)
    • Small values (5-30): Enhance local details
    • Large values (100-300): Correct global illumination
  • --color-restore: Enable MSRCR color restoration
  • --illumination <path>: Save illumination component to file
  • --reflectance <path>: Save raw reflectance to file

Multi-Scale Mode (--mode multi)

Multi-scale Retinex computes the reflectance at multiple Gaussian blur scales and averages the results. This balances local detail enhancement (small sigma) with global illumination correction (large sigma).

How it works:

R_multi = (R_σ1 + R_σ2 + ... + R_σn) / n

Where each R_σ is the reflectance computed with a different sigma value.

Selecting sigma values:

A good default set is 15,80,250:

  • 15: Fine details, edges, textures
  • 80: Medium-scale features, local contrast
  • 250: Large-scale illumination variations, global tone

You can use fewer or more scales depending on the image:

  • Fast processing: --sigmas 30,150
  • High quality: --sigmas 10,40,100,250

What happens if you specify multiple sigmas without --mode multi?

Only the first sigma value is used. The rest are ignored:

# This uses only sigma=15 (single-scale mode)
retinex input.jpg output.jpg --sigmas 15,80,250

# This uses all three sigmas (multi-scale mode)
retinex input.jpg output.jpg --mode multi --sigmas 15,80,250

The --mode flag determines whether multiple sigmas are averaged (multi) or if only the first is used (single).

Technical Details

Normalization

The reflectance output uses percentile-based clipping (2nd to 98th percentile) to handle outliers in the log-domain values. This prevents extreme values from compressing the visible dynamic range.

Color Restoration Formula

// For each pixel and channel:
let sum = r + g + b;
let color_factor = (original[channel] / sum) * 3.0;
let output = reflectance[channel] * color_factor * 255.0;

The color factor reweights each channel based on its proportion in the original image, restoring the original color balance.