使用 PIL,我正在使用getpixel和對給定影像應用彩虹濾鏡setpixel。一個問題,這種方法很慢。完成一張影像大約需要 10 秒。
def Rainbow(i):
x = 1 - abs(((i / 60) % 2) - 1)
i %= 360
if (i >= 0 and i < 60 ): r,g,b = 1, x, 0
if (i >= 60 and i < 120): r,g,b = x, 1, 0
if (i >= 120 and i < 180): r,g,b = 0, 1, x
if (i >= 180 and i < 240): r,g,b = 0, x, 1
if (i >= 240 and i < 300): r,g,b = x, 0, 1
if (i >= 300 and i < 360): r,g,b = 1, 0, x
res = (int(r * 255), int(g * 255), int(b * 255))
return res
def RainbowFilter(img):
for x in range(img.size[0]):
for y in range(img.size[1]):
intensity = sum(img.getpixel((x, y)))
img.putpixel((x, y), Rainbow(intensity x y))
return img
im = Image.open('cat.jpg')
rainbow_im = RainbowFilter(im)
rainbow_im.save('rainbow_im.png')
你能幫我改進我的特定演算法,使用專門的 Numpy 或 Pillow 功能來解決提到的問題嗎?
uj5u.com熱心網友回復:
我對此很感興趣,并決定嘗試優化來自@I'mahdi 的代碼。
我的想法如下:
預先創建并歸零輸出影像,避免在主回圈中寫入已經歸零的元素
僅對外部
nb.prange()回圈使用并行化,因為如果您有 12 個 CPU 內核,則已經創建了 12 個執行緒避免在每次迭代中創建一個新的 3 元素 Numpy 陣列來分配給輸出陣列的 RGB 元素 - 只需直接分配兩個非零值
大幅減少
if陳述句中的測驗數量。原始代碼使用多達 12 次測驗來確定 6 個扇區中的哪個扇區i。i如果在最后一個扇區,它將完成所有 12 個。我的代碼在 2-4 次測驗中完成,更像是二進制搜索。
#!/usr/bin/env python3
from PIL import Image
import numba as nb
import numpy as np
def Rainbow(i):
x = 1 - abs(((i / 60) % 2) - 1)
i %= 360
if (i >= 0 and i < 60 ): r,g,b = 1, x, 0
if (i >= 60 and i < 120): r,g,b = x, 1, 0
if (i >= 120 and i < 180): r,g,b = 0, 1, x
if (i >= 180 and i < 240): r,g,b = 0, x, 1
if (i >= 240 and i < 300): r,g,b = x, 0, 1
if (i >= 300 and i < 360): r,g,b = 1, 0, x
res = (int(r * 255), int(g * 255), int(b * 255))
return res
def RainbowFilter(img):
for x in range(img.size[0]):
for y in range(img.size[1]):
intensity = sum(img.getpixel((x, y)))
img.putpixel((x, y), Rainbow(intensity x y))
return img
@nb.njit(parallel=True)
def imahdi(img):
intensity = img.sum(axis=-1)
row , col = img.shape[:2]
for r in nb.prange(row):
for c in nb.prange(col):
i = (intensity[r,c] r c)
x = 1 - abs(((i / 60) % 2) - 1)
i %= 360
res = np.zeros(3)
if (i >= 0 and i < 60 ): res = np.array([1, x, 0])
elif (i >= 60 and i < 120): res = np.array([x, 1, 0])
elif (i >= 120 and i < 180): res = np.array([0, 1, x])
elif (i >= 180 and i < 240): res = np.array([0, x, 1])
elif (i >= 240 and i < 300): res = np.array([x, 0, 1])
elif (i >= 300 and i < 360): res = np.array([1, 0, x])
img[r,c] = res * 255
return img
@nb.njit(parallel=True)
def mark(img):
intensity = img.sum(axis=-1)
row , col = img.shape[:2]
# Create zeroed result image
res = np.zeros_like(img)
for r in nb.prange(row):
# Only make outer loop parallel else inner one will make more threads than cores
for c in range(col):
i = (intensity[r,c] r c)
x = 1 - abs(((i / 60) % 2) - 1)
x = int(x * 255)
i %= 360
# Split the problem space in half in one test - like binary search
if i < 180:
if i < 60:
# Don't create whole new array here
# Don't assign zeroes, array is empty already
res[r,c,0] = 255
res[r,c,1] = x
elif i < 120:
res[r,c,0] = x
res[r,c,1] = 255
else:
res[r,c,1] = 255
res[r,c,2] = x
else:
if i < 240:
res[r,c,1] = x
res[r,c,2] = 255
elif i < 300:
res[r,c,0] = x
res[r,c,2] = 255
else:
res[r,c,0] = 255
res[r,c,2] = x
return res
orig = Image.open('cat.jpg')
res = RainbowFilter(orig)
res.save('result.png')
im = np.asarray(orig)
res = imahdi(im)
Image.fromarray(res).save('imahdi.ppm')
res = mark(im)
Image.fromarray(res).save('mark.ppm')
以下是時間安排:
In [17]: %timeit res = RainbowFilter(orig)
11.7 s ± 80 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [18]: %timeit res = imahdi(im)
1.52 s ± 4.81 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [13]: %timeit res=mark(im)
35.6 ms ± 928 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
uj5u.com熱心網友回復:
您可以轉換image為NumPy.array然后numba用于提高速度,如下所示:
from PIL import Image
import numba as nb
import numpy as np
@nb.njit(parallel=True)
def new_RainbowFilter(img):
intensity = img.sum(axis=-1)
row , col = img.shape[:2]
for r in nb.prange(row):
for c in nb.prange(col):
i = (intensity[r,c] r c)
x = 1 - abs(((i / 60) % 2) - 1)
i %= 360
res = np.zeros(3)
if (i >= 0 and i < 60 ): res = np.array([1, x, 0])
elif (i >= 60 and i < 120): res = np.array([x, 1, 0])
elif (i >= 120 and i < 180): res = np.array([0, 1, x])
elif (i >= 180 and i < 240): res = np.array([0, x, 1])
elif (i >= 240 and i < 300): res = np.array([x, 0, 1])
elif (i >= 300 and i < 360): res = np.array([1, 0, x])
img[r,c] = res * 255
return img
im = Image.open('cat.jpg')
img = np.asarray(im)
img = new_RainbowFilter(img)
im = Image.fromarray(img)
im.save('rainbow_im.png')
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/456520.html
上一篇:將histeq函式應用于3x3塊
下一篇:在影像中查找框并保存為影像cv2
