Skip to content

Commit

Permalink
0.1.0 initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
RobTillaart committed Jul 30, 2020
1 parent 6b31cc8 commit 9fc53ca
Show file tree
Hide file tree
Showing 10 changed files with 487 additions and 1 deletion.
107 changes: 107 additions & 0 deletions Kelvin2RGB.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//
// FILE: Kelvin2RGB.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// DATE: 2018-01-31
// PURPOSE: Arduino library for converting temperature to RGB values
// URL: https://github.com/RobTillaart/Kelvin2RGB

#include "Kelvin2RGB.h"

#define DIVIDE_255 0.0039215686274509803921568627451

Kelvin2RGB::Kelvin2RGB()
{
_temperature = 0;
_brightness = 0;
_red = 0;
_green = 0;
_blue = 0;
}

void Kelvin2RGB::begin()
{
}


// Tanner Helland formulas
void Kelvin2RGB::convert_TH(float temperature, float brightness)
{
_temperature = constrain(temperature, 0, 65500);
_brightness = constrain(brightness, 0, 100);

_red = _green = _blue = 0;
float t = _temperature * 0.01;

if (t <= 66)
{
_red = 255;
_green = (99.4708025861 * log(t)) - 161.1195681661;
if (t > 19)
{
_blue = (138.5177312231 * log(t - 10)) - 305.0447927307;
}
else _blue = 0;
}
else
{
_red = 329.698727466 * pow(t - 60, -0.1332047592);
_green = 288.1221695283 * pow(t - 60, -0.0755148492);
_blue = 255;
}
float f = 0.01 * _brightness;
_red = f * constrain(_red, 0, 255);
_green = f * constrain(_green, 0, 255);
_blue = f * constrain(_blue, 0, 255);
_rgb = round(_red) * 65536UL + round(_green) * 256UL + round(_blue);

// divide by 255 to get factors between 0..1
_red *= DIVIDE_255;
_green *= DIVIDE_255;
_blue *= DIVIDE_255;
}


// Neil Bartlett formulas
void Kelvin2RGB::convert_NB(float temperature, float brightness)
{
_temperature = constrain(temperature, 0, 65500);
_brightness = constrain(brightness, 0, 100);

_red = _green = _blue = 0;
float t = _temperature * 0.01;

if (t <= 66)
{
_red = 255;
_green = t - 2;
_green = -155.25485562709179 - 0.44596950469579133 * _green + 104.49216199393888 * log(_green);
_blue = 0;
if (t > 20)
{
_blue = t - 10;
_blue = -254.76935184120902 + 0.8274096064007395 * _blue + 115.67994401066147 * log(_blue);
}
}
else
{
_red = t - 55.0;
_red = 351.97690566805693 + 0.114206453784165 * _red - 40.25366309332127 * log(_red);
_green = t - 50.0;
_green = 325.4494125711974 + 0.07943456536662342 * _green - 28.0852963507957 * log(_green);
_blue = 255;
}

float f = 0.01 * _brightness;
_red = f * constrain(_red, 0, 255);
_green = f * constrain(_green, 0, 255);
_blue = f * constrain(_blue, 0, 255);
_rgb = round(_red) * 65536UL + round(_green) * 256UL + round(_blue);

// divide by 255 to get factors between 0..1
_red *= DIVIDE_255;
_green *= DIVIDE_255;
_blue *= DIVIDE_255;
}

// -- END OF FILE --
78 changes: 78 additions & 0 deletions Kelvin2RGB.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once
//
// FILE: Kelvin2RGB.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// DATE: 2018-01-31
// PURPOSE: Arduino library for converting temperature to RGB values
// URL: https://github.com/RobTillaart/Kelvin2RGB
//
// Based upon article Tanner Helland and Neil Bartlett
// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
// http://www.zombieprototypes.com/?p=210
// https://en.wikipedia.org/wiki/Color_temperature#Categorizing_different_lighting

#define KELVIN2RGB_LIB_VERSION "0.1.0"

#include "Arduino.h"

// based on https://en.wikipedia.org/wiki/Color_temperature#Categorizing_different_lighting
// TODO a memory efficient storage -> uint8_t 17 .. 255 (factor 100)
// how? hash function? parameter settings convert(dayLightSetting)
/*
NAME TEMPERATURE
=============================
match = 1700;
sodiumLamp = 1700;
candleFlame = 1850;
sunrise = 1850;
sunset = 1850;
bulb = 2400;
bulbSoftWhite = 2550;
LEDlamp = 2700;
warmWhite = 3000;
studioLight = 3200;
studioCPlight = 3350;
daylightHorizon = 5000;
flashLight = 5700;
xenonLight = 6200;
dayLightBright = 6500;
normal = 6500;
screenlow = 6500;
screenMed = 8000;
screenHigh = 9500;
polewardSky0 = 15000;
polewardSky1 = 19000;
polewardSky2 = 23000;
polewardSky3 = 27000;
*/


class Kelvin2RGB
{
public:
Kelvin2RGB();
void begin();

// temp = 0..65500 brightness = 0.0 .. 100.0%
void convert_TH(float temperature, float brightness = 100);
void convert_NB(float temperature, float brightness = 100);

float temperature() { return _temperature; };
float brightness() { return _brightness; };
inline float red() { return _red; };
inline float green() { return _green; };
inline float blue() { return _blue; };
uint32_t RGB() { return _rgb; }


private:
float _temperature;
float _brightness;
float _red;
float _green;
float _blue;
uint32_t _rgb;
};

