Python PIL - 分割混合两个图像的函数?

发布于 2024-10-31 05:16:40 字数 1535 浏览 6 评论 0原文

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

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

分割混合模式解释(我在这里使用前两张图像作为我的测试源。)

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

我下面的测试代码运行并且接近我正在寻找的内容。生成的图像输出类似于此处的除法混合示例图像: 划分混合模式说明

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

EDIT: Code is working now, thanks to Mark and zephyr. zephyr also has two alternate working solutions below.

I want to divide blend two images with PIL. I found ImageChops.multiply(image1, image2) but I couldn't find a similar divide(image, image2) function.

Divide Blend Mode Explained (I used the first two images here as my test sources.)

Is there a built-in divide blend function that I missed (PIL or otherwise)?

My test code below runs and is getting close to what I'm looking for. The resulting image output is similar to the divide blend example image here: Divide Blend Mode Explained.

Is there a more efficient way to do this divide blend operation (less steps and faster)? At first, I tried using lambda functions in Image.eval and ImageMath.eval to check for black pixels and flip them to white during the division process, but I couldn't get either to produce the correct result.

EDIT: Fixed code and shortened thanks to Mark and zephyr. The resulting image output matches the output from zephyr's numpy and scipy solutions below.

# 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')

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

dawn曙光 2024-11-07 05:16:40

你问的是:

是否有更有效的方法来执行除法混合操作(步骤更少且更快)?

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

You are asking:

Is there a more efficient way to do this divide blend operation (less steps and faster)?

You could also use the python package blend modes. It is written with vectorized Numpy math and generally fast. Install it via pip install blend_modes. I have written the commands in a more verbose way to improve readability, it would be shorter to chain them. Use blend_modes like this to divide your images:

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')

Be aware that for this to work, both images need to have the same dimensions, e.g. imgA.shape == (240,320,3) and imgB.shape == (240,320,3).

世界等同你 2024-11-07 05:16:40

除法函数有一个数学定义:
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')

There is a mathematical definition for the divide function here:
http://www.linuxtopia.org/online_books/graphics_tools/gimp_advanced_guide/gimp_guide_node55_002.html

Here's an implementation with 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)

If you don't want to use matplotlib, you can do it like this (I assume you have 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')

凉城凉梦凉人心 2024-11-07 05:16:40

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

The problem you're having is when you have a zero in image B - it causes a divide by zero. If you convert all of those values to one instead I think you'll get the desired result. That will eliminate the need to check for zeros and fix them in the result.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文