How to Convert Temperature (K) to RGB: Algorithm and Sample Code

Converting temperature (Kelvin) to RGB: an overview

If you don’t know what “color temperature” is, start here.

While working on a “Color Temperature” tool for PhotoDemon, I spent an evening trying to track down a simple, straightforward algorithm for converting between temperature (in Kelvin) and RGB values. This seemed like an easy algorithm to find, since many photo editors provide tools for correcting an image’s color temperature in post-production, and every modern camera – including smartphones – provides a way to adjust white balance based on the lighting conditions of a shot.

Example of a camera white balance screen. Image courtesy of http://digitalcamerareviews2011online.blogspot.com

Little did I know, but it’s pretty much impossible to find a reliable temperature to RGB conversion formula. Granted, there are some algorithms out there, but most work by converting temperature to the XYZ color space, to which you could add your own RGB transformation after the fact. Such algorithms seem to be based off AR Robertson’s method, one implementation of which is here, while another is here.

Unfortunately, that approach isn’t really a mathematical formula – it’s just glorified look-up table interpolation. That might be a reasonable solution under certain circumstances, but when you factor in the additional XYZ -> RGB transformation required, it’s just too slow and overwrought for simple real-time color temperature adjustment.

So I wrote my own algorithm, and it works pretty damn well. Here’s how I did it.

Caveats for using this algorithm

Caveat 1: my algorithm provides a high-quality approximation, but it’s not accurate enough for serious scientific use. It’s designed primarily for photo manipulation – so don’t try and use it for astronomy or medical imaging.

Caveat 2: due to its relative simplicity, this algorithm is fast enough to work in real-time on reasonably sized images (I tested it on 12 megapixel shots), but for best results you should apply mathematical optimizations specific to your programming language. I’m presenting it here without math optimizations so as to not over-complicate it.

Caveat 3: this algorithm is only designed to be used between 1000 K and 40000 K, which is a nice spectrum for photography. (Actually, it’s way larger than most photographic situations will ever call for.) While it will work for temperatures outside these ranges, the estimation quality will decline.

Special thanks to Mitchell Charity

First off, I owe a big debt of gratitude to the source data I used to generate these algorithms – Mitchell Charity’s raw blackbody datafile at http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html. Charity provides two datasets, and my algorithm uses the CIE 1964 10-degree color matching function. A discussion of the CIE 1931 2-degree CMF with Judd Vos corrections versus the 1964 10-degree set is way beyond the scope of this article, but you can start here for a more comprehensive analysis if you’re so inclined.

The Algorithm: sample output

Here’s the output of the algorithm from 1000 K to 40000 K:

Output of my algorithm from 1000 K to 40000 K. The white point occurs at 6500-6600 K, which is perfect for photo manipulation purposes on a modern LCD monitor.

Here’s a more detailed shot of the algorithm in the interesting photographic range, which is 1500 K to 15000 K:

Same algorithm, but from 1500 K to 15000 K

As you can see, banding is minimal – which is a big improvement over the aforementioned look-up table methods. The algorithm also does a great job of preserving the slightly yellow cast leading up to the white point, which is important for imitating daylight in post-production photo manipulation.

How I arrived at this algorithm

My first step in reverse-engineering a reliable formula was to plot Charity’s original blackbody values. You can download my whole worksheet here in LibreOffice / OpenOffice .ods format (430kb).

Here’s how the data looks when plotted:

Mitchell Charity’s original Temperature (K) to RGB (sRGB) data, plotted in LibreOffice Calc. Again, these are based off the CIE 1964 10-degree CMFs. The white point, as desired, occurs between 6500 K and 6600 K (the peak on the left-hand side of the chart). (Source: http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html)

From this, it’s easy to note that there are a few floors and ceilings that make our algorithm easier. Specifically:

  • Red values below 6600 K are always 255
  • Blue values below 2000 K are always 0
  • Blue values above 6500 K are always 255

It’s also important to note that for purposes of fitting a curve to the data, green is best treated as two separate curves – one for temperatures below 6600 K, and a separate one for temperatures above that point.

