PIL和Opencv读取图片的区别

opencv读取图片
1
2
3
4
5
6
7
8
9
10
11
12
import cv2
import numpy as np

img_cv2 = cv2.imread(path)
# 图片路径含有中文
img_cv2 = cv2.imdecode(np.fromfile(path, dtype=np.uint8), -1)

print(img_cv2.shape)
# 输出:(24, 94, 3)

print(type(img_cv2))
# 输出:<class 'numpy.ndarray'>

PIL读取图片
1
2
3
4
5
6
7
8
9
from PIL import Image

img_pil = Image.open(path)

print(img_pil.size)
# 输出:(94, 24)

print(type(img_pil))
# 输出:<class 'PIL.JpegImagePlugin.JpegImageFile'>

两者区别

从以上两个程序的输出结果可以看出如下不同:

  • opencv读取图片后的数据类型为numpy.ndarry,而PIL为PIL.JpegImagePlugin.JpegImageFile

  • opencv读取图片后,查看图片尺寸用img.shape,是一个三维数组,且第一维是图片的高(height),第二维是图片的宽(width)。而PIL读取图片后通过img.size查看尺寸,是一个二维数组,第一维是宽,第二维是高

既然二者读取图片后的数据类型不同,那是否可以相互转换呢?我们可以发现,opencv读取出来后的数据类型为numpy,且多维数组类型的数据转numpy都很方便,所以我们尝试将PIL读取出来的数据转为numpy,结果如下:

1
2
3
4
img = np.array(img_pil, dtype=np.uint8)

print(img.shape)
# 输出:(24, 94, 3)

会发现,现在二者输出的图片尺寸是一样的了,那是不是转换成功了,我们来测试一下:

1
2
print(img == img_cv2)
# 输出:[[[False], [False]...]...]

全都是False,很明显是不对的。既然二者的数据大小都相同了,那为什么不相等呢,我print出了它们的数组,发现在第三维上二者数据的顺序恰好是相反的。

经过查询后得知,opencv读取的是图片的BGR格式,而PIL读取的是RGB格式,这也就解释了数据顺序相反的原因。

既然如此,我们将RGB转为BGR:

1
2
3
4
img = img[:,:,::-1].copy()

print(img == img_cv2)
# 输出结果全为 True