Sunday, 21 of December of 2014

‘Constant Brightness’ HSB to RGB Algorithm

For an embedded project I’m working on, I had to implement an algorithm to convert from HSB (hue/saturation/brightness) to RGB color values. This is what I came up with. It creates a ‘constant brightness’ RGB value: at full saturation (no ‘whitewash’), only two of the 3 RGB colors are on at a time, and their ‘on’ times are mathematically complimentary (though not phase-complimentary) with respect to the max 255 value.

Increasing saturation will increase the overall brightness of the LEDs, but that is to be expected — for a given maximum magnitude, there is more overall energy in white light than there is in light of a particular color. The saturation calculation works by adding a constant ‘floor’ value to all channels. Individual color values are then placed between this floor and the 255 maximum. A saturation value of 0 results in all channels at 100% duty cycle.

The ‘brightness’ is the last calculation performed. It takes a saturation modified hue value, and simply proportions it to the maximum value. So, a brightness of 197 will output light which is ~197/255 of the maximum output value. Naturally, there are losses inherent to integer arithmetic, but it’s close enough for most uses. Further, the linear nature of the brightness control means it is not ‘gamma corrected’ — that would require logarithmic brightness control which, for what I’m doing, is completely unnecessary.

This algorithm uses no sine tables or floating point math, so it’s pretty fast, though it could probably be optimized to use shifts and adds instead of mults and divides. It’s also relatively small. The code itself is in C, so it can be used on most platforms.

/******************************************************************************
 * accepts hue, saturation and brightness values and outputs three 8-bit color
 * values in an array (color[])
 *
 * saturation (sat) and brightness (bright) are 8-bit values.
 *
 * hue (index) is a value between 0 and 767. hue values out of range are
 * rendered as 0.
 *
 *****************************************************************************/
void hsb2rgb(uint16_t index, uint8_t sat, uint8_t bright, uint8_t color[3])
{
	uint16_t r_temp, g_temp, b_temp;
	uint8_t index_mod;
	uint8_t inverse_sat = (sat ^ 255);

	index = index % 768;
	index_mod = index % 256;

	if (index < 256)
	{
		r_temp = index_mod ^ 255;
		g_temp = index_mod;
		b_temp = 0;
	}

	else if (index < 512)
	{
		r_temp = 0;
		g_temp = index_mod ^ 255;
		b_temp = index_mod;
	}

	else if ( index < 768)
	{
		r_temp = index_mod;
		g_temp = 0;
		b_temp = index_mod ^ 255;
	}

	else
	{
		r_temp = 0;
		g_temp = 0;
		b_temp = 0;
	}

	r_temp = ((r_temp * sat) / 255) + inverse_sat;
	g_temp = ((g_temp * sat) / 255) + inverse_sat;
	b_temp = ((b_temp * sat) / 255) + inverse_sat;

	r_temp = (r_temp * bright) / 255;
	g_temp = (g_temp * bright) / 255;
	b_temp = (b_temp * bright) / 255;

	color[RED] 	= (uint8_t)r_temp;
	color[GREEN]	= (uint8_t)g_temp;
	color[BLUE]	= (uint8_t)b_temp;
}

Comments RSS TrackBack 1 comment