[comp.graphics] results of my rainbow-RGB query

hiebeler@cardinal.lanl.gov (David Hiebeler) (07/25/89)

  Here are the results (or at least most of them; I think I got a couple
more which I saved somewhere and can't find just this moment... :-) )
of my query about generating RGB triples for a rainbow.
  I think sines/cosines are a good approach, but didn't quite like the
ones that were sent to me.  Probably with some tuning I can get something
more to my tastes.

  Thanks to everyone who took the time to send me a message about this.

==========


I don't know if this will help, but it was posted about a week ago to
this same newsgroup.  it deals with converting visible wavlengths into
RGB triples.  Here it is 

------- cut here --------
>From awpaeth@watcgl.waterloo.edu Tue Jun 27 22:27:33 1989
From: awpaeth@watcgl.waterloo.edu (Alan Wm Paeth)
Newsgroups: comp.graphics
Subject: Re: Wavelength to XYZ or RGB coordinates
Date: 27 Jun 89 18:47:36 GMT
Reply-To: awpaeth@watcgl.waterloo.edu (Alan Wm Paeth)
Distribution: na
Organization: U. of Waterloo, Ontario

What is required is an electronic transcription of the CIE's table of color-
matching functions -- perhaps their best-known publication (excerpted below).
Note that all table values are non-negative and all columns sum (integrate) to
the same value, which can serve as a normalization constant (eg, make the
brightest white in the scene map to [255 255 255]).

Conversion using a 3x3 matrix multiply to/from broadcast RGB is also given.
(RGB can mean anything to anyone -- no two monitors are alike; I've chosen
the NTSC chromaticities of commercial color broadcasting as they are well-
defined). Most of this technique is over a half-century old; the lengthy
posting is offered in part to help better acquaint and encourage "graphicists"
with known technique from the field of color science.

    /Alan Paeth
    Computer Graphics Laboratory
    University of Waterloo

-------------------
# Excerpted Tristimulus values for spectral colors (L = wavelength in nm)
# for the CIE 1931 Standard Colorimetric Observer (2 degree field of view)

# L	X	Y	Z	x'	y'	u'	v'	

380	0.0014	0.0000	0.0065	0.1772	0.0000	0.2679	0.0000
390	0.0042	0.0001	0.0201	0.1721	0.0041	0.2545	0.0136	
400	0.0143	0.0004	0.0679	0.1731	0.0048	0.2554	0.0161	
410	0.0435	0.0012	0.2074	0.1726	0.0048	0.2545	0.0158	
420	0.1344	0.0040	0.6456	0.1714	0.0051	0.2523	0.0169	
430	0.2839	0.0116	1.3856	0.1689	0.0069	0.2461	0.0226	
440	0.3483	0.0230	1.7471	0.1644	0.0109	0.2348	0.0349	
450	0.3362	0.0380	1.7721	0.1566	0.0177	0.2161	0.0550	
460	0.2908	0.0600	1.6692	0.1440	0.0297	0.1877	0.0871
470	0.1954	0.0910	1.2876	0.1241	0.0578	0.1441	0.1510	
480	0.0956	0.1390	0.8130	0.0913	0.1327	0.0828	0.2708
490	0.0320	0.2080	0.4652	0.0454	0.2950	0.0281	0.4116	
500	0.0049	0.3230	0.2720	0.0082	0.5384	0.0035	0.5131	
510	0.0093	0.5030	0.1582	0.0139	0.7502	0.0046	0.5638	
520	0.0633	0.7100	0.0782	0.0743	0.8338	0.0231	0.5837	
530	0.1655	0.8620	0.0422	0.1547	0.8058	0.0501	0.5867	
540	0.2904	0.9540	0.0203	0.2296	0.7543	0.0792	0.5856	
550	0.4334	0.9950	0.0087	0.3016	0.6924	0.1127	0.5821	
560	0.5945	0.9950	0.0039	0.3731	0.6245	0.1531	0.5766	
570	0.7621	0.9520	0.0021	0.4441	0.5547	0.2026	0.5694	
580	0.9163	0.8700	0.0017	0.5125	0.4866	0.2623	0.5604	
590	1.0263	0.7570	0.0011	0.5752	0.4242	0.3315	0.5501	
600	1.0622	0.6310	0.0008	0.6270	0.3725	0.4031	0.5393	
610	1.0026	0.5030	0.0003	0.6658	0.3340	0.4691	0.5296	
620	0.8544	0.3810	0.0002	0.6915	0.3084	0.5202	0.5219	
630	0.6424	0.2650	0.0000	0.7080	0.2920	0.5565	0.5165	
640	0.4479	0.1750	0.0000	0.7191	0.2809	0.5830	0.5125	
650	0.2835	0.1070	0.0000	0.7260	0.2740	0.6005	0.5099	
660	0.1649	0.0620	0.0000	0.7268	0.2732	0.6024	0.5096	
670	0.0874	0.0320	0.0000	0.7320	0.2680	0.6161	0.5076	
680	0.0468	0.0170	0.0000	0.7335	0.2665	0.6203	0.5070	
690	0.0227	0.0082	0.0000	0.7346	0.2654	0.6232	0.5065	
700	0.0114	0.0041	0.0000	0.7355	0.2645	0.6255	0.5062	
-----------

CIE-XYZ to NTSC-RGB

  | R |   | 1.73 -.48 -.26 |   | X |    # inverse of matrix below, all
  | G | = | -.81 1.65 -.02 | * | Y |    # columns sum to 1.0
  | B |   |  .08 -.17 1.28 |   | Z |    # neg results are out of gamut

NTSC-RGB to CIE-XYZ

  | X |   |  .67  .21  .14 |   | R |    # inverse of matrix above, all
  | Y | = |  .33  .71  .08 | * | G |    # columns sum to 1.0
  | Z |   |  0.0  .08  .78 |   | B |    # Red phosphor (u',v') = .67,.33, etc.

-------- cut here --------

Have fun with it!

==========

I wrote an algorithm to create a lookup table to do just this several years
ago.  I used cosine bells for each of the colors.  Red was centered on the
first entry, green 1/3 of the way (85) through the table and blue 2/3's of
the way (170) through the table.  In tabular form they looked like.

	Start	Peak	End	Rel. Hgt.	Comments
Red	-	1	85	1.0
Green	1	85	170	1.0
Blue	85	170	255	1.0
Red	170	212	255	0.5		To get violet

This implies that the half-period of the cosine bell used is 170.  I used
a cosine bell because it produced much better color mixing at constant
intensity than using a triangle or parabolic function.

==========
[ Note -- I wrote this C program based on some pseudo-code someone
  sent me.  -DH ]

#include <stdio.h>

main()
{
int red[256], green[256], blue[256], Loop, x;
FILE *fp;

for (Loop=0;Loop<=42;++Loop) {
		red[Loop] = 255 ;
		green[Loop] = (int) Loop * 127/42 ;
		blue[Loop] = 0 ;
	}
	for (Loop=43;Loop<=84;++Loop) {
		red[Loop] = 255 ;
		green[Loop] = 127 + (Loop-43) * 128/41 ;
		blue[Loop] = 0 ;
	}
	for (Loop=85;Loop<=126;++Loop) {
		red[Loop] = 255 - (int) (Loop-85) * 255/41 ;
		green[Loop] = 255 ;
		blue[Loop] = 0 ;
	}
	for (Loop=127;Loop<=169;++Loop) {
		red[Loop] = 0 ; 
		green[Loop] = 255 - (int) (Loop-127) * 255/42 ;
		blue[Loop] = (int) (Loop-127) * 255/42 ;
	}
	for (Loop=170;Loop<=211;++Loop) {
		red[Loop] = 0 ;
		green[Loop] = 0 ;
		blue[Loop] = 255 - (int) (Loop-170) * 128/41 ;
	}
	for (Loop=212;Loop<=255;++Loop) {
		red[Loop] = (int) (Loop-212) * 120/42 ;  
		green[Loop] = 0 ;
		blue[Loop]= 127 ;
	}
	if ((fp=fopen("rbow.cmap.256","w"))==NULL) {
	    fprintf(stderr,"Could not open file\n");
	    exit(1);
	}
	for (Loop = 0; Loop < 256; Loop++) {
	    x = (red[Loop]<<16) + (blue[Loop]<<8) + green[Loop];
	    fwrite(&x, sizeof(int), 1, fp);
	}
}


==========

[ This is a little C program Chris Langton threw together some time
  ago; it produces a pretty decent rainbow.  -DH ]


#include "stdio.h"

#define S 256
#define OUTFILE "rainbow.256.cmap"

main()
  {
    int  Map[S];
    int  i,j,k,r,g,b, inc;
    FILE *fp;
    
    inc = 6;
    
    r = 255;
    g = 0;
    b = 0;
    
    for (i = 0; i <= 60; i++)
     {
       Map[i] = (r<<16) + (g<<8) + b;
       g += inc;
       if (g > 255) g = 255;
     }
     
     g = 255;
     
    for (i = 61; i <= 105; i++)
     {
       r -= inc;
       if (r < 0) r = 0;
       Map[i] = (r<<16) + (g<<8) + b;
     }
  
   r = 0;
  
   for (i = 106; i <= 165; i++)
     {
       b += inc;
       if (b > 255) b = 255;
       Map[i] = (r<<16) + (g<<8) + b;
     }
     
   b = 255;
   
   for (i = 166; i <= 210; i++)
     {
       g -= inc;
       if (g  < 0) g = 0;
       Map[i] = (r<<16) + (g<<8) + b;
     }
     
   g = 0;
   
   for (i = 211; i <= 255; i++)
     {
       r += inc;
       if (r > 255) r = 255;
       Map[i] = (r<<16) + (g<<8) + b;
     }

   
  fp = fopen(OUTFILE, "w");
  fwrite(Map, sizeof(int), 256, fp);
  fclose(fp);

}


--
Dave Hiebeler                       hiebeler@cardinal.lanl.gov
Center for Nonlinear Studies        hiebeler@cs.rpi.edu
MS B258                       "xue zai shao"  ("snow is burning")
Los Alamos National Laboratory / Los Alamos, NM 87545