性能检测
在OpenCV中,提供了用于记录代码运行时间的函数:
cv2.getTickCount()
:返回从参考点到这个函数被执行时的时钟数。所以当在一个函数执行前后都调用它的话,
便可以得到代码运行所经历的时钟数。
cv2.getTickFrequency()
:返回时钟频率,或每秒的时钟数。
利用上面两个函数便可以获得执行某段代码所经历的时间。
img = cv2.imread("E:\\1366.jpg")
e1 = cv2.getTickCount()
img2gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
e2 = cv2.getTickCount()
ret, img2 = cv2.threshold(img2gray, 128, 255, cv2.THRESH_BINARY)
e3 = cv2.getTickCount()
t1 = (e2 - e1) / cv2.getTickFrequency()
t2 = (e3 - e2) / cv2.getTickFrequency()
print "BGR2Gray:" + (t1 * 1000).__str__() + " ms"
print "Binary:" + (t2 * 1000).__str__() + " ms"
cv2.imshow("img", img2)
cv2.waitKey(0)
原图为一幅1366×768的jpg图像,在笔记本和平板分别运行得到的耗时如下: 从运行结果可以得到两个结论。一是OpenCV自带的灰度化函数和二值化函数的耗时差异是巨大的。 在笔记本上,二者相差接近9倍。在平板上甚至相差100倍以上。二是笔记本和平板的CPU运算能力 也是相差巨大的。灰度化大约相差了100倍,二值化相差了5倍。
性能提示
1.Python的标量计算比Numpy的标量计算要快,对于仅包含一两个元素的操作,Python标量比Numpy的数组要快。
但当数组稍微大一点时Numpy就会胜出了。
2.同时,一般情况下OpenCV的函数要比Numpy函数快。所以对于相同的操作最好使用OpenCV的函数。当然也有例外,
尤其是当使用Numpy对视图进行操作时。
3.尽量避免使用循环,尤其双层、三层循环,它们天生就是非常慢的。
4.算法中尽量使用向量操作,因为Numpy和OpenCV都对向量操作进行了优化。
5.没必要的话就不要复制数组,使用视图来代替。数组复制是非常浪费时间的。
颜色空间转换
在OpenCV中有超过150种的颜色转换方法。但常用的是BGR→GRAY以及BGR→HSV。OpenCV中转换函数的原型如下:
cv2.cvtColor(input_image,flag)
其中flag就是转换类型。像我们之前用的cv2.COLOR_BGR2GRAY
便是其中一种。同理,对于转换到HSV,只需要修改flag
为cv2.COLOR_BGR2HSV
即可。
在OpenCV的HSV格式中,H(色彩/色度)的取值范围是[0,179],S(饱和度)的取值范围为[0,255],V(亮度)的取值范围为[0,255]。
不同软件使用的值可能不同,所以在对比不同HSV值时,最好先归一化。
颜色转换实例
颜色转换在OpenCV中是非常简单的事情。我们可以在HSV空间中提取某个特定颜色的物体。在HSV中要比在BGR中更容易表示一个 特定的颜色。在我们的程序中,例如要提取一个蓝色的物体。应该有如下几步:
- 从视频中获取每一帧的图像
- 将每一幅图像由BGR空间转换到HSV空间
- 设定HSV阈值在蓝色这一范围,生成掩膜
- 掩膜与原图像进行位操作,提取物体。当然我们还可以做其它任何想做的事。比如在蓝色物体周围画个圈。
代码如下:
# coding=utf-8
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# 设置HSV颜色的范围
lower_blue = np.array([110, 50, 50])
upper_blue = np.array([130, 255, 255])
while cap.isOpened():
# 第一步,获取每一帧的影像
ret, frame = cap.read()
# 第二步,将BGR转换到HSV色彩空间
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 第三步,根据颜色范围生成掩膜
mask = cv2.inRange(frame_hsv, lower_blue, upper_blue)
# 第四步,将掩膜与原图像进行位运算
dst = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow("video_bgr", frame)
cv2.imshow("dst", dst)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
cap.release()
这里一个新知识点是用到了cv2.inRange()
函数。从使用的参数也很容易理解,即对一幅影像
获取介于lower color和upper color之间的区域,返回1给mask。它与cv2.threshold()
有异曲同工的效果。
只不过阈值函数是判断某一个数,而范围函数是判断是否在某个范围。我们将一个脉动的瓶盖进行识别,效果如下:
可以看到,程序可以比较好的识别出蓝色的瓶盖。但也还有一些问题,如边缘有噪声等等。后续继续完善。这只是
识别物体最简单的方法,后续还会学到更多有趣的方法。
进阶版
在上面我们识别了蓝色物体,这里我们不仅要识别蓝色物体,还要同时识别出绿色物体。其实思路很简单,先分别获取 原始图像在蓝色和绿色下的掩膜mask1、mask2,然后对其求并集,便可以得到mask1、mask2表示的所有范围。代码如下:
# coding=utf-8
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# 设置HSV颜色的范围
lower_blue = np.array([110, 50, 50])
upper_blue = np.array([130, 255, 255])
lower_green = np.array([35, 43, 46])
upper_green = np.array([77, 255, 255])
while cap.isOpened():
# 第一步,获取每一帧的影像
ret, frame = cap.read()
# 第二步,将BGR转换到HSV色彩空间
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 第三步,根据颜色范围生成掩膜
mask1 = cv2.inRange(frame_hsv, lower_green, upper_green)
mask2 = cv2.inRange(frame_hsv, lower_blue, upper_blue)
mask3 = cv2.bitwise_or(mask1, mask2)
# 第四步,将掩膜与原图像进行位运算
dst = cv2.bitwise_and(frame, frame, mask=mask3)
cv2.imshow("video_bgr", frame)
cv2.imshow("dst", dst)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
cap.release()
效果如下所示:
获取HSV颜色值
既然我们可以由一幅BGR图像转换到HSV图像,那么对于单个像素值的转换当然也是可以的。依旧使用cv2.cvtColor()
函数。只不过这里我们的输入要稍微修改一下,我们可以用如下代码获得对应的HSV值:
green = np.zeros((1, 1, 3), np.uint8)
green[0, 0, 0] = 0
green[0, 0, 1] = 255
green[0, 0, 2] = 0
hsv_green = cv2.cvtColor(green, cv2.COLOR_BGR2HSV)
print green
print hsv_green
我们新建一个只有一个像素的图片,并将这个像素的颜色设置成我们需要转换的颜色,如绿色。然后调用函数进行转换即可。
当然如果不想写那么多麻烦,还有一种简便的办法,可以写成这样:green = np.uint8([[[0, 255, 0]]])
。这里的三层
中括号分别对应cvArray、cvMat、IplImage。
本文作者原创,未经许可不得转载,谢谢配合