`
hereson
  • 浏览: 1427769 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

OpenCV Computer Vision with Python第二章笔记

 
阅读更多

笔者:此为草稿,操作失误,等待修正。。。 

阅读须知: 

本文不是纯粹的译文,只是比较贴近原文的笔记;

请支持正版,设法购买到出版社出版的书。

         本章介绍了OpenCV的I/O功能。同时还介绍了一个使用面向对象思想的主程序。后续章节中将在这个主程序进行完善和扩充。

图像文件的读写

         OpenCV提供了imread()和imwrite()函数来支持多种格式的图像的读写,可支持的格式有BMP、PNG、JPEG和TIFF。在OpenCV中,可载入一种格式的图像,以另一种格式保存,例如下面就是将一副图像从PNG格式保存成JPEG格式:

import cv2

image = cv2.imread('MyPic.png')

cv2.imwrite('MyPic.jpg', image)

注意,读者可能在其他文章或教程中看到的是在Python中导入的模块前缀是cv或cv2.cv,但这些都是老版本的。新版的OpenCV-Python的绑定中,所有OpenCV函数都是在cv2模块中。

默认情况下,imread()函数返回BGR颜色格式的图像,即读取的是灰度形式的图像。但也可以指定imread()函数读取的模式来手动指定读取模式,如这些就是不同的读取模式:CV_LOAD_IMAGE_COLOR(BGR)、 CV_LOAD_IMAGE_GRAYSCALE (灰度图)或CV_LOAD_IMAGE_UNCHANGED。例如下面就是将一副PNG图以灰度的形式读取并保存。

import cv2

grayImage =cv2.imread('MyPic.png', cv2.CV_LOAD_IMAGE_GRAYSCALE)

cv2.imwrite('MyPicGray.png', grayImage)

(笔者注,等熟悉了,就不用写这么长了,直接使用grayImage = cv2.imread('MyPic.png', 0)即可,0就表示以灰度的形式读取图像。)

除了读取模式,imread()函数还忽略读取图像中的alpha通道(即图像的透明度)。而imwrite()函数则需要图像必须是BGR或灰度图,并且每个通道中位(bit)的数目要符合输出格式的要求。如bmp要求每个通道有8个位,而PNG则允许每个通道有8或16个位。

从概念上来说,一个字节就是范围为0-255的整数。当今大部分实时图像处理程序中,像素一般都是以每个通道一个字节来表示。(当然也有其他表示方法)

OpenCV中的图像是numpy.array类型的二维或三维数组。如8位的灰度图像就是一个含有byte值的二维数组,而24位的BGR图像是含有byte值的三维数组。可通过类似image[0,0] 或image[0, 0, 0]的形式访问这些值。其中第一个索引是像素的Y坐标,也就是图像的行,索引0在最上面。第二个坐标是像素的X坐标,也就是图像的列,索引0在最左边。第三个索引(如果有的话)表示颜色通道。

如在一副8位的灰度图像中左上角的像素是白色,则image[0, 0]是255;而对于24位的BGR图像,如果左上角的像素是蓝色,则image[0, 0]为[255, 0, 0]。(笔者注,此时image[0, 0, 0] 就是255,类似image[0, 0, 1] = 0,image[0, 0, 2] = 0,另外,这是BGR顺序,有些程序使用的是RGB顺序。)

注意:除了使用 image[0, 0] 或image[0, 0] = 128这样的形式,也可使用image.item((0, 0)) 或 image.setitem((0, 0), 128)这样的形式。后者在做单像素操作时更有效率。但从后续章节中可以看到,通常我们是对图像中某一范围内的切片进行操作,而不是操作单个像素。

对于每个通道大小为8位的图像,我们可将其转换为Python标准的一维bytearray类型:

byteArray =bytearray(image)

反之,也可将一个含有适当顺序字节的bytearray转换成图像,如通过改变其维数来获得一个numpy.array对象,这个对象就是一副图像:

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

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

(关于numpy的内容,请参考相关资料,或者可查阅我的博客NumPy简明教程(未完结))

下面的例子介绍如何将含有随机字节的bytearray转成成一副灰度图和一副BGR图像:

import cv2

import numpy

import os

# 创建一个含有12,0000(12万,好读一些)个随机字节的数组。

randomByteArray =bytearray(os.urandom(120000))

flatNumpyArray =numpy.array(randomByteArray)

# 将该数组 转换成 400x300 的灰度图像。

grayImage = flatNumpyArray.reshape(300,400)

cv2.imwrite('RandomGray.png', grayImage)

# 将该数组转换成400x300 的彩色图像。

bgrImage = flatNumpyArray.reshape(100, 400,3)

cv2.imwrite('RandomColor.png', bgrImage)

在运行完这段脚本程序后,将在脚本所在目录看到生成的RandomGray.png和RandomColor.png两幅随机图像。

读写视频文件

OpenCV为许多视频文件格式提供了VideoCapture和VideoWriter类。根据系统的不同,支持的文件格式也不同,但AVI格式总是支持的。通过read()方法,VideoCapture类依次获取图像的每一帧,直到视频播放结束。每一帧都是一个BGR格式的图像。反之,可将一幅图像传递给VideoWriter类的write()方法,将其添加到VideoWriter的文件中。下面的例子展示了如何从AVI文件中读取内容,并以YUV编码的方式写入到另一个AVI文件中:(笔者注:YUV是一种颜色空间,请参考图像处理的书籍)

import cv2

videoCapture =cv2.VideoCapture('MyInputVid.avi')

fps =videoCapture.get(cv2.cv.CV_CAP_PROP_FPS)

size =(int(videoCapture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)),  int(videoCapture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)))

videoWriter =cv2.VideoWriter('MyOutputVid.avi', cv2.cv.CV_FOURCC('I','4','2','0'), fps,size)

success, frame = videoCapture.read()

while success: # 循环处理,直到每一帧都处理完毕。

 videoWriter.write(frame) 

success, frame =videoCapture.read()

需要特别注意传递给VideoWriter类构造器的参数。首先必须指定视频文件的名称,如果有同名的文件,那么该文件就被覆盖掉。同时还将指定视频的编码。不同系统的编码有所不同。有以下这些编码选项:

cv2.cv.CV_FOURCC('I','4','2','0'):这是未压缩的YUV, 采用4:2:0色度抽样。这种编码方式兼容度最高,但生成的文件也比较大。文件扩展名应为avi。

cv2.cv.CV_FOURCC('P','I','M','1'):MPEG-1编码。文件扩展名应为avi。

cv2.cv.CV_FOURCC('M','J','P','G'):motion-JPEG编码。文件扩展名应为avi。

cv2.cv.CV_FOURCC('T','H','E','O') :Ogg-Vorbis编码。 文件扩展名应为 ogv。

cv2.cv.CV_FOURCC('F','L','V','1') :Flash视频。文件扩展名应为flv。

同时还必须指定帧的rate(帧率)和size(大小)。由于这里是从另一个视频复制过来的,所以这些属性可从VideoCapture的get()方法获得。

捕获摄像头的内容

VideoCapture类还可表示摄像头内容构成的流。对于一个摄像头来说,需要通过传递摄像头设备的索引来构造VideoCapture类,而不是传递视频的文件名。下面的例子从摄像头捕捉10秒的视频,并写入到AVI文件中:(代码测试不能正常工作,正在找原因)

import cv2

cameraCapture =cv2.VideoCapture(0)

fps = 30 # an assumption

size =(int(cameraCapture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)),  int(cameraCapture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)))

videoWriter =cv2.VideoWriter(    'MyOutputVid.avi',cv2.cv.CV_FOURCC('I','4','2','0'), fps, size)

success, frame =cameraCapture.read()

numFramesRemaining = 10 * fps –1

while success andnumFramesRemaining > 0: 

videoWriter.write(frame)

success, frame =cameraCapture.read()    

numFramesRemaining -=

不幸的是,VideoCapture类的get()方法不返回摄像头准确的帧率,而总是返回0。为了因此创建合适的VideoWriter类,必须为摄像头假设一个帧率,也可使用计时器来测量摄像头的帧率。

摄像头的索引和顺序取决于系统。但OpenCV不提供查询摄像头数目或属性的功能。如果为VideoCapture类提供了错误的索引,那么VideoCapture类将不显示任何内容,其read()方法将返回(false, None)。

(下面是关于read()方法的进一步讨论,略去。。。)

在窗口中显示摄像头内容

         在OpenCV中,可通过namedWindow()、imshow()和destroyWindow()函数来创建、重绘和摧毁窗口。同样,窗口也可通过waitKey()函数捕获键盘输如,可通过setMouseCallback()函数捕获鼠标输入。下面的例子是在窗体中显示摄像头实时内容:

import cv2

clicked = False

def onMouse(event, x, y, flags, param):

global clicked

if event ==cv2.cv.CV_EVENT_LBUTTONUP:

clicked = True

cameraCapture = cv2.VideoCapture(0)

cv2.namedWindow('MyWindow')

cv2.setMouseCallback('MyWindow', onMouse)

print 'Showing camera feed. Click window orpress any key to stop.'

success, frame = cameraCapture.read()

while success and cv2.waitKey(1) == -1 andnot clicked:

cv2.imshow('MyWindow',frame) 

success, frame =cameraCapture.read()

cv2.destroyWindow('MyWindow')

waitKey()的参数是以微秒为单位的数字,用来表示等待键盘输入的时间。其返回值要么是-1(表示没有按键)或对应按键的ASCII键值,如27表示Esc。在Python中有一个标准函数ord()可返回某个字符的ASCII键值,如ord(‘a’)返回97。

(下面关于waitKey()函数和OpenCV中鼠标事件的一

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics