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
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:

Main differences with the original algorithm:

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 BuildConfiguration Manager, select the desired configuration (most likely Release, x64) then go to BuildBuild 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:

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:

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

III) Filters description

grain

VapoursynthAvisynth+
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:

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

r1, 2022-04-11