YUV数据格式的转换(NV12ToI420)和旋转(旋转90度)

1、几种常见格式的YUV数据

I420(YU12):先存Y,然后U,最后V。YYYYYYYYUUVV

YV12:先存Y,然后V,最后U。YYYYYYYYVVUU

NV12:先存Y,然后UV交错存储,iOS下这种模式。YYYYYYYYUVUV

NV21:先存Y,然后VU交错存储,Android下这种格式。YYYYYYYYVUVU

2、NV12转I420

因为NV12的YUV数据UV是交错存储的,I420的UV是单独存储的,所有NV12转I420的时候,只需要将UV数据分开

void NV12ToI420(uint8_t* src_y, uint8_t* src_uv, 
	uint8_t* dst_y, uint8_t* dst_u, uint8_t* dst_v,
    uint32_t width,uint32_t height) {
	// src_y --> dst_y memcpy
	for (int i = 0; i < (width* height); ++i) {
		dst_y[i] = src_y[i];
	}

	// src_uv --> dst_u,dst_v
	int index = 0;
	for (int i = 0; i < (width* height/2); ++i) {
		dst_u[index] = src_uv[i++];
		dst_v[index] = src_uv[i];
		index++;
	}
}

3、旋转I420数据,旋转90度

首先我们先看这样一张图,代表的是4*8的YUV420数据,每一个Y代表一个像素点,长度为1个字节,每四个Y对应一个U,一个V(相同颜色),也就是每一个2*2的小正方形对应一个U和V。下来我们将图片旋转90度,可以得到下面这张图片

首先我们旋转的是Y,然后旋转U,最后旋转V,因为每一个2*2的小正方形对应一个U和V,所以就是每两个宽和每两个高取一个U和V,所以只要写出Y的旋转,然后U和V的旋转就是将Y旋转的宽和高都变为原来的一半就可以了,具体代码如下

enum Degree { kRotate90, kRotate180, kRotate270 };
// 旋转
void RotateI420(uint8_t* src_y, uint8_t* src_u, uint8_t* src_v,
	uint8_t* dst_y, uint8_t* dst_u, uint8_t* dst_v,
    uint32_t width,uint32_t height,int degree) {
	if (degree != kRotate90) {
		return;
	}
	// 第一步我们只转Y
	// 旋转90度
	int index = 0;
	for (int i = 0; i < width; ++i) {
		for (int j = height- 1; j >= 0; --j) {
			dst_y[index++] = src_y[j*width+ i];
		}
	}

	int uv_index = 0;
	for (int i = 0; i<width/ 2; i++) {
		for (int j = height/2-1; j>=0; j--)
		{
			dst_u[uv_index] = src_u[width/ 2 * j + i];
			dst_v[uv_index] = src_v[width/ 2 * j + i];
			uv_index++;
		}
	}
}

3、当然上面的格式转换和旋转都可以使用libyuv取完成,写好的库,很方便

地址:https://github.com/lemenkov/libyuv

你可以使用以下代码来旋转一个单色灰图的 YUV420sp 格式图像 90 : ```c++ #include <stdio.h> void rotateYUV420sp90Degree(unsigned char *src, unsigned char *dst, int width, int height) { int wh = width * height; int uvHeight = height >> 1; // 旋转 Y 分量 int k = 0; for (int i = 0; i < width; i++) { for (int j = height - 1; j >= 0; j--) { dst[k++] = src[j * width + i]; } } // 旋转 U 和 V 分量 for (int i = 0; i < width; i += 2) { for (int j = uvHeight - 1; j >= 0; j--) { dst[k++] = src[wh + j * width + i]; dst[k++] = src[wh + j * width + i + 1]; } } } int main() { // 假设输入的 YUV420sp 图像是 128x128 大小 int width = 128; int height = 128; int wh = width * height; int uvSize = wh >> 2; unsigned char *src = new unsigned char[wh + uvSize * 2]; unsigned char *dst = new unsigned char[wh + uvSize * 2]; // 假设将输入的图像初始化为某个值 for (int i = 0; i < wh + uvSize * 2; i++) { src[i] = i; } rotateYUV420sp90Degree(src, dst, width, height); // 输出旋转后的图像 for (int i = 0; i < wh + uvSize * 2; i++) { printf("%d ", dst[i]); } delete[] src; delete[] dst; return 0; } ``` 上述代码使用一个 `rotateYUV420sp90Degree` 函数来旋转 YUV420sp 图像。这个函数首先旋转 Y 分量,然后旋转 U 和 V 分量。在 `main` 函数中,假设输入的图像大小为 128x128,将输入的图像初始化为某个值,然后调用 `rotateYUV420sp90Degree` 函数进行旋转,并打印旋转后的图像数据。 请注意,上述代码仅适用于 YUV420sp 格式的图像,如果输入的图像格式不是 YUV420sp,则需要进行相应的修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值