0.简介
1.对图片的基本操作
读取和修改像素数值,选取部分图片区域
2.对图片的算数操作
3.计算改进技术
提高运算效率
4.数学运算工具
opencv中的数学工具例如PCA,SVD等
1.图片的基本操作
1.1 获取和修改像素值
1 | import cv2 |
返回
1 | [157 166 200] |
注意:
numpy是一个快速数组计算的库,所以简单的获取和修改单个像素的值都是缓慢的,不建议如此使用。
上面的方法通常用来选择数组的一个区域,例如前5行和后3列。
对于单个像素的获取,通常用array.item()和array.itemset(),但是它总是返回一个数值,所以如果你想要获取所有BGR的值,就需要分别获取。
1 | #获取 RED 值 |
1.2 获取图片的属性
图片属性包括:行,列,通道,图片数据的类型,像素的数目等等。
1 | print(img.shape) |
图片的数据类型是非常重要的,因为很多的时候错误原因就是不合适的数据类型。
1.3 选取图片的区域 ROI(Region Of Image)
有时候,需要选取某些区域的图像,例如,对于眼睛的检测,需要首先执行面部检测,然后再面部内搜索眼睛,这种方法提高了准确性和性能。
所以,ROI是包含了numpy数组
1 | >>> ball = img[280:340, 330:390] |
1.4 分割和融合图片的通道
B,G,R是彩色图片的通道,对于这个的操作有
1 | b,g,r = cv2.split(img) |
注意cv2.split()是一个时间花费昂贵的运算,只有必要的时候才会使用,一般情况下,numpy数组是更加有效的,并且尽可能用。
1.5 为图片制作边框(Padding)
Padding,内边框,填充,
如果你想在图片的周围制造边框,可以使用cv2.copyMakeBorder()函数,但是对复杂的运算有更多的应用,无内边框等,这个函数有下列的变量:
1 | src |
这样,下面是例程:
1 | import cv2 |
上面有matplotlib,类似于matlab的绘制函数
2.图片的算数操作
2.1 图片加法
通过opencv的函数cv2.add()将两个图片相加,或者通过数组res=img1+img2。所有的图片必须有相同的类型和深度,或者第二个图片可以是一个灰度值。
但是这两个方法有区别:
opencv加法是饱和运算
numpy是取余运算
例如:
1 | >>> x = np.uint8([250]) |
当你添加两个图片时候,opencv函数将会提供更好的结果,最好使用opencv函数。
2.2 图像混合
也是图片加法,但是不同的权重给图片,有混合和透明度的感觉。
1 | g(x) = (1 - a)f0(x) + af1(x) |
将a从0到1,可以将一个图片转换为另一个图片,可以用cv2.addWeighted()来进行图片的混合。
cv2.addWeighted(img1,a,img2,b,c)
out = a * img1 + b * img2 + c
1 | img1 = cv2.imread('img.png') |
2.3 位运算操作
and,or,not或者xor位运算,这些在抽取图片的不矩形部分中,非常有用。
将一个logo放在一个图片上,如果将两个图片直接相加,它将会修改颜色。如果将两个图片进行图像混合,就会有透明度。如果是一个矩形区域就可以直接用之前的ROI图片区域方法。可以通过位操作
1 | # 加载两个图片 |
其中有图片阈值函数,cv2.threshold()函数,当像素的数值大于某个阈值,像素点会被分配为一个数值,其他的分配另外的数值。第一个变量是图片,应该是灰度图。第二个变量是阈值,第三个变量是最大值,代表了如果像素值高于或者低于阈值的时候,所需要的数值,第四个变量是阈值函数的类型,分别有:
1 | cv2.THRESH_BINARY //像素值大于阈值,就修改为最大值,其他的为0 |
备注:
BINARY模式,阈值的最大值是255,也就是白色,特别注意在opencv中,0代表黑色。
TOZERO模式,将部分数值变为0
INV模式,就是相反
之后是cv2.bitwise_and()函数,这里面有一个掩膜,例如
out = cv2.bitwise_and(img1,img2,mask = mask_defined)
首先,img1和img2有相同的大小,而且
out[i] = img1[i] & img2[i] if mask[i] != 0
3.改进运算效率的技术
在图片的运算中,我们每秒需要处理大量的运算,所以,代码不仅仅需要得到正确的解法,而且具有很高的效率,这一部分包含下面的内容:
测量代码运行的效率
提高代码效率的一些小诀窍
需要使用下面的一部分函数:cv2.getTickCount,cv2.getTickFrequency。
除了opencv,python中有time模块,可以用来测量执行的时间,以及profile模块来得到代码的详细内容,例如,代码中每个功能所需要的时间,函数被调用了多少次等。但是,如果你使用IPython,这些特性都很好的被包含在内。
3.1 使用opencv来测量性能
cv2.getTickCount函数用来返回一个相关事件(例如,机器启动的时刻)之后直到这个函数被调用之间的时钟周期数,所以,你可以在函数前后调用这个函数来计算得到这个函数的执行需要多少个时钟周期。
cv2.getTickFrequency函数返回了时钟周期频率,或者可以说每秒的时钟周期数目,所以可以通过下面的代码获取执行时间
1 | e1 = cv2.getTickCount() |
你可以直接使用time模块中的time.time()函数,取两个函数返回值的差大概。没有用过。
3.2 opencv中默认的优化
opencv中的许多函数都通过SSE2,AVX等进行了优化,它还包含了没有优化的代码。所以如果我们的系统支持这些特性,我们应该使用他们,几乎大多数现代处理器都支持他们。在编译的时候这些就默认使用了。所以,当默认使用的时候,opencv运行优化过的代码,否则运行没有优化过的代码。你可以使用cv2.useOptimized()函数来检查它是否已经启用,也可以使用cv2.setUseOptimized()来开启或者关闭优化。
样例
1 | # check if optimization is enabled |
3.3 IPython中的检测性能
首先,IPython是什么:
它只是python中的一个模块,可以通过pip来安装。
然后,它有什么用处:
是python的交互式shell,比默认的python shell好用的多,支持自动缩进,bash shell命令,也内置了很多有用的函数以及功能,可以高效使用python,也是利用python来进行科学计算和交互可视化的平台。
主要功能:
1.运行ipython控制台
2.使用ipython作为系统shell
3.使用历史输入(history)
4.Tab补全
5.使用%run命令运行脚本
6.使用%timeit命令快速测量时间
7.使用%pdb命令快速debug
8.使用pylab进行交互计算
9.使用IPython Notebook
但是,我居然还没用过。。。我直接找一些资料先补充。以后用到再说。
样例
1 | In [10]: x = 5 |
说实话,看到上面的样例,感觉有点像Linux中的time函数,我偶尔发现的。
再次提醒,python的数值计算远快于numpy数值计算。所以仅包含一两个元素的运算,我们尽量使用python的数值运算,当数组的大小更大的时候使用numpy。
1 | In [35]: %timeit z = cv2.countNonZero(img) |
所以opencv函数比numpy函数快25倍,说实话,这是怎么算出来的?370/15.8,恩就这样。
3.4 更多IPython的指令
还有其他命令来测量性能,分析性能,行分析,存储空间测量等。
3.5 优化性能的技巧
注意,首先简单实现算法,之后分析,找到瓶颈对其优化。
1.尽量不要在python中使用循环,尤其是多重循环
2.numpy和opencv已经对向量运算进行了优化,因此尽量使用向量
3.利用缓存?
4.除非必要,不要复制数组,而是尝试使用视图。??
如果这样依旧无法解决问题,那么使用Cython库。
4.opencv中的数学运算工具
这里面很复杂,包含SVD和PCA。
SVD Singular Value Decomposition奇异指分解 数值降维
PCA Principal Component Analysis主成分分析 降维算法
这两个方法我会专门进行补充。。待定