You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PIL正确读取16位PNG?为何与OpenCV读取值存在差异?

问题:PIL与OpenCV读取16位PNG结果不一致,PIL无法正确读取掩码通道

现象重现

使用PIL读取的代码与输出

from PIL import Image
import numpy as np
value = np.asarray(Image.open(open(filename, "rb")))
print(value)

输出:

[[[128 128   0]
  [128 128   0]
  [128 128   0]
  ...
  [128 128   0]
  [128 128   0]
  [128 128   0]]]

使用OpenCV读取的代码与输出

import cv2
im = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
print(im)

输出:

[[[    0 32768 32768]
  [    0 32768 32768]
  [    0 32768 32768]
  ...
  [    1 32768 32768]
  [    0 32768 32768]
  [    0 32768 32768]]]

原因分析

  1. 位深转换差异:PIL的Image.open()默认会将16位图像(像素值范围0-65535)线性压缩到8位(0-255),16位的中间值32768会被映射为8位的128;而OpenCV的cv2.IMREAD_UNCHANGED会保留原始16位位深,不做压缩。
  2. 掩码通道丢失:你的掩码通道是16位的0/1值,被PIL压缩到8位时,1对应的8位值约为0(1/65535*255≈0),所以显示全0,丢失了原始掩码信息。
  3. 通道顺序差异:PIL默认采用RGB通道顺序,OpenCV则是BGR顺序,这也是两者输出通道数值顺序相反的原因。

解决方法:用PIL正确读取16位PNG

要让PIL保留原始16位位深读取图像,可按以下步骤操作:

方法1:转换为16位格式读取

from PIL import Image
import numpy as np

# 打开图像并转换为16位RGB模式
img_16bit = Image.open(filename).convert("RGB;16")
# 转换为numpy数组,指定数据类型为uint16
value = np.asarray(img_16bit, dtype=np.uint16)

# 如果需要和OpenCV的BGR顺序一致,反转通道
value_bgr = value[..., ::-1]
print(value_bgr)

方法2:直接保留原始模式读取

如果图像本身是16位格式,可直接读取后转numpy:

from PIL import Image
import numpy as np

img = Image.open(filename)
# 检查当前图像模式,确认是否为16位格式(如"RGB;16"或"I;16")
print("图像模式:", img.mode)
# 转换为numpy数组,保留16位数据类型
value = np.array(img, dtype=np.uint16)

这样读取后就能得到和OpenCV一致的16位原始像素值,包括掩码通道的0/1信息。


内容的提问来源于stack exchange,提问作者ssuraj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 16:52:47