.rawdata.raw_image and .image after unpack()

Hello,

After reading and trying out Libraw for a few days, I am confused with the structure of imgdata and what unpack() does to it:

When calling unpack(), the documentation at http://www.libraw.org/docs/API-CXX-eng.html#unpack
says:

Unpacks the RAW files of the image, calculates the black level (not for all formats). The results are placed in imgdata.image.

Yet there is also imgdata.rawdata.raw_image which gives me access to the raw unprocessed image.

What is the difference between imgdata.image and imgdata.rawdata.raw_image right after calling unpack()?
Is imgdata.image affected by some imgdata.params fields and imgdata.rawdata.raw_image is not (by definition, it would stay "raw" indeed)?

Should I also understand that unpack() also fill in the imgdata.rawdata.raw_image (and not only imgdata.image)? The latter appeared empty of any value if I print out values before unpack().

Thank you for this clarification. And thank you also for all your efforts on Libraw.

Raphael

Forums: 

Sorry, docs slightly outdated

Sorry, docs slightly outdated in this particular place, to be fixed ASAP.

unpack() in current LibRaw (0.16+) stores raw data in imgdata.rawdata.raw_image (or color3_image, or color4_image). This is one component per pixel for raw_image (bayer)

raw2image() pupulates imgdata.rawdata into imgdata.image[][4] array (4 components per pixel, but only one filled with value for bayer images).

image[][4] than used to all postprocessing by dcraw_process()

this is because of modification made on 0.16 version. Prior to it, unpack() works with imgdata.image[] directly, so
1) multiple processing (dcraw_process()) of same raw data with different settings was impossible.
2) it application uses only raw data and do not need dcraw_process() (so, do own processint), image[] is 4x waste of memory

-- Alex Tutubalin

Thanks Lexa, I understand a

Thanks Lexa, I understand a bit better now, when I look at the unpack() source code.
I'm still missing maybe a last piece of the puzzle to understand the basic pipeline in my particular case:
Canon EOS 5D mark III, and a good old fashioned EOS 350D (although what follows applies to more kind of Bayer sensors).

In unpack(), I see (assuming I do not have/use rawSpeed):

 else if(imgdata.idata.filters || P1.colors == 1) // Bayer image or single color -> decode to raw_image
          {
            imgdata.rawdata.raw_alloc = malloc(rwidth*(rheight+8)*sizeof(imgdata.rawdata.raw_image[0]));
            imgdata.rawdata.raw_image = (ushort*) imgdata.rawdata.raw_alloc; 

(...)

imgdata.rawdata.raw_alloc = imgdata.image;
imgdata.image = 0;

(...)

// recover saved
    if( !(imgdata.idata.filters || P1.colors == 1) && !imgdata.rawdata.color4_image)
      {
        imgdata.image = 0;
        imgdata.rawdata.color4_image = (ushort (*)[4]) imgdata.rawdata.raw_alloc;
      }

So you seem to populate the raw_alloc (and thus raw_image?) with imgdata.image (correct me if i'm wrong). But I still have a hard time tracking up where imgdata.image was populated on the first place.
Looking into libraw_cxx.cpp, I don't see much either. It would be nice to point me where imgdata.image gets the raw data from the .CR2 file. I see hasselblad_full_load_raw() that seems to do something with it, but I'm not sure if that's what i'm looking for. Maybe it happens within open_file and subsequent "stream" functions?

Thank you for your help

Raphael

imgdata.image is populated in

imgdata.image is populated in
1) raw2image() call (use it for compatibility, if you need to use 4-component image[] in your code)
2) dcraw_process() calls raw2image_ex() call, which do populating and black level extraction in single pass.

raw_alloc is just a pointer to allocation (to be free()-ed at recycle() call)
raw_image, color3_image and color4_image are pointers to pixel buffer (allocated by LibRaw or by RawSpeed). Only one pointer is non-zero for given image and this is the only way to know exact image format (1-component bayer/BW, or 3-component LinearDNG /Canon sRAW extracted by RawSpeed, or 4-component 3/4 color image extracted by LibRaw /LinearDNG, Canon sRAW).

The last piece of code (with imagedata.image set to 0) is a way to handle non-bayer image extracted by LibRaw: LinearDNG, canon sraw and 4-shot sinar unpackers works with imgdata.image[] (the code is from dcraw), so after unpacking we need to assign color4_image pointer (and raw_alloc for correct release in recycle()), and clear imgdata.image pointer

