互相转换的BGRA、RGBA和YUV420
一、存储格式
1. BGRA32
BGRA在内存上的排列按B、G、R、A依次排列,32表示每个通道占1个字节8bits,一个像素占4个字节32bits
2. RBGA32
RBGA在内存上的排列按R、B、G、A依次排列
3. YUV420(I420)
YUV420在内存上的排列为,先是全部Y,然后是全部U,最后是全部V
二、格式转换
1. BGRA和RBGA互转
只需遍历一遍,把每4个字节的第一位和第三位互换即可
void ConvertBGRAtoRGBA(BYTE* data, int width, int height)
{
for (int i = 0; i < width * height * 4; i += 4) {
BYTE temp = data[i];
data[i] = data[i + 2];
data[i + 2] = temp;
}
}
2. YUV420转RBGA
按照上图YUV420的存储格式,蓝色部分4个Y、1个U、1个V可以转换出4个像素的RBGA格式。
void I420ToRGBA(const uint8_t* src_y, const uint8_t* src_u, const uint8_t* src_v, uint8_t* dst_rgba, int width, int height)
{
// 计算公式
//R = Y + 1.13983 * V
//G = Y - 0.39465 * U - 0.58060 * V
//B = Y + 2.03211 * U
const int src_y_stride = width;
const int src_u_stride = (width + 1) / 2;
const int src_v_stride = (width + 1) / 2;
const int dst_rgba_stride = width * 4;
for (int y = 0; y < height; ++y) {
const uint8_t* src_y_row = src_y + y * src_y_stride;
const uint8_t* src_u_row = src_u + (y / 2) * src_u_stride;
const uint8_t* src_v_row = src_v + (y / 2) * src_v_stride;
uint8_t* dst_rgba_row = dst_rgba + y * dst_rgba_stride;
for (int x = 0; x < width; ++x) {
const int src_y_val = src_y_row[x];
const int src_u_val = src_u_row[x / 2];
const int src_v_val = src_v_row[x / 2];
const int c_val = src_y_val - 16;
const int d_val = src_u_val - 128;
const int e_val = src_v_val - 128;
const int r_val = (298 * c_val + 409 * e_val + 128) >> 8;
const int g_val = (298 * c_val - 100 * d_val - 208 * e_val + 128) >> 8;
const int b_val = (298 * c_val + 516 * d_val + 128) >> 8;
dst_rgba_row[x * 4 + 0] = static_cast<uint8_t>(max(0, min(255, r_val)));
dst_rgba_row[x * 4 + 1] = static_cast<uint8_t>(max(0, min(255, g_val)));
dst_rgba_row[x * 4 + 2] = static_cast<uint8_t>(max(0, min(255, b_val)));
dst_rgba_row[x * 4 + 3] = 255;
}
}
}
三、图片显示
这里用Windows GDI的方式把图片直接绘制在窗口上 CBitmap用的是BGRA格式的数据,显示I420的话,把格式转换一下再组装为CBitmap即可。
void CPicViewerDlg::DrawBitmap(CWnd *pWnd, int x, int y, int w, int h, unsigned char *pData)
{
CBitmap bitmap;
CDC MemDc;
bitmap.CreateBitmap(w, h, 1, 32, pData);
CDC *pWndDc = pWnd->GetDC();
MemDc.CreateCompatibleDC(pWndDc);
CBitmap *pOldBitmap = MemDc.SelectObject(&bitmap);
pWndDc->BitBlt(x, y, w, h, &MemDc, 0, 0, SRCCOPY);
MemDc.SelectObject(pOldBitmap);
pWnd->ReleaseDC(pWndDc);
pWndDc = NULL;
}
推荐阅读
-
互相转换的BGRA、RGBA和YUV420
-
转换YUV420、YUV422和RGB24的方法
-
深入探讨图像处理的基础知识:yuv420的转换方式与rgb、bayer和yuv、RGB之间的转换机制解析
-
搞定!JS时间戳与日期的互相转换,轻松实现时间戳转日期和日期转时间戳-1. 时间戳变日期的技巧
-
转换详解:YUV420到YUV444的转换方法,以及YUV420和YUV444的数据读取、储存技巧,深入解析YUV颜色空间的显示与播放功能
-
获取 RGBA 值 - 理解颜色的几种转换和值
-
Java中的Long、String和Date对象互相转换的复习
-
js中ASCII码和字符互相转换的方法
-
RGB和十六进制颜色代码的互相转换指南 - 警告须知
-
Python中十进制、十六进制、字符串和字节串的互相转换技巧