-
Notifications
You must be signed in to change notification settings - Fork 0
fourmilab
https://www.fourmilab.ch/documents/specrend/
Цветопередача спектров
Джона Уокера
http://www.fourmilab.ch/
Последнее обновление: 9 марта 2003 г.
Эта программа находится в свободном доступе.
Полную информацию о методах, используемых в
этой программе, см. в документе в Интернете:
http://www.fourmilab.ch/documents/specrend/.
Функция xyz_to_rgb(), которая была неправильной в исходной
версии этой программы, исправлено:
Эндрю
Дж. С. Гамильтоном, 21
мая
1999
г
.. белый.
Программа, использующая эти функции для построения
«языковых» диаграмм CIE, называемая «ppmcie», включена в
набор графических инструментов Netpbm:
http://netpbm.sourceforge.net/ (В более ранних
версиях Netpbm
программа называлась cietoppm .)
/ #include <stdio.h> #include <math.h> / Цветовая система определяется координатами CIE x и y трех основных источников света и координатами x и y точки белого. / struct colorSystem { char name; / Имя системы цвета / double xRed, yRed, / Red x, y / xGreen, yGreen, / Green x, y / xBlue, yBlue, / Blue x, y / xWhite, yWhite, / Точка белого x, y / gamma; / Гамма-коррекция системы / }; / Цветность белой точки. * / #define illuminantc 0,3101, 0,3162 / для NTSC Television* / #define illuminantd65 0,3127, 0,3291 /* для ebu и smpte* / #define illuminante 0,3333333, 0,333333333 /* cie epperegrege gramemange gramemange* / / / / / / / / /еньбарный ganeer* / /* / / / / / / / /еджийский . . См. пункт 45 часто задаваемых вопросов по цвету Чарльза Пойнтона и пункт 6 по GammaFAQ по адресу: http://www.poynton.com/ColorFAQ.html http://www.poynton.com/GammaFAQ.html / #define GAMMA_REC709 0 / Рек. 709 */ static struct colorSystem
/* Имя xRed yRed xGreen yGreen xBlue yBlue Белая точка Гамма */
NTSCsystem = { "NTSC", 0,67, 0,33, 0,21, 0,71, 0,14, 0,08, IlluminantC, GAMMA_REC709 },
EBUsystem = { "EBU (PAL/SECAM)", 0,64, 0,33, 0,29, 0,60, 0,15, 0,06, IlluminantD65, GAMMA_REC709 },
SMPTEsystem = { "SMPTE", 0,630, 0,340, 0,310, 0,595, 0,155, 0,070, IlluminantD65, GAMMA_REC709 },
HDTVsystem = { "HDTV", 0,670, 0,330, 0,210, 0,710, 0,1 50, 0,060, IlluminantD65, GAMMA_REC709 } ,
CIEsystem = { "CIE", 0,7355, 0,2645, 0,2658, 0,7243, 0,1669, 0,0085, IlluminantE, GAMMA_REC709 },
Rec709system = { "CIE REC 709", 0,64, 0,33, 0,30, 0,60, 0,15, 0.06, IlluminantD65, GAMMA_REC709 } ;
/* UPVP_TO_XY
Учитывая координаты 1976 года u', v', определяем цветности 1931 года x, y
*/
void upvp_to_xy(double up, double vp, double *xc, double yc) { xc = (9 * up) / ((6 вверх) – (16вп)+12); yc = (4вп)/((6вп) – (16вп)+12); }
/* XY_TO_UPVP
Учитывая цветности 1931 года x, y, определите координаты 1976 года u', v'
*/
void xy_to_upvp(double xc, double yc, double *up, double vp) { up = (4 * xc) / (( -2хс)+(12ук)+3); *vp = (9 * yc) / ((-2 * xc) + (12 * yc) + 3); }
/* XYZ_TO_RGB
Дана аддитивная трехцветная система CS, определяемая
цветностью CIE x и y ее трех основных цветов (z выводится
тривиально как 1-(x+y)), и желаемая цветность (XC, YC,
ZC) в Пространство CIE определяет вклад каждого
основного цвета в линейную комбинацию, которая в сумме дает желаемую
цветность. Если требуемая цветность выходит за пределы
треугольника Максвелла (цветовой гаммы), образованного тремя
основными цветами, один из весов r, g или b будет отрицательным.
Вызывающий может использовать constrain_rgb() для обесцвечивания
цвета вне гаммы до ближайшего представления в пределах
доступной гаммы и/илиnormal_rgb для нормализации
компонентов RGB, чтобы самый большой ненулевой компонент имел значение 1.
*/
void xyz_to_rgb(struct colorSystem *cs, double xc, двойной yc, двойной zc, двойной *r, двойной *g, двойной *b) { двойной xr, yr, zr, xg, yg, zg, xb, yb, zb; двойной xw, yw, zw; двойной rx, ry, rz, gx, gy, gz, bx, by, bz; двойной рв, гв,чб;
хр = cs->xRed; год = cs->yRed; zr = 1 - (xr + yr);
хг = cs->xGreen; yg = cs->yGreen; zg = 1 - (xg + yg);
хб = cs->xBlue; yb = cs->yBlue; zb = 1 - (xb + yb);
xw = cs->xWhite; yw = cs->yWhite; zw = 1 - (xw + yw);
/* xyz -> матрица RGB, перед масштабированием до белого цвета. */
rx = (yg * zb) - (yb * zg); ry = (xb*zg) - (xg*zb); rz = (xg*yb) – (xb*yg);
gx = (yb*zr) - (yr*zb); gy = (xr*zb) - (xb*zr); gz = (xb*yr) - (xr*yb);
bx = (yr*zg) - (yg*zr); по = (xg*zr) - (xr*zg); bz = (xr*yg) – (xg*yr);
/* Коэффициенты масштабирования белого.
Деление на yw масштабирует яркость белого до единицы, как обычно. */
rw = ((rx * xw) + (ry * yw) + (rz * zw)) / yw;
gw = ((gx * xw) + (gy * yw) + (gz * zw)) / yw;
bw = ((bx * xw) + (by * yw) + (bz * zw)) / yw;
/* xyz -> матрица RGB, правильно масштабированная до белого цвета. */
rx = rx / rw; ry = ry/rw; гз = гз/рв;
гх = гх/гв; gy = gy/gw; гз = гз/гв;
бх = бх/бв; по = по / чб; бз = бз / чб;
/* rgb нужной точки */
*r = (rx * xc) + (ry * yc) + (rz * zc);
*g = (gx * xc) + (gy * yc) + (gz * zc);
*b = (bx * xc) + (by * yc) + (bz * zc);
}
/* INSIDE_GAMUT
Проверяет, находится ли запрошенный цвет в пределах достижимой гаммы
с основными цветами текущей цветовой
системы. Это означает просто проверку того, все ли
первичные веса неотрицательны. */
int Inside_gamut(double r, double g, double b) { return (r >= 0) && (g >= 0) && (b >= 0); }
/* CONSTRAIN_RGB
Если запрошенный оттенок RGB содержит отрицательный вес для
одного из основных цветов, он находится за пределами цветовой гаммы,
доступной из данной тройки основных цветов. Обесцветьте
его, добавив в белый цвет равные количества R, G и B, достаточные,
чтобы сделать RGB полностью положительным. Функция возвращает 1, если
компоненты были изменены, и ноль в противном случае.
*/
int constrain_rgb(double *r, double *g, double *b) { double w;
/* Необходимое количество белого равно w = - min(0, *r, *g, *b) */
w = (0 < *r) ? 0 : *р;
ш = (ш < *g) ? ш: *г;
ш = (ш < *b) ? ш : *б;
ш = -ш;
/* Добавляем ровно столько белого, чтобы все значения r, g, b были положительными. */
if (w > 0) {
*r += w; *г += ш; *б += ш;
возврат 1; /* Цвет изменен в соответствии с гаммой RGB */
}
return 0; /* Цвет в гамме RGB */
}
/* GAMMA_CORRECT_RGB
Преобразуйте линейные значения RGB в нелинейные значения RGB. Рек.
709 — это Рекомендация ITU-R BT. 709 (1990) ``
Значения основных параметров для стандарта HDTV для студий и
международного обмена программами'', ранее CCIR Rec.
709. Подробности см.
на http://www.poynton.com/ColorFAQ.html
http://www.poynton.com/GammaFAQ.html
*/
void gamma_correct(const struct colorSystem *cs, double *c) { double gamma;
гамма = CS->гамма;
if (гамма == GAMMA_REC709) {
/* Рек. 709 гамма-коррекция. */
двойной куб = 0,018;
if (*c <cc) {
*c *= ((1,099 * pow(cc, 0,45)) - 0,099) / cc;
} Еще {
*c = (1,099 * pow(*c, 0,45)) - 0,099;
}
} else {
/* Нелинейный цвет = (Линейный цвет)^(1/gamma) */
*c = pow(*c, 1.0 / gamma);
}
}
void gamma_correct_rgb(const struct colorSystem *cs, double *r, double *g, double *b) { gamma_correct(cs, r); gamma_correct(cs, г); gamma_correct(cs, б); }
/* NORM_RGB
Нормализовать компоненты RGB так, чтобы наиболее интенсивные (если все
они не равны нулю) имели значение 1.
*/
voidnormal_rgb(double *r, double *g, double *b) { #define Max(a, b) ( ((a) > (b)) ? (a) : (b)) двойной наибольший = Max(*r, Max(*g, *b));
if (наибольшая > 0) {
*r /= наибольшая;
*g /= величайший;
*b /= величайший;
}
#undef Max }
/* SPECTRUM_TO_XYZ
Вычисляет координаты CIE X, Y и Z, соответствующие
источнику света со спектральным распределением, заданным функцией
SPEC_INTENS, которая вызывается с серией
длин волн от 380 до 780 нм (аргумент
выражается в метрах), который возвращает эмиттанс на этой
длине волны в произвольных единицах. Координаты цветности
спектра возвращаются в
аргументах x, y и z, которые учитывают идентичность:
x + y + z = 1.
*/
void Spectrum_to_xyz(double (*spec_intens)(double length), double *x, double *y, двойной *z) { int i; двойная лямбда, X = 0, Y = 0, Z = 0, XYZ;
/* Функции сопоставления цветов CIE xBar, yBar и zBar для
длины волн от 380 до 780 нанометров, каждые 5
нанометров. Для лямбда длины волны в этом диапазоне:
cie_colour_match[(lambda - 380) / 5][0] = xBar
cie_colour_match[(lambda - 380) / 5][1] = yBar
cie_colour_match[(lambda - 380) / 5][2 ] = zBar
Чтобы сэкономить память, эту таблицу можно объявить как число с плавающей запятой,
а не как число с двойной точностью; (IEEE) число с плавающей запятой имеет достаточно
значащих битов для представления значений. Здесь он объявлен
как двойной, чтобы избежать предупреждений о «преобразовании
между типами с плавающей запятой» от некоторых привередливых
компиляторов. */
static double cie_colour_match[81][3] = {
{0.0014,0.0000,0.0065}, {0.0022,0.0001,0.0105}, {0.0042,0.0001,0.0201},
{0.0076,0.0002,0.0362}, {0.0143,0.0 004, 0.0679}, {0.0232,0.0006,0.1102},
{0.0435,0.0012,0.2074}, {0.0776,0.0022,0.3713}, {0.1344,0.0040,0.6456},
{0.2148,0.0073,1.0391}, {0,2839,0,0116,1,3856} , {0.3285,0.0168,1.6230},
{0.3483,0.0230,1.7471}, {0.3481,0.0298,1.7826}, {0.3362,0.0380,1.7721}, {0.3187,0.0480,1.7441},
{0.2908 ,0,0600,1,6692}, { 0.2511,0.0739,1.5281},
{0.1954,0.0910,1.2876}, {0.1421,0.1126,1.0419}, {0.0956,0.1390,0.8130}, {0.0580,0.1693,0.6162},
{0.0320,0 .2080,0.4652}, {0.0147, 0.2586,0.3533},
{0.0049,0.3230,0.2720}, {0.0024,0.4073,0.2123}, {0.0093,0.5030,0.1582}, {0.0291,0.6082,0.1117},
{0.0633,0.7100,0 .0782}, {0.1096,0.7932, 0.0573},
{0.1655,0.8620,0.0422}, {0.2257,0.9149,0.0298}, {0.2904,0.9540,0.0203}, {0.3597,0.9803,0.0134}
, {0.4334,0.9950,0.0087}, {0.5121,1.0000,0.0057} ,
{0.5945,0.9950,0.0039}, {0.6784,0.9786,0.0027}, {0.7621,0.9520,0.0021}, {0.8425,0.9154,0.0018},
{0.9163,0.8700,0.0017}, {0.9786 ,0.8163,0.0014},
{ 1.0263,0.7570,0.0011}, {1.0567,0.6949,0.0010}, {1.0622,0.6310,0.0008}, {1.0456,0.5668,0.0006},
{1.0026,0.5030,0.0003}, {0.9384,0 .4412,0.0002},
{0.8544, 0.3810,0.0002}, {0.7514,0.3210,0.0001}, {0.6424,0.2650,0.0000}, {0.5419,0.2170,0.0000},
{0.4479,0.1750,0.0000}, {0.3608,0.1382,0 .0000},
{0.2835,0.1070, 0.0000}, {0.2187,0.0816,0.0000}, {0.1649,0.0610,0.0000},
{0.1212,0.0446,0.0000}, {0.0874,0.0320,0.0000}, {0.0636,0.0232,0.0000},
{0.0468,0.0170,0.0000} , {0.0329,0.0119,0.0000}, {0.0227,0.0082,0.0000},
{0.0020 ,0.0007,0.0000}, { 0.0014,0.0005,0.0000}, {0.0010,0.0004,0.0000},
{0.0158,0.0057,0.0000}, {0.0114,0.0041,0.0000}, {0.0081,0.0029,0.0000},
{0.0058,0.0021,0.0000}, {0.0041,0.0015,0.0000}, {0.0029,0.0010,0.0000}, {0.0007,0.0002,0.0000},
{0.0005,0.0002,0.0000}, {0.0003,0 .0001,0.0000},
{0.0002 ,0.0001,0.0000}, {0.0002,0.0001,0.0000}, {0.0001,0.0000,0.0000},
{0.0001,0.0000,0.0000}, {0.0001,0.0000,0.0000}, {0.0000,0.0000, 0,0000}
};
for (i = 0, лямбда = 380; лямбда <780,1; я++, лямбда += 5) {
double Me;
Я = (*spec_intens)(лямбда);
X += Me * cie_colour_match[i][0];
Y += Me * cie_colour_match[i][1];
Z += Me * cie_colour_match[i][2];
}
XYZ = (X + Y + Z);
*х = Х/XYZ;
*у = Y/XYZ;
*z = Z/XYZ;
}
/* BB_SPECTRUM
Рассчитать, используя закон излучения Планка, эмиттанс черного тела
с температурой bbTemp на заданной длине волны (в метрах). */
двойной bbTemp = 5000; /* Скрытый аргумент температуры для BB_SPECTRUM. / double bb_spectrum(двойная длина волны) { double wlm = длина волны * 1e-9; / Длина волны в метрах */
return (3.74183e-16 * pow(wlm, -5.0)) /
(exp(1.4388e-2 / (wlm * bbTemp)) - 1.0);
}
/* Встроенная тестовая программа, которая отображает значения x, y, Z и RGB для спектров черного тела от 1000 до 10000 градусов Кельвина. При запуске эта программа должна выдать следующий результат:
Температура xyz RGB
----------- ------ ------ ------ ----- -- --- -----
1000 К 0,6528 0,3444 0,0028 1,000 0,007 0,000 (Приближение)
1500 К 0,5857 0,3931 0,0212 1,000 0,126 0,000 (Приближение)
2000 К 0,5267 0,4133 0,0600 1,000 0,234 0,010
2500 К 0,4770 0,4137 0,1093 1,000 0,349 0,067
3000 К 0,4369 0,4041 0.1590 1.000 0.454 0.151
3500 K 0.4053 0.3907 0.2040 1.000 0.549 0.254
4000 K 0.3805 0.3768 0.2428 1.000 0.635 0.370
4500 K 0.3608 0.3636 0.2756 1.000 0.710 0.493
5000 K 0.3451 0.3516 0.3032 1.000 0.778 0.620
5500 K 0.3325 0.3411 0.3265 1.000 0.837 0.746
6000 K 0.3221 0.3318 0.3461 1.000 0,890 0,869
6500 К 0,3135 0,3237 0,3628 1,000 0,937 0,988
7000 К 0,3064 0,3166 0,3770 0,907 0,888 1,000
7500 К 0,3004 0,3103 0 .3893 0,827 0,839 1,000
8000 К 0,2952 0,3048 0 .4000 0.762 0.800 1.000
8500 К 0.2908 0.3000 0.4093 0.711 0.766 1.000
9000 К 0,2869 0,2956 0,4174 0,668 0,738 1,000
9500 К 0,2836 0,2918 0,4246 0,632 0,714 1,000
10000 К 0,2807 0,2884 0,4310 0,602 0,693 1,000
*/
int main() { double t, x, y, z, r, g, b; struct colorSystem *cs = &SMPTEsystem;
printf("Температура xyz RGB\n");
printf("----------- ------ ------ ------ ----- ----- -----\n" );
for (t = 1000; t <= 10000; t+= 500) {
bbTemp = t;
Spectrum_to_xyz(bb_spectrum, &x, &y, &z);
xyz_to_rgb(cs, x, y, z, &r, &g, &b);
printf(" %5.0f K %.4f %.4f %.4f ", t, x, y, z);
if (constrain_rgb(&r, &g, &b)) {
normal_rgb(&r, &g, &b);
printf("%.3f %.3f %.3f (Приближение)\n", r, g, b);
} Еще {
normal_rgb(&r, &g, &b);
printf("%.3f %.3f %.3f\n", r, g, b);
}
}
вернуть 0;
}