Generalized Hyperbolic Stretch

Introduction
The Generalized Hyperbolic Stretch (GHS) process allows you to transform the values of pixels in your image to improve the representation of the underlying data for human visualisation.
The generalised hyperbolic equations used in the GHS process have five defining parameters. This allows significant flexibility in designing the “shape” of the transformation.
Typical uses of pixel intensity transformations include:

  • Initial stretch of pixel data from linear state.
  • Addition of contrast to key areas of the image.
  • Overall brightening or darkening of the image.
  • Adjustment of the dynamic range of the image.
  • Adjustment of pixel data in one colour channel to balance better with other channels.

The control provided by the GHS process is designed to perform well in all these situations.

Origin
I believe that the origin of this algorithm, initially dedicated to astrophotography, is to be attributed to PixlnSight ©, the 2 authors are David Payne in 2021 and Mike Cranfield.
A description of the process and possible settings :

This algorithm is found in Siril © Copyright (C) 2005-2011 Francois Meyer (dulle at free.fr)
Copyright (C) 2012-2023 team free-astro (see more in AUTHORS file)
Reference site is Siril - FreeAstro

You will also find this algorithm adapted to CTL by Alberto in ART @agriggio - thanks to him

In Rawtherapee
I ported this algorithm to Selective Edition (SE) in C++. The choice of SE is important, as it makes it easy to open several RT-spots (not compulsory, of course) and thus to process difficult images of all kinds (landscape, flowers, astro, etc.).
For a better treatment, you can proceed in several steps, creating 2 or more RT-spots each superimposed with the GHS tool. For each of the RT-Spots, the Symmetry point (SP) base value will be different (and of course other settings). Use the peak marker on the histogram to estimate the position of the SP value. For example, you can start the system in RGB mode (1st Spot), then the 2nd Spot in RGB mode with a different SP, and the 3rd in Saturation or Hue mode.
Full Image allows you to differentiate the action according to the color based on the deltaE.

But of course in the majority of cases only one RT-spot is needed.

A general tooltip is always enabled. If you want (or not) to have help associated with each slider you can enable or disable tooltips in Preferences.

You will find this algo in: Shadows/Highlights & Equalizer & GHS

Six settings are available :

  • Stretch factor (D)
    This parameter controls the amount of stretch. If the Stretch factor is set to zero there is no stretch, ie the transformation is the identity transformation.

  • Local intensity (b)
    This parameter controls how tightly focused the stretch is around the Symmetry point (SP) by changing the form of the transform itself. For concentrated stretches (such as initial stretches on linear images) a large ‘b’ factor should be employed to focus a stretch within a histogram peak while de-focusing the stretch away from the histogram peak (such as bright stars). For adjustment of non-linear images, lower ‘b’ parameters should be employed to distribute contrast and brightness more evenly. Large positive values of ‘b’ can be thought of as a histogram widener, ie spreading the histogram wider about the focus point, SP. By contrast, lower values of ‘b’ tend to shift the histogram to a brighter (or dimmer) position without affecting its width too greatly. As a general rule, the level of ‘b’ employed will decrease as a stretch sequence nears completion, although larger ‘b’ values can still be employed for precise placement of additional contrast.

  • Symmetry point (SP)
    Sets the focus point around which the stretch is applied - contrast will be distributed symmetrically about SP. While ‘b’ provides the degree of focus of the stretch, SP determines where that focus is applied. SP should generally be placed within a histogram peak so that the stretch will widen and lower the peak by adding the most contrast in the stretch at that point. Pixel values will move away from the SP location

  • Protect shadows (LP)
    Sets a value below which the stretch is modified to preserve contrast in the shadows/lowlights. This is done by performing a linear stretch of the data below the ‘LP’ level by reserving contrast from the rest of the image. Moving the LP level towards the current setting of SP changes both the scope (range) and the amount of this contrast reservation, the net effect is to push the overal stretch to higher brightness levels while keeping the contrast and definition in the background. The amount of contrast reserved for the lowlights is such that the continuity of the stretch is preserved. This parameter must be greater than or equal to 0 and not greater than the Symmetry point

  • Protect highlights (HP)
    Sets a value above which the stretch is modified to preserve contrast in the highlights/stars. This is done by performing a linear stretch of the data above the ‘HP’ level by reserving contrast from the rest of the image. Moving the HP level towards the current setting of SP increases both the scope (range) and the amount of this contrast reservation, the net effect is to push the overal stretch to lower brightness levels while keeping the contrast and definition in the highlights. The amount of contrast reserved for the highlights is such that the continuity of the stretch is preserved. This parameter must be less than or equal to 1 and not less than the Symmetry point.

  • Highlight Attenuation
    In some cases, heavy stretching can lead to an excessive increase in Highlights, despite the use of HP.
    Smooth and soften highlights areas. Amplifies ‘Protects Highlights (HP)’ action.

