#!/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)
使用
PIL.ImageChops
的另一种方法是将图像数据转换为Numpy数组。与在Python数值对象上执行Python循环相比,Numpy使用本机机器数据类型,其编译例程可以非常快速地处理数组数据。所以Numpy代码的速度可以与ImageChops的速度相媲美。你可以在Numpy中做各种数学运算,或者使用相关的库,比如SciPy。在Numpy提供了一个函数
np.asarray
,它可以从PIL数据创建Numpy数组。并且PIL.Image
有一个.fromarray
方法来从Numpy数组加载图像数据。在下面的脚本显示了两种不同的Numpy方法,以及基于kennytm的ImageChops代码的方法。在
输入图像
输出图像
FWIW,该输出图像是使用
comp_mean_npB
创建的。在由于执行计算的方式不同,由3个函数生成的计算出的信道值可以彼此相差1,但当然,这种差异并不明显。:)
对于这个特定的操作,颜色转换可以写成矩阵乘法,因此可以使用convert()方法和自定义矩阵(假设没有alpha通道):
否则,您可以split()将图像分成3个或4个每个色带的图像,应用您喜欢的任何操作,最后merge()这些色带返回到单个图像。同样,原始图像应该处于RGB或RGBA模式。在
^{pr2}$相关问题 更多 >
编程相关推荐