Reverse engineering Adobe DNG Converter's CameraCalibration matrices for Sony cameras

I’ve been investigating the following caveat in darktable’s documentation for the Color Calibration module:

“Some cameras, most notably those from Olympus and Sony, have unexpected white balance coefficients that will always make the detected CCT invalid even for legitimate daylight scene illuminants. This error most likely comes from issues with the standard input matrix, which is taken from the Adobe DNG Converter.”

I wanted to understand exactly what Adobe DNG Converter does differently for Sony cameras that makes the coefficients “unexpected”.

My understanding is that darktable’s standard input matrix is derived from the DNG ColorMatrix, specifically the matrix associated with the D65 reference illuminant. These matrices are stored in RawSpeed’s camera database.

However, the DNG documentation states that the XYZtoCamera matrix is the product of the AnalogBalance matrix (AB), the CameraCalibration matrix (CC) and the ColorMatrix (CM):

XYZtoCamera = AB*CC*CM

Thus, CM is only approximately equal to XYZtoCamera when AB and CC are close to the identity matrix (note that they are both diagonal). In most cases I found, this is true for AB, but not for CC (for Sony models at least). Furthermore, it can change between pictures from the same camera.

For example, two a6100 files produce:

Camera Calibration: 0.888 0 0 0 1 0 0 0 0.9827

and:

Camera Calibration: 0.9091 0 0 0 1 0 0 0 0.9742

I expected the camera calibration to be static for a given camera, so I initially wondered what was causing the calibration coefficients to change.

Reverse engineering

Looking at the corresponding Sony RAW metadata revealed that the values are closely related to the WB RGB Levels Daylight values.

For example:

WB RGB Levels Daylight: 2928 1024 1848
Camera Calibration:     0.888 1 0.9827

and:

WB RGB Levels Daylight: 2860 1024 1864
Camera Calibration:     0.9091 1 0.9742

It turns out that the red (CC_R) and blue (CC_B) components of the CC matrix are inversely proportional to WB daylight levels (D):

CC_R = c_R / D_R
CC_G = 1
CC_B = c_B / D_B

where c_R and c_B are constants (for the a6100, c_R=2600 and c_B=1816).

I verified this by reverse engineering Adobe DNG Converter using Ghidra. I found that an internal camera identifier is mapped to two constants k_R and k_B, which are the numerators of a division. I have not yet identified the code that supplies the denominator. However, comparing them against the ARW metadata suggests that the denominators are D_R / 1024 and D_B / 1024.

CC_R = k_R / (D_R / 1024)
CC_B = k_B / (D_B / 1024)

For the a6100, the static constants are

k_R = 2.5390625 = 2600 / 1024 = c_R / 1024
k_B = 1.7734375 = 1816 / 1024 = c_B / 1024

Thus, CC_R = 2600 / D_R and CC_B = 1816 / D_B.

Experimentation

I tested additional Sony cameras using ARWs from raw.pixls.us and corresponding DNGs generated with Adobe DNG Converter.

Here are the extracted constants from Adobe DNG converter:

Model Internal ID k_R k_B 1024*k_R 1024*k_B
ILCE-6100 0x2b0 2.5390625 1.7734375 2600 1816
ILCE-6400 0x2b3 2.5390625 1.7734375 2600 1816
ILCE-6600 0x2b6 2.5390625 1.7734375 2600 1816
ILCE-6700 0x2b7 2.641601563 1.705078125 2705 1746
ILCE-7M3 0x2bd 2.40625 1.47265625 2464 1508
ILCE-7M4 0x2be 2.354492188 1.599609375 2411 1638

And here is the relevant metadata extracted from each RAW, along with the resulting CameraCalibration coefficients:

