android yuv数据处理_YUV像素数据处理

YUV简介

YUV,是一种颜色编码方法。常使用在各个视频处理组件中。 YUV在对照片或视频编码时,考虑到人类的感知能力,允许降低色度的带宽。

YUV是编译true-color颜色空间(color space)的种类,Y'UV, YUV, YCbCr,YPbPr等专有名词都可以称为YUV,彼此有重叠。“Y”表示

格式

YUV Formats分成两个格式:

紧缩格式(packed formats):将Y、U、V值存储成Macro Pixels数组,和RGB的存放方式类似。

平面格式(planar formats):将Y、U、V的三个分量分别存放在不同的矩阵中。

紧缩格式(packed format)中的YUV是混合在一起的,对于YUV4:4:4格式而言,用紧缩格式很合适的,因此就有了UYVY、YUYV等。平面格式(planar formats)是指每Y分量,U分量和V分量都是以独立的平面组织的,也就是说所有的U分量必须在Y分量后面,而V分量在所有的U分量后面,此一格式适用于采样(subsample)。平面格式(planar format)有I420(4:2:0)、YV12、IYUV等。

简介总结

为了兼容黑白电视而诞生。Y表示灰度。

对比RBG,需要的带宽小。RGB每一帧需要3*w*h的大小,YUV420这种形式的话,需要w*h*3/2的大小。

YUV420格式了解

在Android上通过Camera可以取到 NV21 与 YV12.YUV数据

YUV420P

8d60ad489bf4

image.png

YV12:

8d60ad489bf4

yv12.png

NV21:

这种格式(NV21)是Android相机预览的标准图片格式。YUV 4:2:0平面图像,8位Y采样,接着是具有8位2x2二次采样色度采样的交织V / U平面。

8d60ad489bf4

NV21.png

YUV像素处理

准备

下载好测试图

8d60ad489bf4

Lenna.png

通过FFmpeg命令,转成NV21

ffmpeg -i Lenna.png -pix_fmt nv21 LennaNv21.yuv

下载YUV Player Deluxe作为图片的预览

http://www.yuvplayer.com/

开始

NV21 To YUV420P

代码

//nv21 YYYYYYYY VU VU => yyyy yyyy uuuu vvvv

public static void nv21ToYuv420(int size, int frameLength, byte[] frame) {

//将Y复制过去

byte[] frameY = new byte[frameLength];

// Arrays.fill(frameY, (byte) 128);

System.arraycopy(frame, 0, frameY, 0, size);

int uvSize = (frameLength - size) / 2;

byte[] uFrame = new byte[uvSize];

byte[] vFrame = new byte[uvSize];

for (int i = 0; i < uvSize * 2; i++) {

int result = i % 2;

int resultIndex = i / 2;

if (result == 0) {

vFrame[resultIndex] = frame[size + i];

// System.out.println("uFrame resultIndex="+resultIndex+", i="+(size+i));

} else {

uFrame[resultIndex] = frame[size + i];

// System.out.println("vFrame resultIndex="+resultIndex+", i="+(size+i));

}

}

System.arraycopy(uFrame, 0, frameY, size, uvSize);

System.arraycopy(vFrame, 0, frameY, size + uvSize, uvSize);

}

结果对比(yuv420格式 512x512预览)

8d60ad489bf4

结果1.png

yuv 420p顺时针 90

代码

public static void yuv420Rotation90(int srcH, int srcW, int frameLength, byte[] frame) {

//将Y复制过去

byte[] frameY = new byte[frameLength];

int size = srcH * srcW;

int uvSize = (frameLength - size) / 2;

//翻转Y

//记录旋转的h w

int rH = 0;

int rW = 0;

for (int oH = 0; oH < srcH; oH++) {

for (int oW = 0; oW < srcW; oW++) {

//第一行->最后一列

//旋转之后,现在的行数等于原来的横向的index

rH = oW;

//现在的w= 原来行数的总和-H

rW = srcH - oH - 1;

frameY[srcW * rH + rW] = frame[srcW * oH + oW];

}

}

//翻转U

//记录旋转的h srcW

srcH = srcH / 2;

srcW = srcW / 2;

for (int oH = 0; oH < srcH; oH++) {

for (int oW = 0; oW < srcW; oW++) {

//第一行->最后一列

//旋转之后,现在的行数等于原来的横向的index

rH = oW;

//现在的w= 原来行数的总和-H

rW = srcH - oH - 1;

frameY[size + srcW * rH + rW] = frame[size + srcW * oH + oW];

}

}

//翻转V

//记录旋转的h srcW

for (int oH = 0; oH < srcH; oH++) {

for (int oW = 0; oW < srcW; oW++) {

//第一行->最后一列

//旋转之后,现在的行数等于原来的横向的index

rH = oW;

//现在的w= 原来行数的总和-H

rW = srcH - oH - 1;

int rP = size + uvSize + srcW * rH + rW;

int oP = size + uvSize + srcW * oH + oW;

frameY[rP] = frame[oP];

}

}

}

结果对比(yuv420格式 512x512预览)

8d60ad489bf4

image.png

翻转

public static void yuv420Flip(int srcH, int srcW, int frameLength, byte[] frame) {

//将Y复制过去

int size = srcW * srcH;

byte[] frameY = new byte[frameLength];

int uvSize = (frameLength - size) / 2;

//翻转Y

//就是讲下面的复制到上面来

for (int i = 0; i < srcH; i++) {

System.arraycopy(frame, (srcH - i - 1) * srcW, frameY, i * srcW, srcW);

}

srcH = srcH / 2;

srcH = srcH / 2;

for (int i = 0; i < srcH; i++) {

System.arraycopy(frame, size + (srcH - i - 1) * srcW, frameY, size + i * srcW, srcW);

}

for (int i = 0; i < srcH; i++) {

System.arraycopy(frame, size + uvSize + (srcH - i - 1) * srcW, frameY, size + uvSize + i * srcW, srcW);

}

}

结果对比(yuv420格式 512x512预览)

8d60ad489bf4

image.png

裁剪

public static void yuv420Clip(int srcH, int srcW, int clipH, int clipW, int startW, int startH, byte[] frame) {

int srcSize = srcH * srcW;

int clipSize = clipH * clipW;

int clipFrameLength = clipH * clipW * 3 / 2;

byte[] frameY2 = new byte[clipFrameLength];

int totalClipH = clipH;

int totalClipW = clipW;

int totalW = srcW;

int totalH = srcH;

//复制Y

for (int i = 0; i < totalClipH; i++) {

//在原来数组中的H

int oH = startH + i;

int srcPos = startW + totalW * oH;

System.arraycopy(frame, srcPos, frameY2, totalClipW * i, totalClipW);

}

totalClipH = clipH / 2;

totalClipW = clipW / 2;

totalW = srcW / 2;

totalH = srcH / 2;

// //复制UV

for (int i = 0; i < totalClipH; i++) {

//在原来数组中的H

int oH = startH / 2 + i;

int srcPos = srcSize + startW / 2 + totalW * oH;

int desPos = clipSize + totalClipW * i;

System.arraycopy(frame, srcPos, frameY2, desPos, totalClipW);

}

for (int i = 0; i < totalClipH; i++) {

//在原来数组中的H

int oH = startH / 2 + i;

int srcPos = srcSize + srcSize / 4 + startW / 2 + totalW * oH;

int desPos = clipSize + clipSize / 4 + totalClipW * i;

System.arraycopy(frame, srcPos, frameY2, desPos, totalClipW);

}

}

结果对比(yuv420格式 左300x300 右512x512预览)

8d60ad489bf4

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值