Things are so complicated because so many RAW flavours exists :(

-- Alex Tutubalin

confused again

I'm confused again. Maybe I missed something else.

In the code samples that I pasted, my trouble was that these were only memory allocation of buffers, and I failed to see where the data from the .CR2 file where going. Then imgdata.image seemed the only time when some non-zero data were passed. But I'm wrong since from what you say imgdata.image is not populated with any raw or processed data at that time: the imgdata.image gets populated only after "raw2image()" or "dcraw_process()". So the quoted codes I sent aren't all there is to see regarding how the raw_data gets populated from a Canon CR2 file , right? Again, the code I sent are only memory allocation, so am i not missing the part where the raw_image is populated with the actual raw data and is not just given the pointer to an initialized, non-populated buffer? That's basically what I'm missing: where in the code is that buffer, whose pointer is given to raw_image, populated with the raw data from the CR2 file.

Just to clarify something else. Can I assume i'm not going into the rawSpeed related blocks when using Bayer image from canon CR2? This is to make sure i'm not missing anything in the pipeline. It was not clear to me what rawSpeed was, and if having a canon DSLR (5d mark III) was of any concern to this.

Thanks (a lot!)

imgdata.image appears

imgdata.image appears temporarily within unpack() (before (*load_raw)() call) if needed, than hided again.

If you need imgdata.image[] in your code, call raw2image() after unpack() to get it.

-- Alex Tutubalin

Is that in fact in

Is that in fact in

 (this->*load_raw)() (within unpack())

that the raw_data buffer gets populated?

No-no-no

No-no-no
load_raw() uses preallocated buffer (unles OWNALLOC specified in decoder flags).

Again:
imgdata.image[] is allocated and populated in raw2image() or raw2image_ex() calls.

imgdata.rawdata.* pointers are initialized in unpack() call.

-- Alex Tutubalin

Initialization of rawdata

Initialization of rawdata buffer in unpack(), can't miss it, it's clear. Populated this raw data buffer, still can't see it within unpack(). I make here a distinction between initializing something, and assigning value (which you call "populate" i guess). That's that part I still don't grasp.

Consider my test (it's done in Qt framework, hence the qDebug() instead of printf() for printing out in debug mode):

 
LibRaw rawProcess;
 
    rawProcess.open_file("/......./F36A7292.CR2");
    rawProcess.unpack()
 
    // printout raw values
    int first_visible_pixel = rawProcess.imgdata.sizes.raw_width*rawProcess.imgdata.sizes.top_margin + rawProcess.imgdata.sizes.left_margin;
    for( int i=0; i< 100; i++)
    {
        qDebug() << "raw_image["<< i << "] =" << rawProcess.imgdata.rawdata.raw_image[i+first_visible_pixel];
    } 

This is giving me my raw values.

And I still don't see how the raw_image values get assigned (populated) within unpack(). In what I pasted in the early post, i don't see the lines of codes where this happen, for the Canon case (Nikon case seems a bit different). All I see is initialized buffer, and freed buffer (for Bayer image, and non-Nikon)

Sorry for repeating the question, I must be missing something obvious. Maybe a slap in my face will make me see. (by Copy pasting that invisible line that I don't see?)
If you don't want to repeat yourself, I'll understand and will go back again to what you say and try to find what i missed.

Thanks.

raw_image values are read in

raw_image values are read in *_load_raw() call (specific to image format) called by
(this->*load_raw)();

-- Alex Tutubalin

I've been doing some testing.

I've been doing some testing. I've selected the 4 first pixels of the data (I ignored the hidden ones for calibration), for a .CR2 file (canon 5D), at 3 stages of processing: after unpack(), after raw2image(), after dcraw_processed(). See below (the 4 "channels" of the 2nd dimension are separated by the separator " | "):

user_qual = -1
imgdata.idata.cdesc = RGBG
unpack(): raw_image[ 0 ] = 2141
unpack(): raw_image[ 1 ] = 2098
unpack(): raw_image[ 2 ] = 2034
unpack(): raw_image[ 3 ] = 2084
raw2image(): imgdata.image[ 0 ][0 to 3] = | 2141 | 0 | 0 | 0
raw2image(): imgdata.image[ 1 ][0 to 3] = | 0 | 2098 | 0 | 0
raw2image(): imgdata.image[ 2 ][0 to 3] = | 2034 | 0 | 0 | 0
raw2image(): imgdata.image[ 3 ][0 to 3] = | 0 | 2084 | 0 | 0
dcraw_processed(): imgdata.image[ 0 ][0 to 3] = | 1576 | 0 | 688 | 0
dcraw_processed(): imgdata.image[ 1 ][0 to 3] = | 616 | 136 | 626 | 0
dcraw_processed(): imgdata.image[ 2 ][0 to 3] = | 0 | 132 | 371 | 0
dcraw_processed(): imgdata.image[ 3 ][0 to 3] = | 0 | 287 | 36 | 0

Why aren't the raw2image() values in the same column and instead, dispatched alternatively in the 0th and 1st column? Is that just to prepare the data for later demosaicing in a way that's compatible with all possible sensors? The values are indeed identical to the raw values. So it is unclear what happens between unpack() raw_image[] values and raw2image() image[][] values

Are the dcraw_processed() values dispatched in the 1st three columns to be considered as the R | G | B (and 4th is unused) components, after demosaicing?

Thanks

raw2image() put pixel values

raw2image() put pixel values according to color of this particular pixel (0 for Red, 1 and 3 for G/G2, 2 for Blue)

-- Alex Tutubalin

Ok, I understand the Bayer

Ok, I understand the Bayer pattern of RGBG. My question is just to be clear on how to read the dimensions.
By printing out:

raw2image(): imgdata.image[ 0 ][0 to 3] = | 2141 | 0 | 0 | 0
raw2image(): imgdata.image[ 1 ][0 to 3] = | 0 | 2098 | 0 | 0
raw2image(): imgdata.image[ 2 ][0 to 3] = | 2034 | 0 | 0 | 0
raw2image(): imgdata.image[ 3 ][0 to 3] = | 0 | 2084 | 0 | 0

Which dimension is going across the R G B G values. At first I thought it was [0 to 3] (2nd dimensions, "columns") which was giving the R G B G (which I abusively call the "channels"). Is that the other way round? Are they, in fact, in the 1st dimension (rows)? I'm often confused on the dimension when I see tables of pointers such as:
imgdata.image = (ushort (*)[4]) calloc(S.iwidth*S.iheight,sizeof(*imgdata.image));

You didn't say anything about the other question:

dcraw_processed(): imgdata.image[ 0 ][0 to 3] = | 1576 | 0 | 688 | 0

Is the row here the demosaiced RGB values of a given pixel (from left to right column) ?

Thanks

row and column are both in 1

row and column are both in 1-st dimension.
The (row,col) pixel values are in
image[row*imgdata.sizes.iwidth + col] [0..3]

iwidth is equal to imgdata.sizes.width for normal processing and width/2 for 'half' interpolation (where imgdata.params.half_size is non-zero).

Border values (1st/last row or 1st/last column) in image may be not fully interpolated because there is no data for it.
Better use image[iwidth*2 + 2] for inspection (this is pixel at (2,2))

-- Alex Tutubalin

Oh ok, indeed I was wondering

Oh ok, indeed I was wondering about 0 values may be due to edges.
Ok, i'll try inspecting away from edges.

You cleared out my question on the dimensions, thanks a lot!

Raphael

Away from edges, I did this:

Away from edges, I did this:

    int iwidth = rawProcess.imgdata.sizes.iwidth;
    // somewhere in the middle of the picture, far from edges.
    int row = 2898;
    int col = 2898;
    // Display just 5 pixels
    int nPixels = 5;
 
    int first_visible_pixel = rawProcess.imgdata.sizes.raw_width*rawProcess.imgdata.sizes.top_margin + rawProcess.imgdata.sizes.left_margin;

then looping over a pixel index with i from 0 to 4 in :

 pixInd = first_visible_pixel + iwidth*row + col+ i;

rawProcess.imgdata.rawdata.raw_image[pixInd] gives:

unpack(): raw_image[ 17273428 ] = 2135
unpack(): raw_image[ 17273429 ] = 2091
unpack(): raw_image[ 17273430 ] = 2126
unpack(): raw_image[ 17273431 ] = 2174
unpack(): raw_image[ 17273432 ] = 2191

after raw2image(), imgdata.image[pixInd][0 to 3] gives, with the following printout arguments:
image[pixInd][0] | image[pixInd][1] | image[pixInd][2] | image[pixInd][3],

with now,  pixInd = iwidth*row + col + i ;

raw2image(): imgdata.image[ 16799706 ][0 to 3] = | 2175 | 0 | 0 | 0
raw2image(): imgdata.image[ 16799707 ][0 to 3] = | 0 | 2207 | 0 | 0
raw2image(): imgdata.image[ 16799708 ][0 to 3] = | 2134 | 0 | 0 | 0
raw2image(): imgdata.image[ 16799709 ][0 to 3] = | 0 | 2161 | 0 | 0
raw2image(): imgdata.image[ 16799710 ][0 to 3] = | 2139 | 0 | 0 | 0

I'd like to understand why the values in imgdata.image, after raw2image() are put alternatively in channel 0 and channel 1.

Currently, to me these values mean (for imgdata.image[][]):

pixel 16799706 has R = 2175 , G = 0, B = 0, G2 = 0
pixel 16799707 has R = 0 , G = 2207, B = 0, G2 = 0
etc...

Which i probably misunderstand as my image is clearly filled with all colors.
What am i missing this time?

Looks normal for me (after

Looks normal for me (after raw2image, not dcraw_process):
Each row (or column )in bayer pattern contains only two colors:
RGRGRGRG
GBGBGBGB
(really G2 in second row)

-- Alex Tutubalin

Hmm... getting there...

Hmm... getting there...

raw2image(): imgdata.image[ 16799706 ][0 to 3] = | 2175 | 0 | 0 | 0
raw2image(): imgdata.image[ 16799707 ][0 to 3] = | 0 | 2207 | 0 | 0
raw2image(): imgdata.image[ 16799708 ][0 to 3] = | 2134 | 0 | 0 | 0
raw2image(): imgdata.image[ 16799709 ][0 to 3] = | 0 | 2161 | 0 | 0
raw2image(): imgdata.image[ 16799710 ][0 to 3] = | 2139 | 0 | 0 | 0

So, do you mean that, above, pixInd 16799706 is telling me that R = 2175, and that
pixInd 16799707 is giving my G2 = 2207 ?
pixInd 16799708 is B = 2134
pixInd 16799709 is G = 2161

and then these 4 values are my RGBG for one non-demosaiced single colored pixel?

Could not understand the

Could not understand the question
pixels 16799706 .... 16799710
are all in the same row
So, only two colors.
Again
ROWn: RGRGRGRGRGRGR
ROWn+1: GBGBGBGBGBGB

-- Alex Tutubalin

Also, please note, that image

Also, please note, that image[] do not contain invisible pixels.

So, raw_image[(row+top_margin)*raw_width + left_margin+col] becomes just image[row*iwidth+col]

-- Alex Tutubalin

yes, that's what I did 2

yes, that's what I did 2 replies above with

 pixInd = iwidth*row + col + i

(I iterated over i 5 times).

Please see my "in-between" reply above. It's really important that I get that cleared out.

Have you noted, that in bayer

Have you noted, that in bayer-pattern cameras (all modern, except foveon sensors) each pixel is monochrome (R _or_ G _or_ B) ?

-- Alex Tutubalin

Yes, I'm aware of how a

Yes, I'm aware of how a detector is structured. I'm confused on the software side.

The RGBG is just confusing me with how they get represented in the ushort (*)[4] array.

I saw your other reply. i'm gonna do some more tests and try to understand it better, displaying Row_N and Row_N+1

Thanks.

raw2images arranges pixel

raw2images arranges pixel values (from raw_image array, 1 value per pixel) to image[][4] array (4 values per pixel).
So, only one of image[N][0..3] is non-zero after raw2image, all other 3 components are still zero.
This is 'prepare for interpolation' step.

Actual interpolation (and white balance, output color profile conversion, brightness adjustment) is made by dcraw_process()

-- Alex Tutubalin

Ok. I'm still processing your

Ok. I'm still processing your explanations:

Let me take one step back on raw_image(). I see the initialization and dimensioning of raw_image, set as a one dimension array (row, or column, that's just an abstraction here):

 imgdata.rawdata.raw_alloc = malloc(rwidth*(rheight+8)*sizeof(imgdata.rawdata.raw_image[0]));
            imgdata.rawdata.raw_image = (ushort*) imgdata.rawdata.raw_alloc; 

When i display the raw values, if I printout the raw_image[] at 4 consecutive indices,
say:

unpack(): raw_image[ i ] = 2135
unpack(): raw_image[ i+1 ] = 2091
unpack(): raw_image[ i+2 ] = 2126
unpack(): raw_image[ i+3 ] = 2174

assuming i'm in row_N, say, at the beginning of the row, are these values corresponding to RGRG?

Then if I print at

unpack(): raw_image[ i + width]
unpack(): raw_image[ i+1 + width]
unpack(): raw_image[ i+2 + width]
unpack(): raw_image[ i+3 +width]

does that go to the next row where I'd see the BGBG associated to the same pixel ? you said 4 values per pixel, as expected for Bayer image, so just checking I understand how they are set in the raw files.

Thanks

Pixels (in raw_image) are

Pixels (in raw_image) are recorded 'as in raw file'.
Colors are depending on camera CFA pattern.
The LibRaw::COLOR(row,col) call will return color for given pixel (row,col) are in image[] coordinate space i.e. visible area (so counted from top_margin,left_margin point of raw_image)

-- Alex Tutubalin

Regarding a correction

Regarding a correction pipeline, would it make sense to make my own corrections on the non-demosaiced raw_image, such as subtracting my own dark image (an average "master" of dark images in fact) taken with the same camera (same parameters), and calling raw2image() on the dark-subtracted raw_image? Or should I better perform this on the imgdata.image after the raw2image() call ?

I'm soon publishing my software for which i'm trying to implement Libraw, so, again, thank you for your time.

If you will use dcraw_process

If you will use dcraw_process() for image postprocessing, you need to fix values in raw_image[] array, because dcraw_process() will call raw2image_ex(), so override any changes made in image[] array.

Also, you need to set imdata.params.user_black and user_cblack[4] to zero to prevent additional black level subtraction in dcraw_process()

-- Alex Tutubalin

Thank you for these caveats.

Thank you for these caveats. I noticed the need of using the user_black, user_cblack.

I notice the use of COLOR() is somehow same as using FC(), right? The latter is used in raw2image() apparently.
I haven't go through those functions yet. COLOR() is not documented so can you say a bit more about how to use this? I had a look in libraw.h
You wrote:

int COLOR(int row, int col) { return libraw_internal_data.internal_output_params.fuji_width? FCF(row,col):FC(row,col);}

If COLOR(row, col) gives a color value at pixel(2,2), that value must be in some color table, right? Where/how do I know which color table this COLOR() output value corresponds to?

Or did you mean, more simply, that COLOR(row,col) is meant to be used like this:

colorValue at pixel (2,2) = imgdata.image(COLOR(row,col)) ?

which would just consist in converting 2D coordinates in the 1D buffer index.

For bayer images, COLOR is

For bayer images, COLOR is just FC()
For fuji (SuperCCD, X-Trans) it is not

-- Alex Tutubalin

color value = image[pixel

color value = image[pixel number][COLOR(row,col)], indeed, but it is not intended to use this way.

If one uses dcraw_process(), he will get image[] with interpolated colors after this call.
If one uses own processing, he hardly need 4-component image[] array.

raw2image is *compatibility layer* for some programs created to use with Libraw pre-0.15 (separate raw_image and image was introduced in version 0.15).

-- Alex Tutubalin

After dcraw_process, image[][

After dcraw_process, image[][] contains demosaiced data? only 3-values RGB and not 4-values-RGBG, is that correct?

After dcraw_process(), if I do:
color value = image[pixel number][COLOR(row,col)] and I get... interpolated color?

Thanks

This is demosaiced, white

This is demosaiced, white balanced, brightness adjusted, not rotated (!) image with linear gamma.

If you wish to get RGB bitmap (8 or 16 bit) with gamma applied and without extra (4th) component. use dcraw_make_mem_image() call.

-- Alex Tutubalin

Ok, I see dcraw_make_mem

Ok, I see dcraw_make_mem_image() in documentation, that's good, I will use it.

I might need to do coaligmnent of series of images with just, say, their green component.
So I need to just extract a bitmap of just one of the three RGB components of the demosaiced image, what function do you recommend to use?

To extract one channel only,

To extract one channel only, there is several ways
1) extract it from raw_image: find 1-st green component (using COLOR) coordinate in (0,0)-(1,1) square and than go from pixel to pixel with +2 increment in both directions
2) do raw2image with params.half_size
It will create half-sized image[] array with all 4 components are non-zero (because each bayer 2x2 square will go into one image[] pixel)
Than use [1] plane from image

-- Alex Tutubalin

Excellent, useful information

Excellent, useful information! Thanks! Will post soon on the other forum topic the github link for the software (opensource of course)

Raphael

Can you confirm the following

Can you confirm the following code, for the usage of COLOR():

In image after dcraw_processed, to get the color of pixel at, e.g., (10, 3):

int row = 3;
int col = 10;
int iwidth = rawProcess.imgdata.sizes.iwidth;
int color value = rawProcess.imgdata.image[iwidth*row + col][COLOR(row, col)];

The row and col variables in image[iwidth*row + col] are the same expected in COLOR(row, col), is that correct?

If image has dcraw_processed(

If image has dcraw_processed() (so, bayer data interpolated), you possibly do not need COLOR():

image[row*iwidth+col][0..3] will contain Red, Green, Blue in 0..2 and some garbage (not-interpolated G2 or zero) in [3]

-- Alex Tutubalin

I think, I need to describe

I think, I need to describe processing stages in LibRaw (simplified case, bayer image)

1) open_file() - reads metadata (EXIF and makernotes)
2) unpack() - decodes file contents into imgdata.rawdata.raw_image.
COLOR() call is useful after that: to know what color has pixel at (row,col).

3) dcraw_process():
- do raw2image() internally, allocate imgdata.image[] and populate
imgdata.image[row*width+col[COLOR(row,col)] = rawdata.raw_image[(row+top)*raw_width+col+left]
- do white balance
- than bayer interpolation
- and other possible postprocessing such as denoise or highlight recovery
- than output color conversion and data scale

After that, image[row*width+col] has [0..2] components filled with RGB values and something in [3]

4) dcraw_make_mem_image() may be used to create 3-component bitmap (with gamma correction), in 8- or 16-bit per component to be written into TIFF/JPEG or displayed on screen..

That's all that simple :)

You may repeat steps 3 and 4 with different imgdata.params settings to get different renderings

-- Alex Tutubalin

That's good.

That's good.

Does dcraw_make_mem_image() also perform:

- do white balance
- than bayer interpolation
- and other possible postprocessing such as denoise or highlight recovery

as dcraw_process()?

Just to be clear:

Do i invoke dcraw_make_mem_image() INSTEAD OF dcraw_process() or AFTER dcraw_process()?

dcraw_make_mem_image() just

dcraw_make_mem_image() just copies values from image[] to separate memory array with
- gamma curve
- 16 to 8 bit correction (if requested; this is default)
- rotation.

It is that simple :)

UPD: so, yes, use it after dcraw_process()

-- Alex Tutubalin

All clear! :-)

All clear! :-)

