LibRaw / C++ Undebayered Buffer

Hi All,

I am using LibRaw to decode raw files from Cannon and Nikon DSLR cameras. My code example currently looks like this:

m_raw_proc = new LibRaw;
 
int ret;
 
m_raw_proc->imgdata.params.use_camera_wb = 1;
m_raw_proc->imgdata.params.output_bps = 16;
m_raw_proc->imgdata.params.output_color = 1;
m_raw_proc->imgdata.params.gamm[0] = 1;
m_raw_proc->imgdata.params.gamm[1] = 1;
m_raw_proc->imgdata.params.highlight = 0;
m_raw_proc->imgdata.params.no_auto_bright = 0;
m_raw_proc->imgdata.params.user_qual = 0;
 
if ((ret = m_raw_proc->open_buffer(data, size)) != 0)
{
     // Handle error
}
 
if ((ret = m_raw_proc->unpack() != 0))
{
    // Handle error
}
 
if ((ret = m_raw_proc->raw2image()) != 0)
{
    // Handle error
}
 
if ((ret = m_raw_proc->dcraw_process()) != 0)
{
	 // Handle error
}
 
buffer = new uint16_t[m_raw_proc->imgdata.sizes.iwidth * m_raw_proc->imgdata.sizes.iheight * 3 + 3];
 
m_Width = m_raw_proc->imgdata.sizes.iwidth;
m_Height = m_raw_proc->imgdata.sizes.iheight;
 
for (int n = 0, m = 0; n < m_Width * m_Height; n++, m += 3)
{
	buffer[m] = m_raw_proc->imgdata.image[n][0];
	buffer[m + 1] = m_raw_proc->imgdata.image[n][1];
	buffer[m + 2] = m_raw_proc->imgdata.image[n][2];
}

The code example above creates RGB image data contained in buffer[] and works perfectly. That is, I can save buffer[] with something like libtiff.

However, the files from high-resolution DSLR cameras produce huge RGB files (especially in 16-bit). I would therefore like to create a data buffer which contains undebayered data which I could then debayer at a later stage (for example, during post-processing). Is this possible with LibRaw? My ultimate aim is to reduce the size of the output without using compression.

Many thanks
Amanda

Forums: 

Original RAW data (after

Original RAW data (after LibRaw::unpack) is available via imgdata.rawdata. arrays (raw_image - for bayer, X-Trans or monochrome, color3_image for 3-color non-bayer files, color4_image for 4-color ones; Only one of these pointers is non-NULL after unpack() call).

Note: this array(s) contains unpacked RAW pixels without any adustment/cropping:
- masked (black area) pixels are in place, pixel array size is imgdata.sizes.raw_width x raw_height
- black level not subtracted

-- Alex Tutubalin @LibRaw LLC

Debayer Pattern

Thank you Alex, this is exactly what I wanted. I can now get a raw undebayered buffer from LibRaw and display it on my image preview screen as a greyscale image. Of course, I see the bayer pattern on the preview display. Ultimately, I would like to be able to debayer the buffer using a nearest neighbour algorithm purely for the live preview screen and save a undebayered TIFF files.

This leads me onto my final question. Is it possible for LibRaw to return the camera bayer pattern, for example, RGGB, BGGR, GBGR or GRGB or is this not possible?

Once again, thank you.

Amanda

Followup:

Followup:
1) colors are in imdata.idata.cdesc string ('RGBG" in most cases, "CMYG" for some very old cameras, etc)
2) For RGBG (modern bayer), values returned by COLOR():
0 - Red
1 - Green
2 - Blue
3 - Green (for some cameras greens are different by black level/amplification/even color response)

-- Alex Tutubalin @LibRaw LLC

Thanks Alex,

Thanks Alex,

I now have my application working perfectly.

Amanda

Visible Pixels

Further to my original post.

My code works for Nikon DSLR cameras via imgdata.rawdata (albeit the images seem to be under-exposed) but images from Canon DSLRs are showing bad data near the top of each image. I've been reading various forum posts and it seems that I need to call raw2image() in order to get data that only contains visible (active pixels) pixels but I am struggling to get unbayered data.

It is my understanding that after calling raw2image() and without calling dcraw_process() I should have an undebayered dataset in imgdata.image[][] which only contains visible pixels, is that correct?

What I need to do is to copy data from imgdata.image[][] to a one dimensional 16-bit integer array (size is width * height) that gets saved as a FITS or a TIFF file which can then be debayered later by my post-processing application.

Here is a code example of what I am currently doing:

if ((ret = m_raw_proc->open_buffer(data, size)) != 0)
{
     // Handle error
}
 
if ((ret = m_raw_proc->unpack() != 0))
{
    // Handle error
}
 
if ((ret = m_raw_proc->raw2image()) != 0)
{
    // Handle error
}
 
m_width = m_raw_proc->imgdata.sizes.iwidth;
m_height = m_raw_proc->imgdata.sizes.iheight;
 
