High-quality reduction of HDR images to 24-bit color
High-quality reduction of HDR images to 24-bit color
I have an HDR image (in EXR format) that I'd like to convert to an 8-bit/channel PNG with as little loss of apparent quality as possible. Most notably, I want to do this with an E-dither to avoid posterization artifacts. (Clamping channels to the [0, 1] range is a given.)
How would I do this in IM? If you do convert in.exr -depth 24 out.png then the colors are simply truncated (i.e. lower bits dropped), so you get posterization. Adding -dither to that does nothing.
(By the way, I'm using this as a test image. It's an extremely subtle vertical gradient.)
I also tried -posterize 256, which seemed like it might do what I want. However, if you examine the resulting image, you see that adjacent pixels have fairly large differences between them; e.g. (127,127,127) and (134,134,134) might be horizontal neighbors. Meaning that the reduction is not optimal.
Is there perhaps a different approach to this that I've missed?
How would I do this in IM? If you do convert in.exr -depth 24 out.png then the colors are simply truncated (i.e. lower bits dropped), so you get posterization. Adding -dither to that does nothing.
(By the way, I'm using this as a test image. It's an extremely subtle vertical gradient.)
I also tried -posterize 256, which seemed like it might do what I want. However, if you examine the resulting image, you see that adjacent pixels have fairly large differences between them; e.g. (127,127,127) and (134,134,134) might be horizontal neighbors. Meaning that the reduction is not optimal.
Is there perhaps a different approach to this that I've missed?
Re: High-quality reduction of HDR images to 24-bit color
When you built ImageMagick did you add --enable-hdri to your configure script? That may help otherwise HDRI support if new to ImageMagick and we are looking for advice on tweaking existing algorithms or developing new algorithms to better support the HDRI community.
Re: High-quality reduction of HDR images to 24-bit color
Ah yes, I should have noted:
FWIW, the most intuitive approach would be something like convert in.exr -depth 24 -dither out.png, where the -depth operator can make use of dithering in the general case of downsampling.
Is there a more roundabout way to get this effect with things as they are, or would new code really be needed?
This is a custom build I'm using, from the SVN source.Version: ImageMagick 6.3.5 07/09/07 Q32 HDRI http://www.imagemagick.org
Copyright: Copyright (C) 1999-2007 ImageMagick Studio LLC
FWIW, the most intuitive approach would be something like convert in.exr -depth 24 -dither out.png, where the -depth operator can make use of dithering in the general case of downsampling.
Is there a more roundabout way to get this effect with things as they are, or would new code really be needed?
Re: High-quality reduction of HDR images to 24-bit color
Does this command not give you the expected results:
- convert grey-gradient.exr.bin +matte -depth 8 image.png
Re: High-quality reduction of HDR images to 24-bit color
Afraid not. That truncates the colors.
Here is the image converted with +matte: grey-gradient-matte.png
And here is the image, dithered with a custom-written Floyd-Steinberg filter: grey-gradient-fsdither.png
If you load them both into an image editor, and expand the color range with the Levels tool, you'll see clear banding in the first, and a gradual dither in the second. Horizontally adjacent pixels in the second image differ in intensity by 1/255 at most, so the dither is as good as it can get. That's what I'm after.
Here is the image converted with +matte: grey-gradient-matte.png
And here is the image, dithered with a custom-written Floyd-Steinberg filter: grey-gradient-fsdither.png
If you load them both into an image editor, and expand the color range with the Levels tool, you'll see clear banding in the first, and a gradual dither in the second. Horizontally adjacent pixels in the second image differ in intensity by 1/255 at most, so the dither is as good as it can get. That's what I'm after.
Re: High-quality reduction of HDR images to 24-bit color
With a patch to ImageMagick 6.3.5-1 Beta we get reasonable results with this command:
- convert grey-gradient.exr.bin -treedepth 8 -colors 256 -depth 8 grey-gradient-hilbertdither.png
Re: High-quality reduction of HDR images to 24-bit color
The SVN build is currently broken, so I can't try that out.
As I understand, however, -colors 256 means that the output image will use no more (and possibly less) than 256 unique colors. Which works for the gradient test image, but the goal is to reduce arbitrary HDR images to 24-bit PNG files, not 8-bit paletted GIFs. Essentially, it would be like -colors 16777216---except that you wouldn't want to waste time building up an optimal color set of that size.
The error distribution isn't an issue, as long as it's not patterned. The whole trick is in treating the 24-bit color space as the "palette," and dithering accordingly. You're not so much reducing the number of colors in the image, as much as rounding each floating-point channel to the nearest 1/255 step and distributing the errors of that.
As I understand, however, -colors 256 means that the output image will use no more (and possibly less) than 256 unique colors. Which works for the gradient test image, but the goal is to reduce arbitrary HDR images to 24-bit PNG files, not 8-bit paletted GIFs. Essentially, it would be like -colors 16777216---except that you wouldn't want to waste time building up an optimal color set of that size.
The error distribution isn't an issue, as long as it's not patterned. The whole trick is in treating the 24-bit color space as the "palette," and dithering accordingly. You're not so much reducing the number of colors in the image, as much as rounding each floating-point channel to the nearest 1/255 step and distributing the errors of that.
Re: High-quality reduction of HDR images to 24-bit color
We understand how FS-dithering works and it probably does a good job distributing error, however, it seems that the proper way to convert HDR images to 8 or 16-bits per channel is with tonal mapping. If you have an algorithm available for proper tonal mapping, post it here. Otherwise we will need to research this topic a bit more and come up with a good tonal map to solve this problem.
Re: High-quality reduction of HDR images to 24-bit color
I think I probably goofed in using the term "HDR" here. I'm working with floating-point images that have already been clamped to [0, 1], so tonal mapping isn't an issue. (Or, to be more precise, my scenario comes after the mapping has been applied.) It's just a straightforward matter of quantization.
As far as code goes, this is as much magic as should be needed:
where N_LEVELS is either 255.0 or 65535.0.
(I agree on the need for tonal mapping in converting arbitrary HDR images to 8- or 16-bit format, but that would be done in a preceding stage of a convert(1) pipeline. That is to say, it's an orthogonal problem.)
As far as code goes, this is as much magic as should be needed:
Code: Select all
px_quant.r = floorf(N_LEVELS * px->r + 0.5) / N_LEVELS;
px_quant.g = floorf(N_LEVELS * px->g + 0.5) / N_LEVELS;
px_quant.b = floorf(N_LEVELS * px->b + 0.5) / N_LEVELS;
px_quant.a = floorf(N_LEVELS * px->a + 0.5) / N_LEVELS;
(I agree on the need for tonal mapping in converting arbitrary HDR images to 8- or 16-bit format, but that would be done in a preceding stage of a convert(1) pipeline. That is to say, it's an orthogonal problem.)
Re: High-quality reduction of HDR images to 24-bit color
ImageMagick 6.3.5-1 return results with a slightly different formulation with this command (see SetImageDepth()):
- convert grey-gradient.exr.bin -depth 8 +matte grey-gradient
Re: High-quality reduction of HDR images to 24-bit color
Huh, so -depth is basically handled by SetImageChannelDepth(), I see. The RoundToQuantum() lines look familiar.
Would it be feasible to enable -dither to work in conjunction with -depth? What I'm after basically boils down to that, and the color-reducing behavior of -depth (when given an appropriate argument) presents a general situation where you may want to resort to dithering. It's applicable outside of HDR images, and even outside of floating-point images: consider the case of reducing 16 bits/channel images to 8.
Would it be feasible to enable -dither to work in conjunction with -depth? What I'm after basically boils down to that, and the color-reducing behavior of -depth (when given an appropriate argument) presents a general situation where you may want to resort to dithering. It's applicable outside of HDR images, and even outside of floating-point images: consider the case of reducing 16 bits/channel images to 8.
Re: High-quality reduction of HDR images to 24-bit color
We have already considered dithering the error in SetImageDepth(). However, SetImageDepth() is a core method and any change could affect a large number of existing workflows. A proper solution will require deep-thought and extensive testing before we could release it.
Re: High-quality reduction of HDR images to 24-bit color
Well, the dithering would occur only if explicitly requested via -dither, wouldn't it? Otherwise, the behavior would remain as now, banding and all. I don't see that there's a need to have -depth dither by default when converting downward, unless the goal is to actually change the default, to make banding a less common result.
Re: High-quality reduction of HDR images to 24-bit color
Dithering is enabled by default. It still would require a bit of work to determine if the dither option was explicitly set as well as enabling the dithering option when setting the image depth. We'll add it to our list of things to do.
Re: High-quality reduction of HDR images to 24-bit color
I understand the difficulty now.
Kind thanks for your patience in this thread, and for taking an interest in the problem. I look forward to making good use of error-diffused depth reduction once it becomes available in IM, and hope others will find it beneficial as well.
Kind thanks for your patience in this thread, and for taking an interest in the problem. I look forward to making good use of error-diffused depth reduction once it becomes available in IM, and hope others will find it beneficial as well.