Model D_R D_G D_B AB_R AB_G AB_B AsShotNeutral (R) AsShotNeutral (G) AsShotNeutral (B) CC_R CC_G CC_B CC_R * D_R CC_B * D_B File
ILCE-6100 2760 1024 1884 1 1 1 0.372093 1 0.543524 0.9420 1 0.9639 2599.92 1815.99 DSC00033.ARW
ILCE-6400 2616 1024 1900 1 1 1 0.363636 1 0.589862 0.9939 1 0.9558 2600.04 1816.02 DSC00087.ARW
ILCE-6400 2524 1024 1880 1 1 1 0.383234 1 0.584475 1.0301 1 0.9660 2599.97 1816.08 DSC00475.ARW
ILCE-6600 2760 1024 1908 1 1 1 0.364154 1 0.550538 0.9420 1 0.9518 2599.92 1816.03 DSC0268.ARW
ILCE-6700 2579 1024 1705 1 1 1 0.408456 1 0.585143 1.0489 1 1.0240 2705.11 1745.92 DSC00001.ARW
ILCE-6700 2579 1024 1705 1 1 1 0.409764 1 0.583144 1.0489 1 1.0240 2705.11 1745.92 DSC00002.ARW
ILCE-7M3 2352 1024 1656 1 1 1 0.450704 1 0.568889 1.0476 1 0.9106 2463.96 1507.95 DSC0009.ARW
ILCE-7M3 2352 1024 1656 1 1 1 0.456328 1 0.561404 1.0476 1 0.9106 2463.96 1507.95 DSC0010.ARW
ILCE-7M4 2456 1024 1691 2.366211 1 1.757813 1 1 1 0.9817 1 0.9687 2411.06 1638.07 ILCE-7M4_DSC06676_FullFrame-LossLess-Compressed-Small.ARW
ILCE-7M4 2456 1024 1691 1 1 1 0.421573 1 0.574313 0.9817 1 0.9687 2411.06 1638.07 ILCE-7M4_DSC06677_FullFrame-Raw-Compressed.ARW

In each case, the relationship holds. All camera models tested went through the same code path for the CC calculation.

The ILCE-7M4 is interesting because the two RAWs have different AnalogBalance values, despite producing the same CameraCalibration coefficients. The files also use different compression modes. I don’t know yet whether the two are related.

I initially suspected that CameraCalibration might be derived from AsShotNeutral, since the first few cameras appeared to show a relationship between the two. However, the ILCE-7M4 disproves this: one of the files has AsShotNeutral = [1,1,1] while the CameraCalibration is still [0.9817,1,0.9687]. The relationship with WB RGB Levels Daylight, on the other hand, continues to hold.

Remaining questions

I’m not sure where the constants come from, what effect they have on the white balance and whether they are unique to Sony. I also don’t know what the mystery IDs I found in the switch case stand for (the camera model?). The fact that different internal IDs can map to the same constants is also interesting.

I’d be particularly interested to know whether anyone recognizes these constants or the purpose of the internal camera identifier.

The remaining question is whether this explains the darktable caveat. I don’t have a definitive answer yet. However, when I apply CC * CM before using the resulting matrix as the input matrix, I obtain correct CCT detection for some of the images where the original matrix produces an invalid result. This suggests that the CameraCalibration values may indeed be related to the issue described in the darktable documentation.

I’m currently doing this manually, but I’m planning to write something that does this automatically using the right constants for my own camera.

Finally, I’m not sure whether AnalogBalance also needs to be incorporated, or exactly how (or whether) darktable should account for these matrices.

11 Likes

I have implemented a patch to RawSpeed that calculates and applies the CameraCalibration matrix for the camera models I have tested. You can test it by compiling my fork of darktable.

If you want to add your camera model, the procedure is to first convert an ARW to DNG using Adobe DNG converter. Then using exiftool, find WB RGB Levels Daylight in the ARW and Camera Calibration 2 in the DNG. You can calculate the red and blue constants by multiplying the corresponding values from these two tags. Then add the constants to src\external\rawspeed\data\cameras.xml and recompile. Assuming your camera works like the other models I have tested it should generate a valid CameraCalibration matrix.

Below are some before and after shots of unedited RAW images with the color calibration settings.

After applying the CC matrix, the a6100 illuminant is correctly detected as daylight. The a6400 illuminant is already detected as daylight, but applying the CC matrix changes the temperature.

Regarding the colors, to me, the before and after images seem identical (which might not mean much since I’m colorblind :sweat_smile:). This is possibly explained by this note in the documentation:

Internally, the illuminant is represented by its absolute chromaticity coordinates in CIE xyY color space. The illuminant selection options in the module are merely interfaces to set up this chromaticity from real-world relationships and are intended to make this process faster. It does not matter to the algorithm if the CCT is tagged “invalid” – this just means that the relationship between the CCT and the corresponding xyY coordinates is not physically accurate. Regardless, the color set for the illuminant, as displayed in the patch, will always be honored by the algorithm.

I’m still confused about how the color calibration module works however, so I don’t know if this is expected or not.

Images

A6100 - Darktable 5.6


A6100 - Darktable 5.6 + CameraCalibration


A6400 - Darktable 5.6


A6400 - Darktable 5.6 + CameraCalibration


As an aside, when opening an image with the previous color calibration settings without resetting the module, there is some sort of magenta tint that can be fixed by resetting the module to fetch the new default.

3 Likes