ChickenDream — realistic film grain generator for Vapoursynth and Avisynth+

# ChickenDream — realistic film grain generator
for Vapoursynth and Avisynth+

## Abstract

Authors: |  | Firesledge (aka Cretindesalpes)
Version: |  | r2
Download: |  | http://ldesoras.free.fr/prod.html
Category: |  | Artistic effect
Requirements: |  | Vapoursynth r55 or Avisynth+ 3.7.0
License: |  | WTFPL

## Table of contents

1. Introduction

1. Description
2. Technical reference

2. Usage
   1. Loading
   2. Examples for Vapoursynth
   3. Examples for Avisynth+
   4. Compiling from the source code
3. Filter description
   1. grain
4. Troubleshooting
5. Changelog

## I) Introduction

### Description

ChickenDream is a plug-in for Vapoursynth and Avisynth+ implementing a realistic film grain generator.

Example: original / with mild grain / with insanely huge grain.

The grain model is based on the microscopic reproduction of a silver halide photographic film. A picture may contain billions of particles which are transparent or opaque to light, depending on their exposure. The effect does not modify the curve of the input picture, it only adds grain corresponding to the light intensity. If you want to emulate a S-shaped film curve too, do it before adding grain.

If the generated grain is too strong for your taste, you can blend the filter output with the input picture to attenuate the effect. Another thing to consider: only the impression on the negative (main capture) is emulated. You may want to add additional layers of grain caused by the positive or any other stage of replication or montage.

Warning: the algorithm is very slow and can take several seconds (multi-threaded) for a single FHD frame. However, in some conditions, the draft mode can be a good compromise between speed and model accuracy.

### Technical reference

The grain model and the basis of the algorithm come from the following papers:

- Alasdair Newson, Julie Delon, Bruno Galerne,
  A Stochastic Film Grain Model for Resolution-Independent Rendering,
  Computer Graphics Forum, Wiley, 2017
- Alasdair Newson, Noura Faraj, Julie Delon, Bruno Galerne,
  Realistic Film Grain Rendering,
  Image Processing On Line 7, 2017, pp. 165–183

Main differences with the original algorithm:

- Sampling of the gaussian filter is done with a quasirandom sequence instead of pure random points. This should give a better uniformity.
- Option: rectangular single-pixel filter instead of the gaussian filter.
- The formula calculating lambda from the grain size standard deviation has been fixed and should not cause any brightness issues anymore.
- For large lambda (high luminance), the Poisson-distributed random variable generation uses an approximation instead of the inverse transform sampling which becomes slow and inaccurate.

There were also several speed optimisations.

## II) Usage

### Loading ChickenDream

Using the Python 3.8 interface (or a higher version, it depends on your Vapoursynth version):

    import vapoursynth as vs
    core = vs.core
    core.std.LoadPlugin (path=r'C:\path\chickendream.dll')

Of course you can avoid the `LoadPlugin` command by copying the plug-in file to the autoloading directory. Check the Vapoursynth manual for more information.

### Examples for Vapoursynth

#### A basic example

Requires fmtconv:

    # Load Vapoursynth
    import vapoursynth as vs
    core = vs.core

    # Load the plug-ins
    core.std.LoadPlugin (path=r'C:\path\chickendream.dll')
    core.std.LoadPlugin (path=r'C:\path\fmtconv.dll')

    # Mid gray picture, assuming it is sRGB.
    c = core.std.BlankClip (width=256, height=256, format=vs.GRAY8, color=[128])

    # Conversion to linear light in 32-bit floating point format
    c = c.fmtc.transfer (transs="srgb", transd="linear", bits=32)

    # Apply the grain
    c = c.chkdr.grain ()

    # Back to gamma-compressed colorspace (sRGB)
    c = c.fmtc.transfer (transs="linear", transd="srgb")

    # Send the processed clip to the calling process
    c.set_output ()

### Examples for Avisynth+

#### The same basic example

Requires fmtconv:

    # Load the plug-in
    LoadPlugin ("C:\path\chickendream.dll")
    LoadPlugin ("C:\path\fmtconv.dll")

    # Mid gray picture, assuming it is sRGB.
    BlankClip (width=256, height=256, pixel_type="Y8", color=$808080)

    # Conversion to linear light in 32-bit floating point format
    fmtc_transfer (transs="srgb", transd="linear", bits=32)

    # Apply the grain
    chkdr_grain ()

    # Back to gamma-compressed colorspace (sRGB)
    fmtc_transfer (transs="linear", transd="srgb")

### Compiling from the source code

#### Visual C++

Visual Studio 2019 or later is required, previous versions are not supported anymore. Just load `build/win/chickendreams.sln`. Go to Build → Configuration Manager, select the desired configuration (most likely Release, x64) then go to Build → Build Solution. The dll is in the `chickendream/(configuration)/` subdirectory.

