Python PIL - 如何将两张图片进行分割混合?
编辑:代码现在可以正常工作了,感谢Mark和zephyr。zephyr下面还有两个其他的可行方案。
我想用PIL把两张图片进行混合,找到了ImageChops.multiply(image1, image2)
这个方法,但没找到类似的divide(image1, image2)
函数。
关于除法混合模式的解释(我用这里的前两张图片作为我的测试素材。)
我是不是漏掉了什么内置的除法混合函数(无论是PIL还是其他的)?
下面我的测试代码运行得不错,结果图像和这里的除法混合示例图像相似:关于除法混合模式的解释。
有没有更高效的方法来进行这个除法混合操作(步骤更少,速度更快)?一开始,我尝试在Image.eval
和ImageMath.eval
中使用lambda函数来检查黑色像素,并在除法过程中把它们变成白色,但我没能得到正确的结果。
编辑:修复了代码,并感谢Mark和zephyr的帮助,结果图像输出与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 个回答
你遇到的问题是因为在图像B中有零,这样就会出现除以零的情况。如果把所有这些零的值都改成一,我觉得你就能得到想要的结果。这样就不需要再检查零的情况,也不用在结果中处理它们了。
你在问:
有没有更高效的方法来进行这个除法混合操作(步骤更少,速度更快)?
你也可以使用一个叫做 blend modes 的Python库。这个库是用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)
。
这里有一个关于“除法”函数的数学定义,大家可以参考一下这个链接: 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')