Jump to content

Gamma Correction Bug


phippu
 Share

Recommended Posts

Hello!
 
I read a lot about the ImageSizer class from processwire, because I want to contribute to get better image resizing. Processwire (horst in special) has implemented a gamma correction before resizing images. Why this has to be done is explained here: http://www.4p8.com/eric.brasseur/gamma.html . I have this link also from a post from Horst. Now I stumbled upon a bug that causes to loose image information. 
 
This is the function I am talking about in ImageSizer.php

protected function gammaCorrection(&$image, $mode) {
if(-1 == $this->defaultGamma || !is_bool($mode)) return;
    if($mode) {
        // linearizes to 1.0
        if(imagegammacorrect($image, $this->defaultGamma, 1.0)) $this->gammaLinearized = true;
    } else {
        if(!isset($this->gammaLinearized) || !$this->gammaLinearized) return;
        // switch back to original Gamma
        if(imagegammacorrect($image, 1.0, $this->defaultGamma)) unset($this->gammaLinearized);
    }
}

 
This function uses the gd-lib function imagegammacorrect to set the gamma value to 1.0 before resizing and set it back after resizing. The imagegammacorrect function provides a datatype int, which has on my server the size of 8 bits, just enough to store a picture that also stores each pixel in 8 bit value.
What the imagegammacorrect function does: It exponentiates each pixel-value of the image with the gamma value entered (2.0 by default on pwire). Then it resizes the image. After that to set back the gamma it exponantiates with the inverse value that was before exponentiated. (1/2.0=0.5 with default value).
 
Because only integer (8bits) is provided the function is rounding the values and makes some error.
 
Here is my test picture (2400x2400 pixels)
 
I resized every image to 300x300 pixels. Here are the resized ones with different gamma values:

Gamma function omitted
testbild.300x0_gamma_-1.jpg

Gamma value 2.0 (standard)

testbild.300x0_gamma_2.0.jpg

Gamma value 3.0

testbild.300x0_gamma_3.0.jpg

Gamma value 4.0

testbild.300x0_gamma_4.0.jpg

 
Now I was curious if I could reconstruct the error in an other program. So I wrote a little script in Matlab and did the same. Heres the script:

% load image
[img,map,alpha] = imread('gamma_dalai_lama_gray.jpg');
%imshow(img, 'InitialMagnification', 100);

gamma = 2;
scale_factor = 300/2400;

figure(1);
imshow(img, 'InitialMagnification', 200);
figure(2);

tmp = double(img).^gamma;
img_gamma = uint8(tmp./((255^gamma)/255));

img_resized = imresize(img_gamma, 0.5);

tmp2 = double(img_resized).^(1/gamma);
img_gamma = uint8(tmp2./((255^(1/gamma))/255));

imshow(img_gamma, 'InitialMagnification', 400);

imwrite(img_gamma, 'testbild_300_gamma_2.0.jpg');

Here's the result pictures:

Gamma value 2.0 (with matlab)

testbild_matlab_300_gamma_2.0.jpg

Gamma value 3.0 (matlab)

testbild_matlab_300_gamma_3.0.jpg

Gamma value 4.0 (matlab)

testbild_matlab_300_gamma_4.0.jpg

Theoretical we would need more than 8bits per pixel to not loose any data. That would be for Gamma 4.0: (2^8)^4=32bits per pixel. Or for Gamma 2.0: (2^8)^2=16bits per pixel. I don't know how to solve this problem in php so I'm writing in here in the hope someone has a good solution or a hint what I'm doing wrong...

Processwire Version 2.5.3

PHP-Version is 5.6.0

If you need more informations let me know.

Edit: My integer size has not the size of 8bits that was 8bytes so 64bits... But as I confirmed with matlab script there is an 8bit cropping going on, maybe in the gd-lib?

Edit: I think I found out where this is caused. It's in the php sources (php-src/ext/gd/gd.c on line 3133). The cropping happens, because an integer is used instead of a double or float value (the dark pattern in my test image gets even darker with gamma correction). My suggestion is to take out the Gamma Correction and contribute code to GD-Lib to implement it there. With plain php we can't make it better for now.

Edited by phippu
  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...