306 学用OpenCV笔记——01.从何学起

用视觉识别可以做很多好玩的东西,比如有趣的互动艺术。不仅如此视觉识别的应用非常广泛,很感兴趣。OpenCV是个免费开源的视觉库,感谢OpenCV降低了门槛,让我这个外行菜鸟也可以学着玩玩视觉识别。

OpenCV (Open Source Computer Vision Library: http://opencv.org)
Learning OpenCV – O’REILLY ,据说这是本OpenCV入门的好书。电子版下载:http://ishare.iask.sina.com.cn/f/6667035.html
呃..,看了一看,发现函数名啊什么的跟我用的OpenCV2.4.5都已经不一样了啊,尝试写代码都不知怎么下手啊
打开OpenCV China网站翻译的中文手册(http://www.opencv.org.cn),呃…,一样的,是OpenCV1.x的文档。最新的也只是OpenCV2.3.2,而且只翻译了很少一部分(2013-06-11)。对我这新手来说1.x文档没用(我装的是最新版本的2.4.5),2.3.2的文档还是能帮助熟悉OpenCV的。
好吧,先把2.3.x中文部分的看了,然后有需要的就自己用dict.cn慢慢啃官方最新的OpenCV2.4.5的英文文档吧
学习资料:
OpenCV2.3.2文档(部分有中文翻译)http://www.opencv.org.cn/opencvdoc/2.3.2/html/index.html
官方OpenCV2.4.5文档 http://docs.opencv.org/ (OpenCV 2.4.5.0 documentation)
学习资料:
core模块. 核心功能 : http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/mat%20-%20the%20basic%20image%20container/mat%20-%20the%20basic%20image%20container.html#
core module. The Core Functionality : http://docs.opencv.org/doc/tutorials/core/table_of_content_core/table_of_content_core.html#table-of-content-core
图像在OpenCV里存在的形式

一副数字图像是由若干像素组成,若干像素的颜色值就形成了一个数值矩阵

OpenCV 其主要目的就是通过处理和操作这些数值矩阵,来获取更高级的信息。因此,OpenCV如何存储并操作图像是首先要学习的。

Mat - 通用的矩阵类(基本图像容器)

 基本上讲 Mat 是一个类,由两个数据部分组成:

一个矩阵信息头(包含矩阵尺寸,存储方法,存储地址等信息)
一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。
OpenCV函数中输出矩阵的内存分配是自动完成的(如果不特别指定的话)。
使用OpenCV的C++接口时不需要考虑内存释放问题。
赋值运算符和拷贝构造函数( ctor )只拷贝信息头和矩阵指针 ,而不拷贝矩阵。
使用函数 clone() 或者 copyTo() 来拷贝矩阵本身(而不只是信息头和矩阵指针)。

存储图像方法

存储像素值,需要指定颜色空间和数据类型
颜色空间:灰度级(黑白),彩色(RGB,HSV,HLS,YCrCb,CIE L*a*b)
数据类型:char(单字节)、float(4字节,32位)、double(8字节,64位)

创建一个 Mat 对象

Mat() 构造函数
Create() function: 函数
MATLAB形式的初始化方式: zeros(), ones(), :eyes()
randu() 来对一个矩阵使用随机数填充,需要指定随机数的上界和下界:

显示 Mat 对象

为了debug,我们会希望看到矩阵的实际值。为此,可以通过 Mat 的运算符 << 来实现,但这只对二维矩阵有效。

基本看懂了,准备在Python里试试创建一个矩阵(Mat)对象。呃..,cv2.?没有 Mat 方法啊

去手册找找,看了半天还是一头雾水,不知道如何下手。直接找个示例代码看看,发现edge.py比较简洁有用,适合入门研究。

示例程序 :edge.py ,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#/usr/bin/env python
 
'''
This sample demonstrates Canny edge detection.
 
Usage:
edge.py [
 
Trackbars control edge thresholds.
 
'''
 
import cv2
import video
import sys
 
if __name__ == '__main__':
print __doc__
 
try: fn = sys.argv[1]
except: fn = 0
 
def nothing(*arg):
pass
 
cv2.namedWindow('edge')
cv2.createTrackbar('thrs1', 'edge', 2000, 5000, nothing)
cv2.createTrackbar('thrs2', 'edge', 4000, 5000, nothing)
 
cap = video.create_capture(fn)
while True:
flag, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thrs1 = cv2.getTrackbarPos('thrs1', 'edge')
thrs2 = cv2.getTrackbarPos('thrs2', 'edge')
edge = cv2.Canny(gray, thrs1, thrs2, apertureSize=5)
vis = img.copy()
vis /= 2
vis[edge != 0] = (0, 255, 0)
cv2.imshow('edge', vis)
ch = cv2.waitKey(5)
if ch == 27:
break
cap.release
cv2.destroyAllWindows()

 

以下是代码里(调用的一些功能语句)
import cv2
import video
import sys
sys.argv

一般的,argv 是命令行传入的参数。在这里是?

cv2.nameWindow

cv2.createTrackbar
cv2.getTrackbarPos
cv2.cvtColor
cv2.Canny
cv2.imshow
cv2.waitKey
cv2.destroyAllWindows
cap=video.create_capture()
cap.read()
img.copy
查手册,哦,发现这些都属于OpenCV API 的使用(XD 真是小白啊),这下知道从哪里查询cv2提供的所有方法函数了,OpenCV API Reference : http://docs.opencv.org/modules/refman.html
虽然还是没搞定 Mat,不过那不重要了,从这里入手,学习如何处理图像,自然后面就知道了
学着写个代码试试:显示摄像头画面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import cv2
import video
 
cap=video.create_capture()
cv2.namedWindow("camera")
 
while True:
img=cap.read()
cv2.imshow("camera",img)
ch = cv2.waitKey(5)
if ch == 27:
break
cap.release
cv2.destroyAllWindows

出现错误:

import video

ImportError: No module named video

原来video不是基本库,查看video.py源代码,改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
import cv2
 
cap=cv2.VideoCapture()
cv2.namedWindow("camera")
 
while True:
img=cap.read()
cv2.imshow("camera",img)
ch = cv2.waitKey(5)
if ch == 27:
break
cap.release
cv2.destroyAllWindows

错误:
    cv2.imshow(“camera”,img)
TypeError: mat is not a numerical tuple
数据结构不对,直接用cv2试了半天还是不行,复制video.py,import video,用img=video.read()也还是不行,同样的错误
再看edge.py的代码,算是终于看明白这一句:flag, img = cap.read()
.read()返回两个数据,retval(应该是return value)是一个返回值,image是返回的图像。所以代码里的flag是用来存储函数返回值的变量,然后才是img保存返回的图像。
如果只用一个变量来存储.read()的返回值,就是retval+image两种数据,所以无法图片,提示数据类型错误。不过也从侧面看出Python语言的方便性。
以下是完整OK的代码,其它的一些错误也纠正了,并添加了注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import cv2
 
cap=cv2.VideoCapture(0) #create a video capture object. ID=0 is default camera
cv2.namedWindow("camera") #create a window object
while True: #loop to get video frame
if not cap.isOpened(): #check camera
print 'camera not opened'
break
flag, img=cap.read() #get video frame
cv2.imshow("camera",img) #show the video frame
if cv2.waitKey(5)==27: #press Esc key to quit
break
cap.release()
cv2.destroyAllWindows()

发现这段程序显示的图像是左右翻着的,也就是我抬左手,视频上显示的是右边的手。那么就需要对读取的图像进行一次左右镜像的处理。
通过搜索发现可以使用cv2.flip()实现此功能。
cv2.flip()语法参考(http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#cv2.flip
cv2.flip(src, flipCode[, dst]) → dst

flip()的说明是,在水平方向或垂直方向或者两个轴向翻转一个二维数组。

flipcode:0 x轴镜像,即图像上下翻转。 1 y轴镜像,即图像左右翻转。-1 x轴+y轴镜像,即垂直翻转且水平翻转。

只要添加一行代码就OK:
img=cv2.flip(img,1) #flip image around horizontal
完成这个程序,开始找到点摸索学习的门道了