This page tries to describe in reasonable detail what processing is done, how it is done, and what are the assumptions. It should enable advanced users and developers to review correctness and understand the underlying code. Any and all feedback or discussion on this description or the underlying code is welcomed on the developers list dlraw-devel@lists.sourceforge.net ( Overview and options )
Following image shows the different operations that can be done on an image. Also it is shown in which colorspace they are done and it is indicated to which 'tab' in the application it is linked.
Remark : the red shapes are as well reference points where a preview
can be done as places where the image data are cached for performance.
| Phase in 'RunPipe' (dlMain.cxx) | Description | Influential parameters |
| Phase=1, SubPhase=1 | Identify Image, Camera, Raw sizes and depending on
the type of raw also some other settings.
All coming from dcraw. |
TheDcRaw-> m_UserSetting_InputFileName |
| Phase=1, SubPhase=1 | Decode Image, Remove bad pixels, Subtract darkframe. All coming from dcraw. When TheDcRaw->m_UserSetting_HalfSize = 1 then 2X2 pixels of the Bayer array are mapped onto one pixel of the Image. This way no interpolation is needed anymore and an important speedgain is made. This feature is coded into the BAYER(row,col) macro. Further also m_MatrixSRGBToCamRGB is calculated here from m_MatrixCamRGBToSRGB. The latter in turn is a not yet (fully) understood function from TheDcRaw->m_UserSetting_CameraMatrix, TheDcRaw->m_UserSetting_CameraWb which sometimes throws in another matrix (m_cmatrix). |
(TheDcRaw->) m_UserSetting_HalfSize m_UserSetting_BadPixelsFileName m_UserSetting_DarkFrameFileName m_UserSetting_CameraMatrix) m_UserSetting_CameraWb) |
| Phase=1, SubPhase=2 | Calculate the multipliers for a correct whitebalance. Largely taken from dcraw. The multipliers can be obtained from user input (TheDcRaw->m_UserSetting_Multiplier) or from a 'greybox' (TheDcRaw->m_UserSetting_GreyBox) that can ultimately extend to the whole image (TheDcRaw->m_UserSetting_AutoWB). Also the whitebalance can be taken from the camera (TheDcRaw->m_UserSetting_CameraWb). Whitebalance from camera can be obtained because the camera provides the multipliers or because the camera provides a sample grey area. The result of this operation is TheDcRaw->m_Multipliers[]. At this stage, and as done by dcraw, also a wavelet denoising algorithm on R-G/G-B is done. This algorithm might rescale the image , resulting in a different m_WhiteLevel and m_BlackLevel. Based on this Multipliers a whitebalanced image is calculated, simply by multiplying the different channels with their respective multiplier. The multipliers are normalized such that the whitelevel of the sensor (the maximum value for that specific camera) is mapped onto the value 0xFFFF for that channel with the largest multiplier. This ensures all other values for all channels are below 0xFFFF. Interpolation (Demosaicing) Largely taken from dcraw. First the m_BlackLevel is subtracted from the image. Then a 'preinterpolation' is done, but in fact this boils down to equalizing G1 to G2 or postpone that if TheDcRaw->m_MixGreen = 1 (which is the case if m_UserSetting_FourColorRGB=1 or m_UserSetting_HalfSize=1). m_Filters is adapted accordingly or set to 0 if m_UserSetting_HalfSize=1 (because then no interpolation is needed) Also dimensions are adapted in case of m_UserSettingHalfSize=1. Then , if there is still a Bayer (m_Filters) , interpolation is done according to one of the 4 algorithms determined by TheDcRaw->m_UserSetting_Quality : linear,vng,ppg or ahd. Finally, if needed, also 'green mixing' is done, as well a median filtering, with a user defined number of passes.. |
(TheDcRaw->) m_UserSetting_Multiplier m_UserSetting_CameraWb m_UserSetting_AutoWb m_UserSetting_GreyBox m_UserSetting_BlackPoint m_UserSetting_Saturation m_UserSetting_HalfSize m_UserSetting_FourColorRGB m_UserSetting_Quality m_UserSetting_RawDenoiseThreshold m_UserSetting_MedianPasses |
| Phase=1, SubPhase=3 | Handling of the highlights This part of the pipe handles the highlights, i.e. those parts of the image that are on the maximum level of the sensor and thus inherently clipped. Different methods are used to handle those highlights. Remember from previous phase that the image is now scaled such that the maximum sensor value of the most multiplied channel arrives at 0xFFFF. This is referred to as the unclipped pixels. Here we recalculate the image with renormalized multipliers such that the maximum sensor value of the least multiplied channel arrives at 0xFFFF. We refer to it as the 'Clipped Pixel' and it has thus the characteristic that all channels are at 0XFFFF as soon as one of the channels obtained its maximum sensor value.
|
(TheDcRaw->) m_UserSetting_dlRaw_ClipMode m_UserSetting_dlRaw_ClipParameter |
| Phase=1, SubPhase=4 | Lensfun lens corrections See the lensfun page. Basically this step applies lens related corrections on photos taken with a lens, provided that the lens is characterized in the lensfun database. The corrections are :
At this moment no effort is made to guess the lense used as this is very unstandardized information. So you have to choose your lenses manually out of a set which is compatible (based on 'mount' information) with the camera. Remark that lensfun functionality is depending on lensparameters being available for the lensfun library, which is a potential weakness. If anyone wants to contribute lenses, please do so to the lensfun project ! Working space conversion. The Image in TheDcRaw is in the color space of the camera, which is some variant on an RGB color space. In previous phases also TheDcRaw->m_MatrixCamRGBToSRGB was obtained, be it via matrices delivered by the camera itself, be it by (Cam RGB -> XYZ) matrices delivered by Adobe (TheDcRaw::adobe_coeff). This matrix (or a profile) will be used to convert to the working RGB color space.
|
(GuiSettings->) m_WorkColor m_CameraProfileName m_EnableLensfun m_LensfunCameraMake; m_LensfunCameraModel; m_LensfunCameraIndex; m_LensfunLensIndex; m_LensfunFocalLength; m_LensfunF; m_LensfunDistance; m_LensfunTCAEnable; m_LensfunHaveTCAModel; m_LensfunTCAModel; m_LensfunVignettingEnable; m_LensfunHaveVignettingModel; m_LensfunVignettingModel; m_LensfunDistortionEnable; m_LensfunHaveDistortionModel; m_LensfunDistortionModel; m_LensfunGeometryEnable; m_LensfunGeometry; m_LensfunScale; |
| Phase=2 |
|
(GuiSettings->) m_Rotate m_Crop m_CropX m_CropY m_CropW m_CropH m_Resize m_ResizeW m_ResizeH m_EnableChannelMixer m_ChannelMixer Exposure AutoExposure WhiteFraction ExposureClipMode m_EnableGamma m_Gamma m_Linearity m_HaveCurve[] |
| Phase=3 |
Conversion to Lab colorspace At least if one of the following operations is effectively requested.
|
(GuiSettings->) m_HaveCurve[dlCurveChannel_L] m_HaveCurve[dlCurveChannel_a] m_HaveCurve[dlCurveChannel_b] m_EnableContrast m_ContrastAmount m_ContrastThreshold m_EnableSaturation m_SaturationAmount m_SaturationThreshold m_LuminanceDenoiseThreshold m_USM m_USMRadius m_USMSigma m_USMAmount m_USMThreshold m_Refocus m_RefocusMatrixRadius m_RefocusRadius m_RefocusGauss m_RefocusCorrelation m_RefocusNoise m_ChromaDenoiseThreshold |
| Phase=4 |
GREYCstoration noise reduction See the GREYCstoration page. The different parameters you can find here. Be aware that this is a very slow algorithm and that sometimes nearly as good results can be obtained by one of the other noise reduction features in a much faster way. |
(GuiSettings->) m_GREYC m_GREYCAmplitude m_GREYCSharpness m_GREYCAnisotropy m_GREYCAlpha m_GREYCSigma m_GREYCdl m_GREYCda m_GREYCGaussPrecision m_GREYCInterpolation m_GREYCFast |
Here, I want to elaborate specifically on gamma on which I believe a lot of confusion is existing.
When an image is gamma encoded, a mathematical relation is applied such that the encoded values are not linear proportional to the intensity of the captured light. Rather the encoding is such that in the most simple case EncodedValue = pow(LinearValue,1/2.2). (the precise function is dependent on system and environment but let's skip for the moment that detail).
In fact there are two reasons for doing so. The first one is nowadays probably the most important. Let's assume LinearValue is ranging from 0 to 100%. Then we get following encoded values :
| Linear | Encoded |
| 0% | 0% |
| 25% | 54% |
| 50% | 73% |
| 75% | 88% |
| 100% | 100% |
What you see is that the first 50% of linear values do use 73% of the available encoded values (f.i. 186 steps of 256 in a 8 bit system). This way much more detail (smaller steps) is kept in the low luminance areas then in the high luminance areas. Like much of our senses, the eye is heavily non-linear and is by far not as sensible in the high luminance areas as it is in the low luminance areas. This way we have an encoding that makes optimum use of the available encoding steps while our eye does not see the 'deceit'.
A second reason for this encoding (and becoming less important) is
coming from CRT and TV technology. It happens that a CRT is not
responding linear neither. The output light is about proportional
to pow(AppliedVoltage,2.2). So if our image is now encoded with a
gamma of 2.2 the two transformations cancel out :
LightOfCRT = pow(EncodedImage,2.2) = pow(pow(LinearLight,1/2.2),2.2) = LinearLight !
Nearly all image processing algorithms are linear and are assuming that the underlying representations are linear. When an image would be gamma-encoded as above, the algorithm gives wrong results.
However, when linear encoding is done, more bits are needed to keep the same 'accuracy' (technically spoken : Signal to Noise Ratio, SNR). Suppose for instance that you have a gamma encoded 8 bit system. Then the encoded value 1/256 corresponds to pow(1/256,2.2) = 5.034e-6. So that's the first fine step representable. When linear encoded, all steps would be equal to 1/256 = 3906e-6, so it is about 1000 times less precise. To obtain the same precision, a number of encoded values of 1/5.034e-6 = 198668 is needed. This would need 18 bits. Let's see however in some more detail to the first encoding steps of a gamma encoded 8 bit system :
| Encoded value | Linear Value | Step | Needed Values | Needed bits |
| 0 | 0 | |||
| 1/256 | 5.034e-6 | 5.034e-6 | 198649 | 18 |
| 2/256 | 23.13e-6 | 18.10e-6 | 55248 | 16 |
| 3/256 | 56.43e-6 | 33.30e-6 | 30030 | 15 |
One can learn from the table that except for the very first quantization step the same precision (SNR) is reached with 16 bits or less as in a gamma encoded 8 bit representation. It is generally accepted that operations in a 16 bit linear encoded representation give sufficient precision.
dlRaw does all of its operations on a 16 bit linear representation !
Here follow some links that might clarify the points made above :
| Value | Encoding |
| 0.0 | 0x0000 |
| 1.0 | 0x8000 |
| 1.0+(32767/32768) | 0xFFFF |
| Value | Encoding |
| 0.0 | 0x0000 |
| 100 | 0xFF00 |
| 100+(25500/65280) | 0xFFFF |
| Value | Encoding |
| -128 | 0x0000 |
| 0 | 0x8000 |
| 127 | 0xFF00 |
| 127+255/256 | 0xFFFF |