Pages Menu
TwitterRssFacebook
Categories Menu

Posted by on 18th January, 2010

Wavelength to Colors

Wavelength to Colors

I did a short experiment several years back on Wavelengths and colors. I was working for Beckman Coulter on their latest Flow Cytometer, which involved working with dozens of lasers of different wavelengths. These lasers would be reflected and filtered to obtain different wavelengths and this needed to be displayed to the user in an intuitive UI.

Back then, I wrote a little Windows application that would convert the wavelength to RGB colors, for my reference.

I figured I could take the same approach and make it a Silverlight application and here it is… As you can see from the code I am using a PolyBezierSegment and modifying the location of the three points of each wave when the trackbar slider is moved.

The corresponding wavelength in nano meters corresponds to the actual color of the light wavelength.

The watermarked curves mark the margins of the visible spectrum. Go ahead and move the slider below:

Get Microsoft Silverlight

mainpage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Silverlight_WavelengthToColor
{
 public partial class MainPage : UserControl
 {
  private const double point1Y = -200.00;
  private const double point2Y = +400.00;
  private const double point3Y = +100.00;
  public MainPage()
  {
   InitializeComponent();
   this.Loaded += new RoutedEventHandler(MainPage_Loaded);
  }
  void MainPage_Loaded(object sender, RoutedEventArgs e)
  {
  this.trackBar1.ValueChanged +=
   new RoutedPropertyChangedEventHandler <double>(trackBar1_ValueChanged);
  }
  void trackBar1_ValueChanged(object sender,
     RoutedPropertyChangedEventArgs <double> e)
  {
   //minimum wavelnegth is 350nm which should display 2.2 waves.
   double slidefactor = (this.trackBar1.Value/3)/2;
   this.spline1.Points = new PointCollection(){
    new Point(slidefactor * 1, point1Y),
    new Point(slidefactor * 2, point2Y),
    new Point(slidefactor * 3, point3Y),
    new Point(slidefactor * 4, point1Y),
    new Point(slidefactor * 5, point2Y),
    new Point(slidefactor * 6, point3Y),
    new Point(slidefactor * 7, point1Y),
    new Point(slidefactor * 8, point2Y),
    new Point(slidefactor * 9, point3Y)
   };
   this.panel1.Fill =
     new SolidColorBrush(this.getColorFromWaveLength((int)e.NewValue));
   this.labelCurrentWaveLength.Text =
     this.trackBar1.Value.ToString("000.00") + " nm";
   this.labelR.Text = "R: " +
     ((Color)getColorFromWaveLength((int)e.NewValue)).R.ToString();
   this.labelG.Text = "G: " +
     ((Color)getColorFromWaveLength((int)e.NewValue)).G.ToString();
   this.labelB.Text = "B: " +
     ((Color)getColorFromWaveLength((int)e.NewValue)).B.ToString();
  }
  private Color getColorFromWaveLength(int Wavelength)
  {
   double Gamma = 1.00;
   int IntensityMax = 255;
   double  Blue;
   double  Green;
   double  Red;
   double  Factor;
   if (Wavelength >= 350 && Wavelength <= 439)
   {
    Red = -(Wavelength - 440d) / (440d - 350d);
    Green = 0.0;
    Blue = 1.0;
   }
   else if (Wavelength >= 440 && Wavelength <= 489)
   {
    Red = 0.0;
    Green = (Wavelength - 440d) / (490d - 440d);
    Blue = 1.0;
   }
   else if (Wavelength >= 490 && Wavelength <= 509)
   {
    Red = 0.0;
    Green = 1.0;
    Blue = -(Wavelength - 510d) / (510d - 490d);
   }
   else if (Wavelength >= 510 && Wavelength <= 579)
   {
    Red = (Wavelength - 510d) / (580d - 510d);
    Green = 1.0;
    Blue = 0.0;
   }
   else if (Wavelength >= 580 && Wavelength <= 644)
   {
    Red = 1.0;
    Green = -(Wavelength - 645d) / (645d - 580d);
    Blue = 0.0;
   }
   else if (Wavelength >= 645 && Wavelength <= 780)
   {
    Red = 1.0;
    Green = 0.0;
    Blue = 0.0;
   }
   else
   {
    Red = 0.0;
    Green = 0.0;
    Blue = 0.0;
   }
   if (Wavelength >= 350 && Wavelength <= 419)
   {
    Factor = 0.3 + 0.7 * (Wavelength - 350d) / (420d - 350d);
   }
   else if (Wavelength >= 420 && Wavelength <= 700)
   {
    Factor = 1.0;
   }
   else if (Wavelength >= 701 && Wavelength <= 780)
   {
    Factor = 0.3 + 0.7 * (780d - Wavelength) / (780d - 700d);
   }
   else
   {
    Factor = 0.0;
   }
   byte A = 255;
   byte R = (byte)this.factorAdjust(Red, Factor, IntensityMax, Gamma);
   byte G = (byte)this.factorAdjust(Green, Factor, IntensityMax, Gamma);
   byte B = (byte)this.factorAdjust(Blue, Factor, IntensityMax, Gamma);
   return Color.FromArgb(A ,R, G, B);
  }
  private int factorAdjust(double Color,
    double Factor,
	int IntensityMax,
	double Gamma)
  {
   if (Color == 0.0)
   {
    return 0;
   }
   else
   {
    return (int)Math.Round(IntensityMax * Math.Pow(Color * Factor, Gamma));
   }
  }
 }
}

mainpage.xaml

<UserControl x:Class="Silverlight_WavelengthToColor.MainPage"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="300">

 <Canvas x:Name="LayoutRoot" Width="400" Height="300" Background="#EDF1F2">
  <Slider x:Name="trackBar1" MaxWidth="384" Minimum="350" Maximum="780"
   Width="390" Height="20" Canvas.Top="11" Value="780" Canvas.Left="8"/>

  <TextBlock x:Name="labelCurrentWaveLength" Canvas.Left="285" Canvas.Top="35"
   Text="780.00 nm" TextWrapping="Wrap" FontSize="18.667" FontWeight="Bold"
   HorizontalAlignment="Right" VerticalAlignment="Bottom"/>

  <Canvas Height="16" Width="389" Canvas.Top="76" Opacity="0.5" Canvas.Left="9">
    <TextBlock Height="16" Width="40" Canvas.Left="175" Text="780nm"
     TextWrapping="Wrap" RenderTransformOrigin="0.625,0.25"/>
    <Path Fill="White" Stretch="Fill" Stroke="Black" Height="1" Width="169"
     UseLayoutRounding="False" Canvas.Left="219" Canvas.Top="7"
     Data="M248,80 L391.75345,80"/>
    <Path Fill="White" Stretch="Fill" Stroke="Black" Height="8" Width="1"
     UseLayoutRounding="False" Canvas.Left="388" Canvas.Top="3.457"
     Data="M392,76 L392,88.023605"/>
    <Path Fill="White" Stretch="Fill" Stroke="Black" Height="1" Width="171"
     UseLayoutRounding="False" Canvas.Left="0" Canvas.Top="7"
     Data="M248,80 L391.75345,80"/>
    <Path Fill="White" Stretch="Fill" Stroke="Black" Height="8" Width="1"
     UseLayoutRounding="False" Canvas.Left="0" Canvas.Top="3.457"
     Data="M392,76 L392,88.023605"/>
  </Canvas>

  <Canvas x:Name="CanvasSplineBackground" Width="390" Height="200"
  Canvas.Left="8" Canvas.Top="92">
   <Rectangle x:Name="panel1" Width="390" Height="200" Fill="Red" Opacity="0.3"
    Stroke="Black" StrokeThickness="1" Canvas.Left="0"/>
   <Rectangle x:Name="panel2" Width="390" Height="200" Fill="Transparent"
    Stroke="Black" StrokeThickness="1" Canvas.Left="0"/>
   <Path Fill="Black" Stretch="Fill" Stroke="Black" StrokeThickness="1"
	Height="1" Width="390" UseLayoutRounding="False"
	Canvas.Left="0" Canvas.Top="100" Data="M72,192 L392,192"/>
   <Path Fill="Black" Stretch="Fill" Stroke="Black" StrokeThickness="1"
	Height="200" Width="1" UseLayoutRounding="False" Canvas.Top="0"
	Data="M232,88 L232,292" Canvas.Left="195"/>
  </Canvas>
  <Canvas x:Name="CanvasSpline" Width="390" Height="200"
	Canvas.Left="8" Canvas.Top="92" >
   <Canvas.Clip>
    <RectangleGeometry Rect="0, 0, 390, 200"/>
   </Canvas.Clip>

   <Path Stroke="Black" StrokeThickness="2" >
    <Path.Data>
     <PathGeometry>
      <PathGeometry.Figures>
       <PathFigureCollection>
        <PathFigure StartPoint="0,100">
         <PathFigure.Segments>
          <PathSegmentCollection>
           <PolyBezierSegment x:Name="spline1"
			Points=" 130,-200 260,400  390,100
                       520,-200 650,400  780,100
                       910,-200 1040,400 1270,100  ">
		   </PolyBezierSegment>
          </PathSegmentCollection>
         </PathFigure.Segments>
        </PathFigure>
       </PathFigureCollection>
      </PathGeometry.Figures>
     </PathGeometry>
    </Path.Data>
   </Path>
   <Path Stroke="Black" StrokeThickness="2" Opacity="0.1">
    <Path.Data>
     <PathGeometry>
      <PathGeometry.Figures>
       <PathFigureCollection>
        <PathFigure StartPoint="0,100">
         <PathFigure.Segments>
          <PathSegmentCollection>
           <PolyBezierSegment x:Name="spline350"
				Points="  58.3333333,-200 116.666667,400 175,100
                       233.333333,-200 291.666667,400 350,100
                       408.333333,-200 466.666666,400 525,100   ">
		   </PolyBezierSegment>
          </PathSegmentCollection>
         </PathFigure.Segments>
        </PathFigure>
       </PathFigureCollection>
      </PathGeometry.Figures>
     </PathGeometry>
    </Path.Data>
   </Path>
   <Path Stroke="Black" StrokeThickness="2" Opacity="0.1">
    <Path.Data>
     <PathGeometry>
      <PathGeometry.Figures>
       <PathFigureCollection>
        <PathFigure StartPoint="0,100">
         <PathFigure.Segments>
          <PathSegmentCollection>
           <PolyBezierSegment x:Name="spline780"
			Points="  130,-200 260,400  390,100
                       520,-200 650,400  780,100
                       910,-200 1040,400 1270,100  ">
		   </PolyBezierSegment>
          </PathSegmentCollection>
         </PathFigure.Segments>
        </PathFigure>
       </PathFigureCollection>
      </PathGeometry.Figures>
     </PathGeometry>
    </Path.Data>
   </Path>
  </Canvas>
  <TextBlock x:Name="labelR" Text="R: 76" TextWrapping="Wrap" FontSize="16"
   FontWeight="Bold" Canvas.Left="9" Canvas.Top="49"
   d:LayoutOverrides="HorizontalMargin"/>
  <TextBlock x:Name="labelG" Text="G: 0" TextWrapping="Wrap" FontSize="16"
   FontWeight="Bold" Canvas.Left="85" Canvas.Top="49"
   d:LayoutOverrides="HorizontalMargin"/>
  <TextBlock x:Name="labelB" Text="B: 76" TextWrapping="Wrap" FontSize="16"
   FontWeight="Bold" Canvas.Left="161" Canvas.Top="49"/>
 </Canvas>
</UserControl>
Enjoy!