00001 #include <cmath>
00002
00003 #include <FCam/Event.h>
00004
00005 namespace FCam {
00006
00007 const float RGBtoXYZ[9] = {
00008 0.4124564, 0.3575761, 0.1804375,
00009 0.2126729, 0.7151522, 0.0721750,
00010 0.0193339, 0.1191920, 0.9503041
00011 };
00012
00013 int xyToCCT(float x, float y) {
00014 const float x_e = 0.3366;
00015 const float y_e = 0.1735;
00016 const float A0 = -949.86315;
00017 const float A1 = 6253.80338;
00018 const float t1 = 0.92159;
00019 const float A2 = 28.70599;
00020 const float t2 = 0.20039;
00021 const float A3 = 0.00004;
00022 const float t3 = 0.07125;
00023
00024 float n = (x - x_e)/(y - y_e);
00025
00026 float CCT = A0 + A1 * std::exp(-n/t1) + A2 * std::exp(-n/t2) + A3 * std::exp(-n/t3);
00027 if (CCT < 3000 || CCT > 50000) {
00028 warning(Event::OutOfRange, "xyToCCT: Conversion only accurate within 3000 to 50000K, result was %d K.\n", CCT);
00029 }
00030 return std::floor(CCT+0.5f);
00031 }
00032
00033 void kelvinToXY(int T, float *x, float *y) {
00034 if (!x || !y) return;
00035
00036 if (T < 1667 || T > 25000) {
00037 warning(Event::OutOfRange, "KelvinToXY: Conversion only accurate within 1667K to 25000K, requested %d K\n", T);
00038 }
00039
00040 const float A_x00 = -0.2661239;
00041 const float A_x01 = -0.2343580;
00042 const float A_x02 = 0.8776956;
00043 const float A_x03 = 0.179910;
00044
00045 const float A_x10 = -3.0258469;
00046 const float A_x11 = 2.1070379;
00047 const float A_x12 = 0.2226347;
00048 const float A_x13 = 0.24039;
00049
00050 const float A_y00 = -1.1063814;
00051 const float A_y01 = -1.34811020;
00052 const float A_y02 = 2.18555832;
00053 const float A_y03 = -0.20219683;
00054
00055 const float A_y10 = -0.9549476;
00056 const float A_y11 = -1.37418593;
00057 const float A_y12 = 2.09137015;
00058 const float A_y13 = -0.16748867;
00059
00060 const float A_y20 = 3.0817580;
00061 const float A_y21 = -5.87338670;
00062 const float A_y22 = 3.75112997;
00063 const float A_y23 = -0.37001483;
00064
00065 float invKiloK = 1000.f/T;
00066 float xc, yc;
00067 if (T <= 4000) {
00068 xc = A_x00*invKiloK*invKiloK*invKiloK +
00069 A_x01*invKiloK*invKiloK +
00070 A_x02*invKiloK +
00071 A_x03;
00072 } else {
00073 xc = A_x10*invKiloK*invKiloK*invKiloK +
00074 A_x11*invKiloK*invKiloK +
00075 A_x12*invKiloK +
00076 A_x13;
00077 }
00078
00079 if (T <= 2222) {
00080 yc = A_y00*xc*xc*xc +
00081 A_y01*xc*xc +
00082 A_y02*xc +
00083 A_y03;
00084 } else if (T <= 4000) {
00085 yc = A_y10*xc*xc*xc +
00086 A_y11*xc*xc +
00087 A_y12*xc +
00088 A_y13;
00089 } else {
00090 yc = A_y20*xc*xc*xc +
00091 A_y21*xc*xc +
00092 A_y22*xc +
00093 A_y23;
00094 }
00095
00096 *x = xc;
00097 *y = yc;
00098
00099 }
00100
00101 void invert3x3(float *in, float *out) {
00102 out[0] = in[4]*in[8]-in[5]*in[7];
00103 out[3] = in[5]*in[6]-in[3]*in[8];
00104 out[6] = in[3]*in[7]-in[4]*in[6];
00105
00106 float invdet = 1.0f/(in[0]*out[0] + in[1]*out[3] + in[2]*out[6]);
00107
00108 out[0] *= invdet;
00109 out[3] *= invdet;
00110 out[6] *= invdet;
00111
00112 out[1] = invdet*(in[7]*in[2]-in[8]*in[1]);
00113 out[4] = invdet*(in[8]*in[0]-in[6]*in[2]);
00114 out[7] = invdet*(in[6]*in[1]-in[7]*in[0]);
00115
00116 out[2] = invdet*(in[1]*in[5]-in[2]*in[4]);
00117 out[5] = invdet*(in[2]*in[3]-in[0]*in[5]);
00118 out[8] = invdet*(in[0]*in[4]-in[1]*in[3]);
00119
00120 }
00121
00122 void invert3x3(double *in, double *out) {
00123 out[0] = in[4]*in[8]-in[5]*in[7];
00124 out[3] = in[5]*in[6]-in[3]*in[8];
00125 out[6] = in[3]*in[7]-in[4]*in[6];
00126
00127 double invdet = 1.0/(in[0]*out[0] + in[1]*out[3] + in[2]*out[6]);
00128
00129 out[0] *= invdet;
00130 out[3] *= invdet;
00131 out[6] *= invdet;
00132
00133 out[1] = invdet*(in[7]*in[2]-in[8]*in[1]);
00134 out[4] = invdet*(in[8]*in[0]-in[6]*in[2]);
00135 out[7] = invdet*(in[6]*in[1]-in[7]*in[0]);
00136
00137 out[2] = invdet*(in[1]*in[5]-in[2]*in[4]);
00138 out[5] = invdet*(in[2]*in[3]-in[0]*in[5]);
00139 out[8] = invdet*(in[0]*in[4]-in[1]*in[3]);
00140
00141 }
00142
00143 void colorMatrixInterpolate(const float *a, const float *b, float alpha, float *result) {
00144
00145 if (alpha == 0.f) {
00146 for (int i=0; i < 12; i++) result[i] = a[i];
00147 return;
00148 }
00149 if (alpha == 1.f) {
00150 for (int i=0; i < 12; i++) result[i] = b[i];
00151 return;
00152 }
00153
00154 for (int i = 0; i < 12; i++) {
00155 result[i] = (1-alpha)*a[i] + alpha*b[i];
00156 }
00157
00158
00159 float rowSum[3] = {result[0] + result[1] + result[2],
00160 result[4] + result[5] + result[6],
00161 result[8] + result[9] + result[10]};
00162 float scale = 1.0f;
00163 if (rowSum[0] < rowSum[1] && rowSum[0] < rowSum[2]) {
00164 scale = 1.0f/rowSum[0];
00165 } else if (rowSum[1] < rowSum[2]) {
00166 scale = 1.0f/rowSum[1];
00167 } else {
00168 scale = 1.0f/rowSum[2];
00169 }
00170
00171 for (int j = 0; j < 3; j++) {
00172 for (int i = 0; i < 3; i++) {
00173 result[j*4+i] *= scale;
00174 }
00175 }
00176
00177 }
00178
00179 }