You can also import all the `*.cpp`, `*.h` and `*.hpp` files located in the `src` directory and its subfolders. Then:

- Add `.` (the `src` directory) as include path.
- For the whole project, enable the SS2 instruction set.
- Enable the AVX2 instruction set for the `*.cpp` files containing `avx2` in their name, and the AVX set for the `avx` files.
- Enable optimizations maximizing speed and “any suitable” functions for inlining.

#### GNU/Linux and other Unix-like systems

On Linux and similar GNU-based systems (including MSYS2 and Cygwin), the `build` directory contains autotools settings:

    cd build/unix
    ./autogen.sh
    ./configure
    make
    make install

You can add some options to the `configure` command:

- `--enable-debug` to activate debugging code
- `CXX='clang++' CC='clang'` to use Clang instead of the default compiler which is usually GCC

Only the Vapoursynth plug-in can be built in the GNU-based environment.

## III) Filters description

### grain

Vapoursynth | Avisynth+
--- | ---
    chkdr.grain (
    	clip  : vnode     ;
    	sigma : float: opt; (0.35)
    	res   : int  : opt; (1024)
    	rad   : float: opt; (0.025)
    	dev   : float: opt; (0)
    	seed  : int  : opt; (12345)
    	cf    : int  : opt; (False)
    	cp    : int  : opt; (False)
    	draft : int  : opt; (False)
    	cpuopt: int  : opt; (-1)
    )
    chkdr_grain (
    	clip   c,
    	float  sigma  (0.35),
    	int    res    (1024),
    	float  rad    (0.025),
    	float  dev    (0),
    	int    seed   (12345),
    	int    cf     (False),
    	int    cp     (False),
    	int    draft  (False),
    	int    cpuopt (-1)
    )

This function takes a picture and adds grain to it with the specified characteristics. For correct results, the picture should be in linear light, not gamma-compressed. This is important for the grain balance between highlights and shadows. Values out of the [0 ;1] range are clipped beforehand. The output format is the same as the input.

The function supports internal multi-threading with AVSTP.

#### Parameters

clip

The input clip. Mandatory. Supported input formats:

- Gray (Y) and planar RGB colorspaces.
- 32-bit floating point only.

sigma

Radius of the gaussian kernel for the vision filter. Valid range: [0 ; 1]. The larger the radius, the smoother the picture. Smallest values are more prone to aliasing. 0 is a special value indicating that a single-pixel rectangular filter should be used instead of a gaussian. For grains with a small radius (standard use), this should be the fastest option, visually equivalent to a sigma of 0.3, offering an excellent quality (minimum leaking between adjascent pixels).

res

Vision filter resolution, greater than 0. The vision filter is a gaussian kernel that turns thousands of grains into a single light intensity, for a given pixel. However it would be very costly to exactly implement such a kernel. Therefore an approximation is used, by sampling the kernel using res points, whose distribution depends on the kernel density. Then each point is tested for its intersection with a grain. This leads to a quantified light intensity related to the number of points, directly translating into output data bitdepth. 1024 is equivalent to a 10-bit output, but keep in mind that the pixel values are linear at this stage. The higher the resolution, the slower the algorithm. Large grains require a smaller res.

rad

Average grain radius, in pixels. Must be greater than 0. The smaller the grains, the higher the picture fidelity (given a high enough res), and the slower the processing.

dev

Standard deviation for the log-norm distribution of the grain radius, in [0 ; 1] range. Offers a more realistic result when the grains are big enough to be individually visible, then 0.25 is a good value. Otherwise, keep it to 0 to avoid wasting processing power.

seed

Seed for the random generator. A fixed seed gives reproductible results; changing the seed helps to build different variations on the same stream with the same parameters.

cf

Indicates that the seed is kept constant for all the frames.

cp

Indicates that the seed is kept constant for all the planes of a single frame. This may slightly reduce the “colored noise” effect on RGB pictures, depending on the content.

draft

Sets ChickenDream in draft mode. Draft mode uses an approximation of the grain model and is much faster to render, but gives decent results only for a restricted set of parameter combinations. The draft mode automatically sets sigma to 0 and works correctly in the same conditions (small rad and dev).

cpuopt

Limits the CPU instruction set. -1: automatic (no limitation, depends on the host hardware), 0: default instruction set only (depends on the compilation settings), 1: limit to SSE2, 7: limit to AVX.

## IV) Troubleshooting

You can reach the author on the Vapoursynth or Avisynth sections of the Doom9 forums.

You can also open an issue on Github repository for the project.

## V) Changelog

r2, 2022-06-02

- Allowed larger grain radius when using large standard deivation values.
- Added a draft parameter.
- Changed the `configure options to compile with Clang.`
- Fixed a crash when the picture width is not a multiple of 8.

r1, 2022-04-11

- Initial release.