OpenCV Python的英文教程可以看这里。
1.准备工作
(1)安装配置Python
[2018-5-12更新] 建议直接安装Python的Anaconda发行版,已经集成了常用的科学计算库,很方便,可以参考这篇博客。 当然如果想自己安装Python,体验一下,按照下面的流程也是可以的。
[更新结束]
这一步针对电脑上没有Python的全新安装,如果已有可以直接跳过。
首先到Python官网下载安装包,点击下载。考虑到兼容性下载2.7.x版本。
下载完成后进行安装。安装界面如下:
这里我们指定安装路径为Python2.7.13,也可以不改,但注意不要出现中文。
然后要记住勾选上Add path…,这样安装程序会自动添加路径到环境变量了,不需要手动添加。
接着便是等待安装,不是很慢。
很快就安装好了。
在控制台里输入python会弹出版本信息,说明安装完成,没有错误。
(2)安装PIP
pip是Python下管理包的方便的工具之一,建议安装。如果电脑上已经有了,可以跳过此步。
我们打开Python安装目录下的Scripts文件夹,发现有一个”easy_install.exe”。
在控制台中切换到这个目录下,然后输入”easy_install.exe pip”,如下图所示。
等待即可完成安装。这时我们在命令行里输入pip list即可出现已安装的包。如下所示。
这一步有可能出现问题说pip不是有效的命令,这是因为没有添加路径造成的。只需要在
系统变量Path里添加上Python的安装路径和Scripts路径,即可正常打开了。
(3)安装Numpy
如果你电脑上之前有了,那么可以跳过,如果是新的,需要安装。因为OpenCV依赖于这个库。 得益于上一步已经安装好的pip,这里我们只需要在控制台中输入”pip install numpy”即可实现自动安装。 并且如果缺少依赖还会自动安装依赖,十分方便。这类似于Ubuntu下面的apt-get和aptitude,都是自动包管理工具。 安装完成后如下图。 我们可以使用”pip list”来查看已安装的包。检测是否安装成功也可以在控制台输入”python”进入python环境,然后 输入”import numpy”,如果没有报错,说明是正确的,否则会提示错误。如下图。 此外由于后续还会用到Matplotlib,因此与上面一样的步骤进行安装,输入”pip install matplotlib”即可。安装时 你会发现他已经自动下载了其它的一些包,把依赖给解决了,不然的话需要手动一个个安装。如下图,除了Matplotlib还提示 安装好了其它必要的包。 利用pip安装包的步骤就是这样,如果以后需要安装其它的包也是同样的方法。下图是我电脑上目前安装的包。
(4)安装PyCharm
如果你电脑上已经有PyCharm可以跳过,或者用你喜欢的IDE都可以。
在配置完Python环境后,需要安装一个能用来编程的IDE,这里推荐PyCharm。因为它有比较强大的代码提示功能,界面也比较友好。
可以直接去官网下载community版本,然后一路安装即可。
(5)安装OpenCV
[2019-6-3更新]
安装Python版OpenCV最简单的办法是用pip
命令,直接pip install opencv-python
即可,默认安装最新版。
如果需要Contrib版,直接pip install opencv-contrib-python
即可,默认最新版。
关于Contrib版的详细说明,见这篇博客。
关于OpenCV安装无需再看下面的内容,当然如果愿意,按照下面的内容安装应该也是没问题的。
[更新结束]
在Python中使用OpenCV之前,首先需要下载OpenCV库。首先可以到OpenCV官网选择对应的版本下载。
需要注意的是OpenCV目前最高支持Python到2.7,因此最好使用对应的版本,不然后续配置很麻烦。
下载完成后双击打开按照提示安装(其实就是解压)。
安装完成后,打开安装目录如下所示。
我们依次进入..\opencv\build\python\2.7\
,这里有x86和x64两个文件夹。如果你安装的Python是64位,则用x64。
如果你系统是64位,但安装的是32位Python,那么依然选择x86文件夹。要以Python的位数为准,否则可能会报如下错误,
说DLL装载失败,不是有效的Win32应用程序。这就是因为Python与OpenCV位数不统一造成的。
由于OpenCV的Python版是依赖于NumPy的,还有可能出现的错误是提示NumPy库版本过低。
解决办法是去NumPy官网升级一下库即可。
可以在Windows命令行中输入Python
查看版本。
我的Python是32位的,所以选择x86。打开会发现有个cv2.pyd文件。
我们只需要将这个文件拷贝到Python的安装目录下的..\Lib\site-packages\
下即可,如图所示。
至此,安装OpenCV库的工作就完成了。
利用PyCharm新建一个Python文件,然后import cv2
即可调用相关函数了。可以看到,有非常丰富的代码提示,
比单纯用文本编辑器好很多。
但PyCharm编辑器在我的老电脑上似乎并不能很好的识别。
会报错提示找不到这个cv2
模块,而且也不会有语法提示。但在我的平板上
全新安装Python环境是可以识别的,而且有代码提示,一切正常。
我们输入以下代码利用OpenCV打开一幅图片并显示,进行简单测试:
import cv2
img = cv2.imread("E:\\test.jpg")
cv2.imshow("test", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果如下,可以看到虽然编辑器无法识别cv2
这个模块,但是可以正常运行,
最后出现了Process finished with exit code 0
。
至此,说明我们正确安装了OpenCV,并成功调用。
它不影响编译和运行,是可以正常运行出结果的,只是IDE编辑器识别不了。说明不是安装的问题,是编译器的问题。
后来我想了一下,应该是IDE解释器设置的问题。在设置完解释器之后,编译器会进行已安装库的扫描和编目。由于在我的
老电脑上一开始PyCharm扫描的时候并没有OpenCV的库,后来我手动将库放进去,但是没有让PyCharm重新扫描更新,所以
出现了虽然能编译,但是没代码提示的情况。所以如果遇到这种情况,有两种解决办法。一种是在PyCharm中重新设置解释器(删除再新建),
然后系统应该会重新扫描已安装的包,如下所示。注意Console和Project都要重新设置。
重新添加解释器后会更新相关库,如下:
第二种办法是重新安装Python,配置环境。这是迫不得已的办法,但也是最有效的办法。一般第一种办法应该就已经可以解决问题了。
至此OpenCV安装便结束了,完成了我们的准备工作,下面就可以进入正题了。
2.图像读取、显示和输出
无论做任何图像处理,这三步是基本的操作。读取一个图片,对其进行各种操作,最后输出处理过的成果。 那么下面分别来看实现的代码。
(1)读取
OpenCV读取图像的函数很简单,即imread()
。其参数为需要读入的图片的路径。如:
img = cv2.imread("E:\\test.jpg")
print type(img)
print img.dtype
print img.shape
表示读取test.jpg并且赋值给img变量。在这里打印出img的相关信息如下:
可以看到,OpenCV将读取到的图像文件转换成了”ndarray”对象,这也正印证了之前说的OpenCV是依赖于NumPy库的。
然后在”ndarray”中,每个元素的类型是“uint8”,一个无符号的8字节的整型变量,对应8bit量化,范围为0 - 255。
然后img的大小为(334, 500, 3),也即长为500,宽为334,高为3。这里的“高”其实可以理解为一幅图像的不同通道。
由于图像是由R、G、B三个通道组成的,因此对应通道数为3。这里还需要注意的一点是,shape中第一个元素保存的是
图像的宽度,第二个元素是长度,在遍历的时候不要弄反了。
此外,该函数还有一个参数,表示是否以灰度形式读取。0表示以灰度方式读取RGB图像,1表示不改变原图。默认是1。
(2)显示
利用OpenCV显示图像非常简单,只需要调用imshow()
函数即可。第一个参数是窗口的名称,第二个参数是演示的数据。
cv2.imshow("test", img)
执行上述代码便可以新建一个窗口并显示图片。但如果执行便会发现问题,窗口一闪而过。这和运行C++的黑框框程序一样,
执行完就自动关闭了。在C++中,解决这个问题很简单。只需要添加引用#include <stdlib.h>
,然后在需要停顿的地方加上
一句system("pause");
则可以了。那么在Python中如何做呢?也非常简单,只需要加上一句cv2.waitKey(0)
即可。
这个函数表示等待用户输入,其中参数表示等待时间,0表示永久等待。再次运行,会发现已经不再是“一闪而过”了。
如果还想更进一步,可以再添上一句cv2.destroyAllWindows()
表示完成之后销毁窗体。完整代码如下:
cv2.imshow("test", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
(3)输出
在我们通过各种算法对图像进行了处理之后,总希望将处理结果保存成文件,以便于和他人交流分享。在OpenCV中,保存文件也是
十分简单的操作,只需要imwrite()
函数便可实现。第一个参数是保存路径,包括你想要保存的扩展名,第二个参数是需要保存的数据。
cv2.imwrite("E:\\output.jpg", img)
执行上述代码后,我们便会在E盘找到一个新的图片文件。对某些格式有额外参数,这些参数都以IMWRITE_
开头。
JPEG格式的文件可以指定画质参数,参数名为cv2.IMWRITE_JPEG_QUALITY
,范围为0 - 100,默认为95。
图像参数以[参数名,参数值,参数名,参数值,…]的形式传递给imwrite()
的第三个参数。
对于PNG来说,第三个参数表示压缩级别。参数名为cv2.IMWRITE_PNG_COMPRESSION
,范围为0到9。0表示不压缩,9表示压缩最大。
压缩级别越高,图像尺寸越小。默认级别为3。
如下是示例代码:
cv2.imwrite("E:\\output_30.jpg", img, [cv2.IMWRITE_JPEG_QUALITY, 30])
cv2.imwrite("E:\\output_8.png", img, [cv2.IMWRITE_PNG_COMPRESSION, 8])
3.图像读取进阶
在第二部分我们介绍了图像IO以及显示相关内容。这一部分我们介绍图像读取的进一步操作。如RGB通道的分离与合并等。 由于OpenCV读取的图像本质上来说是个ndarray数组,因此我们完全可以按照操作数组的一套方法来对其进行操作。当然 OpenCV也自带了很多函数用于相关处理。
(1)RGB通道分离
要实现这个目标,有两种办法。一种基于NumPy数组,一种基于OpenCV。首先介绍第一种。
基于数组
由于在上文提到,img是一个高度为3的数组,分别对应R、G、B三通道,因此我们只需要提取某一层的数组即可。 具体而言,我们可以直接这样去写:
r = img[:, :, 2]
g = img[:, :, 1]
b = img[:, :, 0]
print r.shape
print g.shape
print b.shape
运行的结果如下: 可以看到,正确完成了我们的目标。 不过要注意的是,OpenCV读取顺序并不是RGB,而是BGR。所以在提取的时候不要弄错索引。
基于OpenCV
在OpenCV中,有内置的函数专门用于分离RGB,即split()
函数。函数接受一个参数即为原始图像数据,
返回三个与原始图像类型相同的分量,分别对应B、G、R。
b, g, r = cv2.split(img)
运行此代码,便可以得到各个分量的值。若只想接收某一个通道,只需在后面加上索引即可,如cv2.split(img)[0]
。
需要注意的是,cv2.split()
是个比较耗时的操作。只有真正需要的时候才使用它,能用Numpy索引就尽量使用。
(2)RGB通道合并
这里直接介绍OpenCV的方法。调用merge()
函数即可。参数为分离出来的三个通道。
img2 = cv2.merge([b, g, r])
(3)单像素处理
在我们将图片读取之后,其实我们就可以通过数组索引的方式来获取某个点上的像素灰度值/RGB值了。
print img[9, 9]
print img[9, 9, 2]
上述代码分别获取了第10行、第10列的BGR三个颜色分量和单独的R颜色分量,输出如下所示。
需要注意的是数组下标是从0开始的。所以索引9对应的是第10个元素。
B=107,G=57,R=37,以及单独获取的R分量。我们可以将其在Photoshop中取色,以检验是否正确。
可以看到和我们用代码获取到的RGB颜色值是一样的。
(4)遍历图像
我们可以逐一对图像的像素进行遍历,从而进行相关操作。这与遍历二维数组类似,注意数组不要越界。 例如将img的B通道复制给img2,代码如下:
img2 = np.zeros(img.shape)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
img2[i, j, 0] = img[i, j, 0]
cv2.imshow("copy", img2)
cv2.waitKey(0)
4.实例练习
在掌握上面的知识后,我们可以对上面的知识进行综合,动手实现一个给图片添加椒盐噪声的实例。代码如下:
import numpy as np
import cv2
def addPepperAndSalt(img, n):
img2 = img
for i in range(n):
x = int(np.random.random() * img.shape[0])
y = int(np.random.random() * img.shape[1])
img2[x, y, 0] = 255
img2[x, y, 1] = 255
img2[x, y, 2] = 255
return img2
img = cv2.imread("E:\\Desktop\\img2.png")
img2 = addPepperAndSalt(img, 500)
cv2.imshow("salt and pepper", img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这里我们定义了一个函数addPepperAndSalt(img, n)
用于添加椒盐噪声,第一个参数是图像数据,第二个参数是
添加椒盐噪声的数量,如这里设置成500。由于彩色图像有3个分量,因此需要把RGB全部设置成255。
我们分别将噪声值设置成500、5000、50000,原图与运行的效果分别如下所示:
原图
n=500
n=5000
n=50000
可以看到效果还是很明显的。
5.添加椒盐噪声进阶版
在完成了基本的功能后,我们还可以不断扩展功能。如可以添加黑白椒盐噪声、彩色椒盐噪声等等。代码如下所示:
def peppersalt(img, n, m):
"""
Add peppersalt to image
:param img: the image you want to add noise
:param n: the total number of noise (0 <= n <= width*height)
:param m: different mode
m=1:add only white noise in whole image
m=2:add only black noise in whole image
m=3:add black and white noise in whole image
m=4:add gray scale noise range from 0 to 255
m=5:add color noise in whole image,RGB is combined randomly with every channel ranges from 0 to 255
:return: the processed image
"""
img2 = img
if m == 1:
for i in range(n):
x = int(np.random.random() * img.shape[0])
y = int(np.random.random() * img.shape[1])
img2[x, y, 0] = 255
img2[x, y, 1] = 255
img2[x, y, 2] = 255
elif m == 2:
for i in range(n):
x = int(np.random.random() * img.shape[0])
y = int(np.random.random() * img.shape[1])
img2[x, y, 0] = 0
img2[x, y, 1] = 0
img2[x, y, 2] = 0
elif m == 3:
for i in range(n):
x = int(np.random.random() * img.shape[0])
y = int(np.random.random() * img.shape[1])
flag = np.random.random() * 255
if flag > 128:
img2[x, y, 0] = 255
img2[x, y, 1] = 255
img2[x, y, 2] = 255
else:
img2[x, y, 0] = 0
img2[x, y, 1] = 0
img2[x, y, 2] = 0
elif m == 4:
for i in range(n):
x = int(np.random.random() * img.shape[0])
y = int(np.random.random() * img.shape[1])
flag = int(np.random.random() * 255)
img2[x, y, 0] = flag
img2[x, y, 1] = flag
img2[x, y, 2] = flag
elif m == 5:
for i in range(n):
x = int(np.random.random() * img.shape[0])
y = int(np.random.random() * img.shape[1])
f1 = int(np.random.random() * 255)
f2 = int(np.random.random() * 255)
f3 = int(np.random.random() * 255)
img2[x, y, 0] = f1
img2[x, y, 1] = f2
img2[x, y, 2] = f3
return img2
不同模式下运行结果如下所示:
原图:
添加白色高斯噪声(m=1):
添加黑色高斯噪声(m=2):
添加黑白高斯噪声(m=3):
添加不同灰度高斯噪声(m=4):
添加彩色高斯噪声(m=5):
4.Just for fun
在添加椒盐噪声的实例中,如果我们将x方向上的距离限定在原始图像大小的35%,由于图像的上半部分是美丽的夜空, 添加的椒盐噪声会如同星星一样,十分漂亮。同时可适当减少噪声数。下图中n=200,范围为上35%,效果如图所示:
本文作者原创,未经许可不得转载,谢谢配合