将透明图像叠加到另一个图像上,但保留 RGB 通道

问题描述 投票:0回答:3

我正在尝试在我的图像上叠加水印,这样水印在 R、G、B 通道中可见,但由于 alpha 通道为 0,水印在整个图像上不可见。

我使用

convert watermark.png -alpha set -channel a -evaluate set 0% +channel watermark-t.png

创建了水印

我花了很多时间调整以下命令,尝试同时使用

separate
-combine
,但我束手无策。请帮忙!

magick convert img.png watermark-t.png -gravity North-West -composite img_plus_watermark.png

当我使用上述命令时,水印被覆盖,但在任何(包括 RGB)层中都不可见。

我也尝试过使用 Pillow:

from PIL import Image
img = Image.open("img.png")
watermark = Image.open("watermark-t.png")

r, g, b, a = watermark.split()
watermark = Image.merge("RGB", (r, g, b))
mask = Image.merge("L", (a,))
img.paste(watermark, (0, 0), mask)
img.save("img_plus_watermark.png")

还是不行。

我最接近的是在水印叠加的地方把img和水印遮掉。这会在该区域留下一块透明的图像,但图像和水印在 RGB 层中可见。不过我不想要这个。

PNG 是否因为只有一个 alpha 通道而无法处理这一问题?是否有其他图像格式,如 TIFF,其中包含可以做得更好的图层——如果是的话如何?

水印:

水印原创

水印透明

图片

img+watermark-masked-to-remove-chunk-of-image

img+水印-不透明

img+水印-透明(上面代码的结果)

python-imaging-library imagemagick imagemagick-convert
3个回答
1
投票

如果你想在图像的透明部分隐藏一个秘密,那实际上很简单:从图像中删除 alpha,将你的 RGB 秘密粘贴到图像透明部分的 RGB 部分,然后重新附加原始阿尔法。

例如,这是标准的 PNG 演示图像——背景是透明的:

这是一个小马里奥精灵(也是具有透明背景的 RGBA PNG):

我可以像这样从演示图像和 mario PNG 中删除 alpha(使用 libvips 因为我很了解它,但我相信它在 imagemagick 中也很容易):

$ vips extract_band PNG_transparency_demonstration.png bg.png 0 --n 3
$ vips extract_band mario.png fg.png 0 --n 3

那是提取波段(通道),从波段 0(红色)开始并提取其中三个波段(

--n 3
),所以只有 RGB 部分。

现在我可以将马里奥粘贴到:

$ vips insert bg.png fg.png final-rgb.png 10 10

要制作此 RGB(无 alpha)图像:

最后,我从 PNG 演示中取出原始 alpha 并重新附加它:

$ vips extract_band PNG_transparency_demonstration.png alpha.png 3
$ vips bandjoin "final-rgb.png alpha.png" result.png

为了做到这一点:

看起来像 PNG 演示图像,但它在左上角隐藏了一个秘密马里奥。您需要删除 alpha 才能看到它。


0
投票

我不确定我理解你的问题。只需在 Imagemagick 中执行以下操作:

convert shoe.png \( watermark.png -alpha off \) -compose over -composite result.png

如果这不是您想要的,请进一步说明。

添加

如果你希望结果是透明的,但是水印在 RGB 通道中,那么你可以使用 MPR: in memory storage 来帮助做到这一点。它就像一个命名克隆,以后可以按名称使用。

convert shoe.png \( watermark.png -write mpr:img -alpha off \) \
-compose over -composite \( mpr:img -alpha extract \) \
-alpha off -compose copy_opacity -composite result2.png

convert result2.png -alpha off rgb.png

https://imagemagick.org/Usage/files/#mpr


0
投票

您不能将水印添加到图像并将其隐藏在白色背景后面。这是因为生成的图像每个波段(R、G、B 和 A)只有一组。因此,对于任何给定像素,不可能有两组 RGBA 值。换句话说,当组合两幅图像时,一幅图像的 RGBA 值会覆盖另一幅图像。

alpha 波段 (A) 记录图像中 RGB 值的不透明度。因此,您可以将水印的 alpha 值设置为 0 并将其添加到图像中使其不可见(类似于您已经完成的操作 - 见下文)。

from PIL import Image
img = Image.open("shoe.png")
watermark = Image.open("watermark-t.png")
watermark.putalpha(0)
img.paste(watermark)
img.save("img2.png")

输出:

你会注意到左上角是透明的,但我们可以通过增加 alpha 值来恢复水印。

from PIL import Image
img2 = Image.open("img2.png")
img2.putalpha(1000)
img2.save("img3.png")

输出:

*编辑,根据您对使用 tiff 图像的可能性的评论:

我使用

gdal
库生成一个“7 波段”tiff 文件,其中包含水印的颜色数据但不显示它(需要注意的是,不显示水印可能取决于用于显示的应用程序图像和额外的条带可能会导致某些应用程序无法读取图像)。我要补充一点,这不是完成此任务的最有效方法,但希望它是相当清楚的。

如果使用 Windows 并安装

gdal
我建议下载库的 wheel 文件和
pip install <path to whl>
.

from PIL import Image
from osgeo import gdal
# Convert shoe image from RGBA png to RGBA tif
img = Image.open("shoe.png")
img.save("shoe2.tif")

src_ds = gdal.OpenShared("shoe2.tif")
water_ds = gdal.OpenShared("watermark-t.png")
# Create memory copy of shoe tif
tmp_ds = gdal.GetDriverByName('MEM').CreateCopy('', src_ds, 0)
# Get watermark RGB bands as arrays, add bands to copy of shoe 
for i in range(1,4):
    # Get watermark RGB bands as arrays
    wband = water_ds.GetRasterBand(i).ReadAsArray()
    # Add RGB band to copy of shoe tif in 5,6,7 band slots
    tmp_ds.AddBand()
    tmp_ds.GetRasterBand(i + 4).WriteArray(wband)
# Save as tif
dst_ds = gdal.GetDriverByName('GTiff').CreateCopy("img3.tif", tmp_ds, 0)
del src_ds
del water_ds
del tmp_ds
del dst_ds

输出(

img3.tif
)看起来和上面的第二个输出一样。不幸的是,它太大了,无法上传到这里 (~14mb)。为了证明水印数据在 tif 中仍然完好无损,以下代码将采用 5、6 和 7 波段并将它们输出为 png。

from PIL import Image
from osgeo import gdal
# Create an empty png to store data in, size reflects the shoe image now
new_watermark = Image.new("RGB", (1938,1090))
new_watermark.save("empty.png")

img3_ds = gdal.OpenShared("img3.tif")
png_ds = gdal.OpenShared("empty.png")
water2_ds = gdal.GetDriverByName("MEM").CreateCopy("", png_ds, 0)
for i in range(1,4):
    band = img3_ds.GetRasterBand(i + 4).ReadAsArray()
    water2_ds.GetRasterBand(i).WriteArray(band)
output_ds = gdal.GetDriverByName("PNG").CreateCopy("remake_watermark.png", water2_ds, 0)
del img3_ds
del water2_ds
del output_ds

输出:

© www.soinside.com 2019 - 2024. All rights reserved.