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