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)
//取偶
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++)
}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)
//取偶
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++)
}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)
//取偶
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;
nv21 yuv420sp 水平映象翻轉實現
輸入資料是yuv,輸出是flipyuv,uv分量是交替儲存,uvsize剛好是height 2 width,下面的實現沒有考慮stride的情況。void cvtnv21fliph mat myuv,mat mflipyuv flip vu data int ylen width height fo...