英文:
overlay transparent image onto another image, but keep RGB channels
问题
我试图将水印叠加到我的图像上,以便水印在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")
仍然不起作用。
我接近的解决方案是在叠加水印的区域中对图像和水印进行蒙版处理。这会在那个区域留下一个透明的图像块,但图像和水印在RGB图层中可见。但我不想要这个效果。
PNG文件只有一个Alpha通道,也许无法满足您的需求。是否有其他图像格式,如TIFF,其中包含更多图层可以更好地处理此问题?如果是的话,该如何操作呢?
水印:
img+watermark-masked-to-remove-chunk-of-image
img+watermark-transparent(上述代码的结果)
英文:
I am trying to overlay a watermark onto my image, such that the watermark is visible in the R,G,B channels but since the alpha channel is 0, the watermark is not visible on the overall image.
I created the watermark using convert watermark.png -alpha set -channel a -evaluate set 0% +channel watermark-t.png
I've spent a lot of time tweaking the following command, trying to use separate
and -combine
as well, but I am at my wit's end. Please help!
magick convert img.png watermark-t.png -gravity North-West -composite img_plus_watermark.png
When I use the above command, the watermark gets overlaid, but is not visible in any of the (including RGB) layers.
I've also tried using 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")
Still doesn't work.
The closest I came is to mask the img and watermark in the area where the watermark is overlaid. This leaves a transparent chunk of image in that area, but the image and watermark are visible in the RGB layers. I don't want this though.
Are PNGs just not equipped to handle this since they have only one alpha channel? Are there other image formats like TIFFs which contain layers that can do better -- if yes how?
Watermark:
答案1
得分: 1
如果你试图在图像的透明部分隐藏一个秘密,这实际上相当容易:从图像中去除 alpha 通道,将你的实心 RGB 秘密粘贴到图像的透明部分的 RGB 部分,然后重新附加原始的 alpha 通道。
例如,这是标准的 PNG 演示图像 - 背景是透明的:
这是一个小马里奥精灵(也是具有透明背景的 RGBA PNG):
我可以像这样从演示图像和马里奥 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 通道。
英文:
If you're trying to hide a secret in the transparent parts of an image, that's actually pretty easy: remove the alpha from the image, paste in your solid RGB secret to the RGB parts of some transparent bit of the image, then reattach the original alpha.
For example, here's the standard PNG demo image -- the background is transparent:
And here's a tiny mario sprite (also an RGBA PNG with a transparent background):
I can remove the alpha from the demo image and the mario PNG like this (using libvips because I know it well, but I'm sure it'd be easy in imagemagick too):
$ vips extract_band PNG_transparency_demonstration.png bg.png 0 --n 3
$ vips extract_band mario.png fg.png 0 --n 3
That's extracting the bands (channels), starting at band 0 (red) and taking three of them (--n 3
), so just the RGB parts.
Now I can paste mario in:
$ vips insert bg.png fg.png final-rgb.png 10 10
To make this RGB (no alpha) image:
Finally, I take the original alpha from the PNG demo and reattach it:
$ vips extract_band PNG_transparency_demonstration.png alpha.png 3
$ vips bandjoin "final-rgb.png alpha.png" result.png
To make this:
That looks like the PNG demo image, but it has a secret mario hidden in the top left corner. You need to remove the alpha to see it.
答案2
得分: 0
I am not sure I understand your issue. Just do the following in Imagemagick:
convert shoe.png \( watermark.png -alpha off \) -compose over -composite result.png
如果这不是你想要的,请进一步澄清。
ADDITION
如果你希望结果是透明的,但水印在RGB通道中,那么你可以使用内存存储 MPR: 来帮助实现这一点。它类似于一个可以以后通过名称使用的命名克隆。
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
然后,将 result2.png 转换为去掉 alpha 通道的 RGB 图像。
convert result2.png -alpha off rgb.png
参见 https://imagemagick.org/Usage/files/#mpr
英文:
I am not sure I understand your issue. Just do the following in Imagemagick:
convert shoe.png \( watermark.png -alpha off \) -compose over -composite result.png
If this is not what you want, then please clarify further.
ADDITION
If you want the result to be transparent, but the watermark in the RGB channels, then you can use MPR: in memory storage to help to do that. It is like a named clone that can be used later by name.
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
答案3
得分: 0
你不能将水印隐藏在图像后面。标准的PNG图像只包含每个颜色通道的一个以及一个可选的Alpha通道(R、G、B和A)。因此,对于任何给定的像素,不可能存在两个RGBA值。换句话说,在合并两个PNG时,一个图像的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 <whl文件路径>
进行安装。
from PIL import Image
from osgeo import gdal
# 将RGBA png转换为RGBA tif
img = Image.open("shoe.png")
img.save("shoe2.tif")
# 打开图像
src_ds = gdal.OpenShared("shoe2.tif")
water_ds = gdal.OpenShared("watermark-t.png")
# 创建图像的内存副本
tmp_ds = gdal.GetDriverByName('MEM').CreateCopy('', src_ds, 0)
# 使用gdal GetRasterBand语法循环1,2,3
for i in range(1, 4):
# 获取水印RGB通道作为数组
wband = water_ds.GetRasterBand(i).ReadAsArray()
# 添加第5,6,7通道到tif
tmp_ds.AddBand()
# 将RGB数据写入tif的第5,6,7通道(第4通道是Alpha)
tmp_ds.GetRasterBand(i + 4).WriteArray(wband)
# 保存为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
)看起来与shoe.png
相同。不幸的是,它太大了,无法在此处上传(约14MB)。为了证明水印数据仍然存在于tiff图像中,以下代码将获取第5、6和7通道的数据并将其输出为png图像。
from PIL import Image
from osgeo import gdal
# 创建一个空白的png来存储数据,大小与鞋子图像相同
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
英文:
You cannot hide the watermark behind the image. Standard PNG images only contain one of each color band and one optional Alpha band (R, G, B, & A). So, there cannot be two RGBA values for any given pixel. In other words, when combining two PNGs the RGBA values of one image overwrite the other.
The alpha band (A) records the opacity of the RGB values in the image. So, you could set the alpha values of the watermark to 0 and add it to the image making it invisible (similar to what you've already done - see below).
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")
You'll notice the top left corner is transparent and if the background was transparent too it would blend in but not in this case because it is white.
The code below will increase the alpha values of the image to show the watermark is still in the image.
from PIL import Image
img2 = Image.open("img2.png")
img2.putalpha(1000)
img2.save("img3.png")
Edit
Per your comment about the possibility of using tiff images:
I used the gdal
library to generate a '7-band' tiff file that holds the color data for the watermark but does not display it (With the caveat that the watermark not being displayed may be dependent on the application used for displaying the image and the extra bands may cause some applications to be unable to read the image). I will add, this isn't the most efficient way to accomplish this but hopefully it is fairly clear.
If using Windows and installing gdal
I would recommend downloading the wheel file of the library and using 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")
# Open the images
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)
# loop 1,2,3 for gdal syntax when using GetRasterBand
for i in range(1,4):
# Get watermark RGB bands as arrays
wband = water_ds.GetRasterBand(i).ReadAsArray()
# Add 5,6,7 bands to tif
tmp_ds.AddBand()
# Write RGB data to 5,6,7 bands of tif (4 is for Alpha)
tmp_ds.GetRasterBand(i + 4).WriteArray(wband)
# Save as tif
dst_ds = gdal.GetDriverByName('GTiff').CreateCopy("img3.tif", tmp_ds, 0)
# Clean up
del src_ds
del water_ds
del tmp_ds
del dst_ds
The output (img3.tif
) looks the same as shoe.png
. Unfortunately it is too large to upload here (~14mb). To prove the watermark data is still intact in the tif the following code will take the 5, 6, & 7 bands and output them in a 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论