带Pi的信道混合

2024-05-29 01:56:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我想做一些颜色转换,例如给定的RGB通道

R =  G + B / 2

或者基于同一像素的其他信道的值来计算信道值的其他变换。在

似乎.point()函数只能在一个通道上操作。有办法做我想做的吗?在


Tags: 函数颜色rgb像素point信道办法
2条回答

使用PIL.ImageChops的另一种方法是将图像数据转换为Numpy数组。与在Python数值对象上执行Python循环相比,Numpy使用本机机器数据类型,其编译例程可以非常快速地处理数组数据。所以Numpy代码的速度可以与ImageChops的速度相媲美。你可以在Numpy中做各种数学运算,或者使用相关的库,比如SciPy。在

Numpy提供了一个函数np.asarray,它可以从PIL数据创建Numpy数组。并且PIL.Image有一个.fromarray方法来从Numpy数组加载图像数据。在

下面的脚本显示了两种不同的Numpy方法,以及基于kennytm的ImageChops代码的方法。在

#!/usr/bin/env python3

''' PIL Image channel manipulation demo

    Replace each RGB channel by the mean of the other 2 channels, i.e.,

    R_new = (G_old + B_old) / 2
    G_new = (R_old + B_old) / 2
    B_new = (R_old + G_old) / 2

    This can be done using PIL's own ImageChops functions
    or by converting the pixel data to a Numpy array and
    using standard Numpy aray arithmetic

    Written by kennytm & PM 2Ring 2017.03.18
'''

from PIL import Image, ImageChops
import numpy as np

def comp_mean_pil(iname, oname):
    print('Loading', iname)
    img = Image.open(iname)
    #img.show()

    rgb = img.split()
    half = ImageChops.constant(rgb[0], 128)
    rh, gh, bh = [ImageChops.multiply(x, half) for x in rgb] 
    rgb = [
        ImageChops.add(gh, bh), 
        ImageChops.add(rh, bh), 
        ImageChops.add(rh, gh),
    ]
    out_img = Image.merge(img.mode, rgb)
    out_img.show()
    out_img.save(oname)
    print('Saved to', oname)

# Do the arithmetic using 'uint8' arrays, so we must be 
# careful that the data doesn't overflow
def comp_mean_npA(iname, oname):
    print('Loading', iname)
    img = Image.open(iname)
    in_data = np.asarray(img)

    # Halve all RGB values
    in_data = in_data // 2

    # Split image data into R, G, B channels
    r, g, b = np.split(in_data, 3, axis=2)

    # Create new channel data
    rgb = (g + b), (r + b), (r + g)

    # Merge channels
    out_data = np.concatenate(rgb, axis=2)

    out_img = Image.fromarray(out_data)
    out_img.show()
    out_img.save(oname)
    print('Saved to', oname)

# Do the arithmetic using 'uint16' arrays, so we don't need
# to worry about data overflow. We can use dtype='float'
# if we want to do more sophisticated operations
def comp_mean_npB(iname, oname):
    print('Loading', iname)
    img = Image.open(iname)
    in_data = np.asarray(img, dtype='uint16')

    # Split image data into R, G, B channels
    r, g, b = in_data.T

    # Transform channel data
    r, g, b = (g + b) // 2, (r + b) // 2, (r + g) // 2

    # Merge channels
    out_data = np.stack((r.T, g.T, b.T), axis=2).astype('uint8')

    out_img = Image.fromarray(out_data)
    out_img.show()
    out_img.save(oname)
    print('Saved to', oname)

# Test

iname = 'Glasses0.png'
oname = 'Glasses0_out.png'

comp_mean = comp_mean_npB

comp_mean(iname, oname)

输入图像

Glasses, by Gilles Tran

输出图像

Transformed Glasses

FWIW,该输出图像是使用comp_mean_npB创建的。在

由于执行计算的方式不同,由3个函数生成的计算出的信道值可以彼此相差1,但当然,这种差异并不明显。:)

对于这个特定的操作,颜色转换可以写成矩阵乘法,因此可以使用convert()方法和自定义矩阵(假设没有alpha通道):

# img must be in RGB mode (not RGBA):
transformed_img = img.convert('RGB', (
    0, 1, .5, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
))

否则,您可以split()将图像分成3个或4个每个色带的图像,应用您喜欢的任何操作,最后merge()这些色带返回到单个图像。同样,原始图像应该处于RGB或RGBA模式。在

^{pr2}$

相关问题 更多 >

    热门问题