opencv3计算机视觉+Python(一),,基本I/O脚本读/写


基本I/O脚本

读/写图像文件

OpenCV的imread函数和imwrite函数能支持各种静态图像文件格式。不同系统支持的文件格式不一样,但都支持BMP格式,通常还应该支持PNG、JPEG和TIFF格式。

大多数常用的opencv函数都在cv2模块中。可能也会遇到其他基于cv或cv2.cv模块的opencv帮助,这些都是传统版本。Python模块被称为cv2并不表示该模块是针对OpenCv2.x.x版本的

imread()函数的参数:

1.IMREAD_ANYCOLOR=4

2.IMREAD_ANYDEPTH=2

3.IMREAD_COLOR=1

4.IMREAD_GRAYSCALE=0

5IMREAD_LOAD_GDAL=8

6.IMREAD_UNCHANGED=-1

cv.imshow(‘窗口名’,img)#必须要加上窗口名

且必须加

cv2.waitKey(0)
cv2.destroyAllWindows()否则会一闪跳过

图像与原始字节之间的转换

一个opencv图像是.array类型的二维或三维数组。

8位的灰度图像是一个含有字节值得二维数组。一个24维得RGB图像是一个三维数组,它也包含了字节值。可使用表达式访问这些值,例如image[0,0]或image[0,0,0]。第一个值代表像素y坐标或行,0表示顶部;第二个值是像素得x坐标或列,0表示最左;第三个值(如果可用得话)表示颜色通道。

若一副图像得每个通道为8位,则可将其显示转换为标准得一维Python bytearray格式:

byteArray=bytearray(image)

反之,bytearray含有恰当顺序的字节,可以通过显式转换和重构,得到numpy.array形式得图像:

grayImage=numpy.array(grayByteArray).reshape(height,width)

bgrImage=numpy.array(bgrByteArray).reshape(height,width,3)

视频文件得读/写

opencv提供VideoCapture类和videoWriter类来支持各种格式得视频文件。支持的格式类型会因系统的不同而变化,但应该都支持AVI格式。在到达视频文件末尾之前,VideoCapture类可通过read()函数来获取新的帧,每帧是一副基于BGR格式的图像

可将一幅图像传递给VideoWriter类的write()函数,该函数会将这幅图像加到VideoWriter类所指向的文件中。

特别注意:必须要为VideoWriter类的构造函数指定视频文件名,这个文件名对应的文件若存在,会被覆盖。也必须指定视频编解码器。编解码器的可用性根据系统不同而不同。下面是常用选项:

cv2.VideoWriter_fourcc(‘I’,’4’,’2’,’0’):该选项是一个未压缩的 YUV颜色编码,是4:2:0色度子采样。这种编码有很好的兼容性,但会产生较大文件,文件扩展名为.avi

cv2.VideoWriter_fourcc(‘P’,’I’,’M’,’1’):该选项是MPEG-1编码类型,文件扩展名为.avi

cv2.VideoWriter_fourcc(‘X’,’V’,’I’,’D’):该选项是MPEG-4编码类型,如果希望得到的视频大小为 平均值,推荐使用此选项,文件扩展名为.avi

cv2.VideoWriter_fourcc(‘F’,’L’,’V’,’1’):该选项是一个Flash视频,文件扩展名为.flv。

捕获摄像头的帧

VideoCapture类可以获得摄像头的帧流。但对摄像头而言,通常不是用视频的文件名来构造VideoCapture类,而是需要传递摄像头的设备索引(device index)

然而与前面不一样,VideoCapture类的get()方法不能返回摄像头帧速率(fps)的准确值,它总是返回0

import cv2import numpy as npcameraCapture=cv2.VideoCapture(0)#调用摄像头fps=30size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))videoWriter=cv2.VideoWriter(‘4.avi‘,cv2.VideoWriter_fourcc(‘X‘,‘V‘,‘I‘,‘D‘),fps,size)success,frame=cameraCapture.read()numFramesRemaining=10*fps-1#倒计时while success and numFramesRemaining>0: videoWriter.write(frame) success,frame=cameraCapture.read() numFramesRemaining-=1cameraCapture.release()

