OpenGL YUV 和 RGB 图像转换出现偏色问题怎么解决?

OpenGL YUV 和 RGB 图像转换出现偏色问题怎么解决? thatk 2023-12-22 10:53:00 819

省流版

直接贴出来更精确的转换公式:

vec3 rgb2yuv(vec3 rgb) {
    float y =  0.257 * rgb.r + 0.504 * rgb.g + 0.098 * rgb.b;
    float u = -0.148 * rgb.r - 0.291 * rgb.g + 0.439 * rgb.b;
    float v =  0.439 * rgb.r - 0.368 * rgb.g - 0.071 * rgb.b;
    return vec3(y,u,v);
}


float y = texture2D(texture0, uv).r - 0.063;
float v = texture2D(texture1, uv).r - 0.502;
float u = texture2D(texture2, uv).r - 0.502;

vec3 yuv = vec3(y,u,v);

vec3 yuv2rgb(vec3 yuv) {
    float r = 1.164 * yuv.x + 1.596 * yuv.z;
    float g = 1.164 * yuv.x - 0.392 * yuv.y - 0.813 * yuv.z;
    float b = 1.164 * yuv.x + 2.017 * yuv.y;
    return vec3(r,g,b);
}

刨根问底版

理论上,rgb2yuv 和 yuv2rgb 的转换是可逆的,也就是说,它们可以完美地还原图像,不会引入信息损失,类似于纯粹的数学运算 1+2=3,3-2=1 。

但是在实际情况中,由于计算机表示的精度有限、采样误差以及浮点运算的限制,转换过程中会导致信息损失。但是这个误差要是控制在肉眼无法辨别的范围还是很容易的。

基于上面分析,偏色的根本原因其实就是转换时的精度误差,解决办法就是提高精度(小数点后多精确几位),让误差在人眼无法分辨的范围。

下面来做个试验,利用上面的公式,我们对一张图片反复做多次 rgb2yuv 和 yuv2rgb 转换,然后看下最终图像颜色的变化。

测试代码:

#iChannel0 "https://img-baofun.zhhainiao.com/pcwallpaper_ugc_mobile/static/2ddf8479959f1f3d9f52d0d561d281fe.jpg"

vec3 rgb2yuv(vec3 rgb) {
    float y =  0.257 * rgb.r + 0.504 * rgb.g + 0.098 * rgb.b;
    float u = -0.148 * rgb.r - 0.291 * rgb.g + 0.439 * rgb.b;
    float v =  0.439 * rgb.r - 0.368 * rgb.g - 0.071 * rgb.b;
    return vec3(y,u,v);
}

vec3 yuv2rgb(vec3 yuv) {
    float r = 1.164 * yuv.x + 1.596 * yuv.z;
    float g = 1.164 * yuv.x - 0.392 * yuv.y - 0.813 * yuv.z;
    float b = 1.164 * yuv.x + 2.017 * yuv.y;
    return vec3(r,g,b);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;

    float N = 4000.0;

    vec4 col = texture2D(iChannel0, uv);;

    if(uv.x > 0.5) {
        while(N > 0.0) {
            N--;
            vec3 yuv = rgb2yuv(col.rgb);
            col.rgb = yuv2rgb(yuv);
        }
    }

    fragColor = col;
}

N=10,只做 10 次 yuv 和 rgb 的来回转换,效果如下,这时肉眼已经无法区分颜色的误差。

N=4000,做 4000 次 yuv 和 rgb 的来回转换放大误差,效果如下,这时由于误差不断累计,出现了明显的偏色。不过,转换 4000 次这种操作在实际情况下不太可能出现。

另外,除了小数点后多精确几位,shader 里面的 float 也要声明为高精度:

precision highp float;

OpenGL ES 3.x GL_EXT_YUV_target 扩展,也提供了内置的颜色空间转换函数(推荐使用),精度更高,可以选择不同的转换标准,如:

    yuvCscStandardEXT conv_standard = itu_601;
    yuvCscStandardEXT conv_standard = itu_601_full_range;
    yuvCscStandardEXT conv_standard = itu_709;

贴一个源码展示下内置颜色空间转换函数使用方法。

#version 300 es
#extension GL_EXT_YUV_target: require
precision mediump float;
in vec2 v_texCoord;
layout(yuv) out vec4 outColor;
uniform sampler2D s_TextureMap;
void main()
{
    yuvCscStandardEXT conv_standard = itu_709;
    vec4 rgbaColor = texture(s_TextureMap, v_texCoord);
    vec3 rgbColor = vec3(rgbaColor.r, rgbaColor.g, rgbaColor.b);
    vec3 yuv = rgb_2_yuv(rgbColor, conv_standard);
    outColor = vec4(yuv, 1.0);
}
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
thatk
红包 2 1 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
thatk
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区