opencv C++,可以转化yuv422sp或yuv422p数据到rgb嘛,找不到这个转换格式呀,有懂opencv的吗
#include <iostream>
#include <opencv2/opencv.hpp>
#include "pencv.h"
using namespace std;
using namespace cv;
using namespace pencv;
int main() {
// 读取YUV422SP或YUV422P数据
uchar y_plane[640*480], u_plane[640*480], v_plane[640*480];
FILE* f = fopen("input.yuv", "rb");
fread(y_plane, 1, sizeof(uchar)*640*480, f);
fclose(f);
f = fopen("input.yuv", "rb");
fread(u_plane, 1, sizeof(uchar)*640*480, f);
fclose(f);
f = fopen("input.yuv", "rb");
fread(v_plane, 1, sizeof(uchar)*640*480, f);
fclose(f);
// 将YUV422SP数据转换为RGB数据
int width = 640, height = 480;
int y_size = width * height;
int u_size = width >> 1, v_size = height >> 1;
uint8_t* y_rgb = new uint8_t[y_size * 3];
uint8_t* u_rgb = new uint8_t[u_size * 3];
uint8_t* v_rgb = new uint8_t[v_size * 3];
memset(y_rgb, 0, y_size * 3);
memset(u_rgb, 0, u_size * 3);
memset(v_rgb, 0, v_size * 3);
int y_p = 0, u_p = 0, v_p = 0;
for (int i = 0; i < y_size; i++) {
y_rgb[i] = y_plane[y_p++];
if (i % (width >> 1) == 0) {
u_p = 0;
v_p = i / (width >> 1);
} else if (i % (width >> 1) == (width >> 1)) {
u_p++;
v_p++;
}
if (i % (height >> 1) == 0) {
u_rgb[(width >> 1) * v_p + u_p] = u_plane[u_p++];
v_rgb[(width >> 1) * v_p + u_p] = v_plane[v_p++];
} else if (i % (height >> 1) == (height >> 1)) {
u_rgb[(width >> 1) * v_p + u_p] += u_plane[u_p++];
v_rgb[(width >> 1) * v_p + u_p] += v_plane[v_p++];
}
}
// 将RGB数据写入文件输出
FILE* f = fopen("output.jpg", "wb");
fwrite(y_rgb, sizeof(uint8_t), y_size * 3, f);
fwrite(u_rgb, sizeof(uint8_t), u_size * 3, f);
fwrite(v_rgb, sizeof(uint8
这里不详细介绍YUV420, 简单的介绍一下,比如有一个 HxW 大小的图,如果是RGB颜色分量,那么每个通道都是HxW ,对于一个3通道的RGB来说,在传输的时候,所消耗的带宽是HxWx3。为了节省带宽,在视频传输,经常用的颜色通道是YUV420P, 这就意味着每4个Y共享1个U和V,这也相当于HxW 大小的Y通道,H x W x (1/4) 大小的U和 H x W x (1/4) 大小的V。这样即可节省一半的带宽。
假设有一个YUV视频(*.yuv),从yuv视频中读取帧的代码如下:
fp = open(videofile, 'rb')
filename = videofile.split('/')[-1][:-4] # for save
# fp_out = open(savepath+filename+"_out.yuv", 'wb')
framesize = height * width * 3 // 2
h_h = height // 2
h_w = width // 2
fp.seek(0, 2)
ps = fp.tell()
numfrm = ps // framesize
fp.seek(0, 0)
for i in range(numfrm):
print("%d/ %d"%(i, numfrm))
Yt = np.zeros(shape=(height, width), dtype='uint8')
Ut = np.zeros(shape=(h_h, h_w), dtype='uint8')
Vt = np.zeros(shape=(h_h, h_w), dtype='uint8')
for m in range(height):
for n in range(width):
Yt[m, n] = ord(fp.read(1))
for m in range(h_h):
for n in range(h_w):
Ut[m, n] = ord(fp.read(1))
for m in range(h_h):
for n in range(h_w):
Vt[m, n] = ord(fp.read(1))
img = np.concatenate((Yt.reshape(-1), Ut.reshape(-1), Vt.reshape(-1)))
img = img.reshape((height*3 // 2, width)).astype('uint8')
bgr_img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_I420)
解决方案: 根据参考资料中的公式,可以编写相关的代码实现YUV到RGB的转换。以下提供一种实现:
void yuv422pToRgb(uint8_t* yuv, uint8_t* rgb, size_t height, size_t width)
{
int size = height * width;
uint8_t* yFrame = yuv;
uint8_t* uFrame = yFrame + size;
uint8_t* vFrame = uFrame + size / 2;
int offset = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j += 2)
{
int yIdxL = i * width + j;
int yIdxR = yIdxL + 1;
int uIdx = (i / 2) * (width / 2) + (j / 2);
int vIdx = uIdx;
int R1 = yFrame[yIdxL] + 1.13983 * (vFrame[vIdx] - 128);
int G1 = yFrame[yIdxL] - 0.39465 * (uFrame[uIdx] - 128) - 0.58060 * (vFrame[vIdx] - 128);
int B1 = yFrame[yIdxL] + 2.03211 * (uFrame[uIdx] - 128);
int R2 = yFrame[yIdxR] + 1.13983 * (vFrame[vIdx] - 128);
int G2 = yFrame[yIdxR] - 0.39465 * (uFrame[uIdx] - 128) - 0.58060 * (vFrame[vIdx] - 128);
int B2 = yFrame[yIdxR] + 2.03211 * (uFrame[uIdx] - 128);
R1 = R1 < 255 ? R1 : 255;
G1 = G1 < 255 ? G1 : 255;
B1 = B1 < 255 ? B1 : 255;
R2 = R2 < 255 ? R2 : 255;
G2 = G2 < 255 ? G2 : 255;
B2 = B2 < 255 ? B2 : 255;
R1 = R1 < 0 ? 0 : R1;
G1 = G1 < 0 ? 0 : G1;
B1 = B1 < 0 ? 0 : B1;
R2 = R2 < 0 ? 0 : R2;
G2 = G2 < 0 ? 0 : G2;
B2 = B2 < 0 ? 0 : B2;
rgb[offset++] = (unsigned char)R1;
rgb[offset++] = (unsigned char)G1;
rgb[offset++] = (unsigned char)B1;
rgb[offset++] = (unsigned char)R2;
rgb[offset++] = (unsigned char)G2;
rgb[offset++] = (unsigned char)B2;
}
}
}
该函数将YUV422p格式的视频流转换为了RGB格式,其中输入参数为yuv、输出参数为rgb、视频流的高度为height、视频流的宽度为width。该函数的原理是先将每个像素点的Y、U、V值转换为R、G、B值,再将每个像素点对应的两个RGB值写入输出的rgb数组中。
需要注意的是,该函数只是一种简单的实现方法,不一定适用于所有的视频流。对于不同的视频流,可能需要稍微修改代码中的参数才能得到正确的结果。