GPU 实现 RGB -- YUV 转换

前言

RGB --> YUV 转换的公式是现成的,直接在 CPU 端转换的话,只需要遍历每个像素,得到新的 YUV 值,根据其内存分布规律,合理安排分布即可。然而在 CPU 端进行转换,存在的问题运行效率太低,无法满足高效转换的需求。我们将目光投向拥有流水线体系的支持高速浮点数计算的硬件——GPU.

转换公式如下:

GPU 上面的实现

考虑在 GPU 上执行 RGB --> YUV 转换。GPU 的流水线操作:

vertices
----> Pipeline ----> Out color
texture

所以将 RGB 图像作为纹理输入,流水线输出我们需要的 YUV 数据。前面一部分很好理解,图像作为唯一的纹理输入,没有别的选项。后面一部分的话,需要在输出的时候输出我们需要的 YUV 数据即可,在 fragment shader 中的输出按常理就是每一个 fragment 的颜色,为实现读取像素是 YUV 的目标,要调整输出的数据。

考虑 YUV 格式内存分布,以 NV12 为例,一张图片占用内存大小为:width x height * 3 / 2 (我们认为图像的宽为 width 高为 height). 如果是 RGBA 的格式存储的话,占用的内存空间大小是:width x height x 4 (因为 RGBA 一共4个通道)。如果我们把 OpenGL renderbuffer 大小设置成等于图像的大小,那输出的大小就是 RGBA 那一种的大小,和 YUV 格式的是对不上的。考虑 YUV 的分布特点,设计输出的宽高为 (width / 4, height * 3 / 2). 示意图如下:

Memory of a frame (yuv format)

  width / 4
|-------------|
| |
| | h
| chrominance |
| |
|-------------|
| |
| luminance | h / 2
|-------------|

因为每一个 out color 含有四个分量 RGBA 所以将宽度设为 width / 4, 那么正好每一行的像素就是原来 width 的数量。在 fragment shader 内部计算的时候,需要考虑当前处理的单个 fragment 是属于 chrominance OR luminance, 可以用纹理坐标的 t 值的大小来判断。

Chrominance

所谓的 RGBA 四个分量实际上代表四个不同的像素的 chrominance 值,也就是说需要做一定的 offset, 来获取到当前像素附近的像素的值,我先假定 offset 为 1.0f / width. 故四个分量如下:

  1. (s, t)
  2. (s + off, t)
  3. (s + off x 2.0f, t)
  4. (s + off x 3.0f, t)

根据四个像素的 RGBA 值计算出四个 Y 通道的数据作为这个 fragment 的输出颜色。

Luminance

仍然是一个像素四个分量,但是现在代表的是两对 UV 分量。因为根据一个 RGBA 就可以算出 YUV 值,所以此处只需要做一个偏移。

  1. (s, t)
  2. (s + off x 2, t)

这里 offset 的设置可以乘 1 或 2 或 3,我觉得都可以,我只是取中道选择了 2. 将上面两个像素的 UV 分量作为这个 fragment 的输出颜色。

readback pixel

最终用 glReadpixels() 函数,将我们输出的颜色读回来,就完成了。

补充

实际操作中遇到的一个问题是,如果设置了 GL_BLEND, 最终输出的颜色会是混合以后的颜色,记得一定要确认关闭了 blending.

Written with StackEdit.

