简体   繁体   English

Python PIL - 用于划分混合两个图像的函数?

[英]Python PIL - function to divide blend two images?

EDIT: Code is working now, thanks to Mark and zephyr.编辑:多亏了 Mark 和 zephyr,代码现在可以运行了。 zephyr also has two alternate working solutions below. zephyr 在下面还有两个替代的工作解决方案。

I want to divide blend two images with PIL.我想用 PIL 划分混合两个图像。 I found ImageChops.multiply(image1, image2) but I couldn't find a similar divide(image, image2) function.我找到了ImageChops.multiply(image1, image2)但我找不到类似的ImageChops.multiply(image1, image2) divide(image, image2)函数。

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)?是否有我错过的内置除法混合功能(PIL 或其他)?

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.起初,我尝试在Image.evalImageMath.eval使用 lambda 函数来检查黑色像素并将它们在除法过程中翻转为白色,但我无法得到正确的结果。

EDIT: Fixed code and shortened thanks to Mark and zephyr.编辑:由于 Mark 和 zephyr,修复了代码并缩短了代码 The resulting image output matches the output from zephyr's numpy and scipy solutions below.生成的图像输出与下面 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')

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 .您还可以使用 python 包混合模式 It is written with vectorized Numpy math and generally fast.它是用矢量化的 Numpy 数学编写的,通常速度很快。 Install it via pip install blend_modes .通过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:使用像这样的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')

Be aware that for this to work, both images need to have the same dimensions, eg imgA.shape == (240,320,3) and imgB.shape == (240,320,3) .请注意,要使其工作,两个图像需要具有相同的尺寸,例如imgA.shape == (240,320,3)imgB.shape == (240,320,3)

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这里有一个除法函数的数学定义: http : //www.linuxtopia.org/online_books/graphics_tools/gimp_advanced_guide/gimp_guide_node55_002.html

Here's an implementation with scipy/matplotlib:这是 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):如果你不想使用 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')

The problem you're having is when you have a zero in image B - it causes a divide by zero.您遇到的问题是当图像 B 中有一个零时 - 它会导致除以零。 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.这将消除检查零并在结果中修复它们的需要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM