在项目中遇到一个问题是想将VideoCapture()读到的frame图片转变成PIL的Image图片格式。
兴冲冲地在在网上找到一段代码,将opencv中的imread()图像转成PIL.Image格式,详见python中PIL.Image和OpenCV图像格式相互转换
OpenCV转换成PIL.Image格式:
import cv2
from PIL import Image
import numpy
img = cv2.imread("plane.jpg")
cv2.imshow("OpenCV",img)
image = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
image.show()
cv2.waitKey()
于是将image = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
复制了一遍,结果得到
open cv error: (-215) scn == 3 || scn == 4 in function cvtColor
的错误,参考了下stackflow上类似的回答发觉应该是颜色空间的问题——意思是原来的颜色空间和要改的颜色空间是一样的,比如原来是灰度空间,就不用再cv.COLOR_BGR2GRAY
了,于是这才意识到有可能VideoCapture(0)
和imread()
得到的颜色空间是不同的。
其实VideoCapture()与imread()得到图像的颜色空间并不相同,VideoCapture
得到的图片是RGB
空间的,而imread
得到的图片是BGR
空间的,因此这里不需要cv2.cvtColor(imgmcv2.COLOR_BGR2RGB)
,直接image = Image.fromarray(frame)
即可,frame
是VideoCapture
读到的帧,Image.fromarray()
可以将np.array
转成image
格式的图像。
上一步改完后image = Image.fromarray(frame)
后还是会报错,我寻思是不是frame的格式还是有问题,结果测试得到opencv读取的帧是Nonetype
摄像头也没有画面。
报的错是Image.fromarray(object)
没有Nonetype
这种格式,仔细想了想,以前久遇到过这种问题,就是opencv的VideoCapture
没有读到帧的时候frame
就会返回Nonetype,而ret
返回的是False
,所以在读取视频的循环中加一个条件判断语句即可,if ret ==True:
的时候进行操作:
cap = cv2.VideoCapture(0)
while(1):
ret,frame =cap.read()
if ret==True:
print (type(frame))
print (ret)#观察frame和ret的类型
img = Image.fromarray(frame)#完成np.array向PIL.Image格式的转换
cv2.imshow("frame", frame)#正常显示frame
cv2.waitKey(1)
后面得到的结果就是ret
为True
,frame
的type()为np.array
。
其实出现这么多的坑就是因为对opencv读取图片的颜色空间和数据格式不清楚,他们里面有BGR
和RGB
颜色空间,而一般cv2.imread()
读取的图片都是BGR颜色空间的图片,cv2.VideoCapture()
获取的视频帧是RGB
颜色空间的图片。PIL(Python Image Library
)读取的图片是RGB
颜色空间的。
opencv读取的图片不管是视频帧还是图片都是矩阵形式,即np.array
,转PIL.Image
格式用PIL.Image.fromarray()
函数即可。