MichaelGermany
MichaelGermany

Reputation: 61

Reading DNG file with libraw and passing pixel data to Cimg for image manipulation

I'm reading a DNG file on Android with libraw in C++ which works pretty fine. I want to pass the pixel data to Cimg for manipulation purposes (rotating etc.).

The problem is that the image in Cimg looks weird. I think that problem is that the original pixel data from libraw are stored in a different order than in Cimg. In libraw (due to the DNG file) its RGBGRGBGRGBG while Cimg stores the pixel data in the way RRRRRR....GGGGGGG....BBBBBB. Does anyone know how to convert from RGBGRGBGRGBG to RRRRRR....GGGGGGG....BBBBBB?

Here are both images, on the left is dng file and on the right is tiff file exported from cimg (both imported into Photoshop).

Here is my code:

LibRaw rawProcessor;
rawProcessor.open_file("file.dng");
rawProcessor.unpack();
int  ret2=rawProcessor.dcraw_process();
libraw_processed_image_t* image = rawProcessor.dcraw_make_mem_image(&ret2);

float xres=72.0;
CImg<unsigned char> cimgOriginal(image->data,image->width,image->height, true);
cimgOriginal.shift(10*(-1), 10*(-1),0,0,0);
cimgOriginal.rotate(360.0-5, (float) 1200, (float) 800,0,0);
cimgOriginal.save_tiff("file.tiff", 0, &xres,0,false);

enter image description here

Thanks!

Mike

Upvotes: 1

Views: 321

Answers (2)

MichaelGermany
MichaelGermany

Reputation: 61

Thank you for your help, Mark! In the meantime I've figured out that Cimg can do it from packed RGB to planar RGB - with a method called permute_axes(). The documentation about permute_axes() is very short but here is a good explanation:

https://www.codefull.org/2014/11/cimg-does-not-store-pixels-in-the-interleaved-format/

With the following code I was able to get the image in Cimg. The attached screenshots shows DNG on the left and the image exported to tiff from Cimg.The image with leaves (taken from here: https://www.kenrockwell.com/leica/m9/sample-photos-3.htm) is a 8 bit DNG. The second example (with mouse and pen) shows my 16 bit DNG from Pixel 5. The code works also with 16 bit DNG files:

LibRaw rawProcessor;
rawProcessor.imgdata.params.use_auto_wb         = 0;        // Auto white-Balance
rawProcessor.imgdata.params.use_camera_wb       = 1;        // Use camera WB instead
rawProcessor.imgdata.params.output_color        = 1;        // [0-6] Output colorspace (0=raw, 1=sRGB, 2=Adobe, 3=Wide, 4=ProPhoto, 5=XYZ, 6=ACES)
rawProcessor.imgdata.params.no_auto_bright      = 0;        // No automatic brightnes

// Open the file and read the metadata
rawProcessor.open_file("L1004220.DNG");

// The metadata are accessible through data fields of the class
int w = rawProcessor.imgdata.sizes.width;
int h = rawProcessor.imgdata.sizes.height;
printf("Image size: %d x %d\n",w,h);

// Let us unpack the image
rawProcessor.unpack();

int  ret2=rawProcessor.dcraw_process();
libraw_processed_image_t* image = rawProcessor.dcraw_make_mem_image(&ret2);

float xres=72.0;
CImg<unsigned char> cimgOriginal(image->data, 3, w, h, 1, true);
cimgOriginal.permute_axes("yzcx");
cimgOriginal.save_tiff("L1004220.DNG.tiff", 0,
                       &xres,0,true);

enter image description here

enter image description here

Upvotes: 1

Mark Setchell
Mark Setchell

Reputation: 207345

libraw stores pixels in "packed" (a.k.a. "interleaved") format. So a 3x2 image will be stored like this:

R G B R G B R G B R G B R G B R G B 

CImg, on the other hand, stores pixels in "planar" format, which bunches all the red pixels together in a plane, followed by all the green, then all the blue ones. So that same 3x2 image will be stored like this:

R R R R R R G G G G G G B B B B B B 

I haven't done any C++ for years, so my code will be shockingly awful quality, but it does work at least:

#include "libraw/libraw.h"
#define cimg_display  0
#include "CImg.h"
using namespace cimg_library;
int main(int ac, char *av[])
{
        // Let us create an image processor
        LibRaw rawProcessor;

        // Open the file and read the metadata
        rawProcessor.open_file("image.dng");

        // The metadata are accessible through data fields of the class
        int w = rawProcessor.imgdata.sizes.width;
        int h = rawProcessor.imgdata.sizes.height;
        printf("Image size: %d x %d\n",w,h);

        // Let us unpack the image
        rawProcessor.unpack();

        int  ret2=rawProcessor.dcraw_process();
        libraw_processed_image_t* image = rawProcessor.dcraw_make_mem_image(&ret2);

        // Create buffer that CImg can use
        unsigned char * buffer;
        buffer = new unsigned char [w * h *3];

        // Pointer to the buffer from libraw where our data currently is
        unsigned char *p = image->data;

        // Pointers into the planar buffer for CImg
        unsigned char* Rp = buffer;
        unsigned char* Gp = buffer + h * w;
        unsigned char* Bp = buffer + 2 * h * w;

        // Unpack the packed pixel ino R, G and B planes
        for(int pixel=0; pixel<=w*h; pixel++){
            *Rp++ = *p++;
            *Gp++ = *p++;
            *Bp++ = *p++;
        }

        // Convert RGB packed raw image to planar format CImg in buffer
        CImg<unsigned char> cimgOriginal(buffer, w, h, 1, 3,true);
        float xres = 72;
        cimgOriginal.save_tiff("result.tif", 0, &xres, 0,false);
        rawProcessor.recycle();
        return 0;
}

Compiled on Raspberry Pi OS with:

g++ -O3 main.cpp -L /usr/local/lib -I /usr/local/include -lraw -I CImg

I tested it by downloading the first DNG sample picture from Ken Rockwell, here.

Upvotes: 0

Related Questions