GPU 实现 RGB -- YUV 转换 (OpenGL)的更多相关文章

  1. 最简单的视音频播放示例5:OpenGL播放RGB/YUV

    本文记录OpenGL播放视频的技术.OpenGL是一个和Direct3D同一层面的技术.相比于Direct3D,OpenGL具有跨平台的优势.尽管在游戏领域,DirectX的影响力已渐渐超越OpenG ...

  2. 最简单的视音频播放演示样例5:OpenGL播放RGB/YUV

    ===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...

  3. 【视频处理】YUV与RGB格式转换

    YUV格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式. 因此当要对图像进行后期处理显示时,需要把YUV格式转换成RGB格式. RGB与YUV的变换公式如下: YUV(25 ...

  4. YUV转换成RGB算法

    YUV转换成RGB void yuvtorgb ( double *rgb,unsigned char *yuv) { int i; rgb[] = ] + + ] - ); // r rgb[] = ...

  5. YUV与RGB格式转换

    YUV格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式. 因此当要对图像进行后期处理显示时,需要把YUV格式转换成RGB格式. RGB与YUV的变换公式如下: YUV(25 ...

  6. YUV RGB 格式转换

    第一个公式是RGB转YUV(范围0-255)时用的,第二个公式是用在YUV转换RGB(范围0-255)时用的.1. Y = ; U = -; V = ; 黑色:Y=16 ,U= V =128 红色:Y ...

  7. 【图像处理与医学图像处理】YUV与RGB格式转换速度几种方法对比

    [视频处理]YUV与RGB格式转换 YUV格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式. 因此当要对图像进行后期处理显示时,需要把YUV格式转换成RGB格式. RGB与 ...

  8. 【DSP开发】【VS开发】YUV与RGB格式转换

    [视频处理]YUV与RGB格式转换 YUV格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式. 因此当要对图像进行后期处理显示时,需要把YUV格式转换成RGB格式. RGB与 ...

  9. Android平台Camera实时滤镜实现方法探讨(三)--通过Shader实现YUV转换RBG

    http://blog.csdn.net/oshunz/article/details/50055057 文章例如该链接通过将YUV分成三个纹理,在shader中取出并且经过公式变换,转换成RGB.我 ...

随机推荐

  1. js生成word中图片处理

    首先功能是要求前台导出word,但是前后台是分离的,图片存在后台,所以就存在跨域问题. 导出文字都是没有问题的(jquery.wordexport.js),但是导出图片就存在问题了: 图片是以链接形式 ...

  2. 在阿里云 ECS 搭建 nginx https nodejs 环境(三、nodejs)

    在阿里云 ECS 搭建 nginx https nodejs 环境(三.nodejs) 在阿里云 ECS 搭建 nginx https nodejs 环境(三.nodejs) 第一步 指定版本源 执行 ...

  3. Android studio签名与代码混淆

    签名: 应用程序升级:应用程序模块化:代码或者数据共享 混淆:混淆器将代码中的所有变量.函数.类的名称变为简短的英文字母代号,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义.

  4. SAP Cloud for Customer(C4C)和微信集成系列教程

    这个系列主要从技术层面阐述了如何实现end user在微信app里发送的message能够投递到C4C系统,以及在C4C系统基于微信发送过来的message回复之后,如何将这些回复再push回微信ap ...

  5. linux系统编辑神器 -vim用法大全

    vim编辑器 文本编辑器,字处理器ASCII nano, sed vi: Visual Interfacevim: VI iMproved 全屏编辑器,模式化编辑器 vim模式:编辑模式(命令模式)输 ...

  6. node 和git 在linux(centos) 上的安装

    1. wget命令下载Node.js安装包.  (该安装包是编译好的文件,解压之后,在bin文件夹中就已存在node和npm,无需重复编译.) wget https://nodejs.org/dist ...

  7. window下mySql数据库设置密码

    方法一:用setpassword命令 首先登陆MySQL:mysql -u root 格式:mysql> set password for 用户名@localhost = password('新 ...

  8. .Net IOC框架入门之一 Unity

    一.概述 IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection). 作用:将各层的对象以松耦合的方式组织在一 ...

  9. java实现 比较两个文本相似度-- java 中文版 simHash 实现 ,

    比较两个文本的相似度 这里采用 simHash 算法 ; 分词是 基于 http://hanlp.linrunsoft.com/ 的开源 中文分词包 来实现分词 ; 实现效果图: 直接上源码: htt ...

  10. flask-session组件

    简介 flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持session保存到多个地方,如: redis mem ...