根据两个图像的差异创建Alpha叠加图像

时间:2019-06-19 01:47:42

标签: python numpy opencv python-imaging-library

我一直在经历一个奇怪的困难时期。我有两个图像,我们称它们为基准

和光

(实际图像的分辨率要高得多,但是无论如何,问题都应相同)。我的目标是产生一个新图像,我们将其称为alpha,当它覆盖在base上时会产生light。我已经尝试过进行各种差异/相减,缩放,亮度调整等操作,但是我似乎并没有实际产生结果(通常看起来很接近,但是从不精确)。

例如,这段代码与我所使用的代码差不多,而无需使用图像编辑软件来对其进行猜测和检查。

from PIL import Image, ImageEnhance
import numpy
import blend_modes
import sys
import scipy


background_img_raw = Image.open(sys.argv[1])
background_img_raw.putalpha(255)
background_img = numpy.array(background_img_raw)
background_img_float = background_img.astype(float)
foreground_img_raw = Image.open(sys.argv[2])
foreground_img_raw.putalpha(255)
foreground_img = numpy.array(foreground_img_raw)
foreground_img_float = foreground_img.astype(float)
opacity = 1.0
blended_img_float = blend_modes.difference(background_img_float, foreground_img_float, opacity)
r, g, b, a = np.transpose(blended_img_float)
alpha = np.clip((r+g+b)*2, 0, 255)
r = np.clip(r + 100, 0, 255)
g = np.clip(g + 100, 0, 255)
b = np.clip(b + 100, 0, 255)
blended_img_float = np.transpose([r, g, b, alpha])
blended_img = numpy.uint8(blended_img_float)
blended_img_raw = Image.fromarray(blended_img)
blended_img_raw.save(sys.argv[3])

结果看起来像这样

有什么建议吗?

编辑:在Paint.net上四处乱逛,如果您执行以下操作,您可能会很接近:

  1. 混合->区分层
  2. 在黑色上使用Grim Color Reaper
  3. 最大亮度和最小对比度
  4. 色相稍微偏移,使饱和度最大化,并增加亮度

这是大量的转换,但是结果比我以编程方式得出的结果要近得多。无论“死神”在做什么,都比我在做的更接近纠正。结果如下:

不幸的是,这不能解决问题,因为我需要反复进行此操作,但是它使我希望它可以以某种方式解决。

编辑2:请参见这篇文章,以了解我要完成的工作:https://community.home-assistant.io/t/floorplan-with-many-lights-in-one-area-say-hello-to-transparent-png-files/90006/8

编辑3:我现在需要继续解决这个问题,但是我认为与其努力工作以制作出合适的图像,我还想出了CSS方面的一种解决方法,可以使混合更接近什么合适。现在,我只使用像这样的图像之间的差异:

import numpy as np
from PIL import Image
import sys

def create_mask(foreground_filename, background_filename, output_filename):
    foreground = cv2.imread(foreground_filename)
    background = cv2.imread(background_filename)
    diff = foreground - background
    diff = cv2.cvtColor(diff, cv2.COLOR_BGR2RGB)
    out_pil_image = Image.fromarray(diff)
    out_pil_image.save(output_filename)

if __name__ == "__main__":
    create_mask(sys.argv[1], sys.argv[2], sys.argv[3])

结果如下:https://codepen.io/anon/pen/agBqXr

目前对我来说哪个足够好。如果有人知道,我很想知道这个问题的正确答案!

3 个答案:

答案 0 :(得分:1)

我不太了解Opecv,但是在ImageMagick中,我将执行以下操作:

基础:

enter image description here

灯光:

enter image description here

convert base.png light.png -compose minus -composite minus.png


enter image description here

convert base.png minus.png -compose plus -composite result.png


enter image description here

添加:

这是在原件上构成彩色透明图像的另一种方法。但是您将不得不稍微调整颜色。我在基础图像中测了一个亮黄点。

1) turn the minus image into gray by desaturating it. The stretch the dynamic range, then apply a gamma adjustment.

2) create a look-up table between black and that yellow color and apply it to the gray image with -clut

3) put the gray image into the alpha channel of the colorized image

4) composite the previous image over the base image


convert minus.png -modulate 100,0,100 -auto-level -gamma 1.5 minus_gray.png
convert minus_gray.png \( xc:black xc:"rgb(251,220,120)" +append \) -clut minus_color.png
convert minus_color.png minus_gray.png -alpha off -compose copy_opacity -composite alpha.png
convert base.png alpha.png -compose over -composite result3.png

以下是步骤的结果:

灰色:

enter image description here

彩色灰色:

enter image description here

透明:

enter image description here

结果:

enter image description here

ADDITION2:

convert light.png -alpha copy -channel a -evaluate multiply 2 +channel alpha.png
convert base.png alpha.png -compose over -composite result3.png


阿尔法:

enter image description here