// -- END OF FILE --
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 Rob Tillaart
Copyright (c) 2018-2020 Rob Tillaart

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,82 @@
# Kelvin2RGB

Arduino library for converting temperature to RGB values

## Credentials

This library is based upon an article of Tanner Helland
and a related story by Neil Bartlett
http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
http://www.zombieprototypes.com/?p=210
https://en.wikipedia.org/wiki/Color_temperature#Categorizing_different_lighting

There are more approximation formulas, some claim to be better,
however these are not investigated.

## Description

The library converts a temperature in Kelvin and an brightness (0..100%)
to 3 numbers red, green and blue.
These numbers are weights can be used to correct a colorimage for virtual white temperature.

There are 2 convert functions where the **convert_NB()** is claimed to be the
more accurate one.

With the numbers R,G,B calculated one can convert images so they will look more like
taken with candle light, sunrise or sunset etc.

**pseudo code**
```cpp
Kelvin2RGB KRGB;

KRGB.convert(1850, 100); // sunrise light factors

for each pixel in image
{
red *= KRGB.red();
green *= KRGB.green();
blue *= KRGB.blue();
drawPixel();
}
```

The numbers can also be used to reduce the blue channel so it has less effect
on "getting sleepy".

The library uses floats for the R,G and B weights to keep values as accurate as possible.
Especially with images with more than 8 bits per channel this is preferred.
That said it is also possible to use this on a 565 image or to adjust color lookup tables.


## Interface

The interface is pretty straightforward.

- **Kelvin2RGB()** constructor
- **begin()** for now an empty function.
- **convert_TH(float temperature, float brightness = 100)**
temperature = 0..65500 temperature below 1000 is not well defined.
brightness = 0..100%,
- **convert_NB(float temperature, float brightness = 100)**
temperature = 0..65500 temperature below 1000 is not well defined.
brightness = 0..100%,
Is a bit more accurate and slightly slower (few %). Read link above for more information.
- **float temperature()** returns temperature, to check the value used.
- **float brightness()** returns brightness, to check the value used.
- **float red()** returns red channel weight 0.0 .. 1.0
note this is different from Helland / Bartlett who both use an integer value 0 .. 255
- **float green()** returns green channel weight 0.0 .. 1.0
- **float blue()** returns blue channel weight 0.0 .. 1.0
- **uint32_t RGB()** retuns a 24 bit RGB value,
more efficient than 3 floats for communication.

## future

- separate brightness per color channel to mimic "artificial illumination"
- define constants like candleLight as parameter.


## Operations

See examples

49 changes: 49 additions & 0 deletions examples/Kelvin2RGB_difference/Kelvin2RGB_difference.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// FILE: Kelvin2RGB_difference.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo - shows difference between 2 convert functions.
// DATE: 2020-07-29
// URL: https://github.com/RobTillaart/Kelvin2RGB
//

// shows difference between the two calculations
// best viewed in plotter.

#include "Kelvin2RGB.h"

Kelvin2RGB KRGB;
Kelvin2RGB KRGB2;

void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);

KRGB.begin();
KRGB2.begin();

test_difference();
}

void loop()
{
}

void test_difference()
{
float bright = 100.0;
for (uint32_t temp = 0; temp < 70000; temp += 200)
{
KRGB.convert_TH(temp, bright);
KRGB2.convert_NB(temp, bright);
Serial.print(KRGB.blue() - KRGB2.blue());
Serial.print("\t");
Serial.print(KRGB.red() - KRGB2.red());
Serial.print("\t");
Serial.print(KRGB.green() - KRGB2.green());
Serial.print("\n");
}
}

// -- END OF FILE --
59 changes: 59 additions & 0 deletions examples/Kelvin2RGB_table/Kelvin2RGB_table.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// FILE: Kelvin2RGB_table.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: generate table of values
// DATE: 2020-07-29
// URL: https://github.com/RobTillaart/Kelvin2RGB
//

#include "Kelvin2RGB.h"

Kelvin2RGB KRGB;

void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);

KRGB.begin();
test();
}

void loop()
{
}

void test()
{
float bright = 100.0; // change to 0.0
while (bright <= 100.0)
{
bright += 5;
for (uint32_t temp = 0; temp < 70000; temp += 200)
{
Serial.print(KRGB.temperature(), 0);
Serial.print("\t");
Serial.print(KRGB.brightness(), 0);
Serial.print("\t");

KRGB.convert_TH(temp, bright);
Serial.print(KRGB.red(), 4);
Serial.print("\t");
Serial.print(KRGB.green(), 4);
Serial.print("\t");
Serial.print(KRGB.blue(), 4);
Serial.print("\t");

KRGB.convert_NB(temp, bright);
Serial.print(KRGB.red(), 4);
Serial.print("\t");
Serial.print(KRGB.green(), 4);
Serial.print("\t");
Serial.print(KRGB.blue(), 4);
Serial.print("\n");
}
}
}

// -- END OF FILE --
Loading

0 comments on commit 9fc53ca

Please sign in to comment.