Page 1 of 1

Image Resize is ignoring Gamma

Posted: 2018-10-01T23:53:06-07:00
by carl
I have a picture with an unusually low Gamma value that I am trying to resize. The command I am using:

convert /tmp/in.png -colorspace RGB -resize 160x160 -colorspace sRGB /tmp/out.png

Normally PNG files have a Gamma of about .45, but this image has a Gamma of 0.02. I tried to compensate for this by doing the RGB colorspace conversion and then convert back to sRGB before saving, but this does not work. I would upload the image itself, but there isn't a way to upload to this forum.

The correct output, due to the Gamma correction, should be much darker than the produced image.

Here is the output of identify:

Code: Select all

$ identify -verbose /tmp/in.png
Image: /tmp/in.png
  Format: PNG (Portable Network Graphics)
  Mime type: image/png
  Class: DirectClass
  Geometry: 561x265+0+0
  Units: Undefined
  Type: TrueColor
  Endianess: Undefined
  Colorspace: sRGB
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit
  Channel statistics:
    Pixels: 148665
    Red:
      min: 0 (0)
      max: 255 (1)
      mean: 163.948 (0.642932)
      standard deviation: 76.6095 (0.300429)
      kurtosis: -1.28908
      skewness: -0.410074
    Green:
      min: 4 (0.0156863)
      max: 255 (1)
      mean: 149.554 (0.586487)
      standard deviation: 78.1692 (0.306546)
      kurtosis: -1.43049
      skewness: -0.084559
    Blue:
      min: 0 (0)
      max: 255 (1)
      mean: 106.007 (0.415715)
      standard deviation: 95.4505 (0.374316)
      kurtosis: -1.59065
      skewness: 0.472043
  Image statistics:
    Overall:
      min: 0 (0)
      max: 255 (1)
      mean: 139.836 (0.548378)
      standard deviation: 83.8456 (0.328806)
      kurtosis: -1.32889
      skewness: -0.0904844
  Rendering intent: Perceptual
  Gamma: 0.02
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Background color: white
  Border color: srgb(223,223,223)
  Matte color: grey74
  Transparent color: black
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 561x265+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: Zip
  Orientation: Undefined
  Properties:
    date:create: 2018-10-01T23:48:21-07:00
    date:modify: 2018-10-01T23:48:21-07:00
    png:gAMA: gamma=0.02 (See Gamma, above)
    png:IHDR.bit-depth-orig: 8
    png:IHDR.bit_depth: 8
    png:IHDR.color-type-orig: 2
    png:IHDR.color_type: 2 (Truecolor)
    png:IHDR.interlace_method: 0 (Not interlaced)
    png:IHDR.width,height: 561, 265
    signature: 83f5acaa2aaaf00f14232885a0362090aada8358979382579ce27b7788b4a708
  Artifacts:
    filename: /tmp/in.png
    verbose: true
  Tainted: False
  Filesize: 315KB
  Number pixels: 149K
  Pixels per second: 14.87MB
  User time: 0.010u
  Elapsed time: 0:01.010
  Version: ImageMagick 6.8.9-9 Q16 x86_64 2018-07-10 http://www.imagemagick.org

Re: Image Resize is ignoring Gamma

Posted: 2018-10-02T03:27:13-07:00
by snibgo
You can put the file anywhere on the web, and paste a link here. Don't use an image-hosting site, because that may convert your image. We need to see the exact file you are using.

Resizing, like almost all operations, is independent of gamma. The same input pixel values will give the same output pixel values, whatever the gamma metadata setting. The gamma setting will be copied from input to output.

I'm not sure what you want to happen. Perhaps you want to adjust the gamma to 1.0 before the resize, then adjust it back to 0.02 afterwards:

Code: Select all

convert in.png -gamma 1.0 -resize 160x160 -gamma 0.02 out.png
This gives very small output values, so I suggest you use HDRI to avoid losing precision.

