NEON優化——OpenCV Resize雙線性插值

算法要點

一、基本原理

具體原理可以自行搜索,這裏只大致描述一下,目標圖像上某一個點按比例映射到原始圖像上某一點,不過通常計算得到的原始點座標不是整數,最近鄰的做法是向下取整,而雙線性差值的做法是取與該座標最接近的上下左右四個點來線性加權,在放大的時候不會像最近鄰那樣鋸齒嚴重,但是計算量會大不少。這裏要注意的是加權分爲兩個維度,橫向和縱向。此外,邊界的處理也要注意。

二、優化思路

這裏核心的優化思路有兩點:

  1. 避免重複計算
  2. 浮點轉定點

避免重複計算

首先要分析哪裏存在可能的重複計算。resize是原始圖像和目標圖像之間的映射,這個映射不一定是一對一的。比如對於目標圖像的高大於原始圖像的高的情況,目標圖像的多個行可能會映射到原始圖像的同一行,這樣我們就可以利用之前的計算結果,而不用重複計算。
對於目標圖像上的某個點,映射到原始圖像的座標爲O,相鄰的四個點爲ABCD,則目標圖像的像素值爲val = A(1-fx)(1-fy) + Bfx(1-fy) + C(1-fx)fy + Dfxfy
這個公式可以分解爲兩個過程:HResize和VResize

HResize

val0 = A(1-fx) + Bfx 
val1 = C(1-fx) + Dfx

VResize

val = val0*(1-fy) + val1*fy

之所以分解爲兩步,是因爲上面提到的當目標圖像的多行映射到原始圖像的同一行時,HResize計算的結果是可以複用的,直接拷貝即可。而VResize是無法複用的,因爲即便都映射到同一行,但是fy是不會相同的。

浮點轉定點

浮點轉定點需要乘一個轉換系數。這裏fx和fy都是浮點,OpenCV默認的做法是將fx和fy都乘以固定係數1<<11轉成定點,最後結果再右移22。爲什麼取11,因爲這是保證不溢出的最高的精度。分析上面的val0,假設A和B都取最大255,則val0最大爲2^19。假設val0和val1都取最大值2^19,則val最大爲2^30。如果這個固定係數取12,則val的最大值爲2^32,即便是unsigned也裝不下了。
雖然取11能保證精度最大,但是由於val0最大是2^19,int16是裝不下了,只能進行int32計算,neon一次只能算4個數。因此如果想提升neon向量化計算的並行度,可以給係數降低一點,參考OpenCV的三方庫carotene,係數取的是7,同樣這是爲了保證能進行int16計算的最高精度,因爲這樣val0的最大值爲2^15。此外爲了保證VResize也能進行int16計算,val0和val1要轉回到int8,這一點和OpenCV不一樣。轉換系數的降低可以提升向量化計算的並行度,進而提升性能,不過會對像素值造成一定的精度損失,經過測試,像素值的誤差不會超過3,而轉換系數爲11時這個誤差不會超過1。

整個過程中計算量最重的部分是HResize,我們分析HResize的向量化過程,由於是int16的計算,因此一次最多算8個點,以8UC3爲例,假設映射到原始圖像的8個點分別爲ABCDEFGH,

A = A0 A1 A2 A3 A4 A5 A6 A7
B = B0 B1 B2 B3 B4 B5 B6 B7
C = C0 C1 C2 C3 C4 C5 C6 C7
D = D0 D1 D2 D3 D4 D5 D6 D7
E = E0 E1 E2 E3 E4 E5 E6 E7
F = F0 F1 F2 F3 F4 F5 F6 F7
G = G0 G1 G2 G3 G4 G5 G6 G7
H = H0 H1 H2 H3 H4 H5 H6 H7

對於A點,我們需要

[A0 A1 A2]*K0 + [A3 A4 A5]*K0’,K0=1-fx,K0’=fx,

後面的B~H點同理。

因此向量化計算爲

[A0 B0 C0 D0 E0 F0 G0 H0]*[K0 K1 K2 K3 K4 K5 K6 K7] + [A3 B3 C3 D3 E3 F3 G3 H3]*[K0' K1' K2' K3' K4' K5' K6' K7']
[A1 B1 C1 D1 E1 F1 G1 H1]*[K0 K1 K2 K3 K4 K5 K6 K6] + [A4 B4 C4 D4 E4 F4 G4 H4]*[K0' K1' K2' K3' K4' K5' K6' K7']
[A2 B2 C2 D2 E2 F2 G2 H2]*[K0 K1 K2 K3 K4 K5 K6 K7] + [A5 B5 C5 D5 E5 F5 G5 H5]*[K0' K1' K2' K3' K4' K5' K6' K7']

可見關鍵是要從ABCDEFGH向量中抽取出類似Ai Bi Ci Di Ei Fi Gi Hi(0<=i<6)這樣的向量。

這裏已知兩種做法,一種是轉置,一種是查表。

三、優化結果

輸出336x192,測試以下三種輸入:

phone 224x128 640x360 1280x720
MI6 0.61ms->0.16ms 1.46ms->0.3ms 1.78ms->0.35ms
魅藍5S 1.97ms->0.57ms 4.9ms->1.38ms 5.64ms->1.97ms
IPHONE7 0.31ms->0.06ms 0.7ms->0.12ms 0.8ms->0.17ms

輸出224x128,測試以下三種輸入:

phone 336x192 640x360 1280x720
MI6 0.52ms->0.12ms 0.72ms->0.15ms 0.73ms->0.17ms
魅藍5S 1.67ms->0.45ms 2.33ms->0.64ms 2.59ms->1.25ms
IPHONE7 0.27ms->0.05ms 0.35ms->0.07ms 0.36ms->0.07ms

輸出640x360,測試以下三種輸入:

phone 224x128 336x192 1280x720
MI6 1.51ms->0.36ms 1.84ms->0.45ms 1.91ms->1.21ms
魅藍5S 4.87ms->1.44ms 6.15ms->1.77ms 6.32ms->4.88ms
IPHONE7 0.44ms->0.15ms 0.65ms->0.15ms 0.38ms->0.37ms
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章