for (int n = 0; n < m_width * m_height; n++)
{
	buffer[n] = m_raw_proc->imgdata.image[n][0];
}

However, when I try to debayer the image in an external application, the code above is heavily bias to a specific primary colour. How do I correctly access the undebayered data from imgdata.image[][]?

Thanks
Amanda

Theoretical part:

Theoretical part:
1) Many (not all) digital cameras have 'masked' (opaque) pixel areas (or black frame), so image area is less than full sensor area. These black pixels may be used for black level calibration, banding suppression, etc (the area that may be used is specific for camera model, so we do not discuss it now).

2) imgdata.rawdata.raw_image[] array contains full sensor area decoded from RAW files. It need to be cropped on processing to exclude black frame.
There are several variables in imgdata.sizes that describes sensor area:
- raw_width, raw_height - full sensor size.
- raw_pitch - row pitch (in bytes! so divide it by 2 for raw_image, by 6 for color3_image) in rawdata.* pointers. Usually raw_pitch is just raw_width *2, but this not always so (eg. if file decoded via DNG SDK).
- top_margin, left_maring - pixel coordinates for top-left image visible area
- width, height - size of visible area (there is some special case for Fuji Super-CCD sensors used on very old cameras; let's drop it).

So, there are two ways to use:

A. Continue to use imgdata.rawdata.raw_image array w/o copying it into imgdata.image.
You'll need to change your all-pixel loops to something like (i'll skip some imgdata.sizes prefixes to shorten statements...)
// srow - source row, drow - dest row, same for col

for(srow = imgdata.sizes.top_margin, drow=0; srow <= top_margin + height; srow++, drow++)
for(scol = imgdata.sizes.left_margin, dcol=0; scol <= left_margin+width....
buffer[srow * width + scol] = imgdata.rawdata.raw_image[drow*raw_pitch/2 + dcol];

B. Use LibRaw::raw2image() call:
This call will allocate imdata.image[..][4] array with 4-components per pixel.
After this call, 3 out of 4 components are zero, and only image[row*width+col][COLOR(row,col)] is not.

If you perform debayering in your own code, raw2image may be not optimal choice because of extra memory use. You may consider de-bayering in place (directly in imgdata.image[][4] array) to save memory.

Feel free to ask if you need additional explanations

-- Alex Tutubalin @LibRaw LLC

White Balance

Thanks Alex,

I can now decode images from Canon DSLRs that only show the active area. My test code now looks like this:

m_raw_proc->open_buffer(data, size);
m_raw_proc->unpack();
 
int pos = 0;
int top_margin = m_raw_proc->imgdata.sizes.top_margin;
int left_margin = m_raw_proc->imgdata.sizes.left_margin;
int raw_pitch = m_raw_proc->imgdata.sizes.raw_pitch / 2;
 
for (int r = 0; r < m_raw_proc->imgdata.sizes.height; r++)
{
	for (int c = 0; c < m_raw_proc->imgdata.sizes.width; c++)
	{
		buffer[pos] = m_raw_proc->imgdata.rawdata.raw_image[(r + top_margin) * raw_pitch + left_margin + c];
		pos++;
	}
}

After this code has run, I have undebayered data in buffer[]. This works very well but I have no idea how to apply the in-camera white balance. I would be grateful if you would be able to explain how I apply a white balance or direct me to a resource that explains this. Indeed, is this even possible without using the dcraw functions?

Once again, I thank you for your continued help.

Amanda

Short answer:

Short answer:
- you need to subtract black level values from (unaltered) RAW values
- than multiply to normalized per-channel WB coefficients.

Long(er) answer: use subtract_black(), scale_colors() and pre_inteprolate() functions code as a reference, these functions are called before interpolation (demosaic) call to perform data ajustments before debayering.

-- Alex Tutubalin @LibRaw LLC

Filter Pattern (CFA)

Thanks Alex,

I now have my application working. However, I have one last question.

Is it possible to find the Bayer filter pattern (CFA) from LibRaw? Basically, I need to establish if a specific camera is either:

  • RGGB
  • BGGR
  • GBRG
  • GRBG

I have looked at imgdata.idata.cdesc but this returns RGBG regardless of the camera in use. It seems that my Nikon DSLRs are using BGGR but Canon cameras are using RGGB.

Is it possible to receive this information from LibRaw?

Many thanks for your kind help.

Amanda

I've already answered to that

I've already answered to that (1st/2nd replies in this thread):
LibRaw::COLOR(row,col) returns color index for (row,col)
So, for bayer, 4 calls for (0,0), (0,1), (1,0), (1,1) will give you bayer pattern used.

COLOR() == 3 is 'second green'

-- Alex Tutubalin @LibRaw LLC

Sorry, I misunderstood your

Sorry, I misunderstood your first answer. I have everything working correctly now.

Once again, thanks for your help.

Amanda