Re: Image Resize is ignoring Gamma

Posted: 2018-10-02T03:34:31-07:00
by carl
snibgo wrote: 2018-10-02T03:27:13-07:00 Resizing, like almost all operations, is independent of gamma. The same input pixel values will give the same output pixel values, whatever the gamma metadata setting. The gamma setting will be copied from input to output.

I'm not sure what you want to happen. Perhaps you want to adjust the gamma to 1.0 before the resize, then adjust it back to 0.02 afterwards:

Code: Select all

convert in.png -gamma 1.0 -resize 160x160 -gamma 0.02 out.png
This gives very small output values, so I suggest you use HDRI to avoid losing precision.
Isn't that the point of converting from sRGB, a gamma corrected space, to RGB, which is a linear colorspace? It seems like the conversion should applying the original Gamma in the conversion.

Re: Image Resize is ignoring Gamma

Posted: 2018-10-02T04:06:39-07:00
by snibgo
Conversion between sRGB and RGB is approximately a gamma conversion, but a bit more complicated.

sRGB doesn't have a gamma of 0.02. sRGB gamma is 1.0/2.2. So your input isn't sRGB. I think "-colorspace RGB" should fail, because IM should recognise that the input isn't sRGB or any other known colorspace. Instead, IM operates as though the image were sRGB, and converts it to linear RGB, but with a weird gamma. Then you resize, and convert back to sRGB, again with the weird gamma.

Can you post a link to the input, and explain the weird gamma? I repeat that I'm not sure what you want to happen.

Re: Image Resize is ignoring Gamma

Posted: 2018-10-02T22:37:35-07:00
by carl
snibgo wrote: 2018-10-02T04:06:39-07:00 Conversion between sRGB and RGB is approximately a gamma conversion, but a bit more complicated.

sRGB doesn't have a gamma of 0.02. sRGB gamma is 1.0/2.2. So your input isn't sRGB. I think "-colorspace RGB" should fail, because IM should recognise that the input isn't sRGB or any other known colorspace. Instead, IM operates as though the image were sRGB, and converts it to linear RGB, but with a weird gamma. Then you resize, and convert back to sRGB, again with the weird gamma.

Can you post a link to the input, and explain the weird gamma? I repeat that I'm not sure what you want to happen.
My image hosting will be kinda flaky, but here is what I have.

Here is the pic:
Image

If it looks like a dark picture of a Keurig machine, the Gamma value is being correctly interpreted. If it looks like a woman drinking a beer, it is broken. Try resizing the image without using any special flags.

I constructed it by combining two images together. The source images are here:

Image
Image

As for what should happen: The colorspace is intentionally ambiguous, as the PNG file is missing a cHRM chunk, which ImageMagick normally puts in. (the output is still wrong). While I agree the source image colorspace is not sRGB, that doesn't seem like a good reason to just ignore the Gamma altogether. What am I supposed to do here? Run identify on every image I ever plan on converting, find out if the Gamma is different than 1/2.2, and then pass that in as a flag to convert? It's unreasonable to ignore the gAMA chunk in the PNG in the conversion process.

Re: Image Resize is ignoring Gamma

Posted: 2018-10-03T05:40:55-07:00
by snibgo
That's a cute image. So there are two interleaved source images, at two different gammas. A viewer sees either the Keurig image correctly and the woman image as black, or the woman correctly and Keurig as white.

Adjacent pixels have no relationship to each other because they are from two different source images. So a "-resize" or any operation that interpolates between adjacent pixels will give a meaningless result. But "-scale 200%" works fine.
carl wrote:As for what should happen: The colorspace is intentionally ambiguous, ... While I agree the source image colorspace is not sRGB, that doesn't seem like a good reason to just ignore the Gamma altogether.
IM doesn't totally ignore the gamma, but passes it through to the output. IM doesn't use the gamma setting in resize or other operations. You still haven't said what you would like IM to do with the gamma setting during resize.
carl wrote:It's unreasonable to ignore the gAMA chunk in the PNG in the conversion process.
Okay, so what would be reasonable?

