我想做一些顏色轉換,例如給定的RGB通道頻道混合物與枕頭
R = G + B/2
或其中的信道值是基於相同的像素的其他通道的值計算出的一些其他變換。
看來.point()
函數只能在一個通道上運行。有沒有辦法做我想要的?
我想做一些顏色轉換,例如給定的RGB通道頻道混合物與枕頭
R = G + B/2
或其中的信道值是基於相同的像素的其他通道的值計算出的一些其他變換。
看來.point()
函數只能在一個通道上運行。有沒有辦法做我想要的?
使用PIL.ImageChops
的替代方法是將圖像數據轉換爲Numpy數組。 Numpy使用本地機器數據類型,並且其編譯的例程可以非常快速地處理數組數據,與在Python數字對象上執行Python循環相比。因此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)
輸入圖像
輸出圖像
FWIW,該輸出圖像是使用comp_mean_npB
創建。
由於它們執行計算的方式不同,3個函數產生的計算通道值可能相差1,但當然這些差異不容易看到。 :)
偉大的答案,這種方法是靈活的,可重複使用。 – Paolo
對於這個特定的操作中,色彩變換可以寫爲矩陣乘法,所以你可以使用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張圖像,應用您喜歡的任何操作,最後將這些帶恢復爲單個圖像。同樣,原始圖像應該是RGB或RGBA模式。
(red, green, blue, *rest) = img.split()
half_blue = PIL.ImageChops.multiply(blue, PIL.ImageChops.constant(blue, 128))
new_red = PIL.ImageChops.add(green, half_blue)
transformed_img = PIL.Image.merge(img.mode, (new_red, green, blue, *rest))
順便說一句,您可能也有興趣http://stackoverflow.com/q/40233986/4014959 –