Image Processing in OpenCV
学习目标:
- 如何从一个色彩空间转换到另一个,例如BGR<->Gray
- 创建一个应用程序来提取视频中的彩色对象
- 学习cv.cvtColor(),cv.inRange()等函数
修改色彩空间
在OpenCV中有超过150种可用的色彩空间转换方法。但我们仅看其中的两种BGR<->GRAY和BGR<->HSV。
cv.cvtCOLOR(input_image,flag):函数功能为修改图像的色彩空间。input_image为输入图片,flag为转换的类型。
对于 BGR → 灰度转换,我们使用标志 cv.COLOR_BGR2GRAY。类似地,对于 BGR → HSV,我们使用标志 cv.COLOR_BGR2HSV。
所有COLOR转换方式展示:
>>> import cv2 as cv
>>> flags = [i for i in dir(cv) if i.startswith('COLOR_')]
>>> print( flags )
注:HSV,Opencv中色调范围是色调范围是 [0,180],饱和度范围是 [0,255],数值范围是 [0,255],不同的软件使用不同的比例。所以如果要将Opencv的值与它们进行比较就需要对这些范围进行归一化处理。
物体追踪
现在我们知道如何将BGR图片转换成HSV,我们可以用其来提取彩色对象。在HSV中,表示颜色比BGR色彩空间更容易。我们将使用如下步骤来尝试提取视频中的蓝色对象:
- 获取视频的每一帧
- 将帧从BGR色彩空间转换成HSV色彩空间
- 我们对HSV图像的蓝色范围进行阈值化处理
- 单独提取蓝色对象
代码
import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
while(1):
# 获取每一帧
_, frame = cap.read()
# 将BGR色彩区域转换成HSV
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
# 定义HSV中的蓝色区域
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# 对HSV图像做阈值处理,仅获取蓝色区域
mask = cv.inRange(hsv, lower_blue, upper_blue)
# 对原始图像与掩码做位与操作(mask仅蓝色区域>1,其余区域为0,故做位与操作仅有蓝色区域显示。)
res = cv.bitwise_and(frame,frame, mask= mask)
cv.imshow('frame',frame)
cv.imshow('mask',mask)
cv.imshow('res',res)
k = cv.waitKey(5) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
如何找到想要追踪的HSV值
在stackoverflow.com上的一个常见问题。你可以先获取想要追踪物体的BGR值,再使用cv.cvtCOLOR()来转换为HSV域,之后再打印出HSV值即可。
>>> green = np.uint8([[[0,255,0 ]]])
>>> hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)
>>> print( hsv_green )
[[[ 60 255 255]]]
同时,我也编写了一个HSV调色器,可以拖动滑块修改HSV的值来显示颜色。代码如下:
import numpy as np
import cv2 as cv
def nothing(x):
pass
# 首先初始化一个黑色图和窗口
img = np.zeros((300, 512, 3), np.uint8)
hsv_img = cv.cvtColor(img, cv.COLOR_BGR2HSV)
cv.namedWindow('image')
# 创建HSV的Trackbar
cv.createTrackbar('H', 'image', 0, 180, nothing)
cv.createTrackbar('S', 'image', 0, 255, nothing)
cv.createTrackbar('V', 'image', 0, 255, nothing)
# 开关
switch = '0 : OFF \n1 : ON'
cv.createTrackbar(switch, 'image', 0, 1, nothing)
while True:
k = cv.waitKey(1) & 0xFF
if k == 27: # Exit on 'ESC' key press
break
# 获取Trackbar的值
h = cv.getTrackbarPos('H', 'image')
s = cv.getTrackbarPos('S', 'image')
v = cv.getTrackbarPos('V', 'image')
swt = cv.getTrackbarPos(switch, 'image')
if swt == 0:
#如果switch为0,一直显示黑色图像
to_display = np.zeros_like(img)
else:
hsv_img[:] = [h, s, v]
to_display = cv.cvtColor(hsv_img, cv.COLOR_HSV2BGR)
cv.imshow('image', to_display)
cv.destroyAllWindows()
练习
尝试使用一种方法来同时提取红色、蓝色、绿色对象。
import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
if not cap.isOpened():
cap.open()
while cap.isOpened():
ret,frame = cap.read()
hsv = cv.cvtColor(frame,cv.COLOR_BGR2HSV)
lower_blue = np.array([75,75,50])
upper_blue = np.array([125,255,255])
lower_red = np.array([0,20,20])
upper_red = np.array([5,255,255])
lower_green = np.array([45,50,50])
upper_green = np.array([70,255,255])
mask_blue = cv.inRange(hsv,lower_blue,upper_blue)
mask_green = cv.inRange(hsv, lower_green, upper_green)
mask_red = cv.inRange(hsv, lower_red, upper_red)
#使用bitwise_or来合成三个掩码,即实现同时提取红色、蓝色和绿色对象的功能
mask = cv.bitwise_or(mask_red,cv.bitwise_or(mask_green,mask_blue))
res = cv.bitwise_and(frame,frame,mask = mask)
cv.imshow('frame',frame)
cv.imshow('mask',mask)
cv.imshow('res',res)
k = cv.waitKey(5) & 0xFF
if k == 27:
break
cv.destroyAllWindows()