Will start implementing Libraw functions in my project (still at a very early, poorly documented and modest stage).
You can currently see it as "QtFits" in github: https://github.com/raphaelattie/QtFits.git
Dealing so far with FITS files, the name of the future app will of course change after implementing Libraw-dependent classes, thanks to which I will not just handle FITS files anymore.

Thanks

Hi there,

Hi there,

Made some progress thanks to your explanations. I can play with the color channels and display the results of some personal post-processing. Very nice.

I wanted to ask you some more details on what "banding / debanding" does? In your documentation, I read this for Structure libraw_rawdata_t: holds unpacked RAW data:

int cfaline; float linenoise;
Line noise (banding) reduction.
positive value turns this feature on (default: off).
linenoise - amount of reduction. Useful range is 0.001 to 0.02. Default value is 0.0 i.e. not clean anything.

(...)

int wf_debanding; float wf_deband_treshold[4];
wf_debanding: 1 turns on banding suppression (slow!), 0 turns it off.
wf_deband_treshold[] - per channel debanding thresholds.

I'm reading some general stuff about banding in general, I understand the noise pattern that is targeted. Could you explain in which respect the first parameter (1st block) and the 2nd ones (2nd block) affect the image? They both deal with "banding", so it is unclear what each does.

In addition, do they affect the raw image right after unpack(), or does one, or both, affect only the post-processed one in imgdata.image? (after either raw2image() or dcraw_process())