I opened a Pull Request
Pull Request GHS

Executables (ghs in text)
ghs

I will be away from home for 3 weeks (since Monday) but I will remain in contact with possible less material ?

Jacques

2 Likes

Salut Jacques,
I downloaded the ghs appimage but in Selective Editing I don’t see Shadows/Highlights & Equalizer & GHS. Only Shadows/Highlights & Equalizer, no GHS. Do I oversee something perhaps ?

Salut Paul

Did you take the “ghs” version.

I just loaded the Appimage file under Ubuntu24. It is in French by default and I did not do the translations , so the labels are not modified. But if you switch to English the texts (Labels) are present. But in both cases (english or french) 'GHS" is present.

I have not checked with the Windows executable.

in compiled version and in English both ‘Windows11’ and ‘Ubuntu24’ versions work.

Jacques

I found the problem. The Dutch version does not show the GHS part in Shadows/Highlights & Equalizer & GHS, but the English version does.

But with both languages, GHS is there, it’s in the dropdown menu under Equalizer. I oversaw that.

Btw, the Protect shadows slider turns the image too dark after a certain point. That point correlates to the setting of the Stretch settings slider.

@paulmatth

Thank you for testing… and effecively the Dutch version does not show the GHS … as the french… the spannish,… :wink:

This apparent malfunction is part (at least I think so) of learning how to use this software.

If you look at the documentation I linked, or the tooltips, it is mentioned

3.10 Protect shadows (LP)

Sets a value below which the stretch is modified to preserve contrast in the shadows/lowlights. This is done by performing a linear stretch of the data below the ‘LP’ level by reserving contrast from the rest of the image. Moving the LP level towards the current setting of SP changes both the scope (range) and the amount of this contrast reservation, the net effect is to push the overal stretch to higher brightness levels while keeping the contrast and definition in the background. The amount of contrast reserved for the lowlights is such that the continuity of the stretch is preserved. This parameter must be greater than or equal to 0 and not greater than the Symmetry point.

Valid range: [0, SP]

3.11 Protect highlights (HP)

Sets a value above which the stretch is modified to preserve contrast in the highlights/stars. This is done by performing a linear stretch of the data above the ‘HP’ level by reserving contrast from the rest of the image. Moving the HP level towards the current setting of SP increases both the scope (range) and the amount of this contrast reservation, the net effect is to push the overal stretch to lower brightness levels while keeping the contrast and definition in the highlights. The amount of contrast reserved for the highlights is such that the continuity of the stretch is preserved. This parameter must be less than or equal to 1 and not less than the Symmetry point.

Valid range: [SP, 1]

I don’t think there is a viable solution. Sure it would be easy enough to change the black screen, but the slider will have no effect. So similar questions will arise.

This is mostly a learning issue. The key point is SP - Symmetry point (SP) - linked to peak histogram.

Not sure I’m using it right, be tested on a night image, it look pretty good. First one is lifting the shadows with Shadows/Highlights, second is GHS and third Log Encoding. It think I prefer GHS, although Log is fine too. I tried to tune each to keep details in the moon.



2 Likes

The logic behind this algorithm - which can handle, I think, any general type of images - is different from the usual logics. The key starting point is SP (Symmetry Point). Then, depending on the image, the distribution of the histogram, the other settings will be different and may possibly require several sessions.

The linked documentation on GHS is rich in lessons.

A collective learning is necessary.

Thank you for testing.

Jacques

I think someone was asking about or for this feature in a not too distant post… you will have made them happy. :grin: I’m looking forward to understanding this feature…

1 Like

I’m with you on the ‘understanding’ part :face_with_raised_eyebrow:

But I decided to dive in and give it a shot. After playing with a for a minute or two, I realized that it seems to work well as a ‘portrait light’. In other words, it seems to be able to give natural looking light to part of a face. I admit that I don’t really understand any of the sliders yet, but I just fiddled with them until things looked decent :crazy_face:

Photo credit @zhopudey Help with a poorly lit portrait
Creative Commons, By-Attribution, Share-Alike


20200927_19.30.38_DSC_2839.nef.pp3 (16.7 KB)

1 Like

This seems like a very interesting tool for my use case. It appears to give believable results quite quickly when taming high contrast images. Colours appear to stay intact, which is not straightforward with other tools. Will test more later.

hello

Thank you for all these contributions. I think there is a lot to learn collectively from this algorithm with unsuspected resources

I just added (by copying Siril’s code) the Inverse function for GSH.

