Java RGB至飞利浦色调(HSB)
我正在制作一个音乐播放器来处理学校的作业。飞利浦色调灯将产生一些相应的视觉效果。 我想让每首歌的视觉效果都与众不同。 因此,我获取了播放曲目的封面艺术(使用LastFM API)以获得最常用的颜色,并将其用作创建其他颜色的基础。 飞利浦色调有一种不同的显示颜色的方式,即HSB。所以我通过Java RGB至飞利浦色调(HSB),java,colors,processing,philips-hue,Java,Colors,Processing,Philips Hue,我正在制作一个音乐播放器来处理学校的作业。飞利浦色调灯将产生一些相应的视觉效果。 我想让每首歌的视觉效果都与众不同。 因此,我获取了播放曲目的封面艺术(使用LastFM API)以获得最常用的颜色,并将其用作创建其他颜色的基础。 飞利浦色调有一种不同的显示颜色的方式,即HSB。所以我通过 Color.RGBtoHSB() 例如,它给出了R=127,G=190,B=208的值H=0.5370371,S=0.38942307,B=0.8156863。现在我猜它们是在1的基础上计算的,所以我把亮度乘以
Color.RGBtoHSB()代码>
例如,它给出了R=127,G=190,B=208的值H=0.5370371,S=0.38942307,B=0.8156863。现在我猜它们是在1的基础上计算的,所以我把亮度乘以255。色调是65535。
(如图所示)
在飞利浦色调中设置这些计算值时,无论播放什么歌曲,颜色始终为redish或白色
RGB到HSB之间的转换是否出现问题
应大众要求,我的代码:
作为测试:
Color c = Colorconverter.getMostCommonColour("urltoimage");
float[] f = Colorconverter.getRGBtoHSB(c);
ArrayList<Lamp> myLamps = PhilipsHue.getInstance().getMyLamps();
State state = new State();
state.setBri((int) Math.ceil(f[2]*255));
state.setSat((int) Math.ceil(f[1]*255));
state.setHue((int) Math.ceil(f[0]*65535));
state.setOn(true);
PhilipsHue.setState(myLamps.get(1), state);
作为HSB,您的RGB应分别为193度、39%和82%。所以至少S和B看起来是正确的。查看Philips hue API文档,将这些数字乘以255是正确的
要以度的形式获得H值,请将计算出的H值乘以360。这就是你如何到达193的原因。获得学位后,乘以182得到应发送至飞利浦色调API的值(从):
与使用*65535
方法获得的H值相比,这会给您带来不同的H值。我认为这里的问题是,它含有大量的红色和紫色,但不能在蓝绿色区域产生足够的饱和度
我建议将饱和度设置为最大值255,并且只改变色调
根据文档中给出的表格,色调的“色调”属性不会直接映射到HSV的色调。近似值可能足够接近,但如果不接近,则可能值得尝试一次,然后设置“xy”属性而不是色调。特别感谢StackOverflow用户Gee858eeG注意到我的打字错误和Erickson提供的大量提示和链接
这是一个工作函数,用于将任何RGB颜色转换为Philips色调XY值。返回的列表只包含两个元素,0是X,1是Y。
代码基于以下精彩注释:
尽管这不会返回HSB值,但XY值可以用来替代色调上的颜色变化。希望它能对其他人有所帮助,因为飞利浦的API没有提到任何公式
public static List<Double> getRGBtoXY(Color c) {
// For the hue bulb the corners of the triangle are:
// -Red: 0.675, 0.322
// -Green: 0.4091, 0.518
// -Blue: 0.167, 0.04
double[] normalizedToOne = new double[3];
float cred, cgreen, cblue;
cred = c.getRed();
cgreen = c.getGreen();
cblue = c.getBlue();
normalizedToOne[0] = (cred / 255);
normalizedToOne[1] = (cgreen / 255);
normalizedToOne[2] = (cblue / 255);
float red, green, blue;
// Make red more vivid
if (normalizedToOne[0] > 0.04045) {
red = (float) Math.pow(
(normalizedToOne[0] + 0.055) / (1.0 + 0.055), 2.4);
} else {
red = (float) (normalizedToOne[0] / 12.92);
}
// Make green more vivid
if (normalizedToOne[1] > 0.04045) {
green = (float) Math.pow((normalizedToOne[1] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
green = (float) (normalizedToOne[1] / 12.92);
}
// Make blue more vivid
if (normalizedToOne[2] > 0.04045) {
blue = (float) Math.pow((normalizedToOne[2] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
blue = (float) (normalizedToOne[2] / 12.92);
}
float X = (float) (red * 0.649926 + green * 0.103455 + blue * 0.197109);
float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598);
float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763);
float x = X / (X + Y + Z);
float y = Y / (X + Y + Z);
double[] xy = new double[2];
xy[0] = x;
xy[1] = y;
List<Double> xyAsList = Doubles.asList(xy);
return xyAsList;
}
公共静态列表getRGBtoXY(c色){
//对于色调灯泡,三角形的角是:
//-红色:0.675,0.322
//-绿色:0.4091,0.518
//-蓝色:0.167,0.04
double[]normalizedToOne=新的double[3];
浮动信用、绿色、蓝色;
cred=c.getRed();
cgreen=c.getGreen();
cblue=c.getBlue();
标准化TONE[0]=(cred/255);
normalizedToOne[1]=(cgreen/255);
标准化TONE[2]=(cblue/255);
漂浮着红、绿、蓝;
//使红色更生动
如果(标准化TONE[0]>0.04045){
红色=(浮点)Math.pow(
(标准化TONE[0]+0.055)/(1.0+0.055),2.4);
}否则{
红色=(浮动)(标准化TONE[0]/12.92);
}
//使绿色更生动
如果(标准化TONE[1]>0.04045){
绿色=(浮点)数学功率((标准化TONE[1]+0.055)
/ (1.0 + 0.055), 2.4);
}否则{
绿色=(浮动)(标准化TONE[1]/12.92);
}
//使蓝色更生动
如果(标准化TONE[2]>0.04045){
蓝色=(浮点)数学功率((标准化TONE[2]+0.055)
/ (1.0 + 0.055), 2.4);
}否则{
蓝色=(浮动)(标准化TONE[2]/12.92);
}
浮动X=(浮动)(红色*0.649926+绿色*0.103455+蓝色*0.197109);
浮动Y=(浮动)(红色*0.234327+绿色*0.743075+蓝色*0.022598);
浮动Z=(浮动)(红色*0.0000000+绿色*0.053077+蓝色*1.035763);
浮动x=x/(x+Y+Z);
浮动y=y/(X+y+Z);
double[]xy=新的double[2];
xy[0]=x;
xy[1]=y;
List xyAsList=双倍。asList(xy);
返回xyAsList;
}
HSB值看起来正确。我去了colorpicker.com。它接受的H、S、B的最大值为360、100、100(如Gary所说),因此您的值转换为H=193、S=39、B=82,显示为蓝色,RGB非常接近您的原始值。我会仔细检查硬件文档,找出它期望的值(最重要的是,值的范围)。@GaryKlasen否,使用0-255的值表示亮度和饱和度,0-65535的值表示色调角度。而不是使用从RGB计算的值来测试灯光,尝试对已知颜色的HSB值进行硬编码,并确保灯光正常工作。换言之,通过确定转换是否错误,或者与灯的通信是否中断来隔离问题。我不是说灯泡坏了,而是质疑错误是否在转换中或稍后的代码。划分搜索空间的简单测试是基本的调试策略。发布一篇文章,因为对代码的描述和结果不匹配。确实离题了,但还是忍不住:编写一个灯泡需要多少程序员Pd不同,但仅取决于您引入的舍入误差。RGB到HSB转换返回的色调值是0–1之间的浮点值。0.5370371*65535=35195,接近通过四舍五入色调角度(193.33)和转换因子(182.04)得到的35126值。谢谢!但飞利浦的灯泡仍然显示出白色,而不是colorpicker.com上显示的蓝色。飞利浦API表示色调值是介于0和65535之间的包装值。0和65535都是红色,25500是绿色,46920是蓝色。我的值应该接近46920。如果我做你的计算。0.5370371*360°=193.333356 mul
{
"state": {
"on": true,
"bri": 81,
"hue": 34277,
"sat": 18,
"xy": [
0.298,
0.2471
],
"ct": 153,
"alert": "none",
"effect": "none",
"colormode": "hs",
"reachable": true
},
"type": "Extended color light",
"name": "Hue Spot 1",
"modelid": "LCT003",
"swversion": "66010732",
"pointsymbol": {
"1": "none",
"2": "none",
"3": "none",
"4": "none",
"5": "none",
"6": "none",
"7": "none",
"8": "none"
}
}
hue
The parameters 'hue' and 'sat' are used to set the colour
The 'hue' parameter has the range 0-65535 so represents approximately
182*degrees (technically 182.04 but the difference is imperceptible)
public static List<Double> getRGBtoXY(Color c) {
// For the hue bulb the corners of the triangle are:
// -Red: 0.675, 0.322
// -Green: 0.4091, 0.518
// -Blue: 0.167, 0.04
double[] normalizedToOne = new double[3];
float cred, cgreen, cblue;
cred = c.getRed();
cgreen = c.getGreen();
cblue = c.getBlue();
normalizedToOne[0] = (cred / 255);
normalizedToOne[1] = (cgreen / 255);
normalizedToOne[2] = (cblue / 255);
float red, green, blue;
// Make red more vivid
if (normalizedToOne[0] > 0.04045) {
red = (float) Math.pow(
(normalizedToOne[0] + 0.055) / (1.0 + 0.055), 2.4);
} else {
red = (float) (normalizedToOne[0] / 12.92);
}
// Make green more vivid
if (normalizedToOne[1] > 0.04045) {
green = (float) Math.pow((normalizedToOne[1] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
green = (float) (normalizedToOne[1] / 12.92);
}
// Make blue more vivid
if (normalizedToOne[2] > 0.04045) {
blue = (float) Math.pow((normalizedToOne[2] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
blue = (float) (normalizedToOne[2] / 12.92);
}
float X = (float) (red * 0.649926 + green * 0.103455 + blue * 0.197109);
float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598);
float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763);
float x = X / (X + Y + Z);
float y = Y / (X + Y + Z);
double[] xy = new double[2];
xy[0] = x;
xy[1] = y;
List<Double> xyAsList = Doubles.asList(xy);
return xyAsList;
}