Exemple #1
0
/*
 * R T _ S P E C T _ M A K E _ N T S C _ R G B
 *
 * Using the "Representative set of camera taking sensitivities"
 * for a NTSC television camera, from Benson "Television Engineering
 * Handbook" page 4.58, convert an RGB value in range 0..1 to
 * a spectral curve also in range 0..1.
 *
 * These curves should be used in converting spectral samples
 * to NTSC RGB values.
 */
void
spect_make_NTSC_RGB(struct bn_tabdata **rp,
		    struct bn_tabdata **gp,
		    struct bn_tabdata **bp,
		    const struct bn_table *tabp)
{
    BN_CK_TABLE(tabp);

    /* Convert array of number pairs into bn_tabdata & bn_table */
    rt_NTSC_r_tabdata = bn_tabdata_from_array(&rt_NTSC_R[0][0]);
    rt_NTSC_g_tabdata = bn_tabdata_from_array(&rt_NTSC_G[0][0]);
    rt_NTSC_b_tabdata = bn_tabdata_from_array(&rt_NTSC_B[0][0]);

    bu_log("ntsc_R: area=%g\n", bn_tabdata_area2(rt_NTSC_r_tabdata));
    bn_print_table_and_tabdata("/dev/tty", rt_NTSC_r_tabdata);
    bu_log("ntsc_G: area=%g\n", bn_tabdata_area2(rt_NTSC_g_tabdata));
    bn_print_table_and_tabdata("/dev/tty", rt_NTSC_g_tabdata);
    bu_log("ntsc_B: area=%g\n", bn_tabdata_area2(rt_NTSC_b_tabdata));
    bn_print_table_and_tabdata("/dev/tty", rt_NTSC_b_tabdata);

    /* Resample original NTSC curves to match given bn_table sampling */
#if 0
    /* just to test the routine */
    *rp = bn_tabdata_resample_avg(tabp, rt_NTSC_r_tabdata);
    *gp = bn_tabdata_resample_avg(tabp, rt_NTSC_g_tabdata);
    *bp = bn_tabdata_resample_avg(tabp, rt_NTSC_b_tabdata);
#else
    /* use this one for real */
    *rp = bn_tabdata_resample_max(tabp, rt_NTSC_r_tabdata);
    *gp = bn_tabdata_resample_max(tabp, rt_NTSC_g_tabdata);
    *bp = bn_tabdata_resample_max(tabp, rt_NTSC_b_tabdata);
#endif
}
Exemple #2
0
/**
 * R T _ S P E C T _ R E F L E C T A N C E _ R G B
 *
 * Given reflectance data (in range 0..1) in terms of RGB color,
 * convert that to a spectral reflectance curve.
 *
 * The assumption here is that the spectrum is made up of exactly
 * three non-overlapping bands, and the reflectance is constant over
 * each:
 *
 *	red	572nm to 1, 000, 000nm	(includes the full IR band)
 *	green	492nm to 572nm		(just green)
 *	blue	1nm to 492nm		(includes Ultraviolet)
 *
 * As the caller may be doing a lot of this, the caller is expected to
 * provide a pointer to a valid bn_tabdata structure which is to be
 * filled in.  Allowing caller to re-cycle them rather than doing
 * constant malloc/free cycle.
 */
void
rt_spect_reflectance_rgb(struct bn_tabdata *curve, const float *rgb)
{
    register int	i;
    register const struct bn_table	*tabp;

    BN_CK_TABDATA(curve);
    tabp = curve->table;
    BN_CK_TABLE(tabp);

    /* Fill in blue values, everything up to but not including 492nm */
    for ( i=0; i < tabp->nx; i++ )  {
	if ( tabp->x[i] >= 492 )  break;
	curve->y[i] = rgb[2];
    }

    /* Fill in green values, everything up to but not including 572nm */
    for (; i < tabp->nx; i++ )  {
	if ( tabp->x[i] >= 572 )  break;
	curve->y[i] = rgb[1];
    }

    /* Fill in red values, everything from here up to end of table */
    for (; i < tabp->nx; i++ )  {
	curve->y[i] = rgb[0];
    }
}
Exemple #3
0
/**
 * R T _ S P E C T _ B L A C K _ B O D Y
 *
 * Integrate Planck's Radiation Formula for a black body radiator
 * across the given spectrum.  Returns radiant emittance in W/cm**2
 * for each wavelength interval.
 *
 * Based upon code kindly provided by Russ Moulton, Jr., EOSoft Inc.
 * Compute at 'n-1' wavelengths evenly spaced between ax and bx.
 */
void
rt_spect_black_body(struct bn_tabdata *data, double temp, unsigned int n)

    /* Degrees Kelvin */
    /* # wavelengths to eval at */
{
    const struct bn_table	*tabp;
    int				j;

    BN_CK_TABDATA(data);
    tabp = data->table;
    BN_CK_TABLE(tabp);

    if (bu_debug&BU_DEBUG_TABDATA)  {
	bu_log("rt_spect_black_body( x%x, %g degK ) %g um to %g um\n",
	       data, temp,
	       tabp->x[0] * 0.001,	/* nm to um */
	       tabp->x[tabp->nx] * 0.001	/* nm to um */
	    );
    }

    if ( n < 3 )  n = 3;

    for ( j = 0; j < tabp->nx; j++ )  {
	double	ax;		/* starting wavelength, um */
	double	bx;		/* ending wavelength, um */
	double	dx;		/* wavelength interval, um */
	double	w_sum;		/* sum over wavelengths */
	double	wavlen;		/* current wavelength */
	unsigned long i;

	ax = tabp->x[j] * 0.001;	/* nm to um */
	bx = tabp->x[j+1] * 0.001;	/* nm to um */
	dx = (bx - ax) / (double)n;

	w_sum = 0;
	wavlen = ax;
	for (i=0; i<n; i++)  {
	    w_sum += PLANCK(wavlen, temp);
	    wavlen += dx;
	}
	w_sum *= dx;

	data->y[j] = w_sum;
    }
}
Exemple #4
0
/**
 * R T _ S P E C T _ B L A C K _ B O D Y _ P O I N T S
 *
 * Returns point-sampled values of spectral radiant emittance, in
 * units of watts/cm**2/um, straight from Planck's black-body
 * radiation formula.
 */
void
rt_spect_black_body_points(struct bn_tabdata *data, double temp)

    /* Degrees Kelvin */
{
    const struct bn_table	*tabp;
    int				j;

    BN_CK_TABDATA(data);
    tabp = data->table;
    BN_CK_TABLE(tabp);

    if (bu_debug&BU_DEBUG_TABDATA)  {
	bu_log("rt_spect_black_body_points( x%x, %g degK )\n",
	       data, temp );
    }

    for ( j = 0; j < tabp->nx; j++ )  {
	data->y[j] = PLANCK( (tabp->x[j]*0.001), temp );
    }
}
Exemple #5
0
/**
 * R T _ S P E C T _ M A K E _ C I E _ X Y Z
 *
 * Given as input a spectral sampling distribution, generate the 3
 * curves to match the human eye's response in CIE color parameters X,
 * Y, and Z.  XYZ space can be readily converted to RGB with a 3x3
 * matrix.
 *
 * The tabulated data is linearly interpolated.
 *
 * Pointers to the three spectral weighting functions are "returned",
 * storage for the X, Y, and Z curves is allocated by this routine and
 * must be freed by the caller.
 */
void
rt_spect_make_CIE_XYZ(struct bn_tabdata **x, struct bn_tabdata **y, struct bn_tabdata **z, const struct bn_table *tabp)
{
    struct bn_tabdata	*a, *b, *c;
    fastf_t	xyz_scale;
    int	i;
    int	j;

    BN_CK_TABLE(tabp);

    i = bn_table_interval_num_samples( tabp, 430., 650. );
    if ( i <= 4 )  bu_log("rt_spect_make_CIE_XYZ: insufficient samples (%d) in visible band\n", i);

    BN_GET_TABDATA( a, tabp );
    BN_GET_TABDATA( b, tabp );
    BN_GET_TABDATA( c, tabp );
    *x = a;
    *y = b;
    *z = c;

    /* No CIE data below 380 nm */
    for ( j=0; tabp->x[j] < 380 && j < tabp->nx; j++ )  {
	a->y[j] = b->y[j] = c->y[j] = 0;
    }

    /* Traverse the CIE table.  Produce as many output values as
     * possible before advancing to next CIE table entry.
     */
    for ( i = 0; i < 81-1; i++ )  {
	fastf_t	fract;		/* fraction from [i] to [i+1] */

    again:
	if ( j >= tabp->nx )  break;
	if ( tabp->x[j] < rt_CIE_XYZ[i][0] ) bu_bomb("rt_spect_make_CIE_XYZ assertion1 failed\n");
	if ( tabp->x[j] >= rt_CIE_XYZ[i+1][0] )  continue;
	/* The CIE table has 5nm spacing */
	fract = (tabp->x[j] - rt_CIE_XYZ[i][0] ) / 5;
	if ( fract < 0 || fract > 1 )  bu_bomb("rt_spect_make_CIE_XYZ assertion2 failed\n");
	a->y[j] = (1-fract) * rt_CIE_XYZ[i][1] + fract * rt_CIE_XYZ[i+1][1];
	b->y[j] = (1-fract) * rt_CIE_XYZ[i][2] + fract * rt_CIE_XYZ[i+1][2];
	c->y[j] = (1-fract) * rt_CIE_XYZ[i][3] + fract * rt_CIE_XYZ[i+1][3];
	j++;
	goto again;
    }

    /* No CIE data above 780 nm */
    for (; j < tabp->nx; j++ )  {
	a->y[j] = b->y[j] = c->y[j] = 0;
    }

    /* Normalize the curves so that area under Y curve is 1.0 */
    xyz_scale = bn_tabdata_area2( b );
    if ( fabs(xyz_scale) < VDIVIDE_TOL )  {
	bu_log("rt_spect_make_CIE_XYZ(): Area = 0 (no luminance) in this part of the spectrum, skipping normalization step\n");
	return;
    }
    xyz_scale = 1 / xyz_scale;
    bn_tabdata_scale( a, a, xyz_scale );
    bn_tabdata_scale( b, b, xyz_scale );
    bn_tabdata_scale( c, c, xyz_scale );
}