Python计算机视觉:第十章 OpenCV

来源:互联网 发布:windows桌面消失 编辑:程序博客网 时间:2024/05/13 13:05

第十章 OpenCV

  1. 10.1 OpenCV Python接口
  2. 10.2 OpenCV基础
    1. 10.2.1 读取、写入图像
    2. 10.2.2 颜色空间
    3. 10.2.3 显示图像和结果
  3. 10.3 视频处理
    1. 10.3.1 视频输入
    2. 10.3.2 读取视频到NumPy数组
  4. 10.4 跟踪
    1. 10.4.1 光流法
    2. 10.4.2 Lucas-Kanade算法

这一章主要讲述通过Python接口使用目前流行的计算机视觉编程库OpenCV。OpenCV是一个C++库,用于实时处理计算机视觉方面的问题。

10.1 OpenCV Python接口

OpenCV是一个C++库,它涵盖了很多计算机视觉领域的模块。可以通过访问[http://opencv.willowgarage.com/ documentation/python/index.html]。

OpenCV目前最新的版本是2.4.8。实际上,OpenCV有两个Python接口,老版本的cv模块使用OpenCV内置的数据类型,新版本的cv2模块使用NumPy数组。对于新版本的模块,可以通过下面方式导入:

import cv2

而老版本的模块则通过下面方式导入:

import cv2.cv

在本章中,我们使用cv2模块,译者使用的OpenCV版本是2.4.6。

10.2 OpenCV基础

OpenCV提供了读取图像和写入图像,矩阵操作以及数学库函数。我们先来看看这些基本组件并学习怎样使用它们。

10.2.1 读取、写入图像

下面是一个简短的载入图像、打印尺寸、转换格式及保存图像为.png格斯的例子:

# -*- coding: utf-8 -*-import cv2# 读入图像im = cv2.imread('../data/empire.jpg')# 打印图像尺寸h, w = im.shape[:2]print h, w# 保存原jpg格式的图像为png格式图像cv2.imwrite('../images/ch10/ch10_P210_Reading-and-Writing-Images.png',im)

运行上面代码后,在ch10文件下保存有empire.jpg转换成.png格式的图片,即ch10P210Reading-and-Writing-Images.png,下面是转换格式后保存的.png的图像:ch10_P210_Reading-and-Writing-Images函数imread()将图像返回为一个标准的NumPy数组,如果你喜欢的话,你可以将该函数用于PIL图像读取的备选函数。函数imwrite()能够根据文件后缀自动的进行格式转换。

10.2.2 颜色空间

在OpenCV中,图像不是用常规的RGB颜色通道来存储的,它们用的是BGR顺序。当读取一幅图像后,默认的是BGR,不过有很多转换方式是可以利用的。颜色空间转换可以用函数cvtColor()函数。比如,下面是一个转换为灰度图像的例子:

import cv2im = cv2.imread('../data/empire.jpg')# create a grayscale versiongray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)

10.2.3 显示图像和结果

下面我们看一些用OpenCV进行图像处理并用OpenCV绘图及窗口管理功能显示图像后的结果的示例。

第一个例子是从文件中读取一幅图像,并创建积分图像表示:

# -*- coding: utf-8 -*-import cv2from pylab import *# 添加中文字体支持from matplotlib.font_manager import FontPropertiesfont = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)# 读入图像im = cv2.imread('../data/fisherman.jpg')# 转换颜色空间gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)# 显示积分图像fig = plt.figure()subplot(121)plt.gray()imshow(gray)title(u'灰度图', fontproperties=font)axis('off')# 计算积分图像intim = cv2.integral(gray)# 归一化intim = (255.0*intim) / intim.max()#显示积分图像subplot(122)plt.gray()imshow(intim)title(u'积分图', fontproperties=font)axis('off')show()# 用OpenCV显示图像#cv2.imshow("Image", intim)#cv2.waitKey()# 用OpenCV保存积分图像#cv2.imwrite('../images/ch10/ch10_P211_Displaying-Images-and-Results-cv2.jpg',intim)# 保存figure中的灰度图像和积分图像fig.savefig("../images/ch10/ch10_P211_Displaying-Images-and-Results.png")

运行上面代码,显示如下结果,并在/images/ch10/目录下生成一幅保存有灰度图像和积分图像的图片:ch10_P211_Displaying-Images-and-Results第二个例子从种子像素开始应用泛洪(漫水)填充:

# -*- coding: utf-8 -*-import cv2import numpyfrom pylab import *# 添加中文字体支持from matplotlib.font_manager import FontPropertiesfont = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)# 读入图像filename = '../data/fisherman.jpg'im = cv2.imread(filename)# 转换颜色空间rgbIm = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)# 显示原图fig = plt.figure()subplot(121)plt.gray()imshow(rgbIm)title(u'原图', fontproperties=font)axis('off')# 获取图像尺寸h, w = im.shape[:2]# 泛洪填充diff = (6, 6, 6)mask = zeros((h+2, w+2), numpy.uint8)cv2.floodFill(im, mask, (10, 10), (255, 255, 0), diff, diff)# 显示泛洪填充后的结果subplot(122)imshow(im)title(u'泛洪填充', fontproperties=font)axis('off')show()#fig.savefig("../images/ch10/floodFill.png")# 在OpenCV窗口中显示泛洪填充后的结果# cv2.imshow('flood fill', im)# cv2.waitKey()# 保存结果# cv2.imwrite('../images/ch10/floodFill.jpg',im)

译者使用的是matplotlib显示泛洪填充后的结果,上面代码底下的注释部分是用OpenCV显示泛洪填充的结果。如果你用OpenCV窗口显示上面运行的结果,可以反注释。下面是上面泛洪填充后的结果:floodFill作为最后一个例子,我们看一下提取图像的SURF(加速稳健特征)特征。SURF是SIFT特征的一个快速版本。这里我们也会展示一些OpenCV绘制命令。

# -*- coding: utf-8 -*-import cv2import numpyfrom pylab import *# 读入图像im = cv2.imread('../data/empire.jpg')# 下采样im_lowres = cv2.pyrDown(im)# 转化为灰度图像gray = cv2.cvtColor(im_lowres, cv2.COLOR_RGB2GRAY)# 检测特征点s = cv2.SURF()mask = numpy.uint8(ones(gray.shape))keypoints = s.detect(gray, mask)# 显示图像及特征点vis = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)for k in keypoints[::10]:    cv2.circle(vis, (int(k.pt[0]), int(k.pt[1])), 2, (0, 255, 0), -1)    cv2.circle(vis, (int(k.pt[0]), int(k.pt[1])), int(k.size), (0, 255, 0), 2)cv2.imshow('local descriptors', vis)cv2.waitKey()cv2.imwrite('../images/ch10/ch10_P261_Fig10-3.jpg',vis)

上面代码先读入一幅图像,用pyrDown下采样,得到的一幅尺寸是原图像尺寸一半的降采样图像,即im_lowres,然后将图像转换为灰度图像,并将它传递给SURF关键点检测对象。运行上面代码,可得下面SURF特征点检测结果:ch10_P261_Fig10-3

10.3 视频处理

单纯利用Python处理视频是比较困难的,因为要考虑到速度、编解码器、摄像机、操作系统已经文件格式等问题。目前Python还没有视频处理库。Python处理视频的接口仅有的较好的就是OpenCV。在这一节,我们会展示一些对视频进行处理的基本例子。

10.3.1 视频输入

OpenCV能够很好地支持视频的读入。下面的例子展示了捕获视频帧,并在OpenCV窗口中显示它们:

import cv2# setup video capturecap = cv2.VideoCapture(0)while True:    ret,im = cap.read()    cv2.imshow('video test',im)    key = cv2.waitKey(10)    if key == 27:        break    if key == ord(' '):    cv2.imwrite('vid_result.jpg',im)

上面VideoCapture从摄像头或文件中捕获视频。这里我们给它传递了一个整数作为初始化参数,它实际是视频设备的ID号,对于单个连着的摄像头,其ID号为0。read()方法解码并返回下一视频帧。waitKey()函数等待用户按下“Esc”(对应的ASCII码为27)终止应用,或按“space”将当前帧保存起来。

我们将上面例子进行拓展,使其能够在OpenCV窗口中对输出的视频进行模糊。对上面的例子进行稍微的修改便可实现该功能:

import cv2# setup video capturecap = cv2.VideoCapture(0)# get frame, apply Gaussian smoothing, show resultwhile True:    ret,im = cap.read()    blur = cv2.GaussianBlur(im,(0,0),10)    cv2.imshow('camera blur',blur)    if cv2.waitKey(10) == 27:        break

上面对每一帧图像,将其传给GaussianBlur()函数,该函数实现对图像进行高斯滤波。在这个实例中,我们传递的是彩色图像,每一个颜色通道可以分别对其进行模糊。该函数以一个滤波器大小元组及高斯函数的标准差作为输入,如果滤波器大小设置为0,则它自动赋为标准差。运行上面的结果如下:camera-blur

10.3.2 读取视频到NumPy数组

OpenCV可以从一个文件中读取视频帧序列,并将它们转换成NumPy数组。下面给出了一个从摄像头捕获视频,并将它们存储在NumPy数组中的例子。

import cv2from pylab import *# setup video capturecap = cv2.VideoCapture(0)frames = []# get frame, store in arraywhile True:    ret,im = cap.read()    cv2.imshow('video',im)    frames.append(im)    if cv2.waitKey(10) == 27:        breakframes = array(frames)# check the sizesprint im.shapeprint frames.shape

上面每一帧数组会被添加到列表的末尾直到捕获终止。打印出的数组大小表示的帧数、高度、宽度、3。运行上面代码打印出的结果为:

(480, 640, 3)(40, 480, 640, 3)

这里,记录了40帧。类似如这样的视频数据数组非常适合视频处理,比兔计算视频帧差异以及跟踪。

10.4 跟踪

跟踪是对视频帧序列中的物体进行跟踪。

10.4.1 光流法

10.4.2 Lucas-Kanade算法

Lucas-Kanade算法原理这里略,具体可以参阅中译本。

import lktrackimnames = ['../data/bt/bt.003.pgm', '../data/bt/bt.002.pgm', '../data/bt/bt.001.pgm', '../data/bt/bt.000.pgm']# create tracker objectlkt = lktrack.LKTracker(imnames)# detect in first frame, track in the remaininglkt.detect_points()lkt.draw()for i in range(len(imnames)-1):    lkt.track_points()    lkt.draw()

LKtrack-bt

import lktrackfrom pylab import *imnames = ['../data/viff/viff.000.ppm', '../data/viff/viff.001.ppm',           '../data/viff/viff.002.ppm', '../data/viff/viff.003.ppm', '../data/viff/viff.004.ppm']# track using the LKTracker generatorlkt = lktrack.LKTracker(imnames)for im,ft in lkt.track():    print 'tracking %d features' % len(ft)# plot the tracksfigure()imshow(im)for p in ft:    plot(p[0],p[1],'bo')for t in lkt.tracks:    plot([p[0] for p in t],[p[1] for p in t])axis('off')show()

ch10_fig10-6_generator


from: http://yongyuan.name/pcvwithpython/chapter10.html

0 0