python - 使用带有条件的 numpy 更快地遍历像素的方法?
问题描述
def colorize(im, h, s, l_adjust):
result = Image.new('RGBA', im.size)
pixin = np.copy(im)
pixout = np.array(result)
>>>>>>>>>>>>>>>>> loop <<<<<<<<<<<<<<<<<
for y in range(pixout.shape[1]):
for x in range(pixout.shape[0]):
lum = currentRGB(pixin[x, y][0], pixin[x, y][1], pixin[x, y][2])
r, g, b = colorsys.hls_to_rgb(h, lum, s)
r, g, b = int(r * 255.99), int(g * 255.99), int(b * 255.99)
pixout[x, y] = (r, g, b, 255)
>>>>>>>>>>>>>>>>>>>>> Loop end <<<<<<<<<<<
return result
试图从输入视频的帧中找到每个像素的 HSL 值,但它花费了大约 1.5 秒的时间,但希望将时间减少到至少 0.3 秒内。在不使用这两个循环的情况下有更快的方法吗?使用 NumPy 快捷方式寻找诸如 LUT(查找表)/矢量化/某些东西以避免这 2 个循环。谢谢
或者
第 2 部分 ->>
如果我将自定义 currentRGB() 分解为 for 循环,它看起来像:
def colorize(im, h, s, l_adjust):
result = Image.new('RGBA', im.size)
pixin = np.copy(im)
pixout = np.array(result)
for y in range(pixout.shape[1]):
for x in range(pixout.shape[0]):
currentR, currentG, currentB = pixin[x, y][0]/255 , pixin[x, y][1]/255, pixin[x, y][2]/255
#luminance
lum = (currentR * 0.2126) + (currentG * 0.7152) + (currentB * 0.0722)
if l_adjust > 0:
lum = lum * (1 - l_adjust)
lum = lum + (1.0 - (1.0 - l_adjust))
else:
lum = lum * (l_adjust + 1)
l = lum
r, g, b = colorsys.hls_to_rgb(h, l, s)
r, g, b = int(r * 255.99), int(g * 255.99), int(b * 255.99)
pixout[x, y] = (r, g, b, 255)
return pixout
解决方案
您可以使用Numba大幅加快计算速度。这是实现:
import numba as nb
@nb.njit('float32(float32,float32,float32)')
def hue_to_rgb(p, q, t):
if t < 0: t += 1
if t > 1: t -= 1
if t < 1./6: return p + (q - p) * 6 * t
if t < 1./2: return q
if t < 2./3: return p + (q - p) * (2./3 - t) * 6
return p
@nb.njit('UniTuple(uint8,3)(float32,float32,float32)')
def hls_to_rgb(h, l, s):
if s == 0:
# achromatic
r = g = b = l
else:
q = l * (1 + s) if l < 0.5 else l + s - l * s
p = 2 * l - q
r = hue_to_rgb(p, q, h + 1./3)
g = hue_to_rgb(p, q, h)
b = hue_to_rgb(p, q, h - 1./3)
return (int(r * 255.99), int(g * 255.99), int(b * 255.99))
@nb.njit('void(uint8[:,:,::1],uint8[:,:,::1],float32,float32,float32)', parallel=True)
def colorize_numba(pixin, pixout, h, s, l_adjust):
for x in nb.prange(pixout.shape[0]):
for y in range(pixout.shape[1]):
currentR, currentG, currentB = pixin[x, y, 0]/255 , pixin[x, y, 1]/255, pixin[x, y, 2]/255
#luminance
lum = (currentR * 0.2126) + (currentG * 0.7152) + (currentB * 0.0722)
if l_adjust > 0:
lum = lum * (1 - l_adjust)
lum = lum + (1.0 - (1.0 - l_adjust))
else:
lum = lum * (l_adjust + 1)
l = lum
r, g, b = hls_to_rgb(h, l, s)
pixout[x, y, 0] = r
pixout[x, y, 1] = g
pixout[x, y, 2] = b
pixout[x, y, 3] = 255
def colorize(im, h, s, l_adjust):
result = Image.new('RGBA', im.size)
pixin = np.copy(im)
pixout = np.array(result)
colorize_numba(pixin, pixout, h, s, l_adjust)
return pixout
这种优化的并行实现比我的 6 核机器上的原始代码(在 800x600 图像上)快大约 2000 倍。hls_to_rgb
实施来自这篇文章。请注意,@nb.njit
装饰器中的字符串不是强制性的,但可以让 Numba 提前编译函数,而不是在第一次调用时编译。有关类型的更多信息,请阅读Numba 文档。
推荐阅读
- css - 如何仅为我的自定义 vue 组件包含外部 css 文件?
- progressive-web-apps - NUXT-PWA 缓存 POST 请求
- php - 如何检查产品是否存在 laravel
- flutter - 在综合浏览量中:- 滑动时有时会调用 2-3 次 itemBuilder
- wordpress - 如何在 WordPress 中插入 Bootstrap 4 菜单?
- javascript - 无法将数据从 asp.net 动态传递到 javascript 函数?
- swift - 从 Swift 5 FileManager 特定目标 URL 读取数据
- javascript - 如何使用超级代理从 GET/POST 响应消息中提取值
- flutter - 如何将自己的样式添加到 gmap [google_map_flutter 插件]
- vim - VIM:如何获取当前函数名