Personally, I'd like two new operations in IM:

1. Convert the image to linear. This would need to understand gamma and profiles, to know what TRC (Transfer Response Curve) to apply. For example, AdobeRGB needs a power curve but sRGB is more complex.

2. Undo the action of (1), converting the image back to where it was.

Sadly, I don't think these operations are feasible. Gimp tries to do this, with "Image | Precision | Linear light", but it seems to work accurately only for sRGB images.

Re: Image Resize is ignoring Gamma

Posted: 2018-10-03T20:07:28-07:00
by carl
snibgo wrote: 2018-10-03T05:40:55-07:00 That's a cute image. So there are two interleaved source images, at two different gammas. A viewer sees either the Keurig image correctly and the woman image as black, or the woman correctly and Keurig as white.

Adjacent pixels have no relationship to each other because they are from two different source images. So a "-resize" or any operation that interpolates between adjacent pixels will give a meaningless result. But "-scale 200%" works fine.
You are correct. The image itself is intended to exhibit the gamma differences. When a non compliant program resizes the image, it will misinterpret the gamma, treat the pixels as linear, and end up producing a thumbnail. In the example above, resizing the image should end up looking like the girl. There is an ImageMagick script to produce these, though I didn't use it here.

snibgo wrote: 2018-10-03T05:40:55-07:00 Personally, I'd like two new operations in IM:

1. Convert the image to linear. This would need to understand gamma and profiles, to know what TRC (Transfer Response Curve) to apply. For example, AdobeRGB needs a power curve but sRGB is more complex.

2. Undo the action of (1), converting the image back to where it was.
Yes, this is what I want. I was trying to express that this is what want when using a linear colorspace. In my program that generates these images. I apply the gamma transformation to get to a linear color space. To be honest, I don't even know how you could not use Gamma when doing the RGB colorspace conversion. For a low dynamic range image, the red conversion would be ((R/255))^(1/2.2)*255. By not applying the exponent, the conversion would be a no op. This is why I think it is a bug in ImageMagick; there is only one possible thing* to do in this colorspace conversion, and convert didn't do it.

* The RGB primaries, normally included in the cHRM chunk, may have resulted in some color reinterpretation, but the example file does not include this info.

The PNG spec says the (using your phrasing) TRC does not have the linear ramp near black, and the response curve is purely a power function. Hence it isn't really sRGB to begin with. Again, note that the sRGB chunk in the PNG spec does force proper sRGB handling, but this chunk is also missing from the example file.
snibgo wrote: 2018-10-03T05:40:55-07:00
Sadly, I don't think these operations are feasible. Gimp tries to do this, with "Image | Precision | Linear light", but it seems to work accurately only for sRGB images.
The conversion doesn't have to be perfect, just applying the gamma would be an improvement over existing behavior. I propose making the conversion from 32bit RGBA PNG pixel values to RGB use the gAMA and cHRM chunks to make a dummy color profile. If IM already has color profile support, this might be easy to do.

Re: Image Resize is ignoring Gamma

Posted: 2018-10-03T21:01:37-07:00
by snibgo
ImageMagick, like many image-processing programs, strives to be quick and accurate. It assumes users understand what they are asking for. Hence most operations perform simple arithmetic on the pixel data, without fussing about metadata. It resizes (and does other operations) in the current colorspace. But it lets you do more complex stuff, if you want.

We can save the gamma, change it to 1, resize, then change the gamma back afterwards:

Code: Select all

magick merged.png -set option:GAM %[gamma] -gamma 1 -resize 160x160 -gamma %[GAM] out.png
We often need to do multiple operations, more than a simple resize, and it's clearly more efficient to do the gamma conversions once at the start and once at the end, than wrapped around the individual operations.
carl wrote:In the example above, resizing the image should end up looking like the girl.
I don't see why. Most filters used by "-resize", and certainly the default filters, calculate each output pixel from more than one input pixel, as some type of interpolation between adjacent pixels. But when adjacent pixels come from two different sources, an interpolation is meaningless. And when the sources have massively different gammas, the interpolation is even more meaningless.
carl wrote:This is why I think it is a bug in ImageMagick; there is only one possible thing* to do in this colorspace conversion, and convert didn't do it.
Not a bug, but a design decision.
carl wrote:... just applying the gamma would be an improvement over existing behavior.
Okay, so include the gamma save-change-changeback I show above in your commands.

Re: Image Resize is ignoring Gamma

Posted: 2018-10-03T22:10:58-07:00
by carl
snibgo wrote: 2018-10-03T21:01:37-07:00 ImageMagick, like many image-processing programs, strives to be quick and accurate. It assumes users understand what they are asking for. Hence most operations perform simple arithmetic on the pixel data, without fussing about metadata. It resizes (and does other operations) in the current colorspace. But it lets you do more complex stuff, if you want.

We can save the gamma, change it to 1, resize, then change the gamma back afterwards:

Code: Select all

magick merged.png -set option:GAM %[gamma] -gamma 1 -resize 160x160 -gamma %[GAM] out.png
We often need to do multiple operations, more than a simple resize, and it's clearly more efficient to do the gamma conversions once at the start and once at the end, than wrapped around the individual operations.
First question: why is that not the default behavior? Wouldn't you agree it would be WAY better if the complexities of image processing were abstracted away by sane defaults, rather than assuming all users are experts? If you polled IM users, I think you would find that most of them think grey 128 is half as bright as grey 256. That's a reasonable arithmetic operation that a lot of people know and can reason about. The fact that it is not is surprising. Worse, unless you knew about this effect, your pictures would just look slightly lower in contrast, and you'd never really know why. The outputs would be subtly and irreversibly damaged.

Second question: How is this not identical in expected behavior to what I wrote in my first post? Setting colorspace RGB can be done once at the beginning, and is a linear colorspace implying a gamma of 1.0.
snibgo wrote: 2018-10-03T21:01:37-07:00
carl wrote:In the example above, resizing the image should end up looking like the girl.
I don't see why. Most filters used by "-resize", and certainly the default filters, calculate each output pixel from more than one input pixel, as some type of interpolation between adjacent pixels. But when adjacent pixels come from two different sources, an interpolation is meaningless. And when the sources have massively different gammas, the interpolation is even more meaningless.
Don't get wrapped up in that particular example. When I said "image should end up looking like the girl" I meant IM's behavior today. IM incorrectly resizing the image should result in the girl. For example, if IM was using Bilinear interpolation, it the pixels would be some arithmetic average. The darker pixels, averaged with the brighter pixels, end up looking like the original image. For example, consider the following 2x2 pixels:

Code: Select all

Girl:
    170
150 160

Code: Select all

Keurig:
240

The average brightness of the Girl is 160. When the images are combined:

Code: Select all

240 170
150 160
The average brightness is now 180. Let's imagine we are doing a resize where the the 2x2 pixel would resize down to 1x1. The final pixel should have a brightness of of 160 like before. Since the 240 pixel cannot be made darker (because the novelty of the picture would be lost), we can darken the surrounding pixels. The difference in average is 26.6 units, so we subtract that from the surrounding pixel values:

Code: Select all

240 143
123 134
Which brings the average back to 160. Resizing the image will result in a thumbnail that looks extremely similar to a thumbnail of the original.

snibgo wrote: 2018-10-03T21:01:37-07:00
carl wrote:This is why I think it is a bug in ImageMagick; there is only one possible thing* to do in this colorspace conversion, and convert didn't do it.
Not a bug, but a design decision.
If the flags to transform the colorspace do nothing, that's a bug.