Hi folks,
It's been very quiet on the observational front but some nasty noises have been emanating from my little corner of the Cotswolds. Yes, I've been thinking again...
Actually, I've been dipping a toe into Javascript programming for the first time with a view to writing a PixInsight script to "repair" the H and Sv components of an HSV separation. Today I got to the point of needing to know how HSV is derived from RGB so that I could better understand how the hue and saturation (H and S) values could be "fixed" where the source RGB was tending towards saturation. With apologies to the non-programmers reading this here are the relevant code snippets for conversion between RGB and HSV (
Source):
/**
* Converts an RGB color value to HSV. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and v in the set [0, 1].
*
* @param Number r The red color value
* @param Number g The green color value
* @param Number b The blue color value
* @return Array The HSV representation
*/
function rgbToHsv(r, g, b){
r = r/255, g = g/255, b = b/255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, v = max;
var d = max - min;
s = max == 0 ? 0 : d / max;
if(max == min){
h = 0; // achromatic
}else{
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, v];
}
/**
* Converts an HSV color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes h, s, and v are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param Number h The hue
* @param Number s The saturation
* @param Number v The value
* @return Array The RGB representation
*/
function hsvToRgb(h, s, v){
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch(i % 6){
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return [r * 255, g * 255, b * 255];
}
At first glance this looks bizarre but plugging some numbers in does demonstrate, if demonstration were needed, that one can recover the original RGB values after conversion to and from HSV. But the definition of V (the channel to be stretched) as the maximum of any of red, green or blue looks, at first glance, as though it might be a problem when stretching even though the ratio of R to G to B remains unchanged for any given pixel.
If one stretches an RGB image the non-linear shape of the curve causes an amplification of colour differences in the faint bits and a diminution of colour differences in the bright bits, the latter resulting in the familiar loss of colour in the bright stars and bright nebulosity. While stretching the V component of an HSV separation results in immunity from such colour shifts it occurs to me that there is a potential issue simply because V is defined as whichever is the greater of a pixel's values of red, green or blue.
An example might help so consider three pixels where, one with RGB = (200, 0, 0), one with RGB = (66, 67, 67) and one with RGB = (200, 200, 200) - I've used 8-bit values here just to make it easier to read. The first two might be appear similar in "brightness" (the experts could no doubt refine the numbers) but however you cut it the last one will be lot brighter. That said the V components are, respectively, 200, 67 and 200 for the three pixels. As a result, if I've got my best thinking head on this evening, the application of a (non-linear) stretch of a V image will result in changes in relative luminosity where there are large differences in saturation. OK, the values I used don't need a stretch but the principle stands.
Does this matter? In a search for perfection I'd say "Yes" but that begs the question of how one defines perfection. Arguably the formula I described in
this post uses a more natural definition of luminance, even if using the sum of red, green and blue might have the experts clutching their heads in despair, and it does retain the precise ratios between red, green and blue at every pixel. Hmm, more thinking required...
Bob.