FLIF-hub / FLIF

Free Lossless Image Format
Other
3.72k stars 229 forks source link

FLIF outperformed by Adobe DNG lossless compression on some RAW images #37

Closed bobobo1618 closed 8 years ago

bobobo1618 commented 8 years ago

I've run a few tests on the lossless DNG files that Adobe compressors (Lightroom, Adobe DNG Converter) output and I've found that FLIF underperforms on some types of RAW (this example is produced by an A7II). Not sure what's going on.

Steps to reproduce (using sample data):

Expected results: FLIF file is smaller than DNG and the original Actual results: FLIF is 2.4x the size of the original and the DNG:

 24M    sample.arw
 23M    sample.dng
 57M    sample.flif
139M    sample.ppm

This may be due to Sony's built in lossy compression, however. I think that's doubtful in the DNG's case since Adobe applies its own lossless compression (lossless JPEG 92) and this shouldn't benefit from Sony's.

It may also be due to bit depth. Sony's cRAW only appears to use 8 bits per pixel. Indeed, when I use an 8-bit PPM instead of 12, the size is 23M, the same as the DNG.

I tried this on another DNG derived from a camera that doesn't use lossy RAW compression (Olympus OM-D E-M5) and found that FLIF still underperformed:

> exiftool testImages/PA120012.dng | grep -i bit
Bits Per Sample                 : 16
Valid Bits                      : 12 0
> convert testImages/PA120012.dng -depth 12 testPNGs/PA120012.ppm
> ./flif -vvvvvvvv -b -n -r 3 testPNGs/PA120012.ppm testFlifs/PA120012.flif
  _____  __  (__) _____
 (___  ||  | |  ||  ___)   FLIF 0.1 [2 October 2015]
  (__  ||  |_|__||  __)    Free Lossless Image Format
    (__||______) |__)      (c) 2010-2015 J.Sneyers & P.Wuille, GNU GPL v3+

Loading input file: testPNGs/PA120012.ppm  
Input: 3472x4640, channels: [0] 12 bpp [1] 12 bpp [2] 12 bpp
Transforms: YIQ, BND[0:24..4095][1:516..7630][2:2505..6801]
Plane 0: 24..4095
Plane 1: 516..7630
Plane 2: 2505..6801
Learning a MANIAC tree. Iterating 3 times.
Header: 27 bytes. MANIAC tree: 129315 bytes.
75% done [1/3] ENC[3472x4640]    filesize : 11875219 (+11745877 for 16110080 pixels, 5.832809 bpp)
83% done [2/3] ENC[3472x4640]    filesize : 24216210 (+12340991 for 16110080 pixels, 6.128333 bpp)
91% done [3/3] ENC[3472x4640]    filesize : 35246901 (+11030691 for 16110080 pixels, 5.477659 bpp)
Encoding done, 35246901 bytes for 3472x4640 pixels (2.1879bpp) 
> du -sh testFlifs/PA120012.flif
 34M    testFlifs/PA120012.flif
> du -sh testImages/PA120012.dng
 16M    testImages/PA120012.dng
FLIF-hub commented 8 years ago

Interesting. Maybe the raw format has some pixel layout (RGGB or something) that causes redundancy which is easily taken advantage of if you know the pixel layout but which gets lost after transforming to RGB and then to YIQ?

heri commented 8 years ago

@bobobo1618 Maybe Adobe Converter is at 8 bit depth?

bobobo1618 commented 8 years ago

@jonsneyers you might be right. This is from exiftool sample.dng:

CFA Repeat Pattern Dim          : 2 2
CFA Pattern 2                   : 0 1 1 2
CFA Plane Color                 : Red,Green,Blue
CFA Layout                      : Rectangular

I suspect this means it has a layout of RGGB, which would make sense since the DNG converter can't apply a debayer filter and still retain all information losslessly.

@heri It's definitely not. It doesn't even support downsampling like that.

FLIF-hub commented 8 years ago

If you can find a way to extract the 3 raw channels as separate greyscale images (the G one at higher resolution), then you could try compressing them separately and look at the sum of the sizes.

sipa commented 8 years ago

It would be nice to support these frame formats natively... we could, by treating it as 4 separate planes (R, G1, G2, B).

FLIF-hub commented 8 years ago

Maybe even do some kind of YIQ transform on it...

sipa commented 8 years ago

I guess you can do YIQ transform on (R,G1,B), and then replace G2 with G2-G1.

FLIF-hub commented 8 years ago

Yes, or YIQ on (2R, G1+G2, 2B) and G2-G1, or something like that.

bobobo1618 commented 8 years ago

So it turns out I didn't understand RAW images very well. The reason FLIF was underperforming was that the images it was being fed were debayered. It was being fed 6000x4000 sRGB (4 channels) data while the RAW formats (DNG and ARW) are storing 6000x4000 of what's essentially 12 bit monochrome (single channel) data (RGGB bayer filter pixels). FLIF was compressing 4 times as much data.

I extracted the individual channels and combined them into a single, 4 channel, 12 bit, 3000x2000 (quarter resolution) image and FLIF blew everything else away. The process is messy and flawed but it worked:

for channel in 0 1 2 3
   set xoffset (math "$channel % 2")
   set yoffset (math "$channel/2")
   set local_width (math "$width - $xoffset")
   set local_height (math "$height - $yoffset")
   convert sample.tiff -crop "$local_width"x"$local_height"+0+0 +repage -sample 50% sample_crop_channel$channel.tiff
end
convert sample_crop_channel3.tiff sample_crop_channel2.tiff sample_crop_channel0.tiff -combine thing_combined.png
convert thing_combined.png sample_crop_channel3.tiff -compose copy-opacity -composite thing_rgba.png

After converting this with FLIF, it came out to 16M, making it 0.67 the size of the ARW and 0.68 the size of the DNG.

It'd be fantastic if FLIF could support this more nicely though, it'd save a lot of photographers a lot of space (RAW files are pretty big when you have several tens of thousands of them).

bobobo1618 commented 8 years ago

Actually, turns out FLIF doesn't need the channel hackery. It works fine just being given the monochrome data from dcraw:

> dcraw -o 0 -E -4 sample.arw
> ./flif -vvvvvvvv -b -n -r 3 sample.pgm sample.flif
  _____  __  (__) _____
 (___  ||  | |  ||  ___)   FLIF 0.1 [2 October 2015]
  (__  ||  |_|__||  __)    Free Lossless Image Format
    (__||______) |__)      (c) 2010-2015 J.Sneyers & P.Wuille, GNU GPL v3+

Loading input file: sample.pgm  
Input: 6048x4024, channels: 1, depth: 16 bit
Transforms: BND[0:122..1422]
Plane 0: 122..1422
Learning a MANIAC tree. Iterating 3 times.
Header: 14 bytes. MANIAC tree: 68680 bytes.
75% done [1/1] ENC[6048x4024]    filesize : 17744286 (+17675592 for 24337152 pixels, 5.810242 bpp)
Encoding done, 17744286 bytes for 6048x4024 pixels (0.7291bpp)
FLIF-hub commented 8 years ago

:+1: thanks for the experimentation! You had the power all along, my dear FLIF! ;)