用C语言实现LED全彩屏的Gamma校正:让显示色彩还原更精准
LED全彩屏直接把8位RGB写进PWM/驱动IC,颜色基本都会偏:暗部太暗、中间调跳变、白平衡发飘。根因是LED电光响应不是线性的,人眼对暗部变化又更敏感,数据为“128”并不等于“半亮”。 Gamma校正就是提前把输入灰度按非线性曲线补偿,让屏上亮度变化接近人眼线性感知。
一、为什么必须做Gamma
假设RGB=128发给屏,没校正时实际发光可能只到20%出头,灰阶过渡像被“压扁”;校正后:
暗部细节拉开,低灰不并阶
中间调平滑,渐变不发块
白平衡在不同灰度下更稳定
LED屏Gamma系数不是固定2.2照搬显示器:
室内屏:2.2~2.4
户外强光:2.4~2.6
灯珠批次差/驱动位深低:实测标定
二、查表法代替实时pow
每像素算 pow(x/255, gamma) 在MCU上太贵,标准做法是预生成256项LUT:
#define GAMMA 2.4
static uint8_t gamma_r[256];
static uint8_t gamma_g[256];
static uint8_t gamma_b[256];
void gamma_table_init(void){
for(int i=0;i<256;i++){
/* 8位输出示例;12/16bit PWM把255换成4095/65535 */
gamma_r[i] = (uint8_t)(pow((double)i/255.0, GAMMA)*255.0 + 0.5);
gamma_g[i] = (uint8_t)(pow((double)i/255.0, GAMMA)*255.0 + 0.5);
gamma_b[i] = (uint8_t)(pow((double)i/255.0, GAMMA)*255.0 + 0.5);
}
}
表里头几项是0、中段爬升慢、高端拉开——这正是人眼感知曲线。
工程上表可用Python算好直接贴成const数组,固件里零浮点运算。
三、写屏前查表
像素缓冲里存“逻辑色”,真正发驱动前过一遍LUT:
typedef struct { uint8_t r,g,b; } rgb_t;
void led_set_pixel(int x,int y, rgb_t c){
rgb_t out;
out.r = gamma_r[c.r];
out.g = gamma_g[c.g];
out.b = gamma_b[c.b];
panel_write(x,y,out); // 送接收卡/驱动IC
}
整屏刷新时别逐像素重复算,只做数组下标:
fb_out[i] = gamma_r[fb_in[i].r];
单像素成本就是三次查表,O(1)。
四、RGB三通道分开校正
红绿蓝LED发光效率不一样,同值128下绿最亮、蓝最暗,只用一张表白平衡会偏蓝/偏绿。正确是三张表,或在LUT后乘通道增益:
#define R_GAIN 255
#define G_GAIN 180
#define B_GAIN 220
out.r = gamma_r[c.r];
out.g = (gamma_g[c.g]*G_GAIN)>>8;
out.b = (gamma_b[c.b]*B_GAIN)>>8;
产线标定流程:
显示白场255
色度计测RGB实际亮度比
反推各通道gain
写进参数区
高端屏控系统甚至R/G/B各一套Gamma曲线,避免低灰白平衡漂移。
五、位深别只卡8位
8位LUT进8位PWM,低灰段会“并阶”:输入1~10映射完全是同一个PWM值,暗部反而不顺。
驱动支持12bit(4096)或16bit(65535)时,LUT输出也扩到对应位深:
static uint16_t gamma_16[256];
gamma_16[i] = (uint16_t)(pow(i/255.0,GAMMA)*65535.0 + 0.5);
中间处理用12/16bit,最后按驱动截断,灰阶过渡明显更细。
六、顺序别搞反
常见错误:先Gamma再HSV转换、或动画插值在校正后做。
正确流水线:
算目标颜色(HSV→RGB / 渐变插值)
得逻辑RGB 0~255
过Gamma LUT
写屏缓冲
顺序反了渐变会偏暗、色相漂移。
七、落坑清单
每帧pow→CPU白耗,必卡
单张Gamma表→白平衡低灰偏色
Gamma设3.0以上→暗部发脏、噪点放大
8位进8位PWM→低灰并阶
先校正再插值→渐变颜色歪
LUT没按批次标→换灯板色温飘
逻辑色直接存驱动缓冲→后续混合再校正全乱
只校正不白平衡→白场仍偏
八、量产落地顺序
确定屏目标Gamma(室内2.2~2.4)
离线生成RGB三张LUT
固件init装载,flash存参数
帧缓冲存“未校正逻辑色”
刷屏DMA前批量查表
通道gain按白平衡标
驱动位深12/16bit优先
老化后复校(RGB衰减不一致)
LED全彩屏Gamma校正本质就一句:逻辑色和物理PWM之间加一层非线性映射。C语言实现不需要公式运算,一张256项LUT把“人眼感知”翻译成“LED该发多少”,再补RGB通道增益,暗部不并、白场不飘、渐变顺滑。显示颜色准不准,往往不是灯的问题,是没在校正层把非线性补掉。





