Reading Raw image with libraw and converting to DNG with libtiff

1k views Asked by At

I am reading RAW files (usually NEF format) using Libraw and everything seems ok. After some processing, I need to save the RAW image as a DNG file. However, when I open the DNG file with Photoshop, the colors seem wrong.

For finding the CFA pattern, I look into the first two rows and columns of the pattern using RawProcessor.COLOR. I get the following pattern: \00\01\01\02. So then I write the raw image into file as:

const int width =  RawProcessor.imgdata.sizes.raw_width;
const int height = RawProcessor.imgdata.sizes.raw_height;


const std::array<float, 9> color_matrix = {
   raw_color.cam_xyz[0][0], raw_color.cam_xyz[0][1], raw_color.cam_xyz[0][2],
   raw_color.cam_xyz[1][0], raw_color.cam_xyz[1][1], raw_color.cam_xyz[1][2],
   raw_color.cam_xyz[2][0], raw_color.cam_xyz[2][1], raw_color.cam_xyz[2][2],
};

const std::array<float, 3> as_shot_neutral = {
    1.0f / (raw_color.cam_mul[0] / raw_color.cam_mul[1]),
    1.f,
    1.0f / (raw_color.cam_mul[2] / raw_color.cam_mul[1])
};

const auto base_black_level = static_cast<float>(raw_color.black);
std::array<float, 4> black_level = {
    base_black_level + static_cast<float>(raw_color.cblack[0]),
    base_black_level + static_cast<float>(raw_color.cblack[1]),
    base_black_level + static_cast<float>(raw_color.cblack[2]),
    base_black_level + static_cast<float>(raw_color.cblack[3])
};

if (raw_color.cblack[4] == 2 && raw_color.cblack[5] == 2) {
    for (int x = 0; x < raw_color.cblack[4]; ++x) {
        for (int y = 0; y < raw_color.cblack[5]; ++y) {
            const auto index = y * 2 + x;
            black_level[index] = raw_color.cblack[6 + index];
        }
    }
}
    
static const uint32_t white_level = raw_color.maximum;


static const short bayerPatternDimensions[] = { 2, 2 };

TIFF* tif = TIFFOpen(strAddr.c_str(), "w");
TIFFSetField(tif, TIFFTAG_DNGVERSION, "\01\01\00\00");
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, bayerPatternDimensions);
TIFFSetField(tif, TIFFTAG_CFAPATTERN, 4, "\00\01\01\02"); 
TIFFSetField(tif, TIFFTAG_MAKE, "DNG");
TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, "DNG");
TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, &color_matrix );
TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, &as_shot_neutral );
TIFFSetField(tif, TIFFTAG_BLACKLEVEL, 4, &black_level);
TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &white_level);

for (int i = 0; i < height; i++) 
    TIFFWriteScanline(tif, &RawProcessor.imgdata.rawdata.raw_image[(i)*width], i, 0);

TIFFWriteDirectory(tif);
TIFFClose(tif);

I find cam_xyz using: RawProcessor.imgdata.color.cam_xyz, which is a 4x3 matrix and I remove the last row to get cam_xyz. cam_mul comes from RawProcessor.imgdata.color.cam_mul which has 4 elements and I remove the last element to get cam_mul. The values for cam_mul are inversed before passing to the Tiff tag.

EDIT: Here is the code for reading the RAW image using LibRaw from file:

LibRaw RawProcessor;
int ret;
if ((ret = RawProcessor.open_file(strAddr.c_str())) != LIBRAW_SUCCESS)
    return false;

// Unpack the image
if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS)
        return false;

// Data unpacking
ret = RawProcessor.dcraw_process();

if (LIBRAW_SUCCESS != ret) // error at the previous step
    return false;
else // Successful document processing
{
    std::cout << "Successful document processing..." << std::endl;
    // Process the RAW data             
}

I get the following values for the cam_xyz:

[1.0405 -0.3755 -0.127

-0.5461 1.3787 0.1793

-0.104 0.2015 0.6785

0 0 0 ]

and cam_mul : [1.78906, 1, 1.67969, 1].

  1. As I said I have a big problem which is when I load the DNG image in Photoshop the colors are not correct which can be because of color matrix or white balance.

  2. Another problem is that when I load the original NEF file in Photoshop, the size is 5504x8256, while the size of the DNG file is 5520x8288. I have checked these values also:

    RawProcessor.imgdata.sizes.top_margin: 0

    RawProcessor.imgdata.sizes.left_margin: 2

which does not correspond to the sizes I get opening the NEF file in another software. Any idea where the problem is?

Trying any image from this gallery (https://www.photographyblog.com/previews/nikon_d850_photos) will give a result similar to this, where the original RAW image is the bottom image and the top image is the converted DNG image:

Converted DNG Original RAW

0

There are 0 answers