关于使用Python中OpenCV打开背景透明的.png格式文件的问题

8

我正在学习使用Python的OpenCV。我尝试更改PNG格式图片的颜色,但是在处理PNG背景(该图像具有透明背景)时遇到了一些问题。

当我将其转换为灰度图像时,背景变成了黑色--我的图片不再是透明的。我希望保留图片的透明背景。


原始图片:

我的代码:

img = cv2.imread('line.png',cv2.IMREAD_UNCHANGED)
cv2.imshow('line',img)
cv2.waitKey()

输出图像:

期望输出:

边框图像周围的白色应该是透明的。我该怎么做?


1
我认为这里混合了几个问题。首先,如果您使用imshow,那么透明区域将是黑色的(因为这是使用的背景 - 窗口本身不透明)。其次,即使PNG支持灰度+ alpha,我也不知道如何使用OpenCV保存这样的图像。 - Dan Mašek
2个回答

14

首先,如果您使用cv2.imshow显示具有alpha透明度的图像,则透明区域将是黑色的。


由于您的输入图像已经包含了一个alpha通道,所以解决方案很简单--只需重复使用alpha通道即可。

但有一个小问题--尽管PNG格式允许带有alpha通道的灰度图像,但我认为没有办法使用OpenCV编写这样的图像。

因此,解决方案很简单:取出处理过的灰度图像,将其转换回BGR,添加原始的alpha通道并保存结果。

由于我们使用Python,并且图像被表示为numpy数组,因此我们可以使用数组索引提取我们需要的通道。numpy.dstack使我们可以轻松地添加alpha通道。


示例代码:

import cv2
import numpy as np

src = cv2.imread('51IgH.png', cv2.IMREAD_UNCHANGED)

bgr = src[:,:,:3] # Channels 0..2
gray = cv2.cvtColor(bgr, cv2.COLOR_BGR2GRAY)

# Some sort of processing...

bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
alpha = src[:,:,3] # Channel 3
result = np.dstack([bgr, alpha]) # Add the alpha channel

cv2.imwrite('51IgH_result.png', result)

结果:

再次展示在不同的背景下,您可以看到它真正的透明度:


src[:, :, :3] 的意思是什么?为什么最后一个索引必须是 :3? - zzob
@lyca 这就是我在回答中提到的数组索引 -- 在我看来,阅读文档页面是非常值得花费一些时间的。在这种情况下,它的意思是“给我所有的列、所有的行和所有的通道,直到(但不包括)3”。注意:索引从0开始。| 一个透明图像是一个4通道图像,在本例中,通道为蓝色(0)、绿色(1)、红色(2)、Alpha透明度(3)。因此,该命令基本上消除了透明通道,并让我们只处理颜色信息。 - Dan Mašek
当使用cv2.imshow时,opencv完全忽略透明通道。 - vozman

3

您需要在数组中添加第四个通道,以便透明度信息可以编码在alpha通道中。

以下是Python代码示例:

import cv2
file_name = "source.png"

src = cv2.imread(file_name, cv2.IMREAD_UNCHANGED)

# Save the transparency channel alpha
*_, alpha = cv2.split(src)

gray_layer = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

# ... Your image processing

# Duplicate the grayscale image to mimic the BGR image and finally add the transparency
dst = cv2.merge((gray_layer, gray_layer, gray_layer, alpha))
cv2.imwrite("result.png", dst)

灰度图像的结果:

带透明度的灰度图像

BGR 图像的结果:


你有例子吗? - zzob
2
请不要在代码示例中使用魔法数字。cv2.imread 中的 1 应该替换为 cv2.IMREAD_COLOR。| 但是,再次查看这个问题,似乎很多操作都是不必要的。OP 的输入图像已经包含了透明通道,所以没有必要再使用 threshold 来确定它。 - Dan Mašek
1
@DanMašek 真是太可怕了,整个 OpenCV 文档都充斥着那些让我发疯的小数字(标志、线条粗细等)。 - Avio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接