Python PIL - 分割混合两个图像的功能?

时间:2011-04-09 13:03:22

标签: python image-processing overlay python-imaging-library blend

编辑:由于Mark和Zephyr,代码现在正在运行。西风还有以下两种替代工作方案。

我想用PIL分割混合两个图像。我找到ImageChops.multiply(image1, image2)但我找不到类似的divide(image, image2)函数。

Divide Blend Mode Explained(我在这里使用前两张图片作为我的测试来源。)

是否存在我错过的内置分割混合功能(PIL或其他)?

我的测试代码在下面运行,并且正在接近我正在寻找的内容。生成的图像输出类似于此处的除法混合示例图像:Divide Blend Mode Explained

是否有更有效的方法来进行此分割混合操作(更少步骤和更快)?起初,我尝试在Image.evalImageMath.eval中使用lambda函数来检查黑色像素,并在分割过程中将它们翻转为白色,但我无法获得正确的结果。

编辑:修正代码并缩短了感谢Mark和zephyr。得到的图像输出与下面的西风的numpy和scipy解决方案的输出相匹配。

# PIL Divide Blend test

import Image, os, ImageMath

imgA = Image.open('01background.jpg')
imgA.load()
imgB = Image.open('02testgray.jpg')
imgB.load()

# split RGB images into 3 channels
rA, gA, bA = imgA.split()
rB, gB, bB = imgB.split()

# divide each channel (image1/image2)
rTmp = ImageMath.eval("int(a/((float(b)+1)/256))", a=rA, b=rB).convert('L')
gTmp = ImageMath.eval("int(a/((float(b)+1)/256))", a=gA, b=gB).convert('L')
bTmp = ImageMath.eval("int(a/((float(b)+1)/256))", a=bA, b=bB).convert('L')

# merge channels into RGB image
imgOut = Image.merge("RGB", (rTmp, gTmp, bTmp))

imgOut.save('PILdiv0.png', 'PNG')

os.system('start PILdiv0.png')

3 个答案:

答案 0 :(得分:3)

这里有除数函数的数学定义: http://www.linuxtopia.org/online_books/graphics_tools/gimp_advanced_guide/gimp_guide_node55_002.html

这是scipy / matplotlib的实现:

import numpy as np
import scipy.misc as mpl

a = mpl.imread('01background.jpg')
b = mpl.imread('02testgray.jpg')

c = a/((b.astype('float')+1)/256)
d = c*(c < 255)+255*np.ones(np.shape(c))*(c > 255)

e = d.astype('uint8')

mpl.imshow(e)
mpl.imsave('output.png', e)

如果你不想使用matplotlib,你可以这样做(我假设你有numpy):

imgA = Image.open('01background.jpg')
imgA.load()
imgB = Image.open('02testgray.jpg')
imgB.load()

a = asarray(imgA)
b = asarray(imgB)
c = a/((b.astype('float')+1)/256)
d = c*(c < 255)+255*ones(shape(c))*(c > 255)
e = d.astype('uint8')

imgOut = Image.fromarray(e)
imgOut.save('PILdiv0.png', 'PNG')

答案 1 :(得分:1)

你遇到的问题是当你的图像B为零时 - 它会导致除以零。如果您将所有这些值转换为1,我认为您将获得所需的结果。这样就不需要检查零并在结果中修复它们。

答案 2 :(得分:1)

你在问:

  

是否有更有效的方法来进行此分割混合操作(更少步骤和更快)?

您也可以使用python包blend modes。它是用矢量化的Numpy数学写的,通常很快。通过pip install blend_modes安装。我用更冗长的方式编写命令来提高可读性,链接它们会更短。像这样使用blend_modes来划分你的图像:

from PIL import Image
import numpy
import os
from blend_modes import blend_modes

# Load images
imgA = Image.open('01background.jpg')
imgA = numpy.array(imgA)
# append alpha channel
imgA = numpy.dstack((imgA, numpy.ones((imgA.shape[0], imgA.shape[1], 1))*255))
imgA = imgA.astype(float)

imgB = Image.open('02testgray.jpg')
imgB = numpy.array(imgB)
# append alpha channel
imgB = numpy.dstack((imgB, numpy.ones((imgB.shape[0], imgB.shape[1], 1))*255))
imgB = imgB.astype(float)

# Divide images
imgOut = blend_modes.divide(imgA, imgB, 1.0)

# Save images
imgOut = numpy.uint8(imgOut)
imgOut = Image.fromarray(imgOut)
imgOut.save('PILdiv0.png', 'PNG')

os.system('start PILdiv0.png')

请注意,要使其工作,两个图像都需要具有相同的尺寸,例如imgA.shape == (240,320,3)imgB.shape == (240,320,3)