RGB与YUV格式详解
图像处理
文章目录
- 图像处理
- 前言
- 一、RGB格式
- 二、YUV格式
- 三、RGB与YUV转换
- 四、NV21转换为YUV420p
- 五、YUV旋转
前言
在图像的世界里,一般使用RGB作为存储格式。而在视频的世界里,一般使用YUV作为压缩存储格式。有时候面试官会问:为什么视频使用YUV来压缩存储,而不用RGB?YUV与RGB有什么区别,两者如何转换的?常见的RGB格式有哪些,常见的YUV格式又有哪些?手机摄像头的预览格式是什么,如何转换为YUV420P的?我们带着这些问题,来揭开RGB与YUV格式的面纱。
一、RGB格式
RGB是一种图像存储格式,也是三原色,取值范围[0, 255]。R代表Red红色,G代表Green绿色,B代表Blue蓝色。在openCV中,一般使用BGR格式。在图像中,一般使用32位色的ARGB(或RGBA)代表一个像素,其中A代表Alpha透明度。常见的RGB格式有RGB888、RGBA8888、RGB565等。
1、RGBA8888
关于RGBA8888格式,每个通道占8位,即一个字节。四个通道构成一个像素,总共占32位。排列顺序如下图所示:
2、RGB565
关于RGB565格式,其中R占5位,G占6位,B占5位。三个通道构成一个像素,总共占16位。排列顺序如下图所示:
3、图像的像素阵列
一张图像由宽x高的像素阵列构成,为了内存对齐,会使用stride来填充。如下图所示,由4x3构成的像素阵列,其中P代表pixel:
二、YUV格式
YUV是一种视频压缩存储格式。其中Y代表Luma亮度,U代表Chroma色度,V代表Contrast对比度。常见的YUV采样比例如下:
4:4:4 表示完全采样
4:2:2 表示水平2:1采样,垂直完全采样
4:2:0 表示水平2:1采样,垂直2:1采样
4:1:1 表示水平4:1采样,垂直完全采样
常见的YUV格式有:YUV420p、YUV420sp、NV21等。由于U和V分量都是Y分量的1/4,而RGB888的所有分量占比都是1。进一步可得,YUV整体占比是3/2,RGB整体占比是6/2,YUV所占存储空间比RGB少了3/2。因此,默认采用YUV作为视频压缩存储格式。
1、YUV420p
YUV420p属于平面存储,YUV分量占比为4:1:1,即每4个Y共享一组UV。先是Y分量,然后是U分量,最后是V分量。排列如下图所示:
2、YUV420sp
YUV420sp属于交错存储,YUV分量占比为4:1:1,即每4个Y共享一组UV。先是Y分量,然后是UV分量交错存储。排列如下图所示:
3、NV21
NV21属于交错存储,YUV分量占比为4:1:1,即每4个Y共享一组UV。Android手机摄像头预览数据默认是NV21格式。和YUV420sp的区别是,NV21是VUVU这样排列,如下图所示:
三、RGB与YUV转换
关于YUV与RGB的转换公式,可
参考ITU标准:https://www.itu.int/rec/R-REC-BT.601。
也可以,
参考维基百科:https://zh.wikipedia.org/wiki/YUV。
咱们来看下转换公式:
以rgb转yuv为例,示例代码如下:
void rgb_to_yuv(int8_t *yuv, int *rgb, int width, int height) {int rgbIndex = 0;int yIndex = 0;int uIndex = width * height;int vIndex = width * height * 5 / 4;int R, G, B;float Y, U, V;// 遍历图像,获取所有像素点 for (int i = 0; i < height; i++) {for (int j = 0; j < width; j++) {// 从像素点获取R、G、B分量R = (rgb[rgbIndex] & 0xFF0000) >> 16;G = (rgb[rgbIndex] & 0xFF00) >> 8;B = (rgb[rgbIndex] & 0xFF);// 使用公式把RGB转成YUVY = 0.299 * R + 0.587 * G + 0.114 * B;U = -0.147 * R - 0.289 * G + 0.436 * B;V = 0.615 * R - 0.515 * G - 0.100 * B;// YUV分量赋值给yuv数组yuv[yIndex++] = (int8_t)Y;if (i % 2 == 0 && j % 2 == 0) {yuv[uIndex++] = (int8_t) U;yuv[vIndex++] = (int8_t) V;}rgbIndex++;}}
}
四、NV21转换为YUV420p
由于NV21是交错存储,4个Y共享一组UV,而且是VUVU这样排列。所以,我们需要把偶数的V分量、奇数的U分量读出来,然后赋值给YUV420p。代码如下:
static void nv21_to_yuv420p(int8_t *dst, int8_t *src, int len) {memcpy(dst, src, len); // yfor (int i = 0; i < len / 4; ++i) {*(dst + len + i) = *(src + len + i * 2 + 1); // u*(dst + len * 5 / 4 + i) = *(src + len + i * 2); // v}
}
五、YUV旋转
YUV的存储是有旋转角度的存在。在手机拍摄时,按照逆时针来看,横屏向左是0度,竖屏向下是90度,横屏向右是180度,竖屏向上是270度。既然有旋转角度,我们就需要对YUV进行旋转处理,代码如下:
static void yuv420p_rotate90(int8_t *dst, const int8_t *src, int width, int height) {int n = 0;int wh = width * height;int half_width = width / 2;int half_height = height / 2;// yfor (int j = 0; j < width; j++) {for (int i = height - 1; i >= 0; i--) {dst[n++] = src[width * i + j];}}// ufor (int i = 0; i < half_width; i++) {for (int j = 1; j <= half_height; j++) {dst[n++] = src[wh + ((half_height - j) * half_width + i)];}}// vfor (int i = 0; i < half_width; i++) {for (int j = 1; j <= half_height; j++) {dst[n++] = src[wh + wh / 4 + ((half_height - j) * half_width + i)];}}
}static void yuv420p_rotate180(int8_t *dst, const int8_t *src, int width, int height) {int n = 0;int half_width = width / 2;int half_height = height / 2;// yfor (int j = height - 1; j >= 0; j--) {for (int i = width; i > 0; i--) {dst[n++] = src[width * j + i - 1];}}// uint offset = width * height;for (int j = half_height - 1; j >= 0; j--) {for (int i = half_width; i > 0; i--) {dst[n++] = src[offset + half_width * j + i - 1];}}// voffset += half_width * half_height;for (int j = half_height - 1; j >= 0; j--) {for (int i = half_width; i > 0; i--) {dst[n++] = src[offset + half_width * j + i - 1];}}
}static void yuv420p_rotate270(int8_t *dst, const int8_t *src, int width, int height) {for (int j = 0; j < width; j++) {for (int i = 1; i <= height; i++) {*dst++ = *(src + i * width - j);}}auto *src_u = const_cast<int8_t *>(src + width * height);for (int j = 0; j < width / 2; j++) {for (int i = 1; i <= height / 2; i++) {*dst++ = *(src_u + i * width / 2 - j);}}auto *src_v = const_cast<int8_t *>(src + width * height * 5 / 4);for (int j = 0; j < width / 2; j++) {for (int i = 1; i <= height / 2; i++) {*dst++ = *(src_v + i * width / 2 - j);}}
}static void yuv420p_rotate(int8_t *dst, int8_t *src, int width, int height, int degree) {switch(degree) {case 0:memcpy(dst, src, width * height * 3 / 2);break;case 90:yuv420p_rotate90(dst, src, width, height);break;case 180:yuv420p_rotate180(dst, src, width, height);break;case 270:yuv420p_rotate270(dst, src, width, height);break;default:break;}
}
相关文章:

