使用OpenGL实现RGB到YUV图像格式转换

发布于:2024-10-24 编辑:匿名 来源:网络

面试者:请使用OpenGL实现RGB到YUV图像格式转换。我...最近有读者在后台反馈:参加面试时,面试官要求他使用shader将图像格式RGB转换为YUV。

听完后,他一脸困惑,然后愤怒地对面试官说,“他只用过shader将YUV转换为RGB,不知道RGB转换为YUV的想法是什么。”针对他的疑问,今天写一篇文章介绍如何使用OpenGL将RGB转换为YUV图像格式,帮助读者解决此类问题。

推荐YUV图像查看工具 有读者向我推荐一款YUV图像查看软件。由于手头的工具无法共享,我在Github上搜了一圈,发现这类开源软件有很多bug。

YUV查看工具 最后找到了一个免费的商业软件,YUV Viewer,用起来还可以。代码语言:txt复制,后台回复关键字yuvViewer即可获取。

好处 使用shader将RGB转YUV图像格式有哪些使用场景?它在生产环境中非常常用。上一篇文章介绍了Android OpenGL渲染图像的读取方法,分别是glReadPixels、PBO、ImageReader和HardwareBuffer。

glReadPixels经常用来读取RGBA格式的图像,那么我可以用它来读取YUV格式的图像吗?答案是肯定的,这需要使用shader将RGB图像格式转换为YUV图像格式。 glReadPixels 性能瓶颈通常出现在读取大分辨率图像时。

生产环境中常见的优化方法是在shader中将处理后的RGBA转换为YUV(通常是YUYV),然后根据RGBA格式读出YUV图像。这样,传输的数据量就会减少一半,性能会显着提升,而且不需要考虑兼容性问题。

YUV转RGB这一节首先简单介绍一下YUV转RGB的实现。在上一篇文章中,我介绍了OpenGL实现YUV渲染。

其实就是利用shader来实现YUV(NV21)到RGBA的转换,然后进行渲染。到屏幕上。

以渲染 NV21 格式的图像为例,以下是(4x4)NV21 图像的 YUV 布局: 代码语言:txt copy (0 ~ 3) Y00 Y01 Y02 Y03 (4 ~ 7) Y10 Y11 Y12 Y13 (8 ~ 11) Y20 Y21 Y22 Y23 (12 ~ 15) Y30 Y31 Y32 Y33 (16 ~ 19) V00 U00 V01 U01 (20 ~ 23) V10 U10 V11 U11YUV 渲染步骤:生成2张纹理,编译链接shader程序;确定纹理坐标和对应的顶点坐标;将NV21的两个Plane数据分别加载到2张纹理中,将纹理坐标和顶点坐标数据加载到shader程序中;画。片段着色器脚本:代码语言:txt copy #version es precisionmediump float;在 vec2 v_texCoord 中;布局(位置= 0)输出vec4 outColor;均匀采样器2D y_texture;均匀采样器2D uv_texture; void main() { vec3 yuv;yuv.x = 纹理(y_texture, v_texCoord).r; yuv.y = 纹理(uv_texture, v_texCoord).a-0.5;yuv.z = 纹理(uv_texture, v_texCoord).r-0.5;vec3 rgb =mat3( 1.0, 1.0, 1.0 , 0.0, -0., 1., 1., -0., 0.0) * yuv; outColor = vec4(rgb, 1);}y_texture 和 uv_texture 分别是 NV21 Y Plane 和 UV Plane 纹理的采样器。

纹理采样后形成一个(y,u,v)三维向量,然后将左乘变换矩阵转换为(r,g,b)三维向量。在上面的YUV到RGB着色器转换中,面试官喜欢问问题(带着坏笑):为什么UV分量需要减去0.5? (神秘的自信) 答:因为正常化。

YUV格式图像的UV分量的默认值为:Y分量的默认值为0,8位的取值范围为0~。由于纹理采样值需要在着色器中进行归一化,因此UV分量的采样值需要分别减去0.5,以确保正确的YUV到RGB转换。

需要注意的是,OpenGL ES需要使用GL_LUMINANCE和GL_LUMINANCE_ALPHA格式的纹理来实现YUV渲染。 GL_LUMINANCE纹理用于加载NV21 Y Plane的数据,GL_LUMINANCE_ALPHA纹理用于加载UV Plane的数据。

