如何解决如何从Philips Hue中的ct获取XY值?
如何从ct获取XY值。
例如: ct = 217,我想得到x =“ 0.3127569”,y =“ 0.32908”。
我可以使用以下代码将XY值转换为ct值。
float R1 = [hue[0] floatValue];
float S1 = [hue[1] floatValue];
float result = ((R1-0.332)/(S1-0.1858));
Nsstring *ctString = [Nsstring stringWithFormat:@"%f",((-449*result*result*result)+(3525*result*result)-(6823.3*result)+(5520.33))];
float micro2 = (float) (1 / [ctString floatValue] * 1000000);
Nsstring *ctValue = [Nsstring stringWithFormat:@"%f",micro2];
ctValue = [Nsstring stringWithFormat:@"%d",[ctValue intValue]];
if ([ctValue integerValue] < 153) {
ctValue = [Nsstring stringWithFormat:@"%d",153];
}
现在我想要取反数值,从ct到XY。
解决方法
在Phillips HUE上
在色ct
中将2000K映射为500,将6500K映射为153
,但可以认为实际上是Mired
。
“已死”表示micro reciprocal degree
wikipedia。
可能会使用
ct
,因为它不是100%残缺的。可以肯定Phillips像许多CIE算法一样使用查找表,因为从153到500范围内只有347个索引。
以下不是解决方案,它只是查找表的简单概念。 正如McCamy的CIE 1931 xy转换为CCT公式所建议的found here,也可以使用查找表来查找x和y。 可以找到一个表here,但我不确定这是否是正确的查找表。
提醒,因此以下并不是解决方案,但是找到反向算法可能会对代码有所帮助。
typedef int Kelvin;
typedef float Mired;
Mired linearMiredByKelvin(Kelvin k) {
if (k==0) return 0;
return 1000000.0/k;
}
-(void)mired {
Mired miredMin = 2000.0/13.0; // 153,84 = reciprocal 6500K
Mired miredMax = 500.0; // 500,00 = reciprocal 2000K
Mired lookupMiredByKelvin[6501]; //max 6500 Kelvin + 1 safe index
//Kelvin lookupKelvinByMired[501]; //max 500 Mired + 1 safe index
// dummy stuff,empty unused table space
for (Kelvin k = 0; k < 2000; k++) {
lookupMiredByKelvin[k] = 0;
}
//for (Mired m = 0.0; m < 154.0; m++) {
// lookupKelvinByMired[(int)m] = 0;
//}
for (Kelvin k=2000; k<6501; k++) {
Mired linearMired = linearMiredByKelvin(k);
float dimm = (linearMired - miredMin) / ( miredMax - miredMin);
Kelvin ct = (Kelvin)(1000000.0/(dimm*miredMax - dimm*miredMin + miredMin));
lookupMiredByKelvin[k] = linearMiredByKelvin(ct);
if (k==2000 || k==2250 || k==2500 || k==2750 ||
k==3000 || k==3250 || k==3500 || k==3750 ||
k==4000 || k==4250 || k==4500 || k==4750 ||
k==5000 || k==5250 || k==5500 || k==5750 ||
k==6000 || k==6250 || k==6500 || k==6501 )
fprintf(stderr,"%d %f %f\n",ct,dimm,lookupMiredByKelvin[k]);
}
}
至少这证明x和y不会位于简单的向量上。
CCT
的意思是correlated colour temperature
,就像问题显示中的实现一样,可以通过n= (x-0.3320)/(0.1858-y); CCT = 437*n^3 + 3601*n^2 + 6861*n + 5517
来计算。 (在McCamy之后)
但是cct=217
不在上述链接查找表的范围内。
遵循colour-science中的git-repo中的想法 并移植到C看起来像..
void CCT_to_xy_CIE_D(float cct) {
//if (CCT < 4000 || CCT > 25000) fprintf(stderr,"Correlated colour temperature must be in domain,unpredictable results may occur! \n");
float x = calculateXviaCCT(cct);
float y = calculateYviaX(x);
NSLog(@"cct=%f x%f y%f",cct,x,y);
}
float calculateXviaCCT(float cct) {
float cct_3 = pow(cct,3); //(cct*cct*cct);
float cct_2 = pow(cct,2); //(cct*cct);
if (cct<=7000)
return -4.607 * pow(10,9) / cct_3 + 2.9678 * pow(10,6) / cct_2 + 0.09911 * pow(10,3) / cct + 0.244063;
return -2.0064 * pow(10,9) / cct_3 + 1.9018 * pow(10,6) / cct_2 + 0.24748 * pow(10,3) / cct + 0.23704;
}
float calculateYviaX(float x) {
return -3.000 * pow(x,2) + 2.870 * x - 0.275;
}
CCT_to_xy_CIE_D(6504.38938305); //proof of concept
//cct=6504.389160 x0.312708 y0.329113
CCT_to_xy_CIE_D(217.0);
//cct=217.000000 x-387.131073 y-450722.750000
// so for sure Phillips hue temperature given in ct between 153-500 is not a good starting point
//but
CCT_to_xy_CIE_D(2000.0);
//cct=2000.000000 x0.459693 y0.410366
这在2000到25000之间的CCT中似乎可以很好地工作,但是在Celvin中给出的CCT可能令人困惑。
,编辑
这已经经历了许多修改和想法。为简单起见,我编辑了大部分内容,只是给了您最终结果。
除了中间的一个区域(温度从256到316)有一点偏差之外,这完全适合您的功能。
函数的问题是它具有大约无限的解,因此要很好地解决它,您需要更多的约束,但是呢? Ol Sen的参考文献https://www.waveformlighting.com/tech/calculate-color-temperature-cct-from-cie-1931-xy-coordinates对其进行了详细讨论,然后提到您希望Duv
为零。它还提供了一种计算Duv的方法,因此我将其添加到了优化器中,瞧!
又好又光滑。现在,优化程序可以求解既满足您的功能又使Duv最小化的x和y。
要使其正常工作,我不得不扩展Duv的比例。该页面提到Duv应该很小,所以我认为这是一件好事。另外,随着温度的升高,缩放比例应有助于优化器。
下面的打印从153到500。
#import <Foundation/Foundation.h>
// Function taken from your code
// Simplified a bit
int ctFuncI ( float x,float y )
{
// float R1 = [hue[0] floatValue];
// float S1 = [hue[1] floatValue];
float result = (x-0.332)/(y-0.1858);
float cubic = - 449 * result * result * result + 3525 * result * result - 6823.3 * result + 5520.33;
float micro2 = 1 / cubic * 1000000;
int ct = ( int )( micro2 + 0.5 );
if ( ct < 153 )
{
ct = 153;
}
return ct;
}
// Need this
// Float version of your code
float ctFuncF ( float x,float y )
{
// float R1 = [hue[0] floatValue];
// float S1 = [hue[1] floatValue];
float result = (x-0.332)/(y-0.1858);
float cubic = - 449 * result * result * result + 3525 * result * result - 6823.3 * result + 5520.33;
return 1000000 / cubic;
}
// We need an additional constraint
// https://www.waveformlighting.com/tech/calculate-duv-from-cie-1931-xy-coordinates
// Given x,y calculate Duv
// We want this to be 0
float duv ( float x,float y )
{
float f = 1 / ( - 2 * x + 12 * y + 3 );
float u = 4 * x * f;
float v = 6 * y * f;
// I'm typing float but my heart yells double
float k6 = -0.00616793;
float k5 = 0.0893944;
float k4 = -0.5179722;
float k3 = 1.5317403;
float k2 = -2.4243787;
float k1 = 1.925865;
float k0 = -0.471106;
float du = u - 0.292;
float dv = v - 0.24;
float Lfp = sqrt ( du * du + dv * dv );
float a = acos( du / Lfp );
float Lbb = k6 * pow ( a,6 ) + k5 * pow( a,5 ) + k4 * pow( a,4 ) + k3 * pow( a,3 ) + k2 * pow(a,2) + k1 * a + k0;
return Lfp - Lbb;
}
// Solver!
// Returns iterations
int ctSolve ( int ct,float * x,float * y )
{
int iter = 0;
float dx = 0.001;
float dy = 0.001;
// Error
// Note we scale duv a bit
// Seems the higher the temp,the higher scale we require
// Also note the jump at 255 ...
float s = 1000 * ( ct > 255 ? 10 : 1 );
float d = fabs( ctFuncF ( * x,* y ) - ct ) + s * fabs( duv ( * x,* y ) );
// Approx
while ( d > 0.5 && iter < 250 )
{
iter ++;
dx *= fabs( ctFuncF ( * x + dx,* y ) - ct ) + s * fabs( duv ( * x + dx,* y ) ) < d ? 1.2 : - 0.5;
dy *= fabs( ctFuncF ( * x,* y + dy ) - ct ) + s * fabs( duv ( * x,* y + dy ) ) < d ? 1.2 : - 0.5;
* x += dx;
* y += dy;
d = fabs( ctFuncF ( * x,* y ) );
}
return iter;
}
// Tester
int main(int argc,const char * argv[]) {
@autoreleasepool
{
// insert code here...
NSLog(@"Hello,World!");
float x,y;
int sume = 0;
int sumi = 0;
for ( int ct = 153; ct <= 500; ct ++ )
{
// Initial guess
x = 0.4;
y = 0.4;
// Approx
int iter = ctSolve ( ct,& x,& y );
// CT and error
int ctEst = ctFuncI ( x,y );
int e = ct - ctEst;
// Diagnostics
sume += abs ( e );
sumi += iter;
// Print out results
NSLog ( @"want ct = %d x = %f y = %f got ct %d in %d iter error %d",y,ctEst,iter,e );
}
NSLog ( @"Sum of abs errors %d iterations %d",sume,sumi );
}
return 0;
}
要使用它,请执行以下操作。
// To call it,init x and y to some guess
float x = 0.4;
float y = 0.4;
// Then call solver with your temp
int ct = 217;
ctSolve( ct,& y ); // Note you pass references to x and y
// Done,answer now in x and y
,
更紧凑的答案和来回转换的功能。
请注意,由于存在麦卡米formula的依赖和数学假设,因此存在舍入问题。因此,向后计算也是如此。
如果您想查找更多结果,直接搜索"n= (x-0.3320)/(0.1858-y); CCT = 437*n^3 + 3601*n^2 + 6861*n + 5517"
,则有很多不同的方法来回转换。
这里Phillips-Hue @[@x,@y]
至Phillips-ct
,Phillips-ct
至CCT
,CCT
至x,y
>
void CCT_to_xy_CIE_D(float cct) {
//if (CCT < 4000 || CCT > 25000) fprintf(stderr,unpredictable results may occur! \n");
float x = calculateXviaCCT(cct);
float y = calculateYviaX(x);
fprintf(stderr,"cct=%f x%f y%f",y);
}
float calculateXviaCCT(float cct) {
float cct_3 = pow(cct,2); //(cct*cct);
if (cct<=7000.0)
return -4.607 * pow(10,3) / cct + 0.23704;
}
float calculateYviaX(float x) {
return -3.000 * x*x + 2.870 * x - 0.275;
}
int calculate_PhillipsHueCT_withCCT(float cct) {
if (cct>6500.0) return 2000.0/13.0;
if (cct<2000.0) return 500.0;
//return (float) (1 / cct * 1000000); // same as..
return 1000000 / cct;
}
float calculate_CCT_withPhillipsHueCT(float ct) {
if (ct == 0.0) return 0.0;
return 1000000 / ct;
}
float calculate_CCT_withHueXY(NSArray *hue) {
float x = [hue[0] floatValue]; //R1
float y = [hue[1] floatValue]; //S1
//x = 0.312708; y = 0.329113;
float n = (x-0.3320)/(0.1858-y);
float cct = 437.0*n*n*n + 3601.0*n*n + 6861.0*n + 5517.0;
return cct;
}
// MC Camy formula n=(x-0.3320)/(0.1858-y); cct = 437*n^3 + 3601*n^2 + 6861*n + 5517;
-(void)testPhillipsHueCt_backAndForth {
NSArray *hue = @[@(0.312708),@(0.329113)];
float cct = calculate_CCT_withHueXY(hue);
float ct = calculate_PhillipsHueCT_withCCT(cct);
NSLog(@"ct %f",ct);
CCT_to_xy_CIE_D(cct); // check
CCT_to_xy_CIE_D(6504.38938305); //proof of concept
CCT_to_xy_CIE_D(2000.0);
CCT_to_xy_CIE_D(calculate_CCT_withPhillipsHueCT(217.0));
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。