Normalize video contrast to the full dynamic range with ffmpeg?

Viewed 2298

The following ImageMagick command line normalizes the RGB channels of an image individually, so that in each channel, the smallest value maps to 0 and the largest value maps to 255:

convert fish.jpg -channel all -contrast-stretch 0.003x0.003% fish2.jpg

fish.jpg fish2.jpg

Is there an ffmpeg filter which can normalize the RGB channels of every individual frame of a video?

The only filter I can find is "histeq", which equalizes (flattens) rather than normalizes the contrast. I have applied it per RGB channel using variations on this command line:

ffmpeg -i fish.jpg -vf "format=rgb24,extractplanes=r+g+b[r][g][b],[r]histeq=strength=.1[r2],[g]histeq=strength=.1[g2],[b]histeq=strength=.1[b2],[g2][b2][r2]mergeplanes=0x001020:gbrp" fish3.jpg

but since it tries to flatten the histogram, it always gives a much different (unacceptable) result; for example, the imgur image whose code is eHL51.jpg (not enough reputation for link).

Based on this answer: video normalization with ffmpeg I have also tested -vf "scale=out_range=full" and -vf "pp=al:f" (see the log below) but in both cases the result fish3.jpg was unchanged from fish.jpg, so apparently nothing was done.

C:\Users\Roofus\Desktop>ffmpeg -i fish.jpg -vf scale=out_range=full -color_range 2 -pix_fmt yuvj420p fish3.jpg
ffmpeg version 3.2.4 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 6.3.0 (GCC)
  configuration: --enable-gpl --enable-version3 --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-nvenc --enable-
avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libb
luray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-l
ibmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libope
njpeg --enable-libopus --enable-librtmp --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enabl
e-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable
-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-zli
b
  libavutil      55. 34.101 / 55. 34.101
  libavcodec     57. 64.101 / 57. 64.101
  libavformat    57. 56.101 / 57. 56.101
  libavdevice    57.  1.100 / 57.  1.100
  libavfilter     6. 65.100 /  6. 65.100
  libswscale      4.  2.100 /  4.  2.100
  libswresample   2.  3.100 /  2.  3.100
  libpostproc    54.  1.100 / 54.  1.100
Input #0, image2, from 'fish.jpg':
  Duration: 00:00:00.04, start: 0.000000, bitrate: 3942 kb/s
    Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 960x540 [SAR 96:96 DAR 16:9], 25 tbr, 25 tbn, 25 t
bc
[swscaler @ 0000000000442f60] deprecated pixel format used, make sure you did set range correctly
Output #0, image2, to 'fish3.jpg':
  Metadata:
    encoder         : Lavf57.56.101
    Stream #0:0: Video: mjpeg, yuvj420p(pc), 960x540 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
    Metadata:
      encoder         : Lavc57.64.101 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
Press [q] to stop, [?] for help
frame=    1 fps=0.0 q=2.2 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=   5x
video:23kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

C:\Users\Roofus\Desktop>fish3.jpg

C:\Users\Roofus\Desktop>ffmpeg -i fish.jpg -vf "pp=al:f" -color_range 2 -pix_fmt yuvj420p fish3.jpg
ffmpeg version 3.2.4 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 6.3.0 (GCC)
  configuration: --enable-gpl --enable-version3 --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-nvenc --enable-
avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libb
luray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-l
ibmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libope
njpeg --enable-libopus --enable-librtmp --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enabl
e-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable
-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-zli
b
  libavutil      55. 34.101 / 55. 34.101
  libavcodec     57. 64.101 / 57. 64.101
  libavformat    57. 56.101 / 57. 56.101
  libavdevice    57.  1.100 / 57.  1.100
  libavfilter     6. 65.100 /  6. 65.100
  libswscale      4.  2.100 /  4.  2.100
  libswresample   2.  3.100 /  2.  3.100
  libpostproc    54.  1.100 / 54.  1.100
Input #0, image2, from 'fish.jpg':
  Duration: 00:00:00.04, start: 0.000000, bitrate: 3942 kb/s
    Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 960x540 [SAR 96:96 DAR 16:9], 25 tbr, 25 tbn, 25 t
bc
File 'fish3.jpg' already exists. Overwrite ? [y/N] y
[Parsed_pp_0 @ 0000000000321da0] This syntax is deprecated. Use '|' to separate the list items.
Output #0, image2, to 'fish3.jpg':
  Metadata:
    encoder         : Lavf57.56.101
    Stream #0:0: Video: mjpeg, yuvj420p(pc), 960x540 [SAR 96:96 DAR 16:9], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
    Metadata:
      encoder         : Lavc57.64.101 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
Press [q] to stop, [?] for help
frame=    1 fps=0.0 q=2.2 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=4.44x
video:23kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

C:\Users\Roofus\Desktop>fish3.jpg
0 Answers
Related