Thanks

wf_debanding() is contributed

wf_debanding() is contributed to LibRaw by one of our users.
I've never used it in real processing, just several experiments several years ago. So, try to play with parameters yourself

-- Alex Tutubalin

Ok, that addresses wf

Ok, that addresses wf_debanding(), thanks.

What about the cfaline / linenoise parameters, 1st block, with:

int cfaline; float linenoise;
Line noise (banding) reduction.
positive value turns this feature on (default: off).
linenoise - amount of reduction. Useful range is 0.001 to 0.02. Default value is 0.0

It's used for the same purpose apparently. Is that directly coming from dcraw? You didn't play with it either? Any idea if that's meant to affect things for unpack() or for raw2image()/dcraw_process()/dcraw_make_mem_image()?

I'll try to reverse-engineer this a bit but would be great to have any additional information on what your source code does with this if you have it hanging around. The code is quite... dense on that level!

quote from libraw_cxx:

quote from libraw_cxx:

    if (O.ca_correc >0 ) {cablue=O.cablue; cared=O.cared; CA_correct_RT(cablue, cared);}
    if (O.cfaline >0 ) {linenoise=O.linenoise; cfa_linedn(linenoise);}
    if (O.cfa_clean >0 ) {lclean=O.lclean; cclean=O.cclean; cfa_impulse_gauss(lclean,cclean);}

