如何从Philips Hue中的ct获取XY值?

如何解决如何从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不会位于简单的向量上。

enter image description here

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-ctCCT
CCTx,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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?