使用opencv处理android中的yuv420sp(NV21)图像

NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,每四个Y共用一组UV分量。 ,即Y'00、Y'01、Y'10、Y'11共用Cr00、Cb00。所以,他的容量应该是 y:u:v=4:1:1,即rgb容量的一半。

处理的大概流程是,分离y通道和uv通道,然后对uv通道缩放至正常大小后,分离uv通道,然后合并y,u,v三个通道,最后调用转换函数转换为rgb的图像

下面先给出javacv的测试代码

public static IplImage TransNV21TOIplImage(byte[] buff, int height, int width) {
		//拆分数组,氛围y数组和uv数组
		byte[] y = new byte[width * height];
		byte[] uv = new byte[width * height / 2];
		int index = 0;
		System.arraycopy(buff, index, y, 0, width * height);
		index += width * height;
		System.arraycopy(buff, index, uv, 0, width * height / 2);
		
		//定义一个y通道的图像和一个uv双通道的图像
		IplImage yimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
		IplImage uvimg = cvCreateImage(cvSize(width / 2, height / 2),
				IPL_DEPTH_8U, 2);
		yimg.imageData().put(y);
		uvimg.imageData().put(uv);
		
		//将uv通道的图像从1/4大小,缩放到正常大小
		IplImage fulluvimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 2);
		cvResize(uvimg, fulluvimg, CV_INTER_LINEAR);
		cvReleaseImage(uvimg);
		
		//分离uv通道,用于下一步合并y通道
		IplImage uuimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
		IplImage vvimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
		cvSplit(fulluvimg, uuimg, vvimg, null, null);

		//将y,u,v通道合并
		IplImage yuvimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
		cvMerge(yimg, uuimg, vvimg, null, yuvimg);
		
		//将yuv格式转换为常用的rgb格式
		IplImage rgbimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
		cvCvtColor(yuvimg, rgbimg, CV_YCrCb2BGR);
		
		return rgbimg;
	}

通常情况下android上javacv的兼容性不是特别好,所以通常采用opencv4j+ndk的方式


IplImage* TransNV21TOBGR(char* buff, int height, int width) {

	IplImage* yimg = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, 1);
	IplImage* uvimg = cvCreateImageHeader(cvSize(width / 2, height / 2),
			IPL_DEPTH_8U, 2);

	cvSetData(yimg, buff, width);
	cvSetData(uvimg, buff + width * height, width);

	IplImage* fulluvimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 2);
	cvResize(uvimg, fulluvimg, CV_INTER_LINEAR);
	cvReleaseImageHeader(&uvimg);

	IplImage* uimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
	IplImage* vimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
	cvSplit(fulluvimg, uimg, vimg, NULL, NULL);
	cvReleaseImage(&fulluvimg);

	IplImage* ycrcbimage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U,
				3);
	cvMerge(yimg, uimg, vimg, NULL, ycrcbimage);
	cvReleaseImageHeader(&yimg);
	cvReleaseImage(&uimg);
	cvReleaseImage(&vimg);

	IplImage* rgbimg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
	cvCvtColor(ycrcbimage, rgbimg, CV_YCrCb2BGR);
	cvReleaseImage(&ycrcbimage);
	return rgbimg;
}

测试代码在处理864*480的图像时候,大概耗时500ms左右,效率不是特别高,暂时也没办法优化了

你可能感兴趣的:(opencv)