摄像头的数量和顺序由系统决定。但opencv没有提供任何查询摄像头数量和属性的方法。如果使用无效索引构造了VideoCapture类,就不会得到帧,VideoCapture的read()函数会返回(false,None)。为了不让read()函数从没有正确打开的VideoCapture类中获取数据,可在执行该函数之后使用VideoCapture.isOpened方法做一个判断,该方法返回一个boolean值。

当需要同布一组摄像头或一个多头摄像头时,read()方法就不再适合,可用grab()和retrive()方法代替它。对于一组摄像头,可以使用以下代码

success0=cameraCapture0.grab()success1=cameraCapture1.grab()if success0 and success1:     frame0=cameraCapture0.retrieve()     frame1=cameraCapture1.retrieve()

在窗口显示图像

cv.imshow(‘窗口名’,img)#必须要加上窗口名

且必须加

cv2.waitKey(0)
cv2.destroyAllWindows()否则会一闪跳过

在窗口显示摄像头帧

OpenCV的namedWindow()、imshow()和DestroyWindow()函数允许指定窗口来创建,显示和销毁(destroy)窗口。此外,任意窗口下都可以通过waitKey()函数来获取键盘输入,通过setMouseCallback()函数来获取鼠标输入。

import cv2clicked=Falsedef onMouse(event,x,y,flags,param): global clicked if event==cv2.EVENT_LBUTTONUP: clicked=TrueCameraCapture=cv2.VideoCapture(0)cv2.namedWindow(‘MyWindow‘)cv2.setMouseCallback(‘MyWindow‘,onMouse)print(‘Showing camera feed. Click window or press any key to stop‘)success,frame=CameraCapture.read()while success and cv2.waitKey(1)==-1 and not clicked:#要么键盘输入要么鼠标输入,要么摄像头获取帧不成功,否则会继续 cv2.imshow(‘Mywindow‘,frame) success,frame=CameraCapture.read()cv2.destroyWindow(‘MyWindow‘)CameraCapture.release()

OpenCV的窗口函数和waitKey()函数相互依赖。OpenCV的窗口只有在调用waitKey()函数时才会更新,waitKey()函数只有在OpenCV窗口成为活动窗口时,才能捕获输入信息。

鼠标回调函数setMouseCallback()有5个参数,如前面的示例代码所示。param为可选参数,它是setMouseCallback()函数的第三个参数,默认情况下,该参数为0.回调事件参数可以取如下的值,他们分别对应不同的鼠标事件。

cv2.EVENT_MOUSEMOVE:该事件对应鼠标移动

cv2.EVENT_LBUTTONDOWN:该事件对应鼠标左键按下

cv2.EVENT_RBUTTONDOWN:该事件对应鼠标右键按下

cv2.EVENT_MBUTTONDOWN:该事件对应鼠标中间键按下

cv2.EVENT_LBUTTONUP:该事件对应鼠标左键松开

cv2.EVENT_RBUTTONUP:该事件对应鼠标右键松开

cv2.EVENT_MBUTTONUP:该事件对应鼠标中间键松开

cv2.EVENT_LBUTTONDBLCLK:该事件对应双击鼠标左键

cv2.EVENT_RBUTTONDBLCLK:该事件对应双击鼠标右键

cv2.EVENT_MBUTTONDBLCLK:该事件对应双击鼠标中键

鼠标回调的标志参数可能以下事件的按位组合:

cv2.EVENT_FLAG_LBUTTON:该事件对应按下鼠标左键

cv2.EVENT_FLAG_RBUTTON:该事件对应按下鼠标右键

cv2.EVENT_FLAG_MBUTTON:该事件对应按下鼠标中键

cv2.EVENT_FLAG_CTRLKEY:该事件对应按下Ctrl键

cv2.EVENT_FLAG_SHIFTKEY:该事件对应按下Shift键

cv2.EVENT_FLAG_ALTKEY:该事件对应按下Alt键

然而OpenCV不提供任何处理窗口事件的方法。例如当单击窗口的关闭按钮时不能关闭应用程序。由于Opencv有限的事件处理能力和GUI处理能力。

Cameo——面向对象的设计

Python的应用程序可用纯粹的面向过程语言来实现,像前面讨论的小应用程序(如基本I/O的脚本)通常会这样做。不过为了提高模块化水平和扩展性,下面将采用面向对象的方式实现。

通过前面介绍的OpenCV I/O功能可以知道,所有图像其实都是相似的,尽管图像的来源或去向不同。无论是从哪里获得的图像流,或者要将其输出到哪里,都可以将相同逻辑应用到图像流中的每个帧中。在应用中,将I/O代码与应用程序代码分离会变得特别方便,例如Cameo会使用多个I/O流

可创建CaptureManager类和WindowManager类作为高级的I/O流接口。在应用程序的代码中可以使用CaptureManager来读取新的帧,并能将帧分派到一个或多个输出中,这些输出包括静止的图像文件、视频文件以及窗口(可以通过WindowManager类来实现)。WindowManager类使应用程序代码能以面向对象的形式处理窗口和事件。

CaptureManager和WindowManager都具有可扩展性,因此,实现时可以不依赖OpenCV的I/O.

使用managers.CaptureManager提取视频流

无论该图像流来自视频文件还是摄像头,openCV都可以获取、显示和记录图像流,但是每种情况都有一些需要特殊考虑的地方。CaptureManager类对一些差异进行了抽象,并提供了更高级的接口从获取流中分配图像,再将图像分到一个或多个输出中(如图像文件、视频文件或窗口)。

在VideoCapture类中初始化CaptureManager类,在应用程序主循环的每一次迭代通常应调用CaptureManager类的enterFrame()和exitFrame()函数。在调用enterFrame()和exitFrame()函数之间,应用程序可能会设定通道属性并获取帧属性。通道属性的初始值是0,只有在多头摄像头的情况下,通道属性的初始值非0.帧属性是当调用enterFrame()函数时与当前通道状态对应的图像。

可能会经常调用CaptureManager类的writeImage()、startWritingVideo()和stopWritingVideo()函数。在调用existFrame()函数之前,会延迟写入文件。并且,在调用existFrame()函数的过程中,帧属性可能会在窗口中显示,这取决于应用程序代码是将WindowManager类作为CaptureManager的构造函数参数,还是设置previewWindowManager属性。

如果应用程序代码处理了帧属性,那么在记录文件和窗口中会有所体现。CaptureManager类中有一个称为shouldMirrorPreview的构造函数参数和属性,如果想要帧在窗口中镜像(水平翻转),但不记录在文件中,可将shouldMirrorPreview设置为True.通常,当面对摄像头的时候,用户喜欢摄像头返回镜像图像。

前面介绍过VideoWriter类需要帧速率,但OpenCV不能为摄像头提供准确的帧速率,解决这个问题的方法是通过帧计数器和Python标准的time.time()函数估计帧速率,但这些方法都有问题。由于帧速率不稳定以及time.time()函数需要依赖系统实现,有些时候,估计精度可能会很差。但是,如果在未知的硬件平台上运行应用程序,这样估计得帧速率会比随意假定一个摄像头的帧速率效果要好。

cameo.Cameo的强大实现

Cameo类提供两种方法启动应用程序:run()和onkeypress()。在初始化时,Cameo类会把onKeypress()作为回调函数创建WindowManager类,而CaptureManager类会使用摄像头和WindowManager类。当调用run()函数时,应用程序会执行主循环处理帧和事件,应用程序会调用onkeypress()函数处理事件。按空格键可获取截图信息,按tab键可启动/停止截屏(一个视频记录),按Esc键可以推出应用程序。

opencv3计算机视觉+Python(一)

评论关闭