Hi Jerome,

The problem you're encountering is that your .CR2 file is in a different
color space (AdobeRGB) from your display device (sRGB). In order to
properly view it, you will need to transform each pixel from AdobeRGB to
sRGB (which is exactly what the Windows viewer is doing). This is a linear
transformation, so can be represented by a multiply by a 3x3 matrix. Colour
transforms are usually represented in terms of matrices that go to and from
the CIE XYZ colour space, so you'll need two matrices:

pixel_in_XYZ = [AdobeRGB to CIE XYZ] x pixel_in_adobeRGB
pixel_in_sRGB = [CIE XYZ to sRGB] x pixel_in_XYZ

Matrix multiplication is associative, so you can simplify that to

pixel_in_sRGB = [CIE XYZ to sRGB] x [AdobeRGB to CIE XYZ] x
pixel_in_adobeRGB

*(pixels are assumed to be column vectors in RGB order)*

You can find the matrices you need on the wikipedia pages for AdobeRGB and
sRGB. Note that sRGB uses the same gamut as Rec.709 (also known as Bt.709).

*But wait, there's more:*

Before you transform your pixels from AdobeRGB to sRGB, you'll need to
linearize them. Adobe RGB uses a simple gamma of 2.19921875, so:

linear_pixel_in_adobeRGB = pixel_in_adobeRGB ^ 2.19921875

*(perform this computation on each channel independently)*

Putting this together, we've now got:

linear_pixel_in_adobeRGB = pixel_in_adobeRGB ^ 2.19921875
linear_pixel_in_sRGB = [CIE XYZ to sRGB] x [AdobeRGB to CIE XYZ] x
linear_pixel_in_adobeRGB

The final step is to convert this linearized sRGB pixel to a gamma-correct
sRGB pixel. sRGB has a wacky gamma curve that has a linear segment close to
zero. I'm just going to copy and paste from the wikipedia page (
en.wikipedia.org/wiki/SRGB):

[image: C_\mathrm{srgb}=\begin{cases} 12.92C_\mathrm{linear}, &
C_\mathrm{linear} \le 0.0031308\\ (1+a)C_\mathrm{linear}^{1/2.4}-a, &
C_\mathrm{linear} > 0.0031308 \end{cases}]

   - where [image: a = 0.055]


*(again, apply the computation to each channel independently)*

So your final equation to go from AdobeRGB to sRGB is:

linear_pixel_in_adobeRGB = pixel_in_adobeRGB ^ 2.19921875
linear_pixel_in_sRGB = [CIE XYZ to sRGB] x [AdobeRGB to CIE XYZ] x
linear_pixel_in_adobeRGB
pixel_in_sRGB = C_srgb( linear_pixel_in_sRGB)

You can simply this further by pre-computing the matrix-matrix
multiplication.

If you don't really care about accuracy, you can also replace C_srgb() with
a simple gamma of 2.2:

pixel_in_sRGB = linear_pixel_in_sRGB ^ (1/2.2)

*(More details about this on the wikipedia page, but basically C_srgb
approximates a gamma of 2.2, but has a linear portion near zero to avoid
numerical problems.)*

All of these computations assume your pixels are floating-point in the
range [0.0, 1.0]. Also, note that the AdobeRGB gamut is wider ("has more
colours") than that of sRGB, so you will need to clamp values to [0.0, 1.0]
after the matrix multiply.

You can also do all of this with OpenColorIO, but you'll need to create
spimtx files to go to/from AdobeRGB and add a color space definition. The
steps are essentially the same as above, but a somewhat higher level of
abstraction.

Hope that helps!

cheers,
-Mark





On Sat, Apr 18, 2015 at 2:18 PM, Jerome Esnault <[email protected]>
wrote:

> Hello,
>
> First of all, thanks for this great project :)
>
> I'm trying to read and visualize a .cr2 image into my Qt application with
> OIIO.
> I implemented a QImage converter which work fine for jpg and png formats.
>
> But when I open my cr2 picture, it seems the image have a predominance of
> blue channel pixels...
> If I open it with "standard" windows image viewer, it seems to be good
> looking.
> By opening it with another "free trial" image visualization software on
> windows, I could saw 2 versions of this picture:
>  * the first one is the same strange blue image (marked as sRGB colorspace)
>  * the second one seems to be the right one I would excpected (more like
> the jpg or png ones) which is marked as AdobeRGB colorspace
>
> As I store an ImageBuf* of this picture, I tried to switch ColorSpace
> sequentially (by pressing key c) with this snippet :
>
> std::shared_ptr<ImageBuf> ccSrc (d->mImgBuf); // color-corrected buffer
> ccSrc->read(0,0,true,TypeDesc::FLOAT);
> ImageBufAlgo::colorconvert(*ccSrc, *d->mImgBuf, "current",
> mColorSpace.toStdString() ); // whch could be Linear, sRGB or any available
> OCIO ones like AdobeRGB
> std::swap(d->mImgBuf, ccSrc);
>
> But this have not effect anymore...
> Same result if I try to use oiiotool :  oiiotool <picture.cr2>
> --tocolorspace Linear -o picture.png
> (Note that the -o picture.CR2 doesn't work as OIIO couldn't find any
> corresponding raw format to write it. Is that mean libRaw can read but not
> write CR2 formats?)
>
> This troubles is maybe due to the fact that any other ColorSpace I want to
> use are not possible. The oiio error message is : Could not find ColorSapce
> <anyOtherColorSapceThanLinear>...
>
> I built OIIO with OCIO and set environement variable OCIO to
> imageworks-OpenColorIO-Configs\aces_0.1.1\config.ocio.
> I there anything else I should do to use ColorSapces into OIIO ?
>
> My main question is :
> Is there any way to get an ImageBuf with another corrected pixels color ?
>
> As I'm definitilvely not an expert on the complexity of the formats/colors
> format, what's happening here?
>
> Many thanks,
>
> Jerome
>
> _______________________________________________
> Oiio-dev mailing list
> [email protected]
> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>
>
_______________________________________________
Oiio-dev mailing list
[email protected]
http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org

Reply via email to