wisdom
wisdom

Reputation: 442

OpenCV Tiff Wrong Color Values Readout

I have a 16-bit tiff image with no color profile (camera profile embedded) and I am trying to read its RGB values in OpenCV. However, comparing the output values to the values given when the image is opened by GIMP for example gives totally different values (GIMP being opened with keeping the image's profile option; no profile conversion). I have tried also another image studio software like CaptureOne and the result accords with GIMP differs from OpenCV output.

Not sure if reading and opening the image in OpenCV is wrong somehow, in spite of using IMREAD_UNCHANGED flag.

I have as well tried to read the image using FreeImage library but still the same result.

Here is a snippet of the code reading pixels' values in OpenCV

const float Conv16_8 = 255.f / 65535.f;
cv::Vec3d curVal;
// upperLeft/lowerRight are just some pre-defined corners for the ROI
for (int row = upperLeft.y; row <= lowerRight.y; row++) {
    unsigned char* dataUCPtr = img.data + row * img.step[0];
    unsigned short* dataUSPtr = (unsigned short*)dataUCPtr;

    dataUCPtr += 3 * upperLeft.x;
    dataUSPtr += 3 * upperLeft.x;

    for (int col = upperLeft.x; col <= lowerRight.x; col++) {
        if (/* some check if the pixel is valid */) {
            if (img.depth() == CV_8U) {
                for (int chan = 0; chan < 3; chan++) {
                    curVal[chan] = *dataUCPtr++;
                }

            }
            else if (img.depth() == CV_16U) {
                for (int chan = 0; chan < 3; chan++) {
                    curVal[chan] = (*dataUSPtr++)*Conv16_8;
                }
            }
            avgX += curVal;
        }
        else {
            dataUCPtr += 3;
            dataUSPtr += 3;
        }
    }
}

and here is the image (download the image) I am reading with its RGB readouts in

CaptureOne Studio AdobeRGB:

CaptureOne AdobeRGB Readouts

vs OpenCV RGB (A1=white --> F1=Black):

OpenCV RGB

PS1: I have tried also to change the output color space in GIMP/CaptureOne to sRGB but still the difference is almost the same, not any closer to OpenCV

PS2: I am reversing OpenCV imread channels' order before extracting the RGB values from the image COLOR_RGB2BGR

Upvotes: 0

Views: 560

Answers (2)

Myndex
Myndex

Reputation: 5364

OP said:

I have a 16-bit tiff image with no color profile (camera profile embedded)

Well no, your image definitely has a color profile, and it should not be ignored. The embedded profile is as important as the numeric values of each pixel. Without a defined profile, the pixel values are somewhat meaningless.

From what I can tell, OpenCV does not linearize gamma by default... except when it does... Regardless, the gamma indicated in the profile is unique:

Phase One Profile

Now compare that to sRGB:

sRGB Profile

So the sRGB transformations can't be used.

If you are looking for performance, applying the curve via LUT is usually more efficient than a full-on color management system.

In this case, using a LUT. The following LUT was taken from the color profile, 16bit values, and 256 steps:

    // Phase One TRC from color profile

  profileTRC = [0x0000,0x032A,0x0653,0x097A,0x0CA0,0x0FC2,0x12DF,0x15F8,0x190C,0x1C19,0x1F1E,0x221C,0x2510,0x27FB,0x2ADB,0x2DB0,0x3079,0x3334,0x35E2,0x3882,0x3B11,0x3D91,0x4000,0x425D,0x44A8,0x46E3,0x490C,0x4B26,0x4D2F,0x4F29,0x5113,0x52EF,0x54BC,0x567B,0x582D,0x59D1,0x5B68,0x5CF3,0x5E71,0x5FE3,0x614A,0x62A6,0x63F7,0x653E,0x667B,0x67AE,0x68D8,0x69F9,0x6B12,0x6C23,0x6D2C,0x6E2D,0x6F28,0x701C,0x710A,0x71F2,0x72D4,0x73B2,0x748B,0x755F,0x762F,0x76FC,0x77C6,0x788D,0x7951,0x7A13,0x7AD4,0x7B93,0x7C51,0x7D0F,0x7DCC,0x7E8A,0x7F48,0x8007,0x80C8,0x8189,0x824C,0x8310,0x83D5,0x849B,0x8562,0x862B,0x86F4,0x87BF,0x888A,0x8956,0x8A23,0x8AF2,0x8BC0,0x8C90,0x8D61,0x8E32,0x8F04,0x8FD7,0x90AA,0x917E,0x9252,0x9328,0x93FD,0x94D3,0x95AA,0x9681,0x9758,0x9830,0x9908,0x99E1,0x9ABA,0x9B93,0x9C6C,0x9D45,0x9E1F,0x9EF9,0x9FD3,0xA0AD,0xA187,0xA260,0xA33A,0xA414,0xA4EE,0xA5C8,0xA6A1,0xA77B,0xA854,0xA92D,0xAA05,0xAADD,0xABB5,0xAC8D,0xAD64,0xAE3B,0xAF11,0xAFE7,0xB0BC,0xB191,0xB265,0xB339,0xB40C,0xB4DE,0xB5B0,0xB680,0xB750,0xB820,0xB8EE,0xB9BC,0xBA88,0xBB54,0xBC1F,0xBCE9,0xBDB1,0xBE79,0xBF40,0xC005,0xC0CA,0xC18D,0xC24F,0xC310,0xC3D0,0xC48F,0xC54D,0xC609,0xC6C5,0xC780,0xC839,0xC8F2,0xC9A9,0xCA60,0xCB16,0xCBCA,0xCC7E,0xCD31,0xCDE2,0xCE93,0xCF43,0xCFF2,0xD0A0,0xD14D,0xD1FA,0xD2A5,0xD350,0xD3FA,0xD4A3,0xD54B,0xD5F2,0xD699,0xD73E,0xD7E3,0xD887,0xD92B,0xD9CE,0xDA6F,0xDB11,0xDBB1,0xDC51,0xDCF0,0xDD8F,0xDE2C,0xDEC9,0xDF66,0xE002,0xE09D,0xE138,0xE1D2,0xE26B,0xE304,0xE39C,0xE434,0xE4CB,0xE562,0xE5F8,0xE68D,0xE722,0xE7B7,0xE84B,0xE8DF,0xE972,0xEA04,0xEA97,0xEB29,0xEBBA,0xEC4B,0xECDC,0xED6C,0xEDFC,0xEE8B,0xEF1A,0xEFA9,0xF038,0xF0C6,0xF154,0xF1E1,0xF26F,0xF2FC,0xF388,0xF415,0xF4A1,0xF52D,0xF5B9,0xF645,0xF6D0,0xF75B,0xF7E6,0xF871,0xF8FC,0xF987,0xFA11,0xFA9B,0xFB26,0xFBB0,0xFC3A,0xFCC4,0xFD4E,0xFDD7,0xFE61,0xFEEB,0xFF75,0xFFFF]

If a matching array of the linearized values was needed, it would be

   [0x0000,0x0101,0x0202,0x0303,0x0404....

But such an array is not neded for most uses, as the index value of the PhaseOne TRC array directly relates to the linear value.

I.e. phaseOneTRC[0x80] is 0xAD64
and the linear value is 0x80 * 0x101.

Upvotes: 1

wisdom
wisdom

Reputation: 442

It turned out, it is all about having, loading and applying the proper ICC profile on the cv::Mat data. To do that one must use a color management engine along side OpenCV such as LittleCMS.

Upvotes: 0

Related Questions