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

不同数据类型会有不同取整行为吗?cv2与PIL图像读取差异解析

旧版Pillow(8.4.0)中cv2与PIL读取图像转numpy数组的类型相关差异解析

问题场景

在使用Pillow 8.4.0版本时,发现以下现象:

  • 用cv2.imread读取图像并转RGB后,与PIL.Image.open读取的同一张图像,转换为默认uint8类型的numpy数组时,两者数值存在可见差异;
  • 但将两者的数据类型强制转为int16后,得到的numpy数组结果完全一致。

测试验证

uint8类型测试代码

import cv2
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

img1 = cv2.cvtColor(cv2.imread('post_5c606e629f934.jpg'), cv2.COLOR_BGR2RGB)
img2 = Image.open('post_5c606e629f934.jpg')
fig, ax = plt.subplots(1, 3, figsize=(15, 5))
ax[0].imshow(img1)
ax[0].set_xlabel("cv2.imread")
ax[1].imshow(img2)
ax[1].set_xlabel("PIL.Image.open")
ax[2].imshow(img2 - img1)
ax[2].set_xlabel("difference")
plt.show()

运行结果:
uint8类型下的图像差异对比

int16类型测试代码

img1 = img1.astype(np.int16)
img2 = np.array(img2, dtype=np.int16)
fig, ax = plt.subplots(1, 3, figsize=(15, 5))
ax[0].imshow(img1)
ax[0].set_xlabel("cv2.imread")
ax[1].imshow(img2)
ax[1].set_xlabel("PIL.Image.open")
ax[2].imshow(img2 - img1)
ax[2].set_xlabel("difference")
plt.show()

运行结果:
int16类型下的图像差异对比

原因分析

这是Pillow 8.4.0及更早版本的色彩转换数值处理bug:

  1. 对于JPEG这类基于YCbCr色彩空间的图像,PIL在将其转换为RGB并输出uint8数组时,采用了和OpenCV不同的数值取整/截断逻辑——PIL会在中间浮点计算步骤直接截断小数部分得到uint8值,而OpenCV则采用四舍五入的方式处理;
  2. 当指定转换为int16类型时,PIL会保留色彩转换过程中的完整浮点计算结果,不会提前做uint8的截断处理,因此和OpenCV转int16后的数值完全对齐,差异消失。

修复方案

该问题在Pillow 9.0.0及以上版本中已被官方修复,新版本统一了色彩转换时的数值处理逻辑,和OpenCV等主流图像库的输出结果保持一致,升级Pillow即可解决此差异问题。

内容的提问来源于stack exchange,提问作者Никита Подсеваткин

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:57:35