使用带条件的 numpy 迭代像素的更快方法?

Faster way to iterate through pixel using numpy with conditions?

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(Look up table)/vectorize/something 之类的东西以避免这 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 实现来自 this post. Note that the string in @nb.njit decorators are not mandatory but enable Numba to compile the function ahead of time instead of at the first call. For more information about the types, please read the Numba documentation