结果:

enter image description here

答案 1 :(得分:0)

一种获取两个图像之间差异的方法是使用在scikit-image库中实现的结构相似性索引(SSIM),以进行图像处理。 scikit-image可以与pip install scikit-image一起安装。

具体来说,compare_ssim()函数返回一个score,用于测量两个图像之间的相似度指数,以及一个包含实际图像差异的diff图像。

结果

enter image description here

from skimage.measure import compare_ssim
import cv2

before = cv2.imread('base.png')
after = cv2.imread('light.png')

# Convert images to grayscale
before_gray = cv2.cvtColor(before, cv2.COLOR_BGR2GRAY)
after_gray = cv2.cvtColor(after, cv2.COLOR_BGR2GRAY)

# Compute SSIM between two images
(score, diff) = compare_ssim(before_gray, after_gray, full=True)
print("Image similarity", score)

# The diff image contains the actual image differences between the two images
# and is represented as a floating point data type in the range [0,1] 
# so we must convert the array to 8-bit unsigned integers in the range
# [0,255] before we can use it with OpenCV
diff = (diff * 255).astype("uint8")

cv2.imshow('result', diff)
cv2.imwrite('result.png', diff)
cv2.waitKey(0)

答案 2 :(得分:0)

这是您问题的纯PIL答案。

要获取两个图像之间的差异:-

from PIL import Image, ImageChops, ImageEnhance

img1 = Image.open(r"base.png")
img2 = Image.open(r"light.png")

diff = ImageChops.difference(img2, img1)

ImageChops.difference()接受两个Image对象作为参数,并返回两个像素之间的逐像素差的绝对值。简而言之,它计算两个图像之间的差异

diff.show()的输出:-

enter image description here

现在,由于我们现在已经获得了两个图像的差异点,因此我们现在可以从 diff 图像和原始 base 图像中创建一个合成图像< / p>

将这行代码添加到先前的代码中:-

overlaid_img1 = Image.blend(img1, diff, 0.5)

Image.blend()将两个图像对象和一个阈值作为参数,并使用恒定的alpha(阈值参数)通过在两个输入图像之间进行插值来创建新图像。输出由以下公式指导:-

  

image1 *(1.0-alpha)+ image2 * alpha

其中image1和image2是图像对象,而alpha是阈值。由于我们使用0.5作为阈值,因此公式更改为:-

  

(图像1 * 0.5)+(图像2 * 0.5)

这意味着我们获取的是image1(基础)的一半颜色值和image2(diff)的一半。由于差异图像(diff)主要包含黑色像素,因此,我们的基础图像的彩色像素亮度值减半(或者比以前更暗)。

overlaid_img1.show()的输出:-

enter image description here

现在,为了使基本图像的像素获得原始亮度值,我们需要将Image.blend()获得的输出图像的亮度加倍。

将此行添加到原始代码中:-

bright_overlay_img1 = ImageEnhance.Brightness(overlaid_img1).enhance(2.0)

ImageEnhance.Brightness()是用于调整图像亮度的类。 ImageEnhance.Brightness.enhance()是用于执行此操作的功能。

enhance(2.0)所做的是,它使overlaid_img1图像对象中每个像素的亮度值增加了一倍。

bright_overlay_img1.show()的输出:-

enter image description here

附言:-原始代码是通过在答案中添加所有提供的代码而产生的。我对原始代码进行了细分,以便可以解释每个函数的工作原理及其背后的原因。因此,为使整个工作正常进行,只需附加答案中提供的每个代码。

编辑:-

刚刚看到您对@ fmw42答案的评论,事实证明您的要求与您提出的问题不同。

据我了解,您希望diff(存储两个图像差异的图像)采用支持alpha(透明)格式,而不是全黑图像。

为此,请使用以下代码:-

# This is the full code

from PIL import Image, ImageChops, ImageEnhance

img1 = Image.open(r"base.png")
img2 = Image.open(r"light.png")

diff = ImageChops.difference(img2, img1).convert("RGBA")

pixels = diff.load()

for x in range(diff.size[0]):
    for y in range(diff.size[1]):
        if pixels[x, y] == (0, 0, 0, 255):
            pixels[x, y] = (0, 0, 0, 0)

diff.save("alpha_difference.png")   # saving the difference image (having alpha channel)

overlaid_img1 = Image.blend(img1.convert("RGBA"), diff, 0.5)

bright_overlay_img1 = ImageEnhance.Brightness(overlaid_img1).enhance(2.0).convert("RGB")

上面的代码与我之前提到的代码有何不同,是它将差异图像diff转换为Alpha通道图像,如果它具有完全黑色的颜色,它将使像素透明(与原始图片没有什么不同。

差异图像(具有Alpha通道):-

enter image description here

两个代码段的输出仍然相同。

P.S。:-:我建议您更改问题的标题/说明,并在此处明确说明问题。