视觉学习篇——图像存储格式
文章目录
- 前言
- 一、核心格式分类与底层原理
- 1. RGB系列:最直观的像素表示法
- 2. YUV系列:视频编码的核心格式
- 3. NV12/NV21:移动端的节能格式
- 二、存储原理与内存布局
- 1. RGB的内存布局
- 2. YUV的内存布局
- 三、实战代码:格式转换与处理
- 1. Python(OpenCV实现RGB/YUV转换)
- 2. C++(FFmpeg实现NV12转RGB)
- 四、格式选择策略与优化建议
- 1. 根据任务选择格式
- 2. 性能优化技巧
- 五、总结
前言
图像存储格式决定了像素数据在内存中的组织方式和压缩效率,直接影响图像处理的性能、存储空间和传输带宽。这里将从底层原理、存储结构、格式转换三个维度,详解RGB、YUV、NV12等主流格式的差异,并提供Python(OpenCV)和C++(FFmpeg)实战代码。在今年地平线的比赛中,掌握这几种格式的转换加上ros2的零拷贝方法可以大幅度降低图像传输的延迟。
一、核心格式分类与底层原理
1. RGB系列:最直观的像素表示法
原理: - RGB(红绿蓝):通过三个通道分别表示红色、绿色、蓝色强度,三原色叠加形成任意颜色。
- 存储方式:
- 平面存储:
R1, G1, B1, R2, G2, B2, ...
(如PPM格式) - 交错存储:
R1, G1, B1, R2, G2, B2, ...
(如BMP、JPEG)
- 平面存储:
- 特点:
- 直观易处理,适合本地图像编辑和显示。
- 存储冗余大(每个像素需3字节,无压缩时1920×1080图像≈5.7MB)。
代码示例(Python-OpenCV读取RGB):
import cv2
img = cv2.imread("test.jpg") # OpenCV默认BGR格式(RGB的镜像)
b, g, r = cv2.split(img) # 分离通道
cv2.imshow("Red Channel", r)
2. YUV系列:视频编码的核心格式
原理:
- YUV:将图像分解为**亮度(Y)和色度(U/V)**两部分。
- Y:亮度信号(灰度信息)。
- U/V:色度信号(色彩差异)。
- 优势:
- 人眼对亮度敏感,可大幅压缩色度分量(如4:2:0仅保留1/4色度数据)。
- 适合视频传输和存储(H.264/H.265编码基础)。
常见YUV变体:
- YUV444:每个像素独立存储Y、U、V(无压缩,与RGB等效)。
- YUV422:每2个像素共享1个U/V(水平压缩)。
- YUV420:每4个像素共享1个U/V(垂直+水平压缩)。
3. NV12/NV21:移动端的节能格式
原理:
- NV12:Y平面 + 交错存储UV(U在前,V在后)。
- 存储结构:
Y Y Y Y ... U V U V ...
- 特点:半平面存储,内存占用仅为RGB的1.5倍(1920×1080≈2.6MB)。
- 存储结构:
- NV21:Y平面 + 交错存储VU(V在前,U在后)。
- 区别:仅UV顺序相反,适用于Android Camera原生数据。
适用场景:
- Android/iOS视频采集(摄像头输出多为NV21)。
- 实时视频处理(FFmpeg编码默认支持)。
二、存储原理与内存布局
1. RGB的内存布局
- BGR顺序:OpenCV默认按BGR顺序存储(这玩意属于历史遗留问题没办法哈哈哈)。
- 行对齐:每行像素字节数需是4的倍数(如RGB24格式中,每行填充到4的倍数)。
- 计算公式:
row_size = ((width * 3) + 3) // 4 * 4 # RGB24的行对齐计算
2. YUV的内存布局
- 平面模式(如YUV420P):
YYYYYYYY UUUU VVVV
- Y、U、V分三个独立平面存储。
- 半平面模式(如NV12):
YYYYYYYY UVUVUVUV
- U/V交替存储,节省空间。
三、实战代码:格式转换与处理
1. Python(OpenCV实现RGB/YUV转换)
import cv2
import numpy as np# 读取RGB图像(OpenCV默认BGR)
img_bgr = cv2.imread("test.jpg")# BGR转YUV(I420格式,等同于YUV420P)
yuv_i420 = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2YUV_I420)# YUV转RGB
img_rgb = cv2.cvtColor(yuv_i420, cv2.COLOR_YUV2BGR_I420)# 显示图像
cv2.imshow("RGB", img_rgb)
cv2.waitKey(0)
2. C++(FFmpeg实现NV12转RGB)
#include <iostream>
#include <opencv2/opencv.hpp>// 使用FFmpeg解码NV12数据(示例)
void decode_nv12_to_rgb(const uint8_t* nv12_data, int width, int height) {// 创建OpenCV Mat容器cv::Mat yuv(height * 3 / 2, width, CV_8UC1, (void*)nv12_data);cv::Mat rgb;// 转换为RGB(FFmpeg内部调用libswscale)cv::cvtColor(yuv, rgb, cv::COLOR_YUV2RGB_NV12);// 显示图像cv::imshow("RGB", rgb);cv::waitKey(0);
}int main() {// 加载NV12文件(假设为1920x1080分辨率)FILE* fp = fopen("input.nv12", "rb");std::vector<uint8_t> buffer(1920 * 1080 * 3 / 2);fread(buffer.data(), 1, buffer.size(), fp);fclose(fp);decode_nv12_to_rgb(buffer.data(), 1920, 1080);return 0;
}
四、格式选择策略与优化建议
1. 根据任务选择格式
场景 | 推荐格式 | 原因 |
---|---|---|
屏幕显示 | RGB/BGR | 直接匹配显示器硬件 |
视频编码 | YUV420 | 最高压缩率,兼容H.264/H.265 |
实时视频流 | NV12/NV21 | 移动端低功耗,FFmpeg原生支持 |
医学影像 | RGB/RGBA | 保留Alpha通道(如透射图像) |
2. 性能优化技巧
- 内存对齐:确保每行像素字节数为4的倍数(避免GPU加速时的性能损失)。
- SIMD指令:使用SSE/AVX加速YUV-RGB转换(如OpenCV的
cv::hal::cvtBGRtoYUV
)。 - 异步处理:在视频采集线程和解码线程间使用双缓冲队列。
五、总结
图像存储格式是视觉处理的基石:
- RGB:简单直观,适合本地图像处理。
- YUV:视频编码的核心,平衡画质与压缩率。
- NV12/NV21:移动端实时处理的节能选择。
掌握格式转换的底层原理,能显著提升项目效率:
- 存储优化:YUV420比RGB节省40%空间。
- 计算加速:SIMD指令可提速3-5倍。
- 跨平台兼容:FFmpeg/OpenCV提供统一接口。