Python OpenCV2为16位2D图像数组添加透明Logo时透明度丢失问题
解决透明Logo添加后变为黑色背景的问题
你的问题核心在于没有正确处理Logo的透明通道(Alpha通道),同时代码里还有几个关键的错误点,我来一步步帮你梳理并修正:
问题分析
- Logo读取方式错误:你用
cv2.imread("resources/logo/logo.png", 0)读取的是灰度图,直接丢弃了PNG的Alpha透明通道,导致原本透明的区域变成了黑色(灰度值0)。 - 未初始化的变量:
scale_percent在使用前没有定义,这会直接导致报错,你应该先设置一个缩放比例(比如50代表缩放至50%)。 - 错误的类型转换:把Logo转成
uint16后乘以256,这会破坏像素值的正常范围,而且完全没必要——我们应该让Logo的像素格式和原始图像(单通道uint16)匹配,而不是强行转换。 - 直接覆盖像素:你直接用Logo像素替换原始图像的区域,没有根据Alpha通道做混合,所以透明区域也被黑色覆盖了。
修正方案
下面是符合你需求的代码,保证原始数组的形状和数据类型完全不变,只添加Logo:
import cv2 import numpy as np def add_logo(array): # 1. 读取带Alpha通道的Logo(4通道:BGR+Alpha) logo = cv2.imread("resources/logo/logo.png", cv2.IMREAD_UNCHANGED) if logo is None: raise ValueError("无法读取Logo文件,请检查路径") # 2. 定义缩放比例(根据你的需求调整,比如50就是缩小到50%) scale_percent = 50 # 计算缩放后的尺寸 width = int(logo.shape[1] * scale_percent / 100) height = int(logo.shape[0] * scale_percent / 100) dim = (width, height) # 3. 缩放Logo的BGR通道和Alpha通道 # 先分离BGR和Alpha logo_bgr = logo[:, :, :3] logo_alpha = logo[:, :, 3] # 缩放BGR到目标尺寸,转成灰度图(匹配原始单通道图像) logo_gray = cv2.cvtColor(cv2.resize(logo_bgr, dim, interpolation=cv2.INTER_AREA), cv2.COLOR_BGR2GRAY) # 缩放Alpha通道,保持尺寸一致 logo_alpha_resized = cv2.resize(logo_alpha, dim, interpolation=cv2.INTER_AREA) # 4. 转换格式,匹配原始图像的uint16类型 logo_gray_16 = np.array(logo_gray, dtype=np.uint16) * 256 # 8位转16位,映射到0-65535范围 logo_alpha_16 = np.array(logo_alpha_resized, dtype=np.uint16) # Alpha转16位 # 归一化Alpha到0-1范围,用于混合计算 alpha = logo_alpha_16 / 65535.0 # 5. 获取原始图像中要替换的区域 x_offset = y_offset = 50 roi = array[y_offset:y_offset+height, x_offset:x_offset+width] # 6. Alpha混合:原始像素*(1-alpha) + Logo像素*alpha blended = (roi * (1 - alpha)).astype(np.uint16) + (logo_gray_16 * alpha).astype(np.uint16) # 7. 将混合后的区域赋值回原始数组 array[y_offset:y_offset+height, x_offset:x_offset+width] = blended return array # 假设get_images_from_xxxx()是你的图像获取函数 imgs = get_images_from_xxxx() edited = add_logo(imgs[0]) cv2.imwrite('01.png', edited)
关键细节说明
- Alpha通道处理:我们通过
cv2.IMREAD_UNCHANGED读取Logo的Alpha通道,然后用它来控制混合比例——Alpha值越高,Logo越不透明;Alpha值为0时,完全显示原始图像。 - 格式匹配:原始图像是uint16类型(值范围0-65535),所以我们把8位的Logo灰度图乘以256,映射到相同的16位范围,保证像素值的一致性。
- 区域混合:没有直接覆盖像素,而是通过加权混合的方式,既保留了Logo的内容,又在透明区域保留了原始图像的像素。
内容的提问来源于stack exchange,提问作者toing_toing
相关产品推荐
相关产品推荐