对于初学者来说,这一点非常重要。请仔细看一下。

YUV转RGB(NV21、NV12、I格式图像渲染)的shader实现可以参考文章:OpenGL ES 3.0开发(三):YUV渲染及FFmpeg播放器视频渲染优化。本文主要关注Shader如何实现RGB转YUV。

RGB到YUV的转换就来到了本文的重点,那么如何使用shader来实现RGB到YUV的转换呢?上一节提到,我们先从一个简单的思路开始:首先根据(YUYV)等公式将RGBA转换为YUV,然后根据RGBA排列YUYV,最后使用glReadPixels读取YUYV数据。由于YUYV数据量是RGBA大小的一半,所以需要注意输出缓冲区的大小和视口的宽度(宽度是原来的一半)。

RGB到YUV转换公式: RGB到YUV转换公式开门见山。首先贴上实现RGBA到YUV转换的shader脚本: 代码语言:txt copy #version es precision Mediump float;in vec2 v_texCoord;layout(location = 0) out vec4 outColor; uniform Sampler2D s_TextureMap;//RGBA纹理uniform float u_Offset;//采样偏移//RGB转YUV//Y = 0.R + 0.G + 0.B//U = -0.R - 0.G + 0 .B//V = 0.R - 0.G - 0.Bconst vec3 COEF_Y = vec3( 0., 0., 0.);const vec3 COEF_U = vec3(-0., -0., 0.) ; const vec3 COEF_V = vec3( 0., -0., -0.);void main(){ vec2 texelOffset = vec2(u_Offset, 0.0); vec4 color0 = 纹理(s_TextureMap, v_texCoord); //Offset偏移采样vec4 color1 =texture(s_TextureMap, v_texCoord + texelOffset); float y0 = 点(color0.rgb, COEF_Y);浮动 u0 = 点(color0.rgb, COEF_U) + 0.5;浮点数 v0 = 点(color0.rgb, COEF_V) + 0.5; float y1 = 点(color1.rgb, COEF_Y); outColor = vec4(y0, u0, y1, v0);} 着色器实现 RGB 转 YUV 示意图: 着色器实现 RGB 转 YUV 示意图 我们需要将 RGBA 转换为 YUYV ,数据量不到 RGBA 的一半,其中相当于将两个像素合并为一个像素。

如图所示,我们在shader中进行两次采样,RGBA像素(R0,G0,B0,A0)转换为(Y0,U0,V0),像素(R1,G1,B1,A1)转换为(Y1) ,然后组合成(Y0,U0,Y1,V0),这样8个字节表示的2个RGBA像素就转换成了4个字节表示的2个YUYV像素。转换为YUYV时,数据量减半,那么使用glViewPort时宽度就变成原来的一半,同样使用glReadPixels时宽度就变成原来的一半。

将RGBA转换为YUYV,保证原图分辨率不变,建议使用FBO离屏渲染。这里注意,FBO绑定的纹理是用来容纳YUYV数据的,其宽度要设置为原图的一半。