CA_correct_RT() - is for demosaic pack GPL3, backported code from RawTherapee, chromatic abberration corrector.
cfs_linedn() - some kind of de-banding by high frequency filtering, again from Emil Martinec/RawTherapee/GPL3
cfa_impulse_gauss() - out of range pixels cleaning, same source/copyright

All three was contributed by RawTherapee in 2011.

LibRaw contribution policy is very simple
1) we accept *all* contributed code
2) the default settings are 'not used'
3) no extensive testing, just test that output image is not completely damaged

The same true for dcraw_process() itself.
Our "mission" is to decode RAW data and metadata. We're happy if user (developer) interaction with LibRaw ends just after unpack()/unpack_thumb() calls and all postprocessing is done by calling application. Standard postprocessing is very similar to dcraw (as dcraw_process() implies), it is not fast and not high quality.

-- Alex Tutubalin

After unpack(), I'm trying to

After unpack(), I'm trying to use the raw_image as an input to opencv demosaicing (with cvtColor and type CV_BayerGB2RGB), and thus avoid the use of dcraw_process for demosaicing. opencv here requires a 1-channel data image. Yet when I use the raw data after unpac(), starting from the first visible pixel, it gives me some rubbish image.
As far as you know at least on the Libraw's side, am I getting the raw CFA data wrong? See below:

int raw_width = (int) rawProcess.imgdata.sizes.raw_width;
int top_margin = (int) rawProcess.imgdata.sizes.top_margin;
int left_margin = (int) rawProcess.imgdata.sizes.left_margin;
int first_visible_pixel = (int) (raw_width * top_margin + left_margin);
 
cv::Mat imRaw(naxis2, naxis1, CV_16UC1);
    ushort *rawP = imRaw.ptr<ushort>(0);
    for (int i = 0; i < nPixels; i++)
    {
        rawP[i] = (ushort) rawProcess.imgdata.rawdata.raw_image[i+first_visible_pixel];
    }
 
    cv::Mat demosaiced16;
    cvtColor(imRaw, demosaiced16, CV_BayerGB2RGB);

Above, imRaw.ptr is the pointer to the data buffer in the cv::Mat object where I want to copy my raw_image data.

The expected image (which I get after dcraw_process) is:
https://www.dropbox.com/s/unn695en6hpdr3j/dcraw_process.jpg?dl=0

And instead, I have this:
https://www.dropbox.com/s/c1f8s3fjgqy0tit/Failed_demosaic.jpg?dl=0

Each row contains not visible

Each row contains not visible pixels on both ends:
- on left (0.... left_margin-1)
- and on right (from visible area end to row end)
Also, rows may be aligned for efficient SSE/AVX access. LibRaw internal code do not align rows, but if you use LibRaw+RawSpeed, RawSpeed will align rows on 16 bytes.
So, it is better to use imgdata.sizes.raw_pitch (it is in bytes, so divide /2 for bayer data) instead of raw_width.

So, right (pseudo)code is something like this:

#define VISIBLE_PIXEL(row,col)  \
imgdata.rawdata.raw_image[(row+imgdata.sizes.top_margin)*imgdata.sizes.raw_pitch/2 + imgdata.sizes.left_margin+col]
 
for(int r = 0; r < imgdata.sizes.height; r++)
 for(int c=0; c<imgdata.sizes.width; r++)
  next_pixel = VISIBLE_PIXEL(r,c);

Add your data object name before imgdata to get correct code

-- Alex Tutubalin

Pages