RGB与YUV格式详解
图像处理 文章目录 图像处理前言一、RGB格式二、YUV格式三、RGB与YUV转换四、NV21转换为YUV420p五、YUV旋转 前言 在图像的世界里,一般使用RGB作为存储格式。而在视频的世界里,一般使用YUV作为压缩存储格式。有时候面试官会问:为什么视频使用…...

JS获取当前浏览器名称
在JavaScript中,获取当前浏览器名称的方法并不是一个标准的功能,因为浏览器厂商并没有提供一个直接的API来获取浏览器的名称。但是,你可以通过分析用户代理字符串(User-Agent)来推断出浏览器的名称。 以下是一个简单的…...
学习计算机网络(五)——ICMP协议
ICMP 协议(Internet Control Message Protocol,互联网控制报文协议),主要用于在 IP 网络中传递控制消息和差错报告。 ICMP在IP系统间传递差错和管理报文,是任何IP实现必需和要求的组成部分。 可把ICMP报文分成两类&a…...

request.getRequestURI()与request.getRequestURL()的区别
1.返回值的区别: request.getRequestURL() 返回值是一个StringBuffer类型 request.getRequestURI() 返回值是一个String类型 先看 request.getRequestURL() 返回的是一个具体的地址,访问网页的地址 而 request.getRequestURI() 返回的是一个映射地址&a…...
3154. 到达第 K 级台阶的方案数(24.8.20)
今天发晚了,嘿嘿,玩黑神话玩的 题目 给你有一个 非负 整数 k 。有一个无限长度的台阶,最低 一层编号为 0 。 Alice 有一个整数 jump ,一开始值为 0 。Alice 从台阶 1 开始,可以使用 任意 次操作,目标是到达…...

如何使用docker打包后端项目并部署到阿里云k8s集群上
如何使用docker打包后端项目并部署到阿里云k8s集群上 1. 引言 在现代软件开发中,容器化技术已经成为主流,而Kubernetes (K8s) 是管理容器的首选平台之一。本文将详细介绍如何将一个后端项目使用Docker打包,并将其部署到阿里云的Kubernetes集群上。 2. 前置条件 阿里云账号…...
ES6中解构的使用
一、提取几个属性,构造一个新的对象 在JavaScript中,你可以使用对象解构(Object Destructuring)来提取一个对象中的几个属性,并构造一个新的对象。下面是一个示例: 在这个例子中,name和email属性…...

