Android中摄像头获取的YUV数据转Opencv的Mat

背景

在onPreviewFrame方法中获取的byte[] data数据为420sp格式,排列顺序为width*height个Y(亮度信息,就是我们常见的灰度图像),后面是UV(颜色信息),4个Y共享一个U和V,故byte数组的总大小是width*height*2/3
420sp通常是如下形式(UV交替属于NV12)(或者VU交替属于NV21):

[               [
	Y Y Y Y        Y Y Y Y
	Y Y Y Y  或    Y Y Y Y
	U V U V        V U V U
]               ]

先通过JNI把YUV420sp数据转换成YUV420p数据。420p就是YYYYYYYYUUVV这样存放的格式,相当于数组中的数据交换位置而已,很好实现。(当然,后来发现Opencv可以直接处理sp的数据格式)。
https://www.cnblogs.com/samaritan/p/YUV.html,这个博客详细介绍了YUV数据的格式。
###opencv数据类型
Mat的数据类型分为8U,16S,32F,64F等。在这里我们使用8U类型,YUV数据也是8位无符号类型的。C1,C2,C3,C4为通道数,YUV为单通道,即8UC1。

尝试一(认为可行,结果失败,求大神解答)

想着OpencvForAndroid中,初始化Mat中有一个方法为:

Mat mat = new Mat(int rows, int cols, int type, ByteBuffer data);

其中ByteBuffer为Nio包中的类,可以使用静态方法ByteBuffer.wrap(data)进行转换。使用如下代码:

	Mat mat = new Mat((int)frameHeight*1.5,frameWidth,CvType.CV_8UC1,ByteBuffer.wrap(data));

执行这一句的时候,一直报CvException错误,查看错误中是Mat的本地代码报的错,显示data.total为0。一直不明白怎么回事,放弃。

尝试二

OpencvForAndroid中还有一个方法可以初始化矩阵,或者称给矩阵赋值。

	Mat mat = new Mat(frameHeight*1.5,frameWidth,CvType.CV_8UC1);//初始化一个矩阵,没数据
	mat.put(0,0,data);//从(0,0)开始放数据,直到data放完或者矩阵被填满(若是多通道,则把当前位置的通道全部填满,才继续下一个位置,data长度必须整除通道数).
	Mat bgr_i420 = new Mat();
	Imgproc.cvtColor(mat , bgr_i420, Imgproc.COLOR_YUV2BGR_I420);//转换颜色空间
	//对bgr格式的mat做一些常见的处理.
	Mat result = new Mat();
	Imgproc.cvtColor(bgr_i420, result , Imgproc.COLOR_BGR2YUV_I420);//转换回YUV420p格式
	byte[] data_result = new byte[(int)frameHeight*frameWidth*1.5];
	result.get(0,0,data_result);//从(0,0)开始取数据,过程同上

通过上面的代码,可以把YUV数据转成BGR格式,进行一系列处理,在转换成YUV数据,保存或者推流走。

结语

Imgproc.cvtColor(src, dst , Imgproc.COLOR_XXXXXX);
其中XXX有多种模式可选,可以直接将420SP(NV12/NV21)转换成BGR,具体的常量,自己打开工程试试就知道了。
data转成Mat,基于Mat可以用来做人脸识别、美颜、贴图、换脸等功能。

你可能感兴趣的:(android,opencv)