skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    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 %dn",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


  2. libraw stores pixels in "packed" (a.k.a. "interleaved") format. So a 3×2 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 3×2 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 %dn",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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search