curves

Watch on youtube.com
doc

https://ffmpeg.org/ffmpeg-filters.html#curves-1

Apply color adjustments using curves.

This filter is similar to the Adobe Photoshop and GIMP curves tools. Each component (red, green and blue) has its values defined by N key points tied from each other using a smooth curve. The x-axis represents the pixel values from the input frame, and the y-axis the new pixel values to be set for the output frame.

By default, a component curve is defined by the two points (0;0) and (1;1). This creates a straight line where each original pixel value is “adjusted” to its own value, which means no change to the image.

The filter allows you to redefine these two points and add some more. A new curve (using a natural cubic spline interpolation) will be define to pass smoothly through all these new coordinates. The new defined points needs to be strictly increasing over the x-axis, and their x and y values must be in the [0;1] interval. If the computed curves happened to go outside the vector spaces, the values will be clipped accordingly.

`plot’ option and gnuplot

`A new curve’ mentioned in the official document can be visualized by `plot’ option and gnuplot. For example, your filter graph is like this:

[me@host: ~]$ ffplay input.mp4 -vf "curves=r='0/0 0.5/0.7 1/1':plot=out.plt"

in this case, `curves’ will save gnuplot script of the curves in out.plt like this:

set xtics 0.1
set ytics 0.1
set size square
set grid
plot '-' using 1:2 with lines lc 'red' title '', '-' using 1:2 with points pointtype 3 lc 'red' title '', '-' using 1:2 with lines lc 'green' title '', '-' using 1:2 with lines lc 'blue' title '', '-' using 1:2 with lines lc '#404040' title ''
0.000000 0.000000
0.003922 0.003922
   ... (snip) ...
0.992157 0.996078
0.996078 0.996078
1.000000 1.000000
e
0.000000 0.000000
0.500000 0.700000
1.000000 1.000000
e
0.000000 0.000000
0.003922 0.003922
0.007843 0.007843
   ... (snip) ...
0.984314 0.984314
0.988235 0.988235
0.992157 0.992157
0.996078 0.996078
1.000000 1.000000
e

This script can be passed to gnuplot directly and gnuplot will render it to your display, but you might want to save the graph as image file such as PNG. If so, you must insert gnuplot’s commands like this:

set terminal png size 400,400
set output 'out.png'

set xtics 0.1
set ytics 0.1
set size square
set grid
plot '-' using 1:2 with lines lc 'red' title '', '-' using 1:2 with points pointtype 3 lc 'red' title '', '-' using 1:2 with lines lc 'green' title '', '-' using 1:2 with lines lc 'blue' title '', '-' using 1:2 with lines lc '#404040' title ''
0.000000 0.000000
0.003922 0.003922
   ... (snip) ...
0.992157 0.996078
0.996078 0.996078
1.000000 1.000000
e
0.000000 0.000000
0.500000 0.700000
1.000000 1.000000
e
0.000000 0.000000
0.003922 0.003922
0.007843 0.007843
   ... (snip) ...
0.984314 0.984314
0.988235 0.988235
0.992157 0.992157
0.996078 0.996078
1.000000 1.000000
e

Now you can:

[me@host: ~]$ gnuplot out.plt

and you will get this PNG:

../_images/curves_plt_example.png

using your custom curve

Example 1

00:00:00
#! /bin/sh
ifn="Pexels_flowers.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=
r='0/0 0.5/0.7 1/1'
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_1.png

Example 2

00:00:30
#! /bin/sh
ifn="Pexels_flowers.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=
r='0/0 0.05/0.10 0.95/0.98 1/1':
g='0/0 0.3/0.2 0.8/0.9 1/1':
b='0/0 0.5/0.3 1/1'
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_2.png

using preset curves

preset=color_negative

00:01:00
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=color_negative
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_3.png

preset=cross_process

00:01:08
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=cross_process
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_4.png

preset=darker

00:01:16
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=darker
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_5.png

preset=increase_contrast

00:01:23
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=increase_contrast
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_6.png

preset=lighter

00:01:31
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=lighter
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_7.png

preset=linear_contrast

00:01:38
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=linear_contrast
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_8.png

preset=medium_contrast

00:01:46
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=medium_contrast
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_9.png

preset=negative

00:01:54
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=negative
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_10.png

preset=strong_contrast

00:02:01
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=strong_contrast
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in this script:

../_images/curves_example_plt_11.png

preset=vintage

00:02:09
#! /bin/sh
ifn="Pexels_flowers_fast.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=vintage
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"
00:02:17
#! /bin/sh
ifn="Pexels_2880.mp4"
ifnb="`basename \"${ifn}\" .mp4`"
pref="`basename $0 .sh`"
#
ffmpeg -y -i "${ifn}" -filter_complex "
[0:v]
curves=preset=vintage
[v]" -map '[v]' -an "${pref}_${ifnb}.mp4"

used curves in these script:

../_images/curves_example_plt_12.png