From here, I separated the data (without the “always 0” and “always 255” segments) into individual color components. In a perfect world, a curve could then be fitted to each set of points, but unfortunately it wasn’t that simple. Because there’s a large disparity between the X and Y values in the plot – the x-values are all over 1000, and they are plotted in 100 point segments, while the y values all fall between 255 and 0 – it was necessary to transpose the x data in order to get a better fit. For optimization purposes, I stuck to first dividing the x value (the temperature) by 100 across each color, followed by an additional subtraction if it led to a significantly better fit. Here are the resultant charts for each curve, along with the best-fit curve and corresponding R-squared value:

Apologies for the horrifically poor font kerning and hinting in those charts. I love LibreOffice for many things, but its inability to do font aliasing on charts is downright shameful. I also don’t like having to extract charts from screenshots because they don’t have an export option, but that’s a rant best saved for some other day.

As you can see, the curves all fit reasonably well, with R-square values above .987. I could have spent more time really tweaking the curves, but for purposes of photo manipulation these are plenty close enough. No layperson is going to be able to tell that the curves don’t exactly fit raw idealized blackbody observations, right?

The algorithm

Using that data, here’s the algorithm, in all its glory.

First, pseudocode:



    Start with a temperature, in Kelvin, somewhere between 1000 and 40000.  (Other values may work,
     but I can't make any promises about the quality of the algorithm's estimates above 40000 K.)
    Note also that the temperature and color variables need to be declared as floating-point.

    Set Temperature = Temperature \ 100
    
    Calculate Red:

    If Temperature <= 66 Then
        Red = 255
    Else
        Red = Temperature - 60
        Red = 329.698727446 * (Red ^ -0.1332047592)
        If Red < 0 Then Red = 0
        If Red > 255 Then Red = 255
    End If
    
    Calculate Green:

    If Temperature <= 66 Then
        Green = Temperature
        Green = 99.4708025861 * Ln(Green) - 161.1195681661
        If Green < 0 Then Green = 0
        If Green > 255 Then Green = 255
    Else
        Green = Temperature - 60
        Green = 288.1221695283 * (Green ^ -0.0755148492)
        If Green < 0 Then Green = 0
        If Green > 255 Then Green = 255
    End If
    
    Calculate Blue:

    If Temperature >= 66 Then
        Blue = 255
    Else

        If Temperature <= 19 Then
            Blue = 0
        Else
            Blue = Temperature - 10
            Blue = 138.5177312231 * Ln(Blue) - 305.0447927307
            If Blue < 0 Then Blue = 0
            If Blue > 255 Then Blue = 255
        End If

    End If

In the pseudocode above, note that Ln() means natural logarithm. Note also that you can omit the “If color < 0” checks if you will only ever supply temperatures in the recommended range. (You still need to leave the “If color > 255” checks, though.)

As for actual code, here’s the exact Visual Basic function I’m using in PhotoDemon. It’s not yet optimized (for example, the logarithms would be much faster via look-up table) but at least the code is short and readable:


