2013-06-19 20 views
3

我正在研究圖像處理算法,並且正在研究使用NEON對其進行優化。該算法包括將每個(RGBA,8位)像素乘以某個權重,進行一些加法並最終轉換回uint8_t值。 我遇到的第一個問題是如何有效地將單個uint8_t像素加載並轉換爲NEON的float32x4_t。我搜索一個合適的轉換的參考,並不能找到一個適合,所以我使出了這個醜陋的代碼:如何在ARM NEON中將uint8x8_t加載到float32x4中?

const uint8_t* psrc = ...; // pointer to image data 
float rgba[4]; 
for (int c = 0; c < 4; ++c) { 
    rgba[c] = *psrc++; 
} 
float32x4_t srcpix = vld1q_f32(rgba); 

任何人都可以建議對這個「清潔」的方式?

編輯: 所以我想出了這個,還是覺得很麻煩:

uint8x8_t srcu8 = vld1_u8(psrc); 
uint16x8_t srcu16x8 = vmovl_u8(srcu8); 
uint16x4_t srcu16x4 = vget_low_u16(srcu16x8); 
uint32x4_t srcu32x4 = vmovl_u16(srcu16x4); 
srcpix = vcvtq_f32_u32(srcu32x4); 

回答

0

據我所知,NEON僅支持32位的轉換(使用vcvt_...()可以float32x4_tint32x4_t之間的轉換(例如))。因此,您需要將uint8x8_t轉換爲uint32x4x2_t,然後在uint32x4x2_t的兩半中使用vcvt

編輯: 不幸的是,我不能,因爲我沒有用它做了很多的時間爲您提供的代碼也記不住命令。

+0

感謝您的快速回復,我想出了一個與您的方法類似的不同版本。它仍然看起來像很多拓寬和轉換給我.. – avish

+0

@avish與我談論的完全一樣 – Alex

1

所以,你想要將它們轉換爲浮點運算並將結果轉換回int?這與人們所說的優化完全相反。

堅持NEON真正閃耀的定點算術。

我幾乎無法想象任何情況下,轉換爲浮點數將有意義處理ARGB格式,其中每個通道的大小僅爲8位(精確度)。

顯然你試圖讓NEON只是在ARM完成浮點運算的時候來回轉換,但這正是利用NEON的錯誤方法。

一個合適的NEON優化函數應該讓NEON自己處理數據加載,算術和數據存儲。正確完成後,我確信NEON版本的運行速度將比目前的速度快20倍,速度接近memcpy。 - NEON在定點運算方面非常強大。

請透露更多信息您正在嘗試做什麼。也許我可以幫忙。

+0

嘿,感謝您的評論 - 我正在試驗NEON優化,而且我覺得我在黑暗中刺傷。 在我的C參考impl中,我將RGBA像素的每個通道乘以相同的浮點權重。我認爲使用NEON指令來做到這一點(vmlaq_n_f32)可能會有所幫助。你是說float操作在ARM上運行? – avish

+0

,這裏我透露更多信息:):http://stackoverflow.com/questions/17206315/image-resizing-using-arm-neon – avish

1

VTBX查表指令可以在一個單一的操作進行無符號的8位,32位擴展,但不幸的是,輸出是一個霓虹燈寄存器(將uint32x2_t),所以要「補」,你需要調用它兩次uint32x4_t。對於所有的8個字節的uint8x8_t源的,你必須做的:

uint8x8_t bvec = vld1_u8(psrc); 

uint8x8x4_t tbl = { 
    { 0, -1, -1, -1, 1, -1, -1, -1 }, 
    { 2, -1, -1, -1, 3, -1, -1, -1 } 
    { 4, -1, -1, -1, 5, -1, -1, -1 } 
    { 6, -1, -1, -1, 7, -1, -1, -1 } 
}; 

uint32x4_t ivec[2] = { 
    { 
    vreinterpret_u32_u8(vtbx1_u8(tbl[0], bvec, 0)), 
    vreinterpret_u32_u8(vtbx1_u8(tbl[1], bvec, 0)) 
    }, 
    { 
    vreinterpret_u32_u8(vtbx1_u8(tbl[2], bvec, 0)), 
    vreinterpret_u32_u8(vtbx1_u8(tbl[3], bvec, 0)) 
    } 
}; 

float32x4_t vec[2] = { vcvtq_f32_u32(ivec[0]), vcvtq_f32_u32(ivec[1]) }; 

我不認爲它比你找到了方法較少的指令。查找表也會來自內存,所以它可能會變慢。然後還有需要vreinterpret... ...這是一個免費的操作,但看起來很糟糕。