[FFmpeg-user] Lossless compression of 10bit grayscale images (stored as 16bit pngs)

Tom Vercauteren tom.vercauteren at m4x.org
Sun Nov 7 18:20:38 EET 2021


On Sat, 6 Nov 2021 at 13:01, Paul B Mahol <onemda at gmail.com> wrote:
>
> On Thu, Nov 4, 2021 at 9:41 AM Tom Vercauteren <tom.vercauteren at m4x.org>
> wrote:
>
> > > > Apologies for cross-posting a question I initially posted on
> > stackoverflow
> > > > (
> > > > https://stackoverflow.com/q/69739665/17261462) but having had no
> > response
> > > > there I thought this mailing list may be a better place for it.
> > > >
> > > > I am trying to encode 10 bit images losslessly in a video format. The
> > > > images are stored as 16 bit png files (but only use 10 bit - currently
> > the
> > > > least significant ones) and I have been working with ffmpeg to create
> > and
> > > > read back the video files.
> > > >
> > > > My best attempt so far is based on
> > > > https://stackoverflow.com/a/66180140/17261462 but as mentioned there,
> > I
> > > > get
> > > > some pixel intensity differences which may be due to rounding when
> > > > converting between 10 and 16 bit representation. I tried a few
> > different
> > > > means (bit shifting, left bit replication, floating point based
> > scaling)
> > > > but haven't yet figured out how to get a trully lossless
> > reconstruction.
> > > >
> > > > Below is a small piece of python code to replicate my issue. I
> > probably am
> > > > doing something wrong there so feedback would be appreciated.
> > > >
> > > >
> > > Upload input png somewhere?
> > >
> > > I guess that png files use only first 10bits from least significant bit.
> >
> > Thanks Paul. The python snippet I provided was creating the png on the
> > flies but for convenience I am attaching here an example 16bit png
> > that uses all least significant 10bits. I also provide alternative
> > versions using either the 10 most significant bits, rescaling the
> > intensities with
> >   ROUND(input * MAXOUTSAMPLE / MAXINSAMPLE
> > or using left bit replication
> > (http://www.libpng.org/pub/png/spec/1.1/PNG-Encoders.html).
> >
> > For eae of use, here are also the ffmpeg commands in plain text and an
> > comparison with imagemagick so as to avoid the need for python.
> >
> >
> You can always store it into rawvideo (without any headers) and than
> interpret it as 10bit with specifying ffmpeg rawvideo demuxer parameters.

Thanks, that was very helpful. By using temporary rawvideo files, I am
now able to start from a grayscale16bit png where only the 10 least
significant bits are used, get a 10 bit hevc mkv file, and losslessly
recover a 16 bit png. the commands I use are listed below.

Is there a way to do this without the temporary rawvideo files?

```
# convert to rawvideo in 16 bits
ffmpeg -y -i gradient10bit-lsb.png -f rawvideo -pix_fmt gray16le
gradient10bit-lsb.raw

# convert to mkv in 10 bits by tricking the rawvideo demuxer
# into thinking the input is a 10 bit video
ffmpeg -y -f rawvideo -pixel_format gray10le -video_size 64x64 -i
gradient10bit-lsb.raw -c:v libx265 -x265-params lossless=1 -pix_fmt
gray10le gradient10bit-lsb.mkv

# convert to raw 10 bit
ffmpeg -y -i gradient10bit-lsb.mkv -f rawvideo -pix_fmt gray10le
gradient10bit-lsb-postmkv.raw

# convert back to png 16bits by tricking the rawvideo demuxer
# into thinking the input is 16 bits
ffmpeg -y -f rawvideo -pixel_format gray16le -video_size 64x64 -i
gradient10bit-lsb-postmkv.raw -pix_fmt gray16be
recons-gradient10bit-lsb.png

# compare
magick compare -verbose -metric mae gradient10bit-lsb.png
recons-gradient10bit-lsb.png diff-lsb.png
```

Best wishes,
Tom


More information about the ffmpeg-user mailing list