Journey's End

May 24
2025

Adventures in Compressed DNG

I have been working with industrial cameras and frame-grabbers that simply gives me a dump of their sensor data. To make that data useful it needs to undergo demosaicing, ideally using one of the modern demosaic algorithms like RCD rather than simple interpolation or the rather outdated VNG. Unfortunately the latter are all that OpenCV supports.

To gain access to more advanced demosaic algorithms and sophisticated image processing functions like colour calibration, micro-contrast, dehaze, etc, I encoded the raw colour filter array (CFA) data into DNG using the PiDNG library. With compression disabled this library produces DNGs which is accepted by darktable. However if I enable compression darktable is unable to open it.

Running darktable from the command line, the following error is observed:

    71.5724 [rawspeed] (compression-test.dng) void rawspeed::AbstractDngDecompressor::decompress() const,   
       line 250: Too many errors encountered. Giving up. First Error: virtual Buffer::size_type   
       rawspeed::LJpegDecoder::decodeScan(), line 108: Unsupported predictor mode: 6

This suggests that the predictor used is not supported. By editing the source code of PiDNG, predictor was set to 1 which results in yet another error:

    10.7300 [rawspeed] (compression-test.dng) void rawspeed::AbstractDngDecompressor::decompress() const,   
       line 250: Too many errors encountered. Giving up. First Error: virtual Buffer::size_type   
       rawspeed::LJpegDecoder::decodeScan(), line 141: Maximal output tile size is not a multiple of LJpeg frame size

This error happens because PiDNG uses an optimisation trick to improve the compression ratio. Consider a typical CFA pattern:

RG
GB

The raw sensor data is essentially the above repeated horizontally and vertically:

RGRGRG
GBGBGB
RGRGRG
GBGBGB
RGRGRG
GBGBGB

Lossless JPEG compressed by using a predictor that uses previous pixel values, including those in the previous row. Such a predictor work better if correlated values are closer together. So instead of saving the image as-is, the DNG specification (as of 1.4.0) allows the image data to be stored as an image that is twice as wide but halve as high (preserving the total number of pixels):

RGRGRGGBGBGB 
RGRGRGGBGBGB
RGRGRGGBGBGB

In this new image, correlated pixels are closer together. e.g. the first red pixel had no immediate neighbours that was also red, but now it has an immediate neighbour in the next row. The rawspeed library however doesn't support this optimisation trick (or predictors other than 1), which to be fair is also useless with predictor 1, which only looks at the previous value on the same row. This trick is most useful with predictors that look at values from previous rows, e.g. mode 6 which is the default mode used by PiDNG.

With another modification to the PiDNG library that encodes the sensor data as a JPEG image of the original size, we were able to produce a losslessly compressed DNG file that darktable opens. The compression ratio isn't as good - 80% vs 75%. Hopefully darktable will gain support for predictors 2-7 and we can get better compression. In the meantime I cleaned up the changes to PiDNG and have submitted a PR which will hopefully be accepted.

Rant

DNG v1.4.0 was released in 2012, a time when DEFLATE compression in TIFF files was widely used yet for some reason the DNG specification restricts its use to floating point image data with estoic lossless JPEG, defined 20 years ago in 1992, being the only other lossless compression option. It is not until 2023, with DNG v1.7.0, that JPEG-XL is added for integer image data. Unfortunately JPEG-XL is exotic enough that darktable still doesn't support it in 2025. Why we couldn't have allowed Deflate for integer image data is beyond me. So much space could have been be saved.

Apr 10
2025

Python One-liner for Local QR Code Decoding

Because KeepassXC lacks the ability to decode QR code for TOTP setup and not all MFA implementations show the required secret in text format, I use the following snipet to read the QR code information locally:

  python -c 'from cv2 import QRCodeDetector; from PIL.ImageGrab import grabclipboard; import numpy as …
ts=03:07 tags=[python,software,oss]

Feb 04
2023

Aug 05
2018

IPython Notebook on GPS Timing and CDMA

In \[1\]:
%matplotlib inline import matplotlib import numpy as np import matplotlib.pyplot as plt
# GPS Timing Carrier-phase detection is suppose to yield better timing information than tracking the pseudorandom code stream. The reason for this is supposedly that the higher frequency carrier allows for more accurate measurements of the …

May 07
2016

Sep 12
2014

Sep 12
2014

Adventures in Python Optimisation

Recently I found myself looking at the following piece of code and trying to optimise it:

from __future__ import division

import numpy as np

MagneticPermeability = 4*np.pi*1e-7
MagneticPermeabilityOver4Pi = MagneticPermeability / (4*np.pi)

def fieldfunc_py(p, q, moment):
  r = p - q 
  rmag = np.sqrt(r.dot(r))

  rdash3 = rmag …
ts=14:41 tags=[python,c,code,software]

Jul 21
2012

GNU readline with System Python (OS X 10.7)

By default system python loads "fake" readline (fake because it actually uses libedit) from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/readline.so. Even if you install readline (which goes into /Library/Python/2.7/site-packages), it will still load it, even if you fiddle …

ts=01:46 tags=[python,software,osx]

Jan 27
2011

iPhone 4 layer export script for Gimp

I often mockup iPhone interfaces on the Gimp, then exporting each layer for use as backgrounds. For iOS 4 each image needs to be exported twice: one at full resolution with @2x in its filename, and once at half-resolution without the @2x. e.g. nav_bg@2x.png and nav_bg.png …

Oct 11
2009

qrbackup

I generated a gpg keypair for myself today, and I was looking for a fairly safe way to back it up. I don't particularly trust DVD/CDs, and keeping it on flash is even more worrying. I wanted a means of backup I can see and touch.

Paperbak would be …

Oct 09
2008

Jul 16
2008

Apr 28
2008

{} I <3 thee

Firstly, I am the kind of guy who likes tabs over spaces, because I don't like forcing my particular preferences on to other people. To wax poetic, I like to give other people the freedom of choosing how they want their code indented. This of course brings me into the …

Dec 31
2007

html2pml

I was tired of converting all my HTML ebooks to rtf, then to pdb using Palm Doc Converter only to lose all the nice touches like bold, italics and headings. Since there didn't seem to be a HTML to PML converter for OS X, I wrote one to get more …

ts=10:15 tags=[python,code,palm]