There is a difference while debayer an image with cmd ffmpeg

I have such a bayer image https://drive.google.com/file/d/1OjHQyR44ECMMs4BtlZacejkmgSjeY2Nq/view?usp=sharing

I need to get two output files

  1. Directly debayer this image and save it as .bmp
  2. Debayer the image compress it to .h264 and the decompress and save as .bmp

In order to do this, I use such a batch script

@echo off

set main_dir=my_main_dir
set file_name=orig_bayer
set input=%main_dir%\%file_name%.bmp
set output_direct_debayer_bmp=%main_dir%\gpl_cmd_direct_decompress.bmp
set output_h264=%main_dir%\result_h264_%file_name%.h264
set output_h264_to_bmp=%main_dir%\gpl_cmd_decompress.bmp
set video_size=4096x3000

rem direct debayering 
ffmpeg -y -hide_banner -i %input% -vf format=gray -f rawvideo pipe: | ffmpeg -hide_banner -y -f rawvideo -pixel_format bayer_rggb8 -video_size %video_size% -i pipe: -pix_fmt yuv420p %output_direct_debayer_bmp%

rem debaer -> h264 -> decompress
ffmpeg -y -hide_banner -i %input% -vf format=gray -f rawvideo pipe: | ffmpeg -hide_banner -y -framerate 30 -f rawvideo -pixel_format bayer_rggb8 -video_size %video_size% -i pipe: -c:v hevc_nvenc -qp 0 -pix_fmt yuv420p %output_h264%
ffmpeg -y -i %output_h264% -f image2 %output_h264_to_bmp% -hide_banner

pause

So the problem that with #1 approach I

...
rem direct debayering 
ffmpeg -y -hide_banner -i %input% -vf format=gray -f rawvideo pipe: | ffmpeg -hide_banner -y -f rawvideo -pixel_format bayer_rggb8 -video_size %video_size% -i pipe: -pix_fmt yuv420p %output_direct_debayer_bmp%
...

I get such an output https://drive.google.com/file/d/1-DA2440zZ2F9WRcd15iqFUt3UhtkQRZT/view?usp=sharing

and with #2 approach

...
rem debaer -> h264 -> decompress
ffmpeg -y -hide_banner -i %input% -vf format=gray -f rawvideo pipe: | ffmpeg -hide_banner -y -framerate 30 -f rawvideo -pixel_format bayer_rggb8 -video_size %video_size% -i pipe: -c:v hevc_nvenc -qp 0 -pix_fmt yuv420p %output_h264%
ffmpeg -y -i %output_h264% -f image2 %output_h264_to_bmp% -hide_banner
...

I get such an output https://drive.google.com/file/d/103dtgaDVaXsNy13XHaVLSgugQhh0Uj9N/view?usp=sharing

The second one has a difference in the colors...


It look like a bug in the color conversion algorithm, but I can't be sure.

When replacing -pix_fmt yuv420p with -pix_fmt yuv444p the colors are the same as the direct conversion.

  • The color conversion path: Bayer -> yuv420p modifies the colors.
  • The color conversion path: Bayer -> yuv444p works correctly.

The common Demosaicing algorithms converts from Bayer to RGB, and not from Bayer directly to YUV, but I don't know the internal conversion pipeline used by FFmpeg.

I found a solution that encodes yuv420p with the following color conversion path:
Bayer -> yuv444p -> yuv420p

The solution uses the format video filter.
Add the arguments: -vf format=yuv444p after -i pipe:.

Use the following command:

ffmpeg -y -hide_banner -i %input% -vf format=gray -f rawvideo pipe: | ffmpeg -hide_banner -y -framerate 30 -f rawvideo -pixel_format bayer_rggb8 -video_size %video_size% -i pipe: -vf format=yuv444p -c:v hevc_nvenc -qp 0 -pix_fmt yuv420p %output_h264%

Results (reduced size) left to right:

  • Without -vf format=yuv444p (incorrect colors):
  • With -vf format=yuv444p (correct colors):
  • Direct conversion (correct colors):

enter image description here enter image description here enter image description here


Note:

  • HEVC is H.265 and not H.264