'Given a temperature (in Kelvin), estimate an RGB equivalent
Private Sub getRGBfromTemperature(ByRef r As Long, ByRef g As Long, ByRef b As Long, ByVal tmpKelvin As Long)

    Static tmpCalc As Double

    'Temperature must fall between 1000 and 40000 degrees
    If tmpKelvin < 1000 Then tmpKelvin = 1000
    If tmpKelvin > 40000 Then tmpKelvin = 40000
    
    'All calculations require tmpKelvin \ 100, so only do the conversion once
    tmpKelvin = tmpKelvin \ 100
    
    'Calculate each color in turn
    
    'First: red
    If tmpKelvin <= 66 Then
        r = 255
    Else
        'Note: the R-squared value for this approximation is .988
        tmpCalc = tmpKelvin - 60
        tmpCalc = 329.698727446 * (tmpCalc ^ -0.1332047592)
        r = tmpCalc
        If r < 0 Then r = 0
        If r > 255 Then r = 255
    End If
    
    'Second: green
    If tmpKelvin <= 66 Then
        'Note: the R-squared value for this approximation is .996
        tmpCalc = tmpKelvin
        tmpCalc = 99.4708025861 * Log(tmpCalc) - 161.1195681661
        g = tmpCalc
        If g < 0 Then g = 0
        If g > 255 Then g = 255
    Else
        'Note: the R-squared value for this approximation is .987
        tmpCalc = tmpKelvin - 60
        tmpCalc = 288.1221695283 * (tmpCalc ^ -0.0755148492)
        g = tmpCalc
        If g < 0 Then g = 0
        If g > 255 Then g = 255
    End If
    
    'Third: blue
    If tmpKelvin >= 66 Then
        b = 255
    ElseIf tmpKelvin <= 19 Then
        b = 0
    Else
        'Note: the R-squared value for this approximation is .998
        tmpCalc = tmpKelvin - 10
        tmpCalc = 138.5177312231 * Log(tmpCalc) - 305.0447927307
        
        b = tmpCalc
        If b < 0 Then b = 0
        If b > 255 Then b = 255
    End If
    
End Sub

This function was used to generate the sample output near the start of this article, so I can guarantee that it works.

Sample images

Here’s a great example of what color temperature adjustments can do. The image below – a promotional poster for the HBO series True Blood – nicely demonstrates the potential of color temperature adjustments. On the left is the original shot; on the right, a color temperature adjustment using the code above. In one click, a nighttime scene can been recast in daylight.

Color temperature adjustments in action. (Click for full size)

The actual color temperature tool in my PhotoDemon project looks like this:

PhotoDemon’s Color Temperature tool.

Download it here to see it in action.

addendum October 2014

Renaud Bédard has put together a great online demonstration of this algorithm. Check it out here, and thanks to Renaud for sharing!

addendum April 2015

Thank you to everyone who has suggested improvements to the original algorithm. I know there are a lot of comments on this article, but they’re worth reading if you’re planning on implementing your own version.

I’d like to call out two specific improvements. First, Neil B has helpfully provided a better version of the original curve-fitting functions, which results in slightly modified temperature coefficients. His excellent article describes the changes in detail.

Next, Francis Loch has added some comments and sample images below, which are very helpful if you want to apply these corrections to a photograph. His modifications produce a much more detailed image, as his sample images demonstrate.

How to Access Science and Medical Research without Paying an Arm and a Leg for It

In past articles, I’ve mentioned that I spend much of my career poring over scientific and medical research.  This is equally parts invigorating and frustrating.  On the one hand, the Internet makes it possible to track down just about any research paper imaginable, whether it’s a paper from the turn of the century or one in pre-publication stages.

Unfortunately, this excitement is often tempered by frustration because access to most research papers costs a ridiculous amount of money.  More and more journals are adding free, open-access options, but many of the big hitters (Science, Nature) continue to charge exorbitant amounts for one-time access to individual articles.  As an example – I clicked on the first article from this month’s issue of Nature: “Verbal and non-verbal intelligence changes in the teenage brain.”  This sounded like an interesting article, the kind of thing many laypeople would be interested in, especially parents and teachers of teens.  Unfortunately, the cost for accessing that article is $32 USD.  For that price, you may as well buy a 330-page non-fiction book on the topic (which was published late last year, so it’s even up-to-date).

Sadly, $32 is reasonable compared to some journals.  I’ve seen journals that charge more than $50 USD per research paper – even for ones 20+ years old!

Thus the impetus for this article.  There are a number of ways to legally access scientific and medical research without paying ridiculous per-paper access fees.  I’ve accumulated a lot of these strategies over years of trying to track down papers for FDA regulation purposes.  Some might be obvious (especially to grad students or other researchers), but I still think it worthwhile to mention them.  My hope is to help people – especially those researching medical issues – find the information they need without spending thousands of dollars to do it.

Note: potentially illegal methods of accessing journal articles, including torrenting, Usenet, and other file-sharing techniques, will not be discussed or endorsed.

