700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > OpenCV之Python学习笔记(1)(2): 图像的载入 显示和保存 图像元素的访问 通道分离与合并

OpenCV之Python学习笔记(1)(2): 图像的载入 显示和保存 图像元素的访问 通道分离与合并

时间:2021-08-10 21:57:44

相关推荐

OpenCV之Python学习笔记(1)(2): 图像的载入 显示和保存 图像元素的访问 通道分离与合并

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包,方法为:

[python]view plaincopyimportcv2

读取并显示图像

在Python中不需要声明变量,所以也就不需要C++中的cv::Mat xxxxx了。只需这样:

[python]view plaincopyimg=cv2.imread("D:\cat.jpg")

OpenCV目前支持读取bmp、jpg、png、tiff等常用格式。更详细的请参考OpenCV的参考文档。

接着创建一个窗口

[python]view plaincopycv2.namedWindow("Image")

然后在窗口中显示图像

[python]view plaincopycv2.imshow("Image",img)

最后还要添上一句:

[python]view plaincopycv2.waitKey(0)

如果不添最后一句,在IDLE中执行窗口直接无响应。在命令行中执行的话,则是一闪而过。

完整的程序为:

[python]view plaincopyimportcv2 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是必装的)。如下:

[python]view plaincopyemptyImage=np.zeros(img.shape,np.uint8) 在新的OpenCV-Python绑定中,图像使用NumPy数组的属性来表示图像的尺寸和通道信息。如果输出img.shape,将得到(500, 375, 3),这里是以OpenCV自带的cat.jpg为示例。最后的3表示这是一个RGB图像。

也可以复制原有的图像来获得一副新图像。

[python]view plaincopyemptyImage2=img.copy(); 如果不怕麻烦,还可以用cvtColor获得原图像的副本。[python]view plaincopyemptyImage3=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #emptyImage3[...]=0 后面的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:

[python]view plaincopycv2.imwrite("./cat.png",img,[int(cv2.IMWRITE_PNG_COMPRESSION),0]) cv2.imwrite("./cat2.png",img,[int(cv2.IMWRITE_PNG_COMPRESSION),9]) 保存的图像尺寸如下:

还有一种支持的图像,一般不常用。

完整的代码为:

[python]view plaincopyimportcv2 importnumpyasnp 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的方法完全一样,灰度图为:

[python]view plaincopyimg[j,i]=255 其中j,i分别表示图像的行和列。对于BGR图像,为:[python]view plaincopyimg[j,i,0]=255 img[j,i,1]=255 img[j,i,2]=255 第三个数表示通道。

下面通过对图像添加人工的椒盐现象来进一步说明OpenCVPython中需要注意的一些问题。完整代码如下:

[python]view plaincopyimportcv2 importnumpyasnp defsalt(img,n): forkinrange(n): i=int(np.random.random()*img.shape[1]); j=int(np.random.random()*img.shape[0]); ifimg.ndim==2: img[j,i]=255 elifimg.ndim==3: img[j,i,0]=255 img[j,i,1]=255 img[j,i,2]=255 returnimg 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数组来分离通道。直接法为:

[python]view plaincopyimportcv2 importnumpyasnp 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() 其中split返回RGB三个通道,如果只想返回其中一个通道,可以这样:[python]view plaincopyb=cv2.split(img)[0] g=cv2.split(img)[1] r=cv2.split(img)[2] 最后的索引指出所需要的通道。

也可以直接操作NumPy数组来达到这一目的:

[python]view plaincopyimportcv2 importnumpyasnp 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() 注意先要开辟一个相同大小的图片出来。这是由于numpy中数组的复制有些需要注意的地方,具体事例如下:[python]view plaincopy>>>c=np.zeros(img.shape,dtype=img.dtype) >>>c[:,:,:]=img[:,:,:] >>>d[:,:,:]=img[:,:,:] >>>cisa False >>>disa False >>>c.baseisa False >>>d.baseisa#注意这里!!! True 这里,d只是a的镜像,具体请参考《NumPy简明教程(二,数组3)》中的“复制和镜像”一节。

通道合并

同样,通道合并也有两种方法。第一种是OpenCV自带的merge函数,如下:

[python]view plaincopymerged=cv2.merge([b,g,r])#前面分离出来的三个通道 接着是NumPy的方法:[python]view plaincopymergedByNp=np.dstack([b,g,r]) 注意:这里只是演示,实际使用时请用OpenCV自带的merge函数!用NumPy组合的结果不能在OpenCV中其他函数使用,因为其组合方式与OpenCV自带的不一样,如下:[python]view plaincopymerged=cv2.merge([b,g,r]) print"MergebyOpenCV" printmerged.strides mergedByNp=np.dstack([b,g,r]) print"MergebyNumPy" printmergedByNp.strides 结果为:[python]view plaincopyMergebyOpenCV (1125,3,1) MergebyNumPy (1,500,187500) NumPy数组的strides属性表示的是在每个维数上以字节计算的步长。这怎么理解呢,看下面这个简单点的例子:[python]view plaincopy>>>a=np.arange(6) >>>a array([0,1,2,3,4,5]) >>>a.strides (4,) a数组中每个元素都是NumPy中的整数类型,占4个字节,所以第一维中相邻元素之间的步长为4(个字节)。

同样,2维数组如下:

[python]view plaincopy>>>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) 从里面开始看,里面是一个4个元素的一维整数数组,所以步长应该为4。外面是一个含有3个元素,每个元素的长度是4×4=16。所以步长为16。

下面来看下3维数组:

[python]view plaincopy>>>c=np.arange(27).reshape(3,3,3) 其结果为:[python]view plaincopyarray([[[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]]]) 根据前面了解的,推断下这个数组的步长。从里面开始算,应该为(3×4×3,3×4,4)。验证一下:[python]view plaincopy>>>c.strides (36,12,4) 完整的代码为:[python]view plaincopyimportcv2 importnumpyasnp 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"MergebyOpenCV" printmerged.strides printmerged mergedByNp=np.dstack([b,g,r]) print"MergebyNumPy" printmergedByNp.strides printmergedByNp 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: /sunny2038/article/category/904451

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。