android NV21裁剪算法
程序员文章站
2024-03-16 20:41:58
...
NV21裁剪算法
简要
最近,在做Android摄像头预览方法的事情,usb摄像头出来的数据都是16:9的,无法正常在竖屏状态下显示,所以就要对摄像头的数据进行裁剪处理,摄像头出来的数据是NV21(就是yuv420sp)格式,libyuv的裁剪算法是针对i420格式进行操作,裁剪NV21就得进行格式转换,一个裁剪需要三个操作,效率可想而知,经过测试libyuv对1920x1080进行裁剪,在rk3399上需要耗时40ms左右,算了,自己研究了一下,写了一个裁剪算法,水平差,写了个的NV21裁剪算法,首先是要了解 NV21的数据格式,网上太多文章了,我就不赘述了
NV21格式 YYYYYYYYVUVU
好了,开始裁剪吧,裁剪就是删数据嘛
/**
* NV21裁剪 by lake 算法效率 11ms
*
* @param src 源数据
* @param width 源宽
* @param height 源高
* @param left 顶点坐标
* @param top 顶点坐标
* @param clip_w 裁剪后的宽
* @param clip_h 裁剪后的高
* @return 裁剪后的数据
*/
public static byte[] cropNV21(byte[] src, int width, int height, int left, int top, int clip_w, int clip_h) {
if (left > width || top > height) {
return null;
}
//取偶
int x = left * 2 / 2, y = top * 2 / 2;
int w = clip_w * 2 / 2, h = clip_h * 2 / 2;
int y_unit = w * h;
int src_unit = width * height;
int uv = y_unit >> 1;
byte[] nData = new byte[y_unit + uv];
for (int i = y, len_i = y + h; i < len_i; i++) {
for (int j = x, len_j = x + w; j < len_j; j++) {
nData[(i - y) * w + j - x] = src[i * width + j];
nData[y_unit + ((i - y) / 2) * w + j - x] = src[src_unit + i / 2 * width + j];
}
}
return nData;
}
原理很简单,就是源数据根据条件把yvu塞到一个新数组里,测试一下这个算法,需要11ms,还是太慢了。参照了一下别人c实现的裁剪算法。做了一下修改
/**
* NV21裁剪 算法效率 3ms
*
* @param src 源数据
* @param width 源宽
* @param height 源高
* @param left 顶点坐标
* @param top 顶点坐标
* @param clip_w 裁剪后的宽
* @param clip_h 裁剪后的高
* @return 裁剪后的数据
*/
public static byte[] clipNV21(byte[] src, int width, int height, int left, int top, int clip_w, int clip_h) {
if (left > width || top > height) {
return null;
}
//取偶
int x = left * 2 / 2, y = top * 2 / 2;
int w = clip_w * 2 / 2, h = clip_h * 2 / 2;
int y_unit = w * h;
int uv = y_unit / 2;
byte[] nData = new byte[y_unit + uv];
int uv_index_dst = w * h - y / 2 * w;
int uv_index_src = width * height + x;
int srcPos0 = y * width;
int destPos0 = 0;
int uvSrcPos0 = uv_index_src;
int uvDestPos0 = uv_index_dst;
for (int i = y; i < y + h; i++) {
System.arraycopy(src, srcPos0 + x, nData, destPos0, w);//y内存块复制
srcPos0 += width;
destPos0 += w;
if ((i & 1) == 0) {
System.arraycopy(src, uvSrcPos0, nData, uvDestPos0, w);//uv内存块复制
uvSrcPos0 += width;
uvDestPos0 += w;
}
}
return nData;
}
运行一下,只需要2ms~3ms就能裁剪完。
接着自己又实现了一下NV21裁剪的同时进行镜像操作。
/**
* 剪切NV21数据并且镜像 算法效率1080x1920 14ms 1280x720 6ms
*
* @param src
* @param width
* @param height
* @param left
* @param top
* @param clip_w
* @param clip_h
* @return
*/
public static byte[] clipMirrorNV21(byte[] src, int width, int height, int left, int top, int clip_w, int clip_h) {
if (left > width || top > height) {
return null;
}
//取偶
int x = left, y = top;
int w = clip_w, h = clip_h;
int y_unit = w * h;
int src_unit = width * height;
int uv = y_unit / 2;
byte[] nData = new byte[y_unit + uv];
int nPos = (y - 1) * width;
int mPos;
for (int i = y, len_i = y + h; i < len_i; i++) {
nPos += width;
mPos = src_unit + (i >> 1) * width;
for (int j = x, len_j = x + w; j < len_j; j++) {
nData[(i - y + 1) * w - j + x - 1] = src[nPos + j];
if ((i & 1) == 0) {
int m = y_unit + (((i - y) >> 1) + 1) * w - j + x - 1;
if ((m & 1) == 0) {
m++;
nData[m] = src[mPos + j];
continue;
}
m--;
nData[m] = src[mPos + j];
}
}
}
return nData;
}
就单纯预览的话,这个时间是可以接受的。
上一篇: lintcode 1119 三个数的最大乘积(java实现)
下一篇: 对称加密和非对称加密
推荐阅读
-
android NV21裁剪算法
-
计算机图形学:多边形裁剪算法-Sutherland—Hodgman算法
-
Sutherland-Hodgman算法:OpenGL GLFW实现交互的多边形裁剪
-
用Sutherland-Hodgman算法实现裁剪任意凸多边形
-
在OpenGL环境下, 运用Sutherland_Hodheman算法实现多边形裁剪
-
Android中常用的加密算法——MD5加密
-
java,android,MD5加密算法的实现代码(16位,32位)
-
java,android,MD5加密算法的实现代码(16位,32位)
-
Android拍照或从图库选择图片并裁剪
-
Android裁剪图像实现方法示例