Step 1 – Finding relevant articles

Before doing anything else, you must first locate papers relevant to your research topic.  As someone who has skipped this step before, let me warn you – few things are more frustrating than spending hours tracking down a research paper, only to find out it doesn’t actually discuss what you want.

In my experience, the best place to start is almost always PubMed.  PubMed is a free research database service provided by the U.S. National Library of Medicine.  PubMed is incredibly comprehensive; as of October 2011 it has indexed more than 21 million records going back to 1809, with another half-million articles added every year.  Because PubMed is so comprehensive, many other science and medicine search services use it to fuel their own engines (EBSCO, Google Scholar, Ovid, etc).

The PubMed homepage has a search bar at the top – type the topic of your search there, then hit Enter to see what turns up.

Sample PubMed search for Alzheimers Disease
Here is a sample PubMed search for "Alzheimers Disease." Make note of the "5580 free full-text articles in PubMed Central" box on the lower-right.

PubMed works like Google or any other search engine – generic search queries will return many articles; more targeted search queries will return a shorter, more relevant set of results.

As with a Google search, you can freely peruse PubMed’s list of articles, but I tend to go straight for a particular box on the right-hand side – the one titled “free full-text articles in PubMed Central.”  Clicking on the “See all…” link at the bottom of that box will refine your search results to show ONLY articles whose full contents are available for free.  (Note: a shortcut way to do this is to select “PMC” from the drop-down box on the PubMed homepage.  However, the two clicks required to change the drop-down box is actually more cumbersome than a single-click of “See all…” on the search results page.)

PubMed Central, or PMC, is an awesome subset of PubMed that deals only in free full-text research articles.  PMC is an outgrowth of the National Institute of Health’s goal to make all publicly funded research available to – imagine this – the public.  Originally, researchers funded by the NIH were encouraged (but not required) to make their research publicly available.  This changed in 2007, when H.R. 2764 was passed, requiring NIH-funded research to be made publicly available within twelve months of publication.  I try to avoid political commentary on my site, but I’m not afraid to say that H.R. 2764 is one of the few unilaterally great pieces of legislation George W. Bush signed into law.

If you find what you need at PMC, great!  You’re all done.  Unfortunately, while PMC’s article database is growing at a steady rate, it won’t always have exactly what you need.

For that, we need to turn to something a little broader.

Step 2 – Google Scholar

Google Scholar (scholar.google.com) is a specialized version of Google’s regular search tool.  Google Scholar indexes research articles from standard indices like PubMed, then cross-references those articles with Google’s massive database of regular web pages.  This cross-referencing comes at a trade-off – on the one hand, it will generally return many more articles than a comparable PubMed search.  However, a lot of those extra discoveries will be irrelevant websites, questionable corporate marketing materials that sound like research, alternative medicine books, and an occasional patent or legal opinion.

The big advantage Google Scholar has over PubMed, however, is if a free copy of a research article exists anywhere on the web, Google will usually be able find it and associate it with its actual paper.  Let me demonstrate.  Below is a screenshot from a Google Scholar search for “Alzheimers Disease Coffee.”  I chose this search term because a growing body of research has associated coffee intake with a reduced risk of Alzheimers Disease, and I wanted to learn more about it:

Sample Google Scholar search
Google Scholar results for "Alzheimers disease coffee."

If you look to the right of the search results themselves, you’ll notice that two lines have a additional light blue link.  The first says “[HTML] from oxfordjournals.org” and the second says “[PDF] from indiana.edu”.  These little boxes are Google’s way of notifying you that they think they’ve found a full-text version of this particular article.

The second full-text link – the one associated with “Managing care through the air” – is a fine example of how Google Scholar can help you find papers.  Trying to access that paper through its title link takes you to a “sign in to purchase this article” page.  However, clicking on the PDF link to the right of the title takes you to a PDF version of the paper, which happens to be hosted on a course website from the University of Indiana.

