技术专栏
OpenGL YUV 和 RGB 图像转换出现偏色问题怎么解决?
省流版
直接贴出来更精确的转换公式:
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);
}
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包
2
1
评论
打赏
- 分享
- 举报
评论
0个
手气红包
暂无数据
相关专栏
-
浏览量:7899次2024-01-04 14:35:55
-
浏览量:1243次2023-10-09 19:22:39
-
浏览量:3464次2022-05-17 16:45:07
-
浏览量:969次2023-12-11 11:01:31
-
浏览量:2330次2020-08-05 20:49:45
-
浏览量:3114次2021-12-04 14:07:38
-
浏览量:1257次2023-10-13 10:07:11
-
浏览量:1863次2023-10-26 11:47:50
-
2024-02-01 15:28:12
-
浏览量:1440次2023-03-20 17:36:05
-
浏览量:2573次2020-08-03 19:57:19
-
浏览量:1233次2024-02-22 15:52:02
-
2020-10-21 11:35:55
-
浏览量:1588次2019-12-23 09:44:21
-
浏览量:7814次2017-11-16 16:26:57
-
浏览量:3926次2020-12-23 17:19:19
-
浏览量:2111次2020-09-27 14:08:50
-
浏览量:2083次2018-02-02 22:30:36
-
浏览量:1614次2018-04-12 15:32:47
置顶时间设置
结束时间
删除原因
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
打赏作者
thatk
您的支持将鼓励我继续创作!
打赏金额:
¥1
¥5
¥10
¥50
¥100
支付方式:
微信支付
打赏成功!
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
审核成功
发布时间设置
发布时间:
请选择发布时间设置
是否关联周任务-专栏模块
审核失败
失败原因
请选择失败原因
备注
请输入备注