inRange函数可以用来做什么?
目标跟踪、颜色识别。
inRange应用过程中,重要的就是找到合适的HSV值。
在颜色空间人们听得最多的是RGB,它也是计算机色彩的自然表示,但对于人类来说,HSV颜色空间更符合人类的感知。HSV(色相饱和度值):
H(Hue):色调,取值范围是 [0,179] ,它用来限制某一个颜色的彩色光谱范围;
S(Saturation):饱和度,取值范围是 [0,255] ,它用来限制颜色的深度,值越大颜色越深;
V(Value):色值,取值范围是 [0,255] ,它用来限制像素的亮度,值越大像素越亮。
那如何找到合适的颜色跟踪阈值?
首先读取一张所要跟踪的图片:
import cv2
import imutils
frame = cv2.imread("UAV.jpg")
frame = imutils.resize(frame, width=320) #调整一下图片大小
cv2.imshow('frame', frame)
cv2.waitKey(0)
说明:cv2.waitKey(0) 是一个键盘绑定函数,若不使用该函数,imshow图像即闪即退(或者说是显示不出来)。输出摄像头或视 频时,应指定一个大于0的参数。cv2.waitKey(10):等待10毫秒播放下一帧。
可以看到图像左下角,有显示对应坐标及对应坐标的RGB值。图像中选用了红色及蓝色卡纸作为目标来识别跟踪无人机,选用两张卡纸的目的是标注无人机pitch的正负,也可以说是无人机的头和尾,同时还可以得到无人机与目标点的角度值,从而可以控制yaw。
然后将鼠标放到红色和蓝色卡纸上,得到对应的RGB值,记录下来。(红色:251,136,191 蓝色:153,217,211)
计算得到对应的HSV:
import cv2
import numpy as np
color=np.uint8([[[191 ,136 ,251]]])
hsv_color=cv2.cvtColor(color,cv2.COLOR_BGR2HSV)
print(hsv_color)
说明:opencv是以BGR格式读取图片的,所以要将得到的RGB值倒着输入。
得到HSV:红色:166,117,251 蓝色:87 ,75,217
可以分别用 [H-50 50? 50] 和 [H+50 255? 255] 做上下阈?值(根据实际情况调整,背景干扰少时范围可放宽一些,背景干扰多时范围限制严格一点,但要确保得到的HSV在上下阈值内)
import cv2
import numpy as np
import imutils
frame = cv2.imread("UAV.jpg")
frame = imutils.resize(frame, width=320)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask_red = cv2.inRange(hsv, np.array((110., 50., 50)), np.array((180., 255., 255.)))
mask_red = cv2.medianBlur(mask_red, 3)
cnts_red = cv2.findContours(mask_red.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts_red = cnts_red[0] if imutils.is_cv2() else cnts_red[1]
mask_blue = cv2.inRange(hsv, np.array((40., 50., 50.)), np.array((140., 255., 255.)))
mask_blue = cv2.medianBlur(mask_blue, 3)
cnts_blue = cv2.findContours(mask_blue.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts_blue = cnts_blue[0] if imutils.is_cv2() else cnts_blue[1]
if (len(cnts_red) > 0):
area = [cv2.contourArea(i) for i in cnts_red]
index = np.argmax(area)
rect_red = cv2.minAreaRect(cnts_red[index])
box_red = np.int0(cv2.boxPoints(rect_red))
cv2.drawContours(frame, [box_red], 0, (0, 0, 255), 2)
if (len(cnts_blue) > 0):
area = [cv2.contourArea(i) for i in cnts_blue]
index = np.argmax(area)
rect_blue = cv2.minAreaRect(cnts_blue[index])
box_blue = np.int0(cv2.boxPoints(rect_blue))
cv2.drawContours(frame, [box_blue], 0, (0, 0, 255), 2)
cv2.imshow('frame', frame)
cv2.imshow('mask_red', mask_red)
cv2.imshow('mask_blue', mask_blue)
cv2.waitKey(0)
可以看到,由于单片机是暗红色的,在提取红色时受到了干扰,需要再缩小一点范围。计算得到单片机暗红色H值为177,所以我将 mask_red改为cv2.inRange(hsv, np.array((110., 50., 50)), np.array((170., 255., 255.)))。
至此,测试的对象还只是静态图,当开启摄像头实时跟踪的时候会受到光线的影响,RGB值变化很大,还需要再调节HSV的范围。而且选取目标跟踪颜色时,应选取背景干扰少的颜色。网上也有一张别人测好的HSV范围表可用,我用的效果还蛮好的。
缺陷:inRange对光比较敏感,跟踪需要特定颜色。如若想对任意目标跟踪,可以使用CAMShift。但CAMShift对运动过快的对象容易跟丢。
其它一些应用:
摄像头识别黄色条形码,并保存图片:
源码下载:
https://github.com/LNanL/drone