Files
filmsim/README-filmscan.md

6.3 KiB

filmscan - Film Scan and Negative Reversal Simulation

filmscan is a Python script that simulates the process of scanning a film negative and converting it into a positive image. It is heavily inspired by the "Negadoctor" module found in the popular open-source raw image processor, Darktable. This script aims to provide a "batteries included" experience by auto-detecting several key parameters required for the conversion.

Features

  • Implements a negative-to-positive conversion process similar to Darktable's Negadoctor.
  • Automatic Parameter Detection:
    • Dmin (film base color / brightest part of the negative)
    • Dmax (determines the dynamic range, from darkest part of the negative)
    • Offset (scan exposure bias)
    • Paper Black (density correction for print black point)
    • Print Exposure (overall print exposure adjustment)
  • Color management: Converts input sRGB (assumed) to ACEScg for processing, then back to a chosen output colorspace (sRGB or Display P3).
  • Supports TIFF, PNG, and JPG inputs.
  • Outputs TIFF (16-bit uncompressed), PNG (8-bit), or JPG (8-bit).

Usage

The script is designed to be run with uv, which handles dependency management.

You can run filmscan directly from its Git repository URL:

uv run https://git.dws.rip/dubey/filmsim/raw/branch/main/filmscan -- <input_file> <output_file> [options]

Example:

# Ensure input_negative.tiff is in your current directory or provide a full path
# Output will be output_positive.jpg
uv run https://git.dws.rip/dubey/filmsim/raw/branch/main/filmscan -- input_negative.tiff output_positive.jpg --output_colorspace sRGB

Local Execution

If you have cloned the repository or downloaded the script:

  1. Navigate to the script's directory or ensure it's in your PATH.

  2. Run the script:

    uv run ./filmscan -- <input_file> <output_file> [options]
    

    Or, if filmscan is in the current directory and executable:

    ./filmscan <input_file> <output_file> [options]
    

Arguments

Positional Arguments:

  • input_file: Path to the input negative image.
    • Supported formats: TIFF, PNG, JPG.
    • The image is assumed to be an sRGB encoded film negative scan.
  • output_file: Path to save the processed positive image.
    • Output format is determined by the file extension:
      • .tiff / .tif: 16-bit uncompressed TIFF.
      • .png: 8-bit PNG.
      • .jpg / .jpeg: 8-bit JPG.

Options:

  • --patch_size_ratio FLOAT: Ratio of image minimum dimension for patch size in auto-detection. (Default: 1/128)
    • Smaller values use smaller patches, which can be faster but potentially more susceptible to noise.
  • --min_patch_size INT: Minimum patch size in pixels for auto-detection. (Default: 8)
  • --max_patch_size INT: Maximum patch size in pixels for auto-detection. (Default: 32)
  • --aces_transform TEXT: ACES working space. Currently, ACEScg is used internally and this option is noted for future flexibility but does not change behavior. (Default: ACEScg)
  • --output_colorspace TEXT: Colorspace for the output image.
    • Supported: sRGB (default), Display P3.
    • The output image will be gamma-corrected for the chosen colorspace.

Workflow

  1. Load Image: Reads the input negative image. It's normalized to a 0-1 float range.
  2. Color Conversion (Input):
    • The input image (assumed sRGB) is decoded from its gamma (e.g., sRGB EOTF inverse).
    • The linear sRGB data is then converted to the ACEScg color space for internal processing.
  3. Auto-Parameter Detection:
    • The script analyzes the ACEScg image to automatically determine optimal values for:
      • Dmin: The color of the unexposed film base, found by looking for the brightest representative patch in the negative.
      • Dmax: A measure of the film's maximum density range, calculated using Dmin and the darkest representative patch in the negative (scene highlight).
      • Offset: A scan exposure bias, determined from Dmin, Dmax, and the brightest image content patch.
      • Paper Black: Adjusts the black point of the final print, derived from Dmin, Dmax, Offset, and characteristics of the brightest image patch under default white balance.
      • Print Exposure: Overall brightness adjustment for the final print, calculated using all previously determined parameters and the darkest image patch.
    • Default white balance (WB_HIGH, WB_LOW), gamma (DEFAULT_GAMMA), and soft clip (DEFAULT_SOFT_CLIP) values are used alongside these auto-detected parameters.
  4. Negadoctor Process:
    • The core conversion logic, adapted from Darktable's negadoctor.c.
    • Density Conversion: Input pixel values are converted to log densities relative to Dmin.
    • Density Correction: Densities are adjusted using Dmax, Offset, and white balance parameters.
    • Print Simulation: Corrected densities are transformed to simulate printing on paper, incorporating Print Exposure and Paper Black.
    • Paper Grade (Gamma): A gamma curve (contrast adjustment) is applied.
    • Highlight Compression (Soft Clip): Highlights are compressed to simulate the behavior of photographic paper gloss.
  5. Color Conversion (Output):
    • The processed image (now a positive in ACEScg) is converted to the chosen output_colorspace (e.g., sRGB, Display P3).
    • The image is clipped to the 0-1 range.
    • The appropriate gamma correction (e.g., sRGB OETF) is applied for the output colorspace.
  6. Save Output: The final positive image is saved, converting to 16-bit for TIFF or 8-bit for PNG/JPG.

Notes on Auto-Detection

The auto-detection routines (auto_calculate_dmin, auto_calculate_dmax, etc.) work by finding representative "brightest" or "darkest" patches in the negative image.

  • "Brightest" on a negative typically corresponds to the film base (for Dmin) or unexposed areas that will become deep shadows in the positive.
  • "Darkest" on a negative typically corresponds to scene highlights that will become bright areas in the positive.

The patch_size_ratio, min_patch_size, and max_patch_size arguments control how these patches are sampled.