此代碼是照片中的高斯噪聲符號。存在速度問題:fhd 照片處理時間約為 0.45 秒。這對于我的任務是不允許的。我需要達到至少毫秒的速度。
import numpy as np
import cv2
image = cv2.imread('1.jpg')
row,col,ch= image.shape
mean = 0
var = 0.1
sigma = var**0.5
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
noisy = image gauss
cv2.imwrite('2.jpg', noisy)
已經優化了代碼最慢的部分(生成亂數陣列)(這個操作大約需要0.32s):
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch
我將矩陣縮小一百倍,然后將其乘以一百倍:
roww=int(row/100)
b = timeit.default_timer()
gauss = np.random.normal(mean,sigma,(roww,col,ch))
gauss = gauss.reshape(roww*col*ch)
gauss = np.tile(gauss, 100)
gauss = gauss.reshape(row,col,ch)
上面的代碼需要 20ms,其中大部分時間花在將一個矩陣乘以一個大矩陣(18ms)上:
gauss = np.tile(gauss, 100)
你怎么能讓這個操作更快?
現在是主要問題:所有這些代碼仍然需要很長時間(170ms),最耗時的操作:
添加矩陣需要 30 毫秒。
noisy=image gauss
打開(35ms)
image = cv2.imread("1.jpg"
并保存(90 毫秒)照片:
cv2.imwrite('2.jpg', noisy)
是否可以在 python 中以任何方式加速這些操作?謝謝!
完整代碼:
import numpy as np
import cv2
image = cv2.imread('1.jpg')
row,col,ch= image.shape
mean = 0
var = 0.1
sigma = 10
roww=int(row/100)
gauss = np.random.normal(mean,sigma,(roww,col,ch))
gauss = gauss.reshape(roww*col*ch)
gauss = np.tile(gauss, 100)
gauss = gauss.reshape(row,col,ch)
noisy=image gauss
cv2.imwrite('2.jpg', noisy)
uj5u.com熱心網友回復:
第一個代碼受生成亂數的時間限制。這通常是一個緩慢的操作(無論語言如何,盡管有一些技巧可以加快低級本機代碼的性能)。因此,在 Numpy 中沒有什么可做的。您可以使用 Numba 來并行化此操作,但請注意,當前Numba 的亂數生成器在順序上比 Numpy 慢一些。
讀/寫操作應受您的存盤設備和編碼/解碼速度的限制。對于前者,您可以使用記憶體中的虛擬設備,但如果您無法控制它,那么就沒有什么可做的(除了使用更快的硬體,如 Nvme SSD)。對于后者,OpenCV 的 Python 包裝器已經使用了高度優化的 JPEG 編碼器/解碼器,該編碼器/解碼器在執行操作方面應該已經很快。所以你不能加速這部分,但你可以并行執行多個。
關于Numpy代碼,主要有兩個問題:
首先,np.random.normal生成一個64 位浮點數(float64) 陣列,而影像陣列只包含8 位整數(uint8)。處理 float64 值的成本要高得多比 uint8 的(在最壞的情況下最多慢一個數量級)。不幸的是,沒有(簡單)方法來生成具有正態分布的隨機整數,因為該分布與實數緊密相關。Numpy 也缺少用于 float32 的引數。您重用數字的解決方案非常適合提高性能。盡管如此,添加一個帶有 float64 的 uint8 陣列還是很昂貴的,因為 Numpy 將第一個陣列轉換為一個 float64 陣列,然后生成一個新的 float64 陣列。您可以首先將隨機陣列轉換為 uint8 陣列,但這在實踐中并不容易。實際上,負值無法轉換為正確的 uint8 值,即使可以,添加也可能導致一些溢位。
此外,np.tile理論上不應該復制陣列,但遺憾的是,它確實在這里復制了一份。希望您可以使用廣播洗掉這個昂貴的副本。
這是結果代碼:
row,col,ch= image.shape
mean = 0
var = 0.1
sigma = 10
roww=int(row/100)
gauss = np.random.normal(mean,sigma,(roww,col,ch))
noisy=(image.reshape(-1,roww,col,ch) gauss.astype(np.uint8)).reshape(row, col, ch)
我建議您使用 Numba 執行整個操作:
import numba as nb
@nb.njit('uint8[:,:,::1](uint8[:,:,::1])', parallel=True)
def compute(image):
row, col, ch = image.shape
mean = 0
var = 0.1
sigma = 10
out = np.empty_like(image)
roww=int(row/40)
gauss = np.random.normal(mean,sigma,(roww,col,ch))
for i in nb.prange(row):
iWrap = i % roww
for j in range(col):
for c in range(ch):
rnd = gauss[iWrap, j, c]
intRnd = int(np.round(rnd))
noisedInt = int(image[i, j, c]) intRnd
clampedNoisedInt = min(max(noisedInt, 0), 255)
out[i, j, c] = clampedNoisedInt
return out
以下是我的 6 核機器在 1920x1080x3 影像上的時序(不包括讀/寫影像的時間):
Initial: 23.2 ms
Optimized with Numpy: 17.9 ms
Optimized with Numba: 4.3 ms
如果這還不夠快,那么您需要使用低級快速 SIMD 內在函式和多執行緒在 C 中重寫此操作。
在我的機器上讀/寫分別需要大約 21/42 毫秒(這實際上很好,因為輸入/輸出影像被嚴重壓縮)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/384721.html
