Python PIL Image.open和cv2.imdecode之间的差异

Python PIL Image.open和cv2.imdecode之间的差异,python,opencv,image-processing,python-imaging-library,Python,Opencv,Image Processing,Python Imaging Library,我试图理解这两种使用PIL和OpenCV从字节加载图像的方法之间的区别 def bytes_to_ndarray(bytes): bytes_io = bytearray(bytes) img = Image.open(BytesIO(bytes_io)) return np.array(img) 及 问题是,对于使用OpenCV创建的图像,它们似乎给出了不同的答案。如果image是ndarray,则 bytes = cv2.imencode('.jpg', image

我试图理解这两种使用PIL和OpenCV从字节加载图像的方法之间的区别

def bytes_to_ndarray(bytes):
    bytes_io = bytearray(bytes)
    img = Image.open(BytesIO(bytes_io))
    return np.array(img)

问题是,对于使用OpenCV创建的图像,它们似乎给出了不同的答案。如果
image
ndarray
,则

bytes = cv2.imencode('.jpg', image)
这两种方式将提供不同的输出,例如
skimage.data.audion()

PIL将提供:

而OpenCV将返回正确的图像:


简而言之:这只是RGB和BGR通常的订购方式——但是,结合使用OpenCV的
imencode
imdecode
以及这个特定的图像,一切都变得非常复杂。;-)

skimage.data.audion()
返回带有RGB排序的
ndarray
,因为RGB排序是
skimage
中的标准。相反,OpenCV在内部使用BGR排序。因此,当我们在保存的PNG图像上使用
cv2.imread
时,我们会得到一个带有BGR排序的
ndarray
。此外,OpenCV始终假定其所有操作的BGR排序
ndarrays

现在,使用
cv2.imencode
生成字节流。如上所述,OpenCV假定馈送到该函数的
ndarray
具有BGR顺序。这很重要,因为生成的字节流将具有RGB顺序(
cv2.imencode
mimics
cv2.imwrite
,并且OpenCV正确写入RGB图像)。因此,创建的字节流具有错误的BGR顺序

对于解码,Pillow和OpenCV采用RGB有序字节流。因此,由“枕头方式”创建的
ndarray
实际上具有BGR排序(这不是枕头标准),而由OpenCV的
imdecode
创建的
ndarray
具有RGB排序(这不是OpenCV标准)

最后,Matplotlib(或pyplot)的imshow
imshow
假设RGB有序
ndarrays
用于可视化。因此,将发生以下情况:

  • 显示
    skimage.data.audion()
    中的原始
    ndarray
    应该是正确的(RGB顺序)
  • 显示枕式PNG应正确(RGB订购)
  • 显示OpenCV加载的PNG应该不正确(BGR已订购)
  • 显示解码字节流应不正确(BGR已订购)
  • 显示OpenCV解码字节流应该是正确的(RGB顺序)
让我们看看:

导入cv2
从io导入字节io
从matplotlib导入pyplot作为plt
将numpy作为np导入
从PIL导入图像
进口撇渣
定义字节到数组(字节):
字节\ io=字节数组(字节)
img=Image.open(字节数)
返回np.array(img)
#skimage返回带有RGB排序的数据数组
img_sk=skiliage.data.audion()
#使用Pillow打开此图像的已保存PNG文件将返回带有RGB排序的ndarray
img_pil=Image.open('automotor.png'))
#使用OpenCV打开此图像的已保存PNG文件将返回带有BGR顺序的ndarray
img_cv=cv2.imread('automation.png',cv2.imread_COLOR)
#OpenCV使用BGR排序,因此OpenCV的编码将img_sk[:,:,0]视为蓝色通道,
#虽然它是实际的红色通道(img_sk[:,:,2]也是如此)
#这意味着,编码的字节流现在具有BGR顺序!!
_,bytes=cv2.imencode('.png',img_sk)
#OpenCV使用BGR排序,但OpenCV的解码假设是RGB排序的字节流,所以
#蓝色通道和红色通道在这里再次交换,这样img_cv再次与
#RGB订购!!
img\u byte\u cv=cv2.imdecode(bytes,cv2.IMREAD\u ANYCOLOR)
#Pillow使用RGB排序,并且还假设RGB排序的字节流,但实际字节
#流是BGR排序的,因此img_pil实际上是BGR排序的一个数组
img_byte_pil=字节到数组(字节)
#Matplotlib pyplot imshow使用RGB排序进行可视化!!
plt.图(figsize=(8,12))
plt.子地块(3,2,1),plt.imshow(img_pil),plt.ylabel(‘PNG加载枕头’)
plt.subplot(3,2,2),plt.imshow(img_cv),plt.ylabel('PNG加载了OpenCV')
plt.子地块(3,2,3),plt.imshow(img_sk),plt.ylabel('装载了撇渣')
plt.subplot(3,2,5),plt.imshow(img_byte_pil),plt.ylabel('用枕头解码')
plt.subplot(3,2,6),plt.imshow(img_byte_cv),plt.ylabel('用OpenCV解码')
plt.show()
等等:

下面是用于复制代码的图像的PNG副本:

底线:当使用OpenCV的
imencode
时,确保传递的
ndarray
具有BGR顺序

希望有帮助

bytes = cv2.imencode('.jpg', image)