views:

110

answers:

2

I have a (spectrographic profile) data set of Wavelength (x-axis) and Intensity (y-axis, in arbitrary units that can have different ranges...)

I want to convert this numeric data to a graphical view as shown at the bottom of the image below.

But, I've never done anything in Delphi (2010) with Canvas's, TImages, bitmaps, or whatever way I'd get this to the screen.

(Obviously, if I can convert my data to one row of image pixels, I then simply copy that row as many times as needed for my desired image height.)

Can anyone point me in the right direction or supply sample code that traverses the x,y values, creating the color image? I'm hoping my solution will allow me (or the user) to adjust levels (contrast, brightness).

Thanks in advance.

alt text

Related SO posts: http://stackoverflow.com/questions/2374959/algorithm-to-convert-any-positive-integer-to-an-rgb-value

http://stackoverflow.com/questions/1472514/convert-light-frequency-to-rgb

+1  A: 

Well, it looks to me like your wavelengths are hues, and your intensity is another word for brightness. Getting the right colors would be a really simple task if only you had a model that represents colors in terms of hue and brightness and a way to convert between it and RGB... :-)

Displaying the colors is actually very simple. You can use a standard TImage component on a form. Once you work out what TColor value goes at a certain position, you can set it with

image.Canvas.Pixels[x, y] := aColor;

EDIT: How to map wavelength to hue:

This is a little tricky since the left hand side of your spectrum seems to be the violet, with the red on the right. In HSL, red is at the 0 position. You're going to have to invert your X axis so red is 0 and violet is high. You can get this by basically saying value := MAX_VALUE - value;

Then you need to calibrate the line. Set the wavelength corresponding to full red equal to 0, and the far blue end equal to whatever its corresponding hue is. (If you can convert a wavelength to a TColor and then a TColor to HSL that shouldn't be difficult to calculate.) That's your range, and you need to normalize all wavelengths to fit into that range.

Just eyeballing it, it looks to me like the left end of your example spectrum is at around 270 degrees hue on the color wheel, which equates to 192 on a scale of 0--255. So take your spectrum from red to blue--again, remember red is LOW, not HIGH--and normalize it to the range 0--192 (or whatever the actual high value is) and you've got your H value.

Also, if you've got some colors on the right end of your color line that go beyond full red towards purple a little, then you'll have a negative hue, which wraps around back to 255.

Mason Wheeler
I actually have a function (in the very nice SDL component library) that converts HSI to RGB: procedure HSItoRGB (Hue, Sat, Intens: double; var r, g, b: integer); So my problem now is how to I go from WaveLength to HSI?!
Robert Frank
Pretty simple actually. Figure out the difference between wavelength 0 and hue 0, and then normalize the x axis to a range of 0..255, and that's your H. Normalize the Y axis to 0..255, and that's your L. S is always 255, to produce the bright, vibrant colors your example shows.
Mason Wheeler
Thanks, Mason! Still not sure how to map wavelength (or frequency of light) to hue though...
Robert Frank
The last link you added to your question covers exactly that topic, Robert. [The second most popular answer there](http://stackoverflow.com/questions/1472514/convert-light-frequency-to-rgb/1472535#1472535) even links to [a page with *Delphi* code and a demo program](http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm). What are you having difficulty with? If it's that the code coverts from wavelength to RGB and you just need hue, then convert from RGB to HSI, take the H value, apply your I value, and then convert back to RGB.
Rob Kennedy
@Robert: Added a basic explanation of how to map wavelengths to hue.
Mason Wheeler
I had been hesitant to encode and decode the information back and forth between formats. But, although perhaps inelegant, it's working fine now: convert wavelength to RGB, RGB to HSI. Adjust HSI intensity. Convert HSI to RGB. Assign to canvas. Thanks so much for your help. I flagged your answer, Mason, as the answer, AND voted up your comment too.
Robert Frank
@Robert: I hope you didn't hit the "flag" link. That's StackOverflow's version of "report abuse". To select an accepted answer, hit the checkmark symbol underneath the score widget.
Mason Wheeler
+1  A: 

You have exactly what you need in that Delphi library from efg.
But you really should read the article on Visible Light Spectrum first: Spectra.
"The purpose of this program is to display RGB colors as a function of wavelength for visible light (380 to 780 nm)."

The only modification you have to add is to modulate for intensity. But as Mason suggested, going through HSI representation makes it easy to adjust the Intensity: so a quick'n'dirty solution is, once you get the RGB from wavelength, to convert to HSI, adjust I than convert back to RGB.

François