处理文件、摄像头和图形界面
基本I/O脚本
读/写图像文件
一张图片有大量的像素点组成,基本组成方式有两种
- 灰度图像,二维数组组成
import numpy as np np.array([[0,0,0], [0,0,0], [0,0,0] ],dtype=np.uint8) #9个像素点
- 彩色图像,三维数组,相比二维另外一维为通道(3通道),三个二维数组分别对应三原色B、G、R的值
np.array([[[0,0,0], [0,0,0], [0,0,0]], [[0,0,0], [0,0,0], [0,0,0]], [[0,0,0], [0,0,0], [0,0,0]] ],dtype=np.uint8)
基本读取、写入图像文件操作
image=cv2.imread('hello.jpg')
cv2.imwrite('hello1.png',image)
#显示图像
cv2.imshow('windowName',image)
#等待按键按下
cv2.waitKey(0)
#可以看到写入图像还能进行图像类型的转换,本例将jpg的文件读出,写入png类型的图像
cv2.imread
方法可以携带第二个参数
image=cv2.imread('hello.jpg',cv2.IMREAD_GRAYSCALE)
#将图像转化为灰度图像读出(转化为二维)
若一副图像的每个通道为8位(也有可能不是8位,PNG格式允许每个通道有16位 ),则可将其显示转换为 标准的一维 Python bytearray 格式:
bytearray=bytearray(image)
再通过numpy转化为灰度图像或者BGR图像:
grayImage=np.array(bytearray).reshape(width,height)
colorImage=np.array(bytearray).reshape(width,height,3)
下面介绍一个详细的例子,将随机字节的bytearray转换为灰度图像和BGR图像:
import cv2
import numpy as np
import os
flatArray=np.array(bytearray(os.urandom(120000)))
# 转化为灰度图像
grayImage=flatArray.reshape(300,400)
cv2.imwrite('grayImage.jpg',grayImage)
# 转化为BGR图像
colorImage=flatArray.reshape(100,400,3)
cv2.imwrite('colorImage.jpg',colorImage)
结果生成两个图像:
- BGR图像:
- 灰度图像
访问图像数据
如果想要获取某个特定像素点的B值(不局限于B),或者设定某个像素点的B值,使用item和itemset方法会很方便
print('获取[0,0]像素点的B值',image.item(0,0,0))
# 设定[0,0]像素点B值为255
image.itemset((0,0,0),255)
其他访问图像的方法类似与numpy,下面是一个有趣的示例:
image=cv2.imread('hello.jpg')
publicArea=image[0:100,0:100]
image[200:300,200:300]=publicArea
cv2.imshow('publicDisplay',image)
cv2.waitKey(0)
结果:
视频文件的读/写
使用 VideoCapture 和 VideoWriter 类对视频文件进行读和写。示例:
import cv2
import numpy as np
videoCapture=cv2.VideoCapture('pikaqiu.mp4')
fps=videoCapture.get(cv2.CAP_PROP_FPS)
size=(int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)))
success,fram=videoCapture.read()
videoWriter=cv2.VideoWriter('myout.mp4',cv2.VideoWriter_fourcc('I','4','2','0'),fps,size)
#循环遍历直到没有更多的帧
while success:
videoWriter.write(fram)
success,fram=videoCapture.read()
VideoWriter 类必须指定输出位置、视频编解码器、帧速率(fps)、帧大小(size),帧速率和帧大小可以通过 VideoCapture 类的get()
方法获得,编解码常用方式:
- (‘I’,‘4’,‘2’,‘0’):该选项为未压缩的YUV颜色编码,是4:2:0的色度子采样。有很好的兼容性,但会产生较大文件,文件扩展名为 .avi
- (‘P’,‘I’,‘M’,‘1’):该选项是MPEG-1的编码类型,文件扩展名为 .avi
- (‘X’,‘V’,‘I’,‘D’):该选项是MPEG-4的编码类型,如果希望得到视频大小的平均值,使用该类型,文件扩展名为 .avi
- (‘T’,‘H’,‘E’,‘O’):该选项是Ogg Vorbis:文件扩展名为 .ogv
- (‘F’,‘L’,‘V’,‘1’):该选项为Flash 视频,文件扩展名为 .flv
捕获摄像头帧
如果捕获摄像头帧就不能传递视频参数了,应该传递的是摄像头的设备索引,如下
cameraCapture=cv2.VideoCapture(0)
捕获摄像头帧会存在一个问题,VideoCapture 类的get()
方法并不能准确获取摄像头的帧速率,总是返回零,官方解释为:
当VideoCapture终端不支持所查询的这个属性时,返回值为零
为了解决这个问题,一般是假设帧速率,如fps=30
,OpenCV 没有提供查询摄像头数量和属性的方法,如果使用无效的索引构造 VideoCapture ,可能得不到帧,出现错误,所以可在read()
方法后使用 VideoCapture.isOpened 方法判断是否正确的获取到帧数据,该方法返回一个 Boolean 值
当要调用多个摄像头时, VideoCapture 类的read()
方法就不那么的好用了,这个时候需要使用grab()
和retrieve()
方法代替read()
success0=cameraCapture0.grab()
success1=cameraCapture1.grab()
while success0 and success1:
frame0=cameraCapture0.retrieve()
frame1=cameraCapture1.retrieve()
实时显示摄像头帧
主要方法:namedWindow()、imshow()、destroyWindow()对窗口进行创建、显示、销毁
使用 waitKey()、setMouseCallback() 获取键盘和鼠标的输入,下边给出一个实时显示摄像头帧的示例:
import cv2
clicked=False
def onMouse(event,x,y,flags,param):
global clicked
if event==cv2.EVENT_LBUTTONUP:
clicked=True
cameraCapture=cv2.VideoCapture(0)
cv2.namedWindow('myWindow')
cv2.setMouseCallback('MyWindow',onMouse)
success,frame=cameraCapture.read()
while success and cv2.waitKey(1)==-1 and not clicked:
cv2.imshow('myWindow',frame)
success,frame=cameraCapture.read()
cv2.destroyAllWindows()
cameraCapture.release()
OpenCV 的窗口函数和waitKey()
函数是相互依赖的,只有waitKey() 调用时,窗口才会更新,只有OpenCV 成为活动窗口时,才能捕获按键信息,waitKey()
的返回值为ASCLL码,当没有按键按下时为负值,鼠标事件(26)