背景
最近需要對Android攝像頭採集出來的的NV21數據,做個順時針90度的旋轉,流暢352x288,與標清640x480算法都還能滿足,但是高清1280x720的時候,算法A明顯落後算法B.現在沒時間研究,只能記錄下來,希望你可以提出你們寶貴的意見,讓我少走點彎路.
現象
- 在352x288分辨率下,兩者耗時相當20ms左右;
- 在640x480時,算法A平均耗時50ms,而算法B平均耗時23ms;
- 在1280x720是,算法A平均耗時133ms,而算法B平均耗時55ms;
算法類別\分辨率 | 352x288 | 640x480 | 1280x720 |
---|---|---|---|
算法A | 20ms | 50ms | 133ms |
算法B | 20ms | 23ms | 54ms |
算法A
算法A共有3段代碼
第一段
/**
* NV21數據 順時針旋轉90度
* @param inData
* @param outData
* @param width
* @param height
*/
public static void rotateNV21(byte[] inData, byte[] outData, int width, int height) {
int ySize = width * height;
int uvSize = ySize / 2;
//旋轉Y
clockwise90Planar(inData, 0, ySize,outData, 0, width, height);
//旋轉UV
clockwise90Packed(inData, ySize, uvSize, outData, ySize, width, height / 2, 2);
}
第二段
/**
* 順時針旋轉90度 矩陣數據
* @param in_data 輸入數據
* @param width 旋轉前 寬
* @param height 旋轉前 高
* @param out_data 輸出數據
* @param srcOffset 輸入數據起始座標
* @param length 操作數據長度
* @param offset 輸出數據其實座標
*/
public static void clockwise90Planar(byte[] in_data, int srcOffset,int length, byte[] out_data, int offset, int width, int height) {
// if((length % width !=0) || (length % height !=0)) {
// Log.e("Rotate", "clockwise90() data is valid!");
// }
int x,y,/*x,y*/
xp,yp;/*x',y'*/
int outIndex = 0;//輸出數組的下標
for (int index = 0; index < length - 1; index++) {
/** The first step is to convert the index => (x,y) */
x = index % width;
y = index / width;
/** The second step is to convert the (x',y') => out_index */
xp = (height - y -1);
yp = x;
outIndex = yp * height/*此處爲新矩陣的width',所以用原來矩陣的height*/ + xp;
// String s = String.format(" value - x = %d, y = %d, x' = %d, y' = %d, index = %d, oindex = %d, px = %d", x, y, xp, yp, index, outIndex, in_data[index]);
// Log.i("Rotate", s);
/** fill data */
out_data[offset + outIndex] = in_data[srcOffset + index];
/** outIndex = ((index % width) + 1) x height - (index / width) - 1 */
}
}
第三段
/**
* 順時針旋轉90度 矩陣數據Packed類型
* @param in_data 輸入數據
* @param width 旋轉前 寬
* @param height 旋轉前 高
* @param out_data 輸出數據
* @param srcOffset 輸入數據起始座標
* @param length 操作數據長度
* @param offset 輸出數據其實座標
* @param pNum 每個組合的個數 如:YYYYYYYY UVUV 其中UV爲一個旋轉組合,pNum = 2
*/
public static void clockwise90Packed(byte[] in_data, int srcOffset,int length, byte[] out_data, int offset, int iWidth, int iHeight, int pNum) {
// if((length % width !=0) || (length % height !=0)) {
// Log.e("Rotate", "clockwise90() data is valid!");
// }
int widthPerNum = iWidth / pNum;
int heightPerNum = iHeight;
/** 遍歷uv集合的個數 */
int len = length / pNum;
int x,y,/*x,y*/
xp,yp;/*x',y'*/
int outIndex = 0;//輸出數組的下標
for (int index = 0; index < len; index++) {
/** The first step is to convert the index => (x,y) */
x = index % widthPerNum;
y = index / widthPerNum;
/** The second step is to convert the (x',y') => out_index */
xp = (heightPerNum - y -1);
yp = x;
outIndex = yp * heightPerNum/*此處爲新矩陣的width',所以用原來矩陣的height*/ + xp;
// String s = String.format(" value - x = %d, y = %d, x' = %d, y' = %d, index = %d, oindex = %d, px = %d", x, y, xp, yp, index, outIndex, in_data[pNum * index]);
// System.out.println(s);
/** fill data */
for (int j = 0; j < pNum; j++) {
out_data[offset + pNum * outIndex + j] = in_data[srcOffset + pNum * index + j];
}
/** outIndex = ((index % width) + 1) x height - (index / width) - 1 */
}
}
算法B
代碼如下
/**
* 旋轉NV21
* @param src
* @param dst
* @param W
* @param H
*/
public static void rotateNV21F(byte[] src,byte[] dst,int W,int H)
{
/*
*
* YYYYYYYYVUVU
*
*/
int k=0;
//--1--rotate Y-----
for(int i=0;i<W;i++)
{
for(int j=H-1;j>=0;j--)
{
dst[k++] = src[j*W+i];
}
}
//--2--rotate VU---
int start = W*H;
int row = H/2;
int col = W/2;
for(int i=0;i<col;i++)//VU的列
{
for(int j=row-1;j>=0;j--)//VU的行數
{
dst[k++]=src[start + (j*col+i)*2];//V
dst[k++]=src[start + (j*col+i)*2+1]; //U
}
}
}