I'm trying to scale an RGB image in a gamma-correct way, i.e. with a gamma transform before and after the scaler. Because gamma correction at 8 bits/channel creates "banding", I convert the image to 16 bits/channel (gbrp16le) at the beginning, and then back to rgb24 when everything's done.
Problem is, this process somehow results in inaccurate colors: instead of black (rgb 0,0,0) I get a dark violet (rgb 25,0,27).
My command line (Windows batch, so the ^ character escapes double-quotes and newlines):
ffmpeg -loglevel 42 -hide_banner -y -i testcase.png -vf ^"^
format=gbrp16le,^
lutrgb='r=gammaval(2.2):g=gammaval(2.2):b=gammaval(2.2)',^
scale=iw/2:ih/2:flags=bicubic,^
lutrgb='r=gammaval(0.454545):g=gammaval(0.454545):b=gammaval(0.454545)',^
format=gbrp16le,^
format=rgb24^" ^
testcase-out.png
(The second format=gbrp16le
is because the scaler itself seems to convert to rgb24 otherwise, and gives me banding after the 2nd gamma transform)
Sample input "testcase.png" - the black area surrounding the bars is rgb 0,0,0:
And the output is this. Maybe hard to see, but if you actually check the color values, the blacks have now become 25,0,27 (#19001B):
At this loglevel I also get the following details about what the filtergraph is doing:
[Parsed_scale_2 @ 0000000002c90340] w:iw/2 h:ih/2 flags:'bicubic' interl:0
[graph 0 input from stream 0:0 @ 000000000019d200] w:420 h:212 pixfmt:rgb24 tb:1/25 fr:25/1 sar:0/1
[auto_scaler_0 @ 00000000001aa4c0] w:iw h:ih flags:'bicubic' interl:0
[Parsed_format_0 @ 00000000006f8f00] auto-inserting filter 'auto_scaler_0' between the filter 'graph 0 input from stream 0:0' and the filter 'Parsed_format_0'
[auto_scaler_1 @ 00000000001aa5c0] w:iw h:ih flags:'bicubic' interl:0
[Parsed_format_5 @ 000000000019cf80] auto-inserting filter 'auto_scaler_1' between the filter 'Parsed_format_4' and the filter 'Parsed_format_5'
[auto_scaler_0 @ 00000000001aa4c0] w:420 h:212 fmt:rgb24 sar:0/1 -> w:420 h:212 fmt:gbrp16le sar:0/1 flags:0x4
[Parsed_scale_2 @ 0000000002c90340] w:420 h:212 fmt:gbrp16le sar:0/1 -> w:210 h:106 fmt:gbrp16le sar:0/1 flags:0x4
[auto_scaler_1 @ 00000000001aa5c0] w:210 h:106 fmt:gbrp16le sar:0/1 -> w:210 h:106 fmt:rgb24 sar:0/1 flags:0x4
Is there a clue there? How can this be fixed?
A few things I've already tried:
- Adding other scaler flags (accurate_rnd, full_chroma_int, full_chroma_inp, bitexact)
- Changing
src_range
anddst_range
in the scaler options, just in case it's a "full" vs. "limited" issue (although the green channel is not affected) - Removing ICC profile from the input .png
- Changing
gbrp16le
to other pixel formats with >8 bits/channel, e.g.gbrp10le
- Using different scaling algorithms (e.g. lanczos, neighbor)
None of the above helps...