This kind of cross-referencing can help you find papers that would be almost impossible to otherwise locate.  Sometimes an author will chose to provide a modified copy of the paper on a personal website, or perhaps the corporation who funded a paper will choose to make a copy available on their corporate site.  I have personal experience with this; a paper I co-authored on vitamin D supplementation is still in the pre-publication stages, but a poster of the research (containing most of the relevant data) is available from the Science section of the company that performed the research.  Google Scholar can help you track down these “hidden” copies of research articles.

While Google Scholar is very useful, a caveat is in order.  Sometimes Google will link you to copies of a paper that may not have been obtained legally.  Oftentimes these are hosted on questionable non-English sites.  Whether or not you choose to access papers via that method is up to you.  The legality of something like that is questionable; the morality of it… well, a discussion of the morality of copyright is beyond the scope of this article.  :)  I’ll leave it up to you whether or not you choose to make use of those kinds of Google search results.

Step 3 – Contact the paper’s authors (or even better, the financial sponsor)

This step applies specifically to privately funded research.  Many times, the organization who funds or performs research will keep copies of the paper on hand for marketing purposes.  All companies I’ve worked for did this, and I’m certain others do as well.  When we were emailed questions about research we had performed and/or funded, we typically replied with a copy of the paper.  Some journals also give paper authors a set amount of free copies of their article, which the author rarely has use for.  (After all, they wrote the paper – they know what it says!)  Send that author a nice email, and you might be rewarded with shiny PDF for your trouble.

Step 4 – Try your local library

This step is very much a YMMV one, but it’s still worth a try.  Some community libraries have access deals with research journals or conglomerates like EBSCO.  These deals allow library patrons to access any research journals that are part of the library’s access package.  In most cases this is limited to the big journals, like Science and Nature; few public libraries have the funds to provide access to specialized journals.

Still, it’s always worth a try, and if the library doesn’t have what you need, a librarian may still be able to help you in your search.

Step 5 – Find a college student or professor

I debated leaving this step for last, since it’s probably the most foolproof way to access science and medical journals… but because it is contingent on knowing (or being) a university student or professor, it may not work for everyone.

While local libraries don’t often have funds to pay for unlimited access to thousands of medical journals, many university libraries do.  Again, this will vary from library to library, but university libraries are capable of negotiating very favorable access to a wide range of research journals.  This is obviously in their best interest – the more research students and professors have access to, the stronger their ability to learn and perform their own research.  Some have argued that library quality should be a major aspect of a student’s college selection.  I agree.

If you know a college student or professor, provide them a reference to the research articles you’re interested in and see if they can help you track down a copy.  If you live close to a university – especially a public one – see if the school’s library allows non-students to sign up for library cards.  Most state schools have provisions for this.

Finally, if you are an alumni of a university or college, you may still have certain access rights to the school’s library.  A phone call or email may be all it takes to get a copy of a research article for personal use.

Conclusion

We live in a golden age of scientific and medical research.  Each year, tens of thousands of top-quality articles are published in peer-reviewed journals.  Many of these articles are directly funded by your tax dollars, or indirectly funded by your patronage to a particular business or institution.

It saddens me that most of this knowledge is kept out of the public’s reach by poorly built websites and ridiculously overpriced journal subscriptions – subscription costs that don’t go toward funding more research, but paying for outmoded things like printed copies of thousand-page medical journals that will sit, dust-covered and unread, on the back of some library shelf.  It is even more frustrating that the laypeople most inclined to search through medical literature – those currently suffering from illness or injury – are often the least capable of affording what many scientific journals charge.

As a researcher myself, I am certainly interested in researchers being paid for their hard work – and they are, by the universities and companies that employ them.  When you pay $30-50 USD for a journal article, that money does not go to the researcher.  Even worse, it has even been argued that such subscription costs lead to sensational science instead of good science.  I strongly recommend reading the linked article if you are interested in the dynamics of science publication.

Anyway, I hope this article helps anyone interested in scientific or medical research.  Additional suggestions are always welcome; feel free to use the comments section or my contact page.