1. 程式人生 > >Android平臺-彩色RGB影象灰度化-neon優化例項解析

Android平臺-彩色RGB影象灰度化-neon優化例項解析

影象的灰度化公式比較簡單。

Y = (R * 77 + G * 151 + B * 28 ) / 256

傳統的C語言一次處理一個畫素點,neon指令可以一次處理8個畫素點,下面看看neon優化後的加速效果。

在Android  NDK Samples 中有一個hello-neon的工程,裡面有一個濾波器的C程式碼和neon優化程式碼時間對比,

這裡可以在這個框架上加入RGB灰度化的neon例項。

程式碼如下:

//image gray sample
//NEON優化前的程式碼
void reference_convert (uint8_t * __restrict dest, uint8_t * __restrict src, int n)
{
	 int i;
	 for (i=0; i<n; i++)
	 {
		   int r = *src++; // load red
		   int g = *src++; // load green
		   int b = *src++; // load blue

		   // build weighted average:
		   int y = (r*77)+(g*151)+(b*28);

		   // undo the scale by 256 and write to memory:
		   *dest++ = (y>>8);
	 }
}
//NEON優化後的程式碼
void neon_convert (uint8_t * __restrict dest, uint8_t * __restrict src, int n)
{
	 int i;
	 uint8x8_t rfac = vdup_n_u8 (77);       // 轉換權值  R
	 uint8x8_t gfac = vdup_n_u8 (151);    // 轉換權值  G
	 uint8x8_t bfac = vdup_n_u8 (28);      // 轉換權值  B
	 n/=8;

	 for (i=0; i<n; i++)
	 {
		   uint16x8_t  temp;
		   uint8x8x3_t rgb  = vld3_u8 (src);
		   uint8x8_t result;

		   temp = vmull_u8 (rgb.val[0],      rfac);       // vmull_u8 每個位元組(8bit)對應相乘,結果為每個單位2位元組(16bit)
		   temp = vmlal_u8 (temp,rgb.val[1], gfac);  // 每個位元對應相乘並加上
		   temp = vmlal_u8 (temp,rgb.val[2], bfac);

		   result = vshrn_n_u16 (temp, 8);  // 全部移位8位
		   vst1_u8 (dest, result);   // 轉存運算結果
		   src  += 8*3;
		   dest += 8;
	 }
}

程式碼解析:

uint8x8_t 為一個8位的向量,向量的每個元素的資料型別為uint8_t型別,實際上也就是 unsigned char型別

uint16x8_t 為一個8位的向量,向量的每個元素的資料型別為uint16_t型別,實際上也就是 unsigned short型別

vdup_n_u8 裝載8位常數向量

uint8x8x3_t 是一個結構定義:

struct int8x8x3_t

{

int8x8_t val[3];

};

包含了3個int8x8_t資料型別

vmull_u8 每個位元組對應相乘

vmlal_u8 乘累加

vshrn_n_u16

右移操作vst1_u8 資料轉存,

從uint8X8_t變為位元組流