基于Python的OpenCV图像处理4

May 6,2017   3398 words   13 min


性能检测

在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。

本文作者原创,未经许可不得转载,谢谢配合

返回顶部