Maximum/saturation pixel value

I am having some trouble determining the maximum or saturation level for my pixels, I thought it was LibRaw::imgdata.color.maximum, however I find in some cases that after processing I have values bigger than this value. My code is below:

	// Create an image processor
	LibRaw iProcessor;
	// Open the file and read the metadata
	size_t width = iProcessor.imgdata.sizes.width;
	size_t height = iProcessor.imgdata.sizes.height;
	// Unpack the image
	iProcessor.imgdata.params.user_qual=4; // DCB interpolation
	iProcessor.imgdata.params.output_color = 0; // Raw output
	//do no white balance
	iProcessor.imgdata.params.use_camera_wb = 0;
	iProcessor.imgdata.params.user_mul[0] = 1.0f;
	iProcessor.imgdata.params.user_mul[1] = 1.0f;
	iProcessor.imgdata.params.user_mul[2] = 1.0f;
	iProcessor.imgdata.params.user_mul[3] = 1.0f;
	//Copy the luminosity into a vector
	std::vector<unsigned short> data(width * height);
	unsigned int maxLuminosity = 0;
	for (size_t i = 0; i < data.size(); ++i)
		unsigned int luminosity = ((unsigned int)iProcessor.imgdata.image[i][0] * 2 + (unsigned int)iProcessor.imgdata.image[i][1] * 3 + (unsigned int)iProcessor.imgdata.image[i][2])/6;
		data[i] = luminosity;
		maxLuminosity = luminosity > maxLuminosity ? luminosity : maxLuminosity;
		if (luminosity > iProcessor.imgdata.color.maximum)
			std::cout << "Pixel " << i << " has luminosity too high\n";

If I break in my debugger where I do the std::cout, then I can see that individual pixel values are higher than iProcessor.imgdata.color.maximum.

Is there something I am doing wrong? The region where I am getting the higher values is probably overexposed in one or both of red and green ( it is a sunset picture). I have just spotted the highlight option, but this is set to 0, which I think should clip. Is this correct?


color.maximum is 'maximum

color.maximum is 'maximum data value permitted by data format'.
In some cases, real maximum is smaller.
There is color.data_maximum field, but it is filled /based on real data/ on raw2image (or dcraw_process) stage, so not available just after unpack().

In your example you compare raw data maximum (so, data range of raw data) with processed values.
This is not correct, because output data are scaled to use full data range (16 bit).

-- Alex Tutubalin @LibRaw LLC

Hmm, It seems to me that

Hmm, It seems to me that processed data are not being scaled to the 0-65535 range. In fact the data that are not saturated fall into the range 0 - colour.maximum, only saturated values are larger than color.maximum.

Is there a way I can upload an image to the forum? I have generated a greyscale jpeg from the data vector in my code above using

std::vector<unsigned char> jpegData(data.size());
for(size_t i=0; i<data.size(); ++i)
	jpegData[i] = unsigned char((data[i]*255)/iProcessor.imgdata.color.maximum);

The ouput shows the buffer overrun from conversion to unsigned char very clearly.


imgdata.image is indeed

imgdata.image is indeed scaled in LibRaw::scale_colors() call

For your test: what contained in data array?

-- Alex Tutubalin @LibRaw LLC

Not so. It looks like you've

Not so. It looks like you've divided data by 256 (than recover it back?). This step is missing
In your code:

unsigned int luminosity = ((unsigned int)iProcessor.imgdata.image[i][0] * 2 + (unsigned int)iProcessor.imgdata.image[i][1] * 3 + (unsigned int)iProcessor.imgdata.image[i][2])/6;
		data[i] = luminosity;

data should be in 16bit (64k) range.
Next step:

jpegData[i] = unsigned char((data[i]*255)/iProcessor.imgdata.color.maximum);

Data is upscaled to 24 bit?

-- Alex Tutubalin @LibRaw LLC

And if data is scaled to 8

And if data is scaled to 8 bit somewhere, your result looks correct.

coloir.maximum is in RAW data domain, so for 14-bit camera it is about 16000.
imgdata.image[], after processing, is in 0..64k range.
your luminocity calculation, in first assumption, is in same range as imdata.image, so 64k.

So your jpeg generation code will show upper two stops of image as 'overflow'

-- Alex Tutubalin @LibRaw LLC