拖拽式报表设计器优点好 实现流程化办公就靠它!
当前,实现流程化办公是很多企业都想要实现的目标。利用低代码技术平台、拖拽式报表设计器的优势特点,可以为企业降低开发成本、提升办公效率、创造更多市场价值。那么,您知道拖拽式报表设计器的优点是什么吗?通过本文一起了解拖拽…...

Spring项目:文字花园(四)
一.实现登录 传统思路: • 登陆⻚⾯把⽤⼾名密码提交给服务器. • 服务器端验证⽤⼾名密码是否正确, 并返回校验结果给后端 • 如果密码正确, 则在服务器端创建 Session . 通过 Cookie 把 sessionId 返回给浏览器. 问题: 集群环境下⽆法直接使⽤Session. 原因分析: 我们开…...

Web开发:ORM框架之Freesql的入门和技巧使用小结
目录 零、官网链接 一、字段映射表 二、查询 1.freesql独特封装:between关键字 2.分页(每页 20 条数据,查询第 1 页) 3.Withsql(子查询,不建议) 3.简单查询、映射查询 4.参数查询、自定义…...
软件工程(4)面向对象方法:面向对象软件工程OOSE与案例实践
OOSE(Object-Oriented Software Engineering,面向对象软件工程)是一种用于开发软件系统的工程方法论,它强调使用面向对象的技术和方法来设计和实现软件。OOSE 方法是由 Ivar Jacobson 提出的,主要包括以下几个关键方面…...

【数据结构篇】~链表算法题1(含快慢指针的解析)
前言 关于环形指针与快慢指针是算法题中的常客,如果能掌握将是我们的一大助力! 1.快慢指针 1 移除链表元素 https://leetcode.cn/problems/remove-linked-list-elements/description/ 1)思路 这道题可以用一个新链表来保存原链表中不…...
洛谷 P1135 奇怪的电梯
链接直达:P1135 奇怪的电梯 - 洛谷 | 计算机科学教育新生态 题目来源 洛谷 题目内容 奇怪的电梯 题目背景 感谢 yummy 提供的一些数据。 题目描述 呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯&…...

vue使用axios请求后端数据
前后端分离项目的基础: 前后端跨域访问 vite.config.js中加入 // 1.为什么要跨域 //因为浏览器的同源策略,不同站点之间访问需要跨域 //实现跨域的方式:server: {proxy: {// 假设要跨域访问的后端 API 地址以 /api 开头/api: { //表示拦截以/api开头的…...

目标检测 | yolov10 原理和介绍
相关系列: 目标检测 | yolov1 原理和介绍 目标检测 | yolov2/yolo9000 原理和介绍 目标检测 | yolov3 原理和介绍 目标检测 | yolov4 原理和介绍 目标检测 | yolov5 原理和介绍 目标检测 | yolov6 原理和介绍 目标检测 | yolov7 原理和介绍 目标检测 | yolov8 原理和…...

基于Springboot 和Vue 的高校宿舍管理系统源码
网络上很多宿舍管理系统都不完整,大多数缺少数据库文件,所在使用极其不方便,由于本人程序员,根据代码,自己花时间不全了数据库文件,并且可以完美运行!!!!&…...

3:2比例的程序员专业显示器,效率提升显著,摸鱼时间又多了
对于我们程序员来说,显示器的重要性不言而喻,作为我们与代码交流的直接工具,他影响着我们的工作效率、舒适度和整体编程体验。我在家用的是自己笔记本的屏幕,简单写写代码还行,涉及到多任务协同或者大代码量开发就有点…...

vue3 cascader省市区三级联动如何指定字段,如何根据id查到对应的名字
如果我们接口数据字段名不是value和code。要加个props :props"{ value:code,label:regionName}"根据id查name需要一个ref和一个change事件<el-cascader :options"areaData" ref"addressCodeRef" change"handleChange" :props"…...
算法4:前缀和(上)
文章目录 一维前缀和二维前缀和寻找数组的中心下标除自身以外数组的乘积 一维前缀和 二维前缀和 寻找数组的中心下标 class Solution { public:int pivotIndex(vector<int>& nums) {int n nums.size();vector<int> f(n), g(n);f[0] nums[0];g[n - 1] num…...

美国政府紧急应对三星Galaxy手机安全漏洞
一、美国政府紧急通知更新三星Galaxy手机系统 美国政府近日发布紧急通知,要求联邦政府雇员在8月28日前更新三星Galaxy手机系统,否则将面临禁止使用这些设备的后果。这是继7月针对Pixel手机用户的类似要求之后的又一次紧急行动。此次事件的导火索是谷歌发…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...