Numpy,Opencv及PIL.Image 格式相互转换

参考资料

  1. Python OpenCV中的numpy与图像类型转换
  2. 解决ndarray的类型错误
  3. Python OpenCV格式和PIL.Image格式 互转
  4. python模块 opencv-python与PIL.Image图像常用方法与相互转换
  5. OpenCV读取图片与PIL读取图片的差别
  6. python中PIL.Image,OpenCV,Numpy图像格式相互转换
  7. PIL.Image和np.ndarray图片与Tensor之间的转换

Numpy与Opencv格式互转

参照资料1

Python OpenCV存储图像使用的是Numpy存储,所以可以将Numpy当做图像类型操作,操作之前还需进行类型转换,转换到int8类型

对Opencv存储的图像格式进行验证

  • 输入:
1
2
3
4
5
6
7
8
9
10
11
"""
numpy与Opencv图像类型的转换
> Python OpenCV存储图像使用的是Numpy存储,所以可以将Numpy当做图像类型操作,操作之前还需进行类型转换,转换到int8类型
"""
import cv2
import numpy as np
from PIL import Image

img = cv2.imread('./Messi.jpg')
print("shape:" + str(img.shape))
print(type(img)) #数据类型显示为numpy.ndarray
  • 输出:
1
2
shape:(500, 500, 3)
<class 'numpy.ndarray'>

存储类型为numpy.ndarray,这是否表明numpy与Opencv可以直接互操作呢?答案是否定的。因为图像存放时,每个像素值都是非负的,并且取值范围受限于存储位数的限制,所以将numpy.ndarray存储为图像格式,需要先将其进行类型转换。

  • 输入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
array = np.ones([20, 30])
print("shape:" + str(array.shape))
print(type(array)) #数据类型显示numpy.ndarray 与Opencv图像类型格式相同

# 可以将ndarray作为Opencv图片进行处理,但在处理之前一般进行类型转换
"""
类型转换时需注意,我参照博客转成int8类型,可以写入,但是单通道转多通道会出错
Assertion failed) VScn::contains(scn) && VDcn::contains(dcn) && VDepth::contains(depth) in function 'CvtHelper'
参照github是类型错误导致的
"""
array = np.uint8(array)
print("shape:" + str(array.shape))
cv2.imwrite('test.jpg', array)

# 类型转换
array = cv2.cvtColor(array, cv2.COLOR_GRAY2BGR)
print("shape:" + str(array.shape))
cv2.imwrite('test2.jpg', array)
  • 输出:
1
2
3
4
shape:(20, 30)
<class 'numpy.ndarray'>
shape:(20, 30)
shape:(20, 30, 3)

正如注释所写,类型转换时,要注意,我参照资料1转为int8,在通道转换时出现了错误Assertion failed) VScn::contains(scn) && VDcn::contains(dcn) && VDepth::contains(depth) in function ‘CvtHelper’,参照资料2进行解决。

IPL.Image与Opencv相互转换

先复习一下Opencv与IPL.Image的读,写,显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"""
Opencv 图像的读,写,显示
PIL.Image的读,写,显示
"""

# Opencv读
img = cv2.imread('Messi.jpg')
# Opencv写
cv2.imwrite('Messi2.jpg', img)
# Opencv显示
cv2.imshow('Messi', img)


# PIL.Image读
img = Image.open('Messi.jpg')
# PIL.Image写
img.save('Messi3.jpg')
# PIL.Image显示
img.show()

Image.open()读取的通道顺序是RGB,cv2.imread()读取的通道顺序为BGR。 Image.open()函数只是保持了图像被读取的状态,但是图像的真实数据并未被读取,因此如果对需要操作图像每个元素,如输出某个像素的RGB值等,需要执行对象的load()方法读取数据 PIL.Image.save()直接保存RGB的图片 cv2.imwirte()保存图片的时候相当于做了BGR2RGB再去保存

OpenCV转换成PIL.Image格式

  • 代码:
1
2
3
4
5
6
import cv2  
from PIL import Image
import numpy
img = cv2.imread("Messi.jpg")
cv2.imshow("OpenCV",img)
Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))

PIL.Image转换成OpenCV格式:

  • 代码:
1
2
3
4
5
import cv2  
from PIL import Image
import numpy
image = Image.open("Messi.jpg")
img = cv2.cvtColor(numpy.asarray(image),cv2.COLOR_RGB2BGR)

PIL.Image与Numpy格式的相互转换

相当于 Opencv与PIL.Image的相互转换少了通道的变换。

  • Numpy转PIL.Image
1
2
3
4
5
import cv2
from PIL import Image
import numpy
array = np.ones(100, 200)
Image.fromarray(array)
  • PIL.Image转Numpy
1
2
3
4
5
import cv2
from PIL import Image
import numpy
image = Image.open("Messi.jpg")
array = numpy.asarray(image)

补充

参考资料6

list与tuple转换

1
2
3
a = [1, 2, 3]#a is a list
b = tuple(a) # b is a tuple
c = list(b) # c is a list

list,tuple,ndarray转换

1
2
3
a = [1, 2, 3] # a is a list
arr = np.array(a) # arr is a ndarray
b = tuple(arr) # b is a tuple
1
2
3
a = (1, 2, 3)# a is a tuple
arr = np.arr(a) # arr is a ndarray
b = list(arr) # b is a list

torch的tensor与numpy转换

1
2
3
4
5
# tensor 转numpy
array = a.numpy() # a is a tensor

# numpy 转tensor
torch.from_numpy(array) # array is a ndarray

tensor与PIL image转换

pytorch官方提供了torchvision.transforms包,可以用transforms来实现tensor 与PIL image的转换

ToTensor把一个取值范围是[0,255]的PIL.Image或者shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W],取值范围是[0,1.0]的torch.FloadTensor

  • tensor与PIL image的转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import torch
from torchvision import transforms
from PIL import Image
import cv2

# PIL Image转tensor

transform1 = transforms.Compose([
pass, # 这里可以写对PIL的相关操作(裁剪,旋转等)
transforms.ToTensor(),
]
)
img_PIL = Image.open('test.jpg').convert('RGB')
img_PIL_tensor = transform1(img_PIL)# 将PIL image转为tensor
print(type(img_PIL))
print(type(img_PIL_tensor))

# transforms也提供了tensor转PIL image的方法
new_img_PIL = transforms.ToPILImage()(img_PIL_Tensor).convert('RGB')

transform2 = transforms.Compose([
pass, # transform没有对Opencv的相关操作(裁剪,旋转等)
transforms.ToTensor(),
]
)

img_Opencv = cv2.imread('test'.jpg)
img_Opencv_tensor = transform2(img_Opencv)