The inverse GHS is useful for working in negative space. Inverted transform add contrast on the far right and left histogram, brighten the dims, dim the brights and squeez the histogram to the middle.

Of course you can mix (with 2 spot) Normal and Inverse GHS.

Tutorial by the authors
Tutorial

Executables
GHS

Jacques

Still just fiddling around, found that you can quite easily generate artifacts. They always have this look about them.

All tools can generate artifacts when used improperly. This is mostly a heads up for people testing to look out for this kind of effect.

As I mentioned the tool is excellent for managing contrast in against the light photos and the like.

@nosle

Of course, any algorithm can (must?) generate artifacts under certain conditions. GHS is no exception to this rule.

Thanks for your remarks in first evaluation.

On the image you show we see that SP is at 0. which is very unlikely. SP is the key point of the algorithm where a kind of “switch” is made. In a way, but the comparison stops there, it is a concept quite close to “middle grey” or “Yb” (cam16).

I just added what I think is the last missing setting: ‘Black point’ correction in linear mode.

Executables
ghs

Jacques

1 Like

I’m finding that certain combinations of slider have sudden hard shifts by changing the last decimal number. LP for instance flips between a gradual change in image until 0.26805 the suddenly at 0.26806 the image is almost black.


It was repeatable on other images but I could also produce the same effect of sudden step with other slider combinations. With the same settings I can lower the SP slider causes the same switch between bright at pitch black image between 0.12240 and 0.1239. SP and LP follow each other so lowering LP means the switch happens at equally lower SP value.

I it an expected part of the algorithm that there are hard thresholds where a slider goes from gradual change to suddenly a strong and completely different effect?

Yes, the algorithm can be sensitive to some settings. You can end up with black screens because the RGb values ​​are zero. But I think I have prevented the crashes.
I don’t think there is a solution, other than changing the algorithm (I haven’t changed anything major).

I spent some time to display the generated curve - a bit like in Siril. It is a personal solution that uses the curves interface but does not use it at all.
You can thus see the impact of each setting

image

But nothing is perfect. :wink:

Executables
Ghs with Show S curve

Jacques

I just added the last 2 settings for GHS (in Pixlnsight by Mike Cranfield).
Black point and White point. I made some changes.

I attach the 2 comments inspired by the author.

Black Point
Sets the Black point for a linear stretch of the image. Note that any pixel with values less than the Black point input will be clipped and the data lost. Contrast gained by performing the linear stretch will be evenly distributed over the image, which will be dimmed. Pixels with values less than the Black point will appear black and have 0 value.
I added a change in function of the slider (positive or negative values).

White point
Sets the White point for a linear stretch of the image. Note that any pixel with value greater than the White point input will be clipped and the data lost. Contrast gained by performing the linear stretch will be evenly distributed over the image, which will be brightened. Pixels with values greater than the White point will appear white and have a value of 1. Setting this parameter to a value greater than 1 will extend the dynamic range at the high end.

Executable
ghs

I just made several behavior improvments to white point, black point, highlight attenuation (new executables in progress)
Jacques

2 Likes

The curve is very helpful! Makes it easier to understand what’s happening. Just have to loose the option to edit the nodes and chose different curve types for editing.

I’ve just made 2 changes to the GUI (and code Rtengine).

The first concerns the 3 sliders :

  • Symmetry point (SP),
  • Protect shadows (LP),
  • Protect highlights (HP).

Until now, it was up to the user to ensure that LP was lower than SP, and HP higher than SP. Otherwise, black screens, artifacts…

Now the minimum of HP and the maximum of LP is the value entered for SP. (I hope everything works). And this doesn’t mean that the algorithm doesn’t produce artifacts.
I’ve also set a default value of SP = 0.03 which is different from zero, because at zero not much works. In most cases, this value will be too low - it should correspond to the peak of the histogram (even if this is difficult to determine). It may be a bit too high for very underexposed images. To repeat myself, SP is the key point of the algorithm - the balance point.

The second point concerns the visualization of the “S” curve representing the GHS action. I remind you that this is not a curve in the Rawtherapee sense, but a representation.
GUI is not my strong point. I’ve had to tinker to get this result.
So now there are no selection points (copy, edit, etc.).

Executables
ghs

Jacques

1 Like

Salut Jacques, p’tit problème… Strange behavior of the S curve when choosing Manual or Flexible curve type. All at default ghs values.

ghs

Hello Paul

I’ve solved some GUI issues, but I don’t think I know how to do this. Only the “Control cage” (and linear) choice works. I’ll check…

I think I didn’t understand what you meant, I’ll look again

This is absolutely not a “curve”, but only a representation

Jacques