欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

互相转换的BGRA、RGBA和YUV420

最编程 2024-08-15 16:33:29
...

一、存储格式

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;

}