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