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

Posted

技术标签:

【中文标题】Python PIL - 分割混合两个图像的功能?【英文标题】:Python PIL - function to divide blend two images? 【发布时间】:2011-04-09 13:03:22 【问题描述】:

编辑: 感谢 Mark 和 zephyr,代码现在可以运行了。 zephyr 下面还有两种替代的工作解决方案。

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

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

是否有我错过的内置除法混合功能(PIL 或其他)?

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

有没有更有效的方法来执行这种除法混合操作(步骤更少,速度更快)?起初,我尝试在 Image.evalImageMath.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')

【问题讨论】:

【参考方案1】:

这里有一个除法函数的数学定义: 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 &lt 255)+255*ones(形状(c))*(c &gt 255) e = d.astype('uint8') imgOut = Image.fromarray(e) imgOut.save('PILdiv0.png', 'PNG')

【讨论】:

感谢您的解决方案。这要简单得多。我将看看 pylab 和 matplotlib。我想PIL没有那么简单的事情吗?该链接对于了解其他混合模式也非常有帮助。 对不起,我对 PIL 不是很熟悉。我只用它来加载/保存文件。我想可能有办法做到这一点,但我发现在 numpy 中做数学事情更容易。 再次感谢。我已经有 numpy 和 scipy,所以我也会尝试你的 numpy 方法。 (哦,我知道我也有 matplotlib。)我试图将您之前的帖子转换回我的 PIL 函数,但它还没有完全工作。我看到你在此期间更新了一些东西,所以我会再试一次。 谢谢。我运行了您的两个解决方案并将更改合并到我原来的 PIL 版本中(删减了很多)。所有三个版本在我的测试图像上逐位匹配。我不太了解您的 d= 行,但我猜它的工作原理类似于 GIMP 指南等式中的 min(255,c) 。我无法将其压缩到我的 ImageMath.eval 中,但输出仍然与您的匹配。 ImageMath.eval 可能内置了 255 的剪辑。【参考方案2】:

你在问:

有没有更有效的方法来执行这种除法混合操作(步骤更少,速度更快)?

您也可以使用 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)

【讨论】:

【参考方案3】:

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

【讨论】:

感谢您的帮助。我会修复它,看看它是如何工作的。

以上是关于Python PIL - 分割混合两个图像的功能?的主要内容,如果未能解决你的问题,请参考以下文章

python3安装PIL

python3安装PIL

比较Python中的两个PIL图像

python之pil的使用

一秒钟带你走进P图世界-----(python)PIL库的使用

python图像处理之PIL库