首页 > 解决方案 > 使用 Numpy 更有效地改变色调

问题描述

我正在制作一个在线图像编辑器,并且我正在实现一个 Hue/Sat/Lum 编辑器。这是我用给定值更改图像的功能。

def make_edit(pixels, hue, sat, lum):
    shape = pixels.shape
    new = np.empty(shape)
    print(time.time())
    for row_count, row in enumerate(pixels):
        for pixel_count, p in enumerate(row):
            new_hue = p[0] + hue
            if new_hue < 0:
                new_hue += 255
            elif new_hue > 255:
                new_hue -= 255

            new_sat = p[1] + sat
            if new_sat < 0:
                new_sat += 255
            elif new_sat > 255:
                new_sat -= 255

            new_lum = p[2] + lum
            if new_lum < 0:
                new_lum = 0
            elif new_lum > 255:
                new_lum = 255

            new[row_count, pixel_count] = np.array([new_hue, new_sat, new_lum])
    print(time.time())
    return new

该函数采用一个形状为 numpy 的数组(高度、宽度、3)。我逐个像素地做,然后将色调、饱和度和亮度值添加到每个像素。然而,这需要 13 秒(在 (648, 1152, 3) 形状的阵列上),显然太长了。是否有一个 numpy 函数可以将所有值抵消我给它的数量。ps 该功能还没有工作,hue 似乎可以,但是 sat 和 lum 没有给出正确的图像。

标签: pythonnumpypython-imaging-libraryhsv

解决方案


我不认为您的算法或接受的答案是正确的-如果您将pixels数组创建为uint8(而不是int64当前的),您将看到这一点,如果您将输出限制在范围 0.. 255.

您需要将色调与饱和度和亮度区别对待。色调是圆形的,这意味着它“环绕”了一个 0..255 “度”的圆圈。这意味着当它达到 255 并且您添加 1 时,您应该回到零并重新开始。在数学上,这意味着一个模数%。饱和度和亮度不是圆形的,这意味着如果图像几乎完全明亮,比如 250,如果将亮度增加 100,它应该最大程度地“烧毁”。从数学上讲,这是“剪裁”。饱和度也是如此。

所以,我相信你想要更像这样的东西:

#!/usr/bin/env python3

import numpy as np

def make_edit(im, hue, sat, lum):
    # Make signed and larger to accommodate wrap-around
    im = im.astype(np.int32)

    # Add constant amount of hue to each pixel, wrapping around at 255
    im[:,:,0] = (im[:,:,0] + hue) % 256 

    # Add constant amount of saturation, and lightness to each pixel
    im[:,:,1] += sat
    im[:,:,2] += lum

    # Clip results to range 0..255 and return as uint8
    return np.clip(im,0,255).astype(np.uint8)

# Make our randomness deterministic!
np.random.seed(42)

# Create 4x2 array of HSL pixels - note UINT8
im = np.random.randint(0,255,(2,4,3),dtype=np.uint8) 

# array([[[102, 220, 225],
#        [ 95, 179,  61],
#        [234, 203,  92],
#        [  3,  98, 243]],
#
#       [[ 14, 149, 245],
#        [ 46, 106, 244],
#        [ 99, 187,  71],
#        [212, 153, 199]]], dtype=uint8)

res = make_edit(im, 100, 50, 20)
print(res)

#[[[202 255 245]
#  [195 229  81]
#  [ 78 253 112]
#  [103 148 255]]
#
# [[114 199 255]
#  [146 156 255]
#  [199 237  91]
#  [ 56 203 219]]]

res = make_edit(im, -100, -50, -20)
print(res)

#[[[  2 170 205]
#  [251 129  41]
#  [134 153  72]
#  [159  48 223]]
#
# [[170  99 225]
#  [202  56 224]
#  [255 137  51]
#  [112 103 179]]]

请注意,如果您只想通过在终端中运行命令来测试代码,则可以使用ImageMagick 。您可以像这样使用-modulate运算符:

magick INPUTIMAGE -modulate BRIGHTNESS,SATURATION,HUE OUTPUTIMAGE

例如,将亮度减半:

magick input.png -modulate 50 result.jpg

要将亮度保持在其先前值的 100% 不变,请将饱和度增加 20% 并将色相逆时针旋转 90 度(因为 180 的 50% 是 90):

magic input.png -modulate 100,120,50 result.jpg

关键词:Python,图像处理,色调旋转,HSL,HSV,调制。


推荐阅读