【RGB=HSI】单片机控制RGB单灯与HSI互转算法

最近在做一个RGB补光灯的小玩意儿,项目上有一个OLED屏幕显示当前灯光的HSI参数,对于HSI我是完全陌生的,由于时间紧任务重,我也没想过去百度一下HSI是个啥,直接拿着样品测试了一组参数,自己去演算了一个HSI转RGB的函数,虽然花了不少时间,还存在一点误差,误差主要是范围的问题,RGB的范围应该是0-255,我演算的时候为了方便计算将范围设置为0-100,最终结果算是好的吧。

但是在RGB转HSI的时候,已经没有时间去推算了,这才想起来去请教身边的一位大佬,这才知道HSI颜色模型是个啥,还给我普及了这个互转算法,拿来给我优化使用,在这记录一下优化后C语言写法,随便参考一下百科对HSI的介绍,加深理解。

HSI〔Hue-Saturation-Intensity(Lightness),HSI或HSL〕颜色模型用H、S、I三参数描述颜色特性,其中H定义颜色的频率,称为色调;S表示颜色的深浅程度,称为饱和度;I表示强度或亮度。

HSI 颜色模型中的H 分量是确定颜色的主要因素,当它发生变化时色调值也将变化;S 分量越大(接近1),颜色越纯,S 分量越小(接近0),颜色越接近纯灰色

 C语言代码实现:

/**
     * HSV -> RGB.
     * @param hue Hue.In the range[0..360]
     * @param saturation Saturation. In the range[0..100].
     * @param value Value. In the range[0..100].
     * @return RGB color space. In the range[0..255].
     */
u8 *HSVtoRGB(u16 h, u16 s, u16 i)
{
    static u8 rgb[3] = {0};
    float hue = (float)h;
    float saturation = (float)(s/100.0);
    float value = (float)(i/100.0);
    float hi= (float)((u32)(hue / 60.0) % 6);
    float f = (float)((hue / 60.0) - (u32)(hue / 60.0));
    float p = (float)(value * (1.0 - saturation));
    float q = (float)(value * (1.0 - (f * saturation)));
    float t = (float)(value * (1.0 - ((1.0 - f) * saturation)));

    if (hi == 0){
        rgb[0] = (int)(value * 255);
        rgb[1] = (int)(t * 255);
        rgb[2] = (int)(p * 255);
    }
    else if (hi == 1){
        rgb[0] = (int)(q * 255);
        rgb[1] = (int)(value * 255);
        rgb[2] = (int)(p * 255);
    }
    else if (hi == 2){
        rgb[0] = (int)(p * 255);
        rgb[1] = (int)(value * 255);
        rgb[2] = (int)(t * 255);
    }
    else if (hi == 3){
        rgb[0] = (int)(p * 255);
        rgb[2] = (int)(value * 255);
        rgb[1] = (int)(q * 255);
    }
    else if (hi == 4){
        rgb[0] = (int)(t * 255);
        rgb[2] = (int)(value * 255);
        rgb[1] = (int)(p * 255);
    }
    else if (hi == 5){
        rgb[0] = (int)(value * 255);
        rgb[1] = (int)(p * 255);
        rgb[2] = (int)(q * 255);
    }
    return rgb;
}

#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
/**
 * RGB -> HSV.
 * Adds (hue + 360) % 360 for represent hue in the range [0..359].
 * @param red Red coefficient. Values in the range [0..255].
 * @param green Green coefficient. Values in the range [0..255].
 * @param blue Blue coefficient. Values in the range [0..255].
 * @return HSV color space.
 */
int *RGBtoHSV(u16 r, u16 g, u16 b)
{
    static int hsv[3] = {0};
    int max = MAX(r,MAX(g,b));
    int min = MIN(r,MIN(g,b));
    int delta = max - min;

    // Hue
    if (max == min){
        hsv[0] = 0;
    }
    else if (max == r){
        hsv[0] = (60*(g - b) / delta);
    }
    else if (max == g){
        hsv[0] = (60*(b - r) / delta) + 120;
    }
    else if (max == b){
        hsv[0] = (60*(r - g) / delta) + 240;
    }
    if(hsv[0] < 0) {
       hsv[0] += 360;
    }
    // Saturation
    if (delta == 0)
        hsv[1] = 0;
    else
        hsv[1] = (100*delta/ max);

    //Value
    hsv[2] = 100*max/255;
    return hsv;
}

最后说明一下,关于HSI算法模型的资料网上确实有很多,我这个只是单灯互转的小需求,所以也没花太多时间去整理,只是去实现了最简单的功能,还有就是我的工程对float的处理不是那么友好,在传参时都转成了整数处理,在测试到一些特定值的转换结果会出现一点点误差,在此请教各路大佬,有没有更好的优化方法或者代码实现。

猜你喜欢

转载自blog.csdn.net/Main_BUG/article/details/124703456
HSI