May 24
2025
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:
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.
Dec 23
2023
There now exists NSDateFormatter and NSISO8601DateFormatter and their behaviour when a timezone is not set is not the same: NSDateFormatter produces strings formatted for local time while NSISO8601DateFormatter produces string formatted for UTC.
As an example, given a date-time of 2000-12-31T23:00:00Z
NSDateFormatter with no timezone set and full …
Feb 19
2022
I recently tried my hands at implementing motion event support for canvas widgets in Toga on Linux, which uses GTK3 as its GUI back end. In the process I had learn to navigate GDK's event handling mechanics and documentation. This post is a summary of notes I made during the …
Aug 05
2018
# 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 …
Apr 12
2016
A common pitfall of trying to use message forwarding in Objective-C is forgetting to implement
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
in addition to
- (void)forwardInvocation:(NSInvocation *)anInvocation
Another problem is that sometimes calling objects will use
- (BOOL)respondsToSelector:(SEL)aSelector
to determine if your proxy object can respond to a particular …
Sep 12
2014
Previously we found that PyPy achieves the best performance gain, executing fieldfunc_py in ~6 us. At the end of that article, I mentioned that the C implementation is up to 50x faster, managing the same calculation in ~0.12 us.
The naive conclusion is that the best thing is to …
Sep 12
2014
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 …
Aug 26
2014
This is sort of a placeholder post. Busy meeting a deadline, but this should help future Steve and anyone else when you need to turn your Lyx document into a Word document while keeping the format mostly sane. Broken, but sane.
- Export as
Latex (plain).
-
Run
Aug 26
2014
 |
Fluorescence image of
cavitation effects,visualised
using FITC-Dextran.
|
If, like me, you use Nikon's NIS Elements to do fluorescence imaging, you would have also noticed that nothing other than NIS Elements can read the metadata that is saved with TIFFs. ImageJ can't read it, the GIMP can't read it, tiffinfo …
Jan 27
2012
- Create a virtual env and activate it
- hg clone https://code.google.com/p/pyglet/
- pushd pyglet; python setup.py install
- popd
- easy_install pyobjc==2.3 # the ==2.3 is required as of 2012-01-27, or pyobjc-core will not install
- python -c "import pyglet" # this step should not fail
Cheers,
Steve …
May 18
2011
svn st | grep '^?' | sed 's/^[? ]*/"/' | sed 's/\$/"/' | xargs svn add
Cheers,
Steve
May 08
2011
Here is my firehol.conf that allows multicast mDNS packets through:
# define mdns so we will accept it
server_mdns_ports="udp/5353"
client_mdns_ports="5353"
interface eth+ multi
policy return
server mdns accept
server multicast accept
interface eth+ home src "\${home_ips}"
server all accept
client all accept
Initially I had the server …
Apr 17
2011
- const char *foo; is not the same as char * const foo; The former declares a pointer to constant char, while the latter declares a constant pointer to char.
- - [NSError localizedDescription] returns the object for key NSLocalizedDescriptionKey in the error's userInfo dictionary. I always wondered how to set it since there …
Jan 27
2011
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 …
Jan 22
2011
Socket.IO is a great library and framework that doesn't seem to have a good description of the protocol available. In interest of helping others when they google "socket.io framing protocol", this post was born.
The description of the framing protocol used by Socket.IO below is taken from …
Jan 16
2011
I generate UIImages in some of my iOS applications, and prior to the iPhone 4 they all worked fine. With the introduction of the iPhone 4 and Retina Display, I realised my generated images were blurry even though I am rendering them at twice the resolution.
It turns out this …
Sep 21
2010
I would like to start this post off by saying that emotionally I agree with the sentiment that HTML is not a programming language. Intellectually, however, my position is that HTML is a programming language.
My argument for HTML as a programming language is very abstract, and to put it …
Jun 09
2010
This script produces an IPA, then verifies to make sure the IPA is actually valid.
PRODUCT_NAME=""
IPA="\\({PRODUCT_NAME}.ipa"
APP="\\).app"
if [ -z "\${PRODUCT_NAME}" ]; then
echo "PRODUCT_NAME not set";
exit 1;
fi
rm -rf ipa
mkdir -p ipa/Payload &&
cp -R build/Debug-iphoneos/\\({APP} ipa/Payload/ &&
pushd ipa &&
zip -q …
Mar 26
2010
- Maximum RA guide pulse is 1000ms (1s). If PHD is not locking on to the star and it says "dur=1000" in the status bar, a better polar alignment is required.
- RA hysteresis is used in a 2-term weighted moving average:
RA_dist = (1.0 - RA_hysteresis) * RA_dist + RA_hysteresis * last_guide
Cheers,
Steve …
Mar 11
2010

If you have a xcdatamodel file, open it, and using the menu: File > New File > Cocoa Class, you will see an extra item: Managed Object Class. This will autogenerate the required header and implementation files for your CoreData entities so you can use the convenience accessors instead of [setValue:forKey …