That code is a lot more complicated than it needs to be. p is an unsigned
char*, so there's no point doing the &0xff (unsigned chars only range from
0-255), and if i is looping up to spec.nchannels, there's no reason to do the
mod. To have the same behavior, you could replace the entire scanline loop
with:
int n = std::min (3, spec.nchannels);
for ( int x = 0; x < spec.width; x++ )
{
float rgb[3] = { 0, 0, 0 };
for(int i=0; i<n; ++i) {
rgb[i] = pixels[x*spec.nchannels+i];
}
newQImage.setPixel( x, y, qRgb( rgb[0], rgb[1], rgb[2] ) );
}
That is still fairly inefficient -- I bet that there's a way to set an entire
scanline (or image) at once, without having to call setPixel separately for
every pixel, that's going to be very slow. Also, you are allocating 'pixels'
on every scanline, which will make quite a memory leak.
Now, back to the meat of your question. The way your code is structured,
you're reading the OpenEXR file (which is inherently floating point, either
full or half precision, with 1.0 meaning "white") and converting it into UINT8
(8 bit unsigned integer, 255 means white) in read_scanline, then copying those
values back to r, g, b, which are float -- copying without any rescaling -- and
passing those to qRgb.
So here's an important question: does qRgb expect those floating-point values
to be in the 0.0-1.0 range? Or 0.0-255.0? You're passing the latter right
now. I'll try to give a solution both ways.
And the idea is that you think the OpenEXR file is linear values, but that you
need the QImage to have sRGB values?
Also, since you seem to need floating point anyway, you should just keep it
float all along.
inline float linear_to_sRGB() (float x) {
if (x < 0.0f)
return 0.0f;
return (x <= 0.0031308f) ? (12.92f * x)
: (1.055f * std::pow (x, 1.f/2.4f) - 0.055f);
}
QImage newQImage( spec.width, spec.height, QImage::Format_RGB32 );
int size = spec.width*spec.nchannels;
std::vector<float> pixels (size); // note: will deallocate when it leaves
scope
int n = std::min (3, spec.nchannels);
for (int y = 0; y < spec.height; y++) {
in->read_scanline( y+spec.y, 0+spec.z, TypeDesc::FLOAT, &pixels[0] );
for ( int x = 0; x < spec.width; x++ ) {
float rgb[3] = { 0, 0, 0 };
for (int i=0; i<n; ++i) {
rgb[i] = linear_to_sRGB (pixels[x*spec.nchannels+i]);
// AND, if you think qRgb needs 0-255.0 values, rather than
0-1.0,
// then also do this:
// rgb[i] *= 255.0f;
}
newQImage.setPixel( x, y, qRgb( rgb[0], rgb[1], rgb[2] ) );
}
}
How does that look?
On Jul 14, 2011, at 7:05 AM, jeronimo wrote:
>
> Hi,
>
> I would like to read exr files with linear color space. For that I'm using
> OIIO but my viewer(Qt's QGraphicsView) shows the picture with sRGB color
> space.
> How should I read log or linear color space inputs? Should I use OpenColorIO
> for that task or develop an algorithm that converts from sRGB to
> linear(lookup table)? I've copied the piece of code that it's reading the
> file. Could you tell me if I'm reading correctly the files?
>
> QImage newQImage( spec.width, spec.height, QImage::Format_RGB32 );
> int size = spec.width*spec.nchannels;
> for (int y = 0; y < spec.height; y++) {
> unsigned char *pixels = new unsigned char[ size ];
> in->read_scanline( y+spec.y, 0+spec.z, TypeDesc::UINT8, pixels );
> for ( int x = 0; x < spec.width; x++ )
> {
> float r = 0;
> float g = 0;
> float b = 0;
>
> unsigned char *p = ( (unsigned char*) (pixels) );
> for(int i=0; i<spec.nchannels; ++i)
> {
> int mod = i%spec.nchannels;
> if(mod ==0)
> {
> r = ((*p) & 0xff);
> }
> else if(mod ==1)
> {
> g = ((*p) & 0xff);
> }
> else if(mod ==2)
> {
> b = ((*p) & 0xff);
> }
> p++;
> }
> newQImage.setPixel( x, y, qRgb( r, g, b ) );
> pixels = p;
> }
> }
>
> Thank you very much,
>
> Jero
>
> _______________________________________________
> Oiio-dev mailing list
> [email protected]
> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
--
Larry Gritz
[email protected]
_______________________________________________
Oiio-dev mailing list
[email protected]
http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org