OpenCV之Python学习笔记
一直都在用Python+OpenCV做一些算法的原型。本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段。现在看到一本国外的新书《OpenCV Computer Vision with Python》,于是就看一遍,顺便把自己掌握的东西整合一下,写成学习笔记了。更需要的朋友参考。
阅读须知:
本文不是纯粹的译文,只是比较贴近原文的笔记;
请设法购买到出版社出版的书,支持正版。
从书名就能看出来本书是介绍在Python中使用OpenCV,全书分为5章,两个附录:
- 第一章OpenCV设置,介绍如何在Windows、Mac和Ubuntu上设置Pyhton、OpenCV和相关库的环境。还讨论了OpenCV社区、OpenCV文档以及官方的示例代码。
- 第二章处理文件、摄像头和GUI,讨论OpenCV的I/O功能,接着使用面向对象的设计编写一个主应用程序,用于显示摄像头实时场景、处理键盘输入、将摄像头写入视频文件和静态图像文件。
- 第三章图像过滤,介绍使用OpenCV、NumPy和SciPy来编写图像过滤器。过滤器可用于线性颜色操作、曲线颜色操作、模糊化、锐化和寻找边缘。本章修改第一章的主程序,将过滤器应用到实时摄像头场景中。
- 第四章使用Haar Cascades追踪人脸,本章将编写一个层次化的人脸追踪器,使用OpenCV定位图像中的脸部、眼睛、鼻子和嘴巴。同时还编写了用于复制和改变图像中某块区域的大小。同样,本章也将修改之前的主应用程序,让其可以用于找到并处理摄像头场景中的人脸。
- 第五章检测前景/背景区域和深度。通过本章将了解有关OpenCV(在OpenNI和SensorKinect的支持下)从深度摄像头中获得的数据类型的信息。接着编写一些函数,使用这些数据对前景区域施加一些限制效果。最后将这些函数整合到主程序中,使得在处理人脸之前先进行细化操作。
- 附录A,与Pygame整合。修改主程序,用Pygame替换OpenCV来处理特定的I/O事件。(Pygame提供了更多样的事件处理函数。)
- 附录B,为自定义目标生成Haar Cascades,允许我们检测一系列的OpenCV工具,来对任何类型的目标或模式构建跟踪器,而不仅仅是人脸。
本书第一章是介绍在不同操作系统上对OpenCV、Python及相关库的配置,这里就不介绍了。下一篇文章将直接从第二章开始介绍。
OpenCV Python教程(1、图像的载入、显示和保存)
本文是OpenCV 2 Computer Vision Application Programming Cookbook读书笔记的第一篇。在笔记中将以Python语言改写每章的代码。
PythonOpenCV的配置这里就不介绍了。
注意,现在OpenCV for Python就是通过NumPy进行绑定的。所以在使用时必须掌握一些NumPy的相关知识!
图像就是一个矩阵,在OpenCV for Python中,图像就是NumPy中的数组!
如果读取图像首先要导入OpenCV包,方法为:
- import cv2
读取并显示图像
在Python中不需要声明变量,所以也就不需要C++中的cv::Mat xxxxx了。只需这样:
- img = cv2.imread("D:\cat.jpg")
OpenCV目前支持读取bmp、jpg、png、tiff等常用格式。更详细的请参考OpenCV的参考文档。
接着创建一个窗口
- cv2.namedWindow("Image")
然后在窗口中显示图像
- cv2.imshow("Image", img)
最后还要添上一句:
- cv2.waitKey (0)
如果不添最后一句,在IDLE中执行窗口直接无响应。在命令行中执行的话,则是一闪而过。
完整的程序为:
- import cv2
- img = cv2.imread("D:\\cat.jpg")
- cv2.namedWindow("Image")
- cv2.imshow("Image", img)
- cv2.waitKey (0)
- cv2.destroyAllWindows()
创建/复制图像
新的OpenCV的接口中没有CreateImage接口。即没有cv2.CreateImage这样的函数。如果要创建图像,需要使用numpy的函数(现在使用OpenCV-Python绑定,numpy是必装的)。如下:
- emptyImage = np.zeros(img.shape, np.uint8)
也可以复制原有的图像来获得一副新图像。
- emptyImage2 = img.copy();
- emptyImage3=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- #emptyImage3[...]=0
保存图像
保存图像很简单,直接用cv2.imwrite即可。
cv2.imwrite("D:\\cat2.jpg", img)
第一个参数是保存的路径及文件名,第二个是图像矩阵。其中,imwrite()有个可选的第三个参数,如下:
cv2.imwrite("D:\\cat2.jpg", img,[int(cv2.IMWRITE_JPEG_QUALITY), 5])
第三个参数针对特定的格式: 对于JPEG,其表示的是图像的质量,用0-100的整数表示,默认为95。 注意,cv2.IMWRITE_JPEG_QUALITY类型为Long,必须转换成int。下面是以不同质量存储的两幅图:
对于PNG,第三个参数表示的是压缩级别。cv2.IMWRITE_PNG_COMPRESSION,从0到9,压缩级别越高,图像尺寸越小。默认级别为3:
- cv2.imwrite("./cat.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])
- cv2.imwrite("./cat2.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
还有一种支持的图像,一般不常用。
完整的代码为:
- import cv2
- import numpy as np
- img = cv2.imread("./cat.jpg")
- emptyImage = np.zeros(img.shape, np.uint8)
- emptyImage2 = img.copy()
- emptyImage3=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- #emptyImage3[...]=0
- cv2.imshow("EmptyImage", emptyImage)
- cv2.imshow("Image", img)
- cv2.imshow("EmptyImage2", emptyImage2)
- cv2.imshow("EmptyImage3", emptyImage3)
- cv2.imwrite("./cat2.jpg", img, [int(cv2.IMWRITE_JPEG_QUALITY), 5])
- cv2.imwrite("./cat3.jpg", img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
- cv2.imwrite("./cat.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])
- cv2.imwrite("./cat2.png", img, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
- cv2.waitKey (0)
- cv2.destroyAllWindows()
参考资料:
《OpenCV References Manuel》
《OpenCV 2 Computer Vision Application Programming Cookbook》
《OpenCV Computer Vision with Python》
OpenCV Python教程(2、图像元素的访问、通道分离与合并)
OpenCV Python教程之图像元素的访问、通道分离与合并
转载请详细注明原作者及出处,谢谢!
访问像素
像素的访问和访问numpy中ndarray的方法完全一样,灰度图为:
- img[j,i] = 255
- img[j,i,0]= 255
- img[j,i,1]= 255
- img[j,i,2]= 255
下面通过对图像添加人工的椒盐现象来进一步说明OpenCV Python中需要注意的一些问题。完整代码如下:
- import cv2
- import numpy as np
- def salt(img, n):
- for k in range(n):
- i = int(np.random.random() * img.shape[1]);
- j = int(np.random.random() * img.shape[0]);
- if img.ndim == 2:
- img[j,i] = 255
- elif img.ndim == 3:
- img[j,i,0]= 255
- img[j,i,1]= 255
- img[j,i,2]= 255
- return img
- if __name__ == '__main__':
- img = cv2.imread("图像路径")
- saltImage = salt(img, 500)
- cv2.imshow("Salt", saltImage)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
上面的代码需要注意几点:
1、与C++不同,在Python中灰度图的img.ndim = 2,而C++中灰度图图像的通道数img.channel() =1
2、为什么使用np.random.random()?
这里使用了numpy的随机数,Python自身也有一个随机数生成函数。这里只是一种习惯,np.random模块中拥有更多的方法,而Python自带的random只是一个轻量级的模块。不过需要注意的是np.random.seed()不是线程安全的,而Python自带的random.seed()是线程安全的。如果使用随机数时需要用到多线程,建议使用Python自带的random()和random.seed(),或者构建一个本地的np.random.Random类的实例。
分离、合并通道
由于OpenCV Python和NumPy结合的很紧,所以即可以使用OpenCV自带的split函数,也可以直接操作numpy数组来分离通道。直接法为:
- import cv2
- import numpy as np
- img = cv2.imread("D:/cat.jpg")
- b, g, r = cv2.split(img)
- cv2.imshow("Blue", r)
- cv2.imshow("Red", g)
- cv2.imshow("Green", b)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- b = cv2.split(img)[0]
- g = cv2.split(img)[1]
- r = cv2.split(img)[2]
也可以直接操作NumPy数组来达到这一目的:
- import cv2
- import numpy as np
- img = cv2.imread("D:/cat.jpg")
- b = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- g = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- r = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- b[:,:] = img[:,:,0]
- g[:,:] = img[:,:,1]
- r[:,:] = img[:,:,2]
- cv2.imshow("Blue", r)
- cv2.imshow("Red", g)
- cv2.imshow("Green", b)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- >>> c= np.zeros(img.shape, dtype=img.dtype)
- >>> c[:,:,:] = img[:,:,:]
- >>> d[:,:,:] = img[:,:,:]
- >>> c is a
- False
- >>> d is a
- False
- >>> c.base is a
- False
- >>> d.base is a #注意这里!!!
- True
通道合并
同样,通道合并也有两种方法。第一种是OpenCV自带的merge函数,如下:
- merged = cv2.merge([b,g,r]) #前面分离出来的三个通道
- mergedByNp = np.dstack([b,g,r])
- merged = cv2.merge([b,g,r])
- print "Merge by OpenCV"
- print merged.strides
- mergedByNp = np.dstack([b,g,r])
- print "Merge by NumPy "
- print mergedByNp.strides
- Merge by OpenCV
- (1125, 3, 1)
- Merge by NumPy
- (1, 500, 187500)
- >>> a = np.arange(6)
- >>> a
- array([0, 1, 2, 3, 4, 5])
- >>> a.strides
- (4,)
同样,2维数组如下:
- >>> b = np.arange(12).reshape(3,4)
- >>> b
- array([[ 0, 1, 2, 3],
- [ 4, 5, 6, 7],
- [ 8, 9, 10, 11]])
- >>> b.strides
- (16, 4)
下面来看下3维数组:
- >>> c = np.arange(27).reshape(3,3,3)
- array([[[ 0, 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]]])
- >>> c.strides
- (36, 12, 4)
- import cv2
- import numpy as np
- img = cv2.imread("D:/cat.jpg")
- b = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- g = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- r = np.zeros((img.shape[0],img.shape[1]), dtype=img.dtype)
- b[:,:] = img[:,:,0]
- g[:,:] = img[:,:,1]
- r[:,:] = img[:,:,2]
- merged = cv2.merge([b,g,r])
- print "Merge by OpenCV"
- print merged.strides
- print merged
- mergedByNp = np.dstack([b,g,r])
- print "Merge by NumPy "
- print mergedByNp.strides
- print mergedByNp
- cv2.imshow("Merged", merged)
- cv2.imshow("MergedByNp", merged)
- cv2.imshow("Blue", b)
- cv2.imshow("Red", r)
- cv2.imshow("Green", g)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
from: http://blog.csdn.net/sunny2038/article/category/904451