代码语言:txt copy bool RGB2YUVSample::CreateFrameBufferObj(){//创建并初始化FBO纹理 glGenTextures(1, &m_FboTextureId);glBindTexture(GL_TEXTURE_2D, m_FboTextureId);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE _2D、GL_TEXTURE_WRAP_T、GL_CLAMP_TO_EDGE );glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, GL_NONE);//创建并初始化FBOglGenFramebuffers(1, & m_FboId);glBindFrame缓冲区(GL_FRAMEBUFFER,m_FboId);glBindTexture(GL_TEXTURE_2D , m_FboTextureId);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_FboTextureId, 0);//FBO纹理用于容纳YUYV数据,其宽度应设置为原图的一半 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_R enderImage .width / 2, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);if (glCheckFramebufferStatus(GL_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE) {LOGCATE("RGB2YUVSample::CreateFrameBufferObj glCheckFramebufferStatus status != GL_FRAMEBUFFER_COMPLETE");return false;}glBindTexture(GL_TEXTURE_2D, GL_NONE);glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);return true;}离屏渲染并读取YUYV数据: 代码语言:txt复制 glBindFramebuffer(GL_FRAME BUFFER, m_FboId );//渲染成yuyv,像素宽度减半,glviewport宽度减半 glViewport(0, 0, m_RenderImage.width / 2, m_RenderImage.height);glUseProgram(m_FboProgramObj);glBindVertexArray(m_VaoIds[ 1]);glActiveTexture(GL_TEXTURE0) ;glBindTexture(GL_TEXTURE_2D, m_ImageTextureId);glUniform1i(m_FboSamplerLoc, 0);//参考原理图,偏移量要设置为1/(width / 2) * 1/2 = 1 / width; 理论上一半的纹素 float texelOffset = (float) (1.f / (float) m_RenderImage.width);GLUtils::setFloat(m_FboProgramObj, "u_Offset", texelOffset);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, ( const void *)0);glBindVertexArray( 0);glBindTexture(GL_TEXTURE_2D, 0);//YUYV 缓冲区 = 宽度 * 高度 * 2;转换为YUYV时,数据量减半。注意 bufferuint8_t *pBuffer = new uint8_t[m_RenderImage.width * m_RenderImage.height * 2];NativeImage nativeImage = m_RenderImage;nativeImage.format = IMAGE_FORMAT_YUYV;nativeImage.ppPlane[0] = pBuffer;//当glReadPixels时,宽度变成原来的一半 glReadPixels(0, 0, m_RenderImage.width / 2 , nativeImage .height, GL_RGBA, GL_UNSIGNED_BYTE, pBuffer);DumpNativeImage(&nativeImage, "/sdcard/DCIM");delete []pBuffer;glBindFramebuffer(GL_FRAMEBUFFER, 0);完整代码参考下面工程,选择OpenGL RGB to YUV demo: 代码语言:txt 复制RGBA到YUV着色器,为什么UV分量需要加0.5?请读者根据上述文章给予强有力的反击。

使用OpenGL实现RGB到YUV图像格式转换

站长声明

版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。

标签:

相关文章

  • 受Model 3注册量下降影响,一季度特斯拉在加州的汽车注册量同比小幅下降

    受Model 3注册量下降影响,一季度特斯拉在加州的汽车注册量同比小幅下降

    根据市场研究公司Cross-Sell的数据,今年第一季度,特斯拉的汽车注册量加州的增幅略低于去年同期。 下降的主要原因是 Model 3 注册量下降。 数据显示,加州的 Model 3 注册量同比下降 54% 至 7 辆,而 Model Y 紧凑型跨界车的数量为 7 辆。 加州一直是特斯拉在美国市场的领头

    06-18

  • 小马智行获新融资2.67亿美元,估值超53亿美元

    小马智行获新融资2.67亿美元,估值超53亿美元

    投资界消息(微信ID:pedialy),自动驾驶独角兽公司Pony.ai宣布获得安省教师基金资助加拿大退休基金会(OTPP)旗下教师创新平台(TIP)领投C轮融资,总额达2.67亿美元。 本轮投资方还包括Fidelity China Special Situations PLC、五源资本(原晨兴资本)、凯明投资、耀明资本

    06-17

  • 工业互联网服务商“未明智能”获Pre-A+轮融资,4个月内完成两轮融资

    工业互联网服务商“未明智能”获Pre-A+轮融资,4个月内完成两轮融资

    无锡未明智能科技有限公司(以下简称“未明智能”)完成Pre-A+轮融资墨量资本投资的A+轮融资 -A+轮融资。 本轮融资将继续用于产研迭代、业务拓展、人才引进和渠道建设。 7月30日,公司刚刚完成百卡创投领投的Pre-A轮融资。 未名智能成立于2007年,是金属加工领域的工业互联网

    06-18

  • 腾讯再发阳光奖,价值超6万元

    腾讯再发阳光奖,价值超6万元

    从不少腾讯员工处获悉,腾讯今年的阳光奖今天已经揭晓。 每位腾讯员工将获得腾讯股票,提升期为一年。 如果按照当前价格计算,腾讯股票市值约为7.4万港元,折合人民币约6.1万元。 此外,入职不满一年的员工也可以获得此奖项,去年12月加入公司的员工也收到了通知。 (界面)L

    06-18

  • 潮流手表品牌“HappieWatch”获数千万天使轮融资

    潮流手表品牌“HappieWatch”获数千万天使轮融资

    手表及生活潮流品牌“HappieWatch”完成数千万天使轮融资,由德讯投资领投,君尚资本、春妮跟投资本充当专属财务顾问。 本轮融资将用于产品研发、加大品牌建设、渠道拓展等。 听,中小企业反馈平台。 倾听用户的需求,倾听创业者的声音,解决中小企业的痛点。 点击立即参与调

    06-17

  • 东方银星拟成立半导体产业基金投资8英寸MEMS射频产线

    东方银星拟成立半导体产业基金投资8英寸MEMS射频产线

    5月12日,东方银星(53)公告称,为全面加速公司战略转型,公司计划重点关注关于MEMS射频滤波器产业化的方向是成立投资管理公司,打造整合产业资源的投资平台。 公司拟出资1万元投资设立上海兴泰股权投资管理有限公司(名称暂定,具体名称以注册地工商登记机关最终核准为准)

    06-06

  • 【谁说消费不行了·“变强”】AMIRO:今年品牌已进入10亿俱乐部

    【谁说消费不行了·“变强”】AMIRO:今年品牌已进入10亿俱乐部

    编者按“今年消费不行了”简直成为了今年的俗话,人人都可以说吧,大家都在议论。 说“不”的人主要有两个原因:一是资本市场遇冷,二是疫情导致消费市场萎缩。 ——岁末年末,在疫情似乎无休无止的时候,清流资本不得不站出来唱反调:谁说消费不再可以了? !确实,对于大多

    06-18

  • The North Face 和 Balenciaga 都很受欢迎,是全世界男生人必备的

    The North Face 和 Balenciaga 都很受欢迎,是全世界男生人必备的

    最近一张性感孕肚照就获得了1万个点赞,并吸引了6.4万条网友评论。 难道是因为这套Gucci内衣的售价是¥(美元)? ▲ 图片来自:Instagram @chrissyteigen 照片中的辣妈就是曾登上“年度最高片酬模特”榜单的福布斯传奇嫂子 Chrissy Teigen。 两年前,她经历了儿子出生半小时

    06-21

  • 神州数码赴台上市获批并获赛富、IDG投资

    神州数码赴台上市获批并获赛富、IDG投资

    据投资界11月10日消息,神州数码控股有限公司(以下简称“神州数码”)宣布,去年晚间将发行台湾存托凭证(TDR) 台湾TDR的配售架构及发行申请已获台湾中央银行、台湾证券交易所及台湾金融监督管理委员会批准。 至此,神州数码已完成台湾TDR发行的全部审批工作,预计11月24日

    06-17

  • 我的宝城一票投给了东北小镇

    我的宝城一票投给了东北小镇

    最近,黑龙江边陲小城黑河热闹非凡。 9月21日,黑龙江省黑河市恢复中俄团体旅游免签业务。 随后,进出黑河口岸的人数激增。 一手拿着包子,一手拿着啤酒,眼睛盯着即将出炉的鸡蛋汉堡,黑河早市上有很多俄罗斯人。 相关视频也在社交平台上走红。 “俄罗斯人成群结队去黑龙江

    06-18

  • 据悉,英特尔将投资数百亿美元在德国、法国和意大利建厂

    据悉,英特尔将投资数百亿美元在德国、法国和意大利建厂

    北京时间12月23日晚间消息。 据报道,知情人士今天表示,为了增加产能并重新获得技术优势,英特尔计划投资数百亿美元在德国、法国和意大利建设芯片工厂和研发中心。 知情人士称,英特尔将在法国建立一个研究和设计中心,在意大利建立一个测试和组装工厂,在德国建立一个芯片制

    06-08

  • 上海全面推进制造业数字化,参与制定80多项改造标准,

    上海全面推进制造业数字化,参与制定80多项改造标准,

    上头条,上海市委常委、副主席吴清在9月9日的新闻发布会上表示,上海将全面推进城市数字化转型,其中制造业是关键对经济。 数字化转型的重要主线之一。 据悉,为加快全要素生态系统建设,目前已牵头或参与制定80余项制造业数字化转型标准。 《上海市先进制造业发展“十四五”

    06-17