Sometimes you need to clip. For example when using a Hald CLUT.
@Elle, well, I was just thinking about the raw data pipeline: applying black and white point, CA, impulse noise and other corrections, white balancing, demosaicing, noise reduction, luminance recovery, etcetera. After converting the raw data to a color space, Iâm not sure if itâs feasible at all.
We should totally use that from now on.
I would like to add the word âscoochâ to the technical lexicon. With respect to curve control points, it refers to their slight movement to achieve a particular image transform. For each scooch, Iâm sure thereâs a polynomial somewhereâŚ
Negative (more generally, out-of-gamut) values confuse the heck out of me, but they are a sad fact of life.
They can arise even when in monochrome, even when not messing with profiles. For example: suppose an image has only three pixels. They are black, white and 25% gray. We resize the image to be twice as large, six pixels. What gray levels are they?
It depends on the resizing method we use. The default ImageMagick HDRI (floating-point) resizing gives:
convert xc:black xc:white xc:gray(25%) +append -resize â6x1^!â txt:
0,0: srgb(-3.08924%,-3.08924%,-3.08924%)
1,0: srgb(24.6607%,24.6607%,24.6607%)
2,0: srgb(76.497%,76.497%,76.497%)
3,0: srgb(83.3832%,83.3832%,83.3832%)
4,0: srgb(44.1264%,44.1264%,44.1264%)
5,0: srgb(22.6831%,22.6831%,22.6831%)
Thatâs squirrelly.
What has happened? Think of a graph that passes through 3 points: 0, 1 and 0.25. Resizing will re-sample the graph. The algorithm used by IM assumes the graph is a curve, rather than a pair of straight lines. So the resampled points can be outside the values bounded by the inputs.
Another example: unsharp masking can push values out of gamut. This is obvious if you think about what USM does, but hereâs an example. Make an image that is black and white only, 3x3 white pixels surrounded by a black border 3 pixels thick:
convert -size 3x3 xc:white -bordercolor Black -border 3 -format âMIN=[fx:minima]\nMAX=[fx:maxima]â info:
MIN=0
MAX=1
Unsharp-mask it:
convert -size 3x3 xc:white -bordercolor Black -border 3 -unsharp 0x2 -format âMIN=[fx:minima]\nMAX=[fx:maxima]â info:
MIN=-0.197727
MAX=1.75652
Eek! Values now range from -19.7% to +176%.
Yes, OOG values (especially the negative ones) will cause some algorithms to fail, eg:
f:\web\im>%IMDEV%convert xc:gray(-10%) -evaluate Pow 2.2 txt:
0,0: gray(-nan%)
Double-eek! The pixel is not-a-number!
Software routinely avoids the problem by clipping, but this is a sledgehammer technique that destroys data. We can do better, I hope.
@snibgo This becomes increasingly apparent as I use GâMIC and IM more regularly. It confuses the heck out of me as well. I suppose it is a case by case but how have you tackled the problem besides clipping? No one seems to be ready to discuss this in practical terms whenever I bring this up but we have to start somewhere.
I think itâs just the inevitable consequence of manipulation. Almost every operation inflicted upon digital data requires an implicit decision to âbucketâ the result into an adjacent discrete value, losing accuracy. This starts with the sensor ADC.
The effects described in earlier posts are new and interesting to me, compelling me to reconsider some indiscriminate image manipulation. Well, maybe not, the resulting images appealed to me, and the loss of data didnât take anything from that. Might be a different story if a museum came to me with a proposal for a showing, all images in 6â x 8â (thatâs feet) size. Fat chance of thatâŚ
What I decided when I took on a floating point internal format for rawproc was to let the over/underruns accumulate, and clip for output. This intuitively seems prudent, as itâs the data Iâll see that matters to me. Indeed, Iâve had some images where Iâve had to lose some clarity in light sources in order to properly develop the rest of the scene, pushing the light off the visible range. Canât afford a D850, for the dynamic range.
Passing unbounded image data to, say, GIMP opens the opportunity to recover some of the spill with tools Iâll never be able to implement. Thatâs what I proposeâŚ
My current strategy, if you can call it that, is to favor manipulations that donât deviate from the bounds as much. For me, +ve values are scoochable but the -ve OOG ones are squirrel-aggressive.
We need to write a paperâŚ
maybe (in fact, likelyâŚ) Iâm being naive, but if you donât know how to handle out of range values, why donât you just leave them untouched? i.e.:
-
apply transformations that are identity for values out of the [0,1] interval, and
-
clip upon reading the pixels instead of when writing (i.e. if you are combining the pixel with its neighbour, just pretend that it is in range)
why wouldnât this work (besides introducing overhead if you read more than you write â which is likely the case)? experts please enlighten me
Thanks for you input. Compared to my level, you are all experts .
Software could give users a choice about out of gamut (OOG) values, such as:
-
Never clip or tame OOG values.
-
Always clip after every operation.
-
Always clip before every operation that OOG would cause to fail.
-
As (1) but apply a non-destructive process to put OOG inside the box.
-
As (2) but apply a non-destructive process to put OOG inside the box.
Non-destructive processes (âscoochingâ?) include applying a gain and bias (eg ImageMagickâs â-autolevelâ), and methods I show in Putting OOG back in the box. Other methods are possible, eg the four ICC profile intents (only two of which have a precise definition).
This choice could be a generic user-preference, and/or selected for individual operations.
I have limited time to give to this at the moment, but some thoughtsâŚ
-
@snibgo, in your 3 pixel example I can see I think why applying some maths in the upscaling would lead to negatives, but it makes no physical sense if weâre talking black and white and colour spaces are not involved. Of course with lots of these operations, the boundary conditions have to be dealt with, and with only 3 pixels in a line (if I understand correctly) thatâs much more boundary than interior!
-
Iâve not seen anyone address the point I made recently in the other thread where values are multiplied by 2 and then clipped; as opposed to just multiplying by the max suitable value and not needing to clip.
-
Elleâs site has warnings about unbounded operations ( Limitations of unbounded sRGB as a universal editing space ) but on a quick read these problems perhaps go away as long as the working space is big like prophoto (and better still if linear gamma also used). Though I have yet to try linear g. properly.
-
Re. further discussion of this and âwhite paperâ, maybe an approach is to limit it initially to photos intended to be realistic / natural-looking, thus perhaps simplifying the issue by not considering some of the more complicated operations, e.g. ? blend modes that are rarely needed? (though I donât know what most of them do in any case!). Consider the complication raised where two negative values are multiplied hence a plus. I can understand multiplying an image by say 1.6 to increase contrast, sort of, but 2 negatives, i.e. multiplying one OOG colour by another OOG, what does that mean in reality?!
sounds good, does this mean it scales all the time (in fl.point) to keep everything in gamut? (havenât tried IM)
- Say youâre editing / RT-ing in prophoto and want to see how itâs going re. gamut. How about a nice new OOG tool where you say what space youâre thinking of converting to, and it highlights the OOG parts, but in addition you have a slider, which at one end says âshow everything thatâs OOGâ and at the other âJust show the most OOG partâ. Like soft-proofing but more generalised. It shows where the problems are then itâs up to you what you want to do about it.
My 3-pixel example was chosen for simplicity. The same problem can occur with mega-pixel images: if it has an area of high contrast, a USM can increase contrast to push values OOG.
Yes, operations can be designed to never generate OOG values. This would mean an unsharp mask would be adaptive, with varying effect depending on how much it would push values OOG. Thatâs not a trivial problem.
Sadly, no. The issues I show apply to any bounded working space. No matter how large it is, there will always be operations that can push pixels OOG.
Of course, for many purposes we just donât care. If we just want a pretty picture and a handful of pixels out of a few million get clipped, so what? But how about 1%? Or 10%? Or what if we are preparing images for use in a larger project, where damage by clipping might be magnified?
The ImageMagick â-auto-levelâ operation is called only when the user asks for it. So I can call it after the USM, eg:
convert -size 3x3 xc:white -bordercolor Black -border 3 -unsharp 0x2 -auto-level -format âMIN=[fx:minima]\nMAX=[fx:maxima]â info:
MIN=0
MAX=1
In this case, â-auto-levelâ pushes all values inwards, so they span just 0.0 to 1.0. Aesthetically, this is often a bad idea. Imagine a photo with all pixels in gamut except for one pixel that is at 200%. â-auto-levelâ will halve the brightness of all pixels.
Yes, I think we need better OOG tools. And my point in these posts is to highlight that OOG occurs frequently, but we just donât notice because software silently clips the issue away.
rawproc might be the basis for a case study in what tools do. Without considering the things weâve discussed here, I simply let all my tools work the data, and what will be, will be. Clipping doesnât occur except for 1) display, and 2) output to one of the image formats, currently JPEG and integer TIFF, soon to add PNG and unbounded floating point TIFF.
I have a reference image I use for testing, slightly underexposed (in both ETTR and JPEG terms) except for a glaring locomotive headlight, which clips even in the original linear capture. I have a image stats dialog box which I can call for any tool in the chain, reports among other things min/max RGB values. i was somewhat surprised to see maxes around 2.0 in some channels on this image after applying a series of tools, but it then occurred to me I was just pushing more of the headlight into oblivion.
Currently, all looks well in display because the image pulled for display is clipped to the display range, but Iâm considering a selectable âblinkiesâ mode (donât worry, I in no way am going to make pixels blink, probably some cyan/magenta coloration) to show out-of-bounds regions of pixels.
Even then, Iâll not consider automatically clipping or recovering OOB values in the tools, save maybe to implement a separate ârecoverâ tool. Iâm probably not smart enough to do that, however, so I look forward to the opportunity to save to unbounded floating point TIFF, then open that image intact in GIMP to do recovery magicâŚ
The white paper this thread reminds me of the most is on audio technology, the dbx type IV a/d conversion system where input is limited logarithmically after a linear segment in order to extend headroom before reaching logical clipping. It is a form of dynamic range compression, and introduces aurally pleasing artifacts (third harmonic distortion) instead of a hard clip.
I like this because you can see very clearly something is happening and deal with it. Suppose the tools in RT or Gimp had an option to do the operation either with clipping or auto-level, and you could flick between them and see the difference. Or at least have the ability to do the operation with auto-level for some tools. If you were increasing contrast, I suppose it would work as expected until pixels hit the limit, then the image would mostly go darker and less contrasty the more you increased the slider. This would indicate an OOG or highlights issue and then depending on its importance in the photo, you could decide to do the contrast adjustment with clipping, or e.g. do a local edit and reduce the saturation of the offending parts (or the whole image), etc.
@RawConvert Unsure whether it is wise to expose an auto-level v clip option, etc., to user-facing tools. That would over-complicate and clutter the GUI. I would rather have the devs make most of those decisions for us. Also, certain things only work as intended with clipping, as least visually. If you are interested in that stuff, I suggest you try using GâMIC and / or IM, if you arenât already doing so.
@RawConvert is right to note that when starting from a raw file, converting the interpolated image to a smaller color space such as sRGB, using an unbounded ICC profile conversion at floating point precision, is much more likely to produce RGB values with channel values less than 0.0 and/or greater than 1.0 (âout of display rangeâ, letâs say âoodrâ for short), compared to converting to converting to a larger color space such as Rec.2020.
As @snigbo notes, some operations can cause âoodrâ channel values even when thatâs not the intention and regardless of how large the RGB color space might be, such as resizing and sharpening. For unsharp mask, personally I use a layer mask to mask out highlight and shadow areas. For resizing, maybe Normalize? followed by Curves to restore the shadow/highlight tonality? Or as this only affects brightest/darkest portions of an image, I suppose one could decrease the dynamic range, resize, and then restore the dynamic range, either way might work.
In terms of âwhat operations cause completely squirrelly colors with âoodrâ channel valuesâ, thatâs easy enough to answer:
-
Any operation that involves multiply or divide, except when at least one of the colors is gray, white, or black (thereâs an exception, thatâs too complicated to explain here, but see Section D of this article, in which âmultiplyâ essentially acts like addition: Combining painting and photography
-
Many blend modes such as Soft Light, Hard Light, etc that use a midpoint to determine whether a color gets darker or lighter - multiply/divide are used here.
-
âgammaâ operations, which also ultimately involves multiply/divide
-
And etc.
Operations that donât produce squirrelly colors include:
-
operations that are elaborations on addition/subtract: gaussian blur, most or all Transform operations such as rotate, scale, etc
-
operations that convert from RGB to XYZ (and maybe then to other color spaces such as LAB/LCH/xyY), such as Luminance conversions to black and white, the various LAB/LCH operations.
-
Levels, Curves, Brightness, Exposure, etc, when all three RGB channels are changed by the same amount. On the other hand, changing channels individually is like multiplying/dividing by a color, so if the operation causes colors to go âoodrâ, squirrelly colors can result.
GEGL and GIMP code has already made a lot of progress dealing with âwhen is it better to clipâ and âwhen should the operations be kept unclippedâ, as searching through open and closed bug reports will show. Plus there is a âclipâ operation the user can invoke, that allows to set shadow and highlight clipping separately.
There is no âone size fits allâ solution. It depends on where the values came from, whether the user made such values deliberately and plans subsequent edits to deal with them, and what the ultimate editing goals are. For example, Normalize (Auto-stretch contrast in GIMP) is often a good step when the goal is to bring all colors to within display range. But a sprinkling of really really âoodrâ values can completely defeat getting good results out of this operation, as I found when I filed a bug report about a layer mask turning to solid gray: Bug 777836 â auto stretch-contrast sometimes produces unexpected and unuseable results
Before even beginning to talk about these issues, itâs important to understand the difference between âoodrâ channel values, which involves any channel value thatâs greater than 1.0 or less than 0.0, and channel values that are only greater than 1.0, which of course are required for HDR images (my âModels for image editing: Display-referred and scene-referredâ referenced above goes through the difference).
I wrote a GIMP tutorial that works through the process of generating and dealing with âoodrâ channel values while editing separately for tonality and color (which for some people is a sort of âholy grailâ of editing). As with most of my articles about GIMP, the tutorial is somewhat out of date. But the tutorial - which includes a file to download and process, to follow along the steps - does go through some issues with, and benefits of, keeping âoodrâ channel values even when the ultimate goal is to output a display-range image:
Autumn colors: An Introduction to High Bit Depth GIMPâs New Editing Capabilities
https://ninedegreesbelow.com/photography/high-bit-depth-gimp-tutorial-edit-tonality-color-separately.html