Skip to content

fourmilab

Bankn8II©$A edited this page Apr 12, 2024 · 1 revision

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; 

}

Clone this wiki locally