一、颜色空间介绍
RGB 颜色空间是大家最熟悉的颜色空间,即三基色空间,任何一种颜色都可以由该三种 颜色混合而成。然而一般对颜色空间的图像进行有效处理都是在 HSV 空间进行的,HSV(色调 Hue,饱和度 Saturation,亮度 Value)是根据颜色的直观特性创建的一种颜色空间, 也称六角锥体模型。
为什么会选择 HSV 空间而不是 RGB 空间? 对于图像而言,识别相应的颜色在 RGB 空间、 HSV 空间或者其它颜色空间都是可行的。之所以选择 HSV,是因为 H 代表的色调基本上可以 确定某种颜色,再结合饱和度和亮度信息判断大于某一个阈值。而 RGB 由三个分量构成, 需要判断每种分量的贡献比例。即 HSV 空间的识别的范围更广,更方便。
二、三种颜色空间转换(Gray,RGB,HSV)
在OpenCV中有超过150种的颜色空间转换的方法,但是我们经常会用到的也就只有两种,即 BGR->Gray 和 BGR->HSV。注意 Gray 和 HSV 不可以互相转换。 颜色空间转换函数是:cv2.cvtColor(input_image, flag)
BGR->Gray: flag 就是 cv2.COLOR_BGR2GRAY
BGR->HSV: flag 就是 cv2.COLOR_BGR2HSV
三、OpenCV 中 HSV 颜色空间的取值范围:H [0, 179] S [0, 255] V [0, 255]
四、下面先来说一下指定颜色的识别,这里我们利用摄像头来识别黄色,然后把黄色区域用一个圆给框起来。例如,我们可以使用黄色的乒乓球来做实验。
import cv2
import time
import numpy as np
cap=cv2.VideoCapture(0)
#设置摄像头分辨率为(640,480)
#如果感觉图像卡顿严重,可以降低为(320,240)
cap.set(3,480)
cap.set(4,320)
#设置黄色的阙值
yellow_lower=np.array([156,43,46])
yellow_upper=np.array([180,255,255])
time.sleep(1)
while 1:
#ret为是否找到图像,frame是帧本身
ret,frame=cap.read()
frame=cv2.GaussianBlur(frame,(5,5),0)#高斯滤波
hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) #转hsv
'''
这一句代码是关键,它是根据你设置的阈值,比如上面的黄色的阈值,
在这个掩膜中,原图像素值在阈值之间的像素点会被设置为255,否则
就设置为0
'''
mask=cv2.inRange(hsv,yellow_lower,yellow_upper) #生成掩膜
#形态学操作,对掩膜进行一系列形态学操作,使后面的与运算效果更好
mask=cv2.erode(mask,None,iterations=2)#腐蚀操作
mask=cv2.dilate(mask,None,iterations=2)#膨胀操作
mask=cv2.GaussianBlur(mask,(3,3),0)#高斯滤波
#这个是进行与运算之后的结果,只有黄色部分被保留
#其实在这个例子中的res和mask是一样的,都是黄色部分被保留了下来
res=cv2.bitwise_and(frame,frame,mask=mask)#与运算
#检测颜色的轮廓
cnts=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[-2]
if len(cnts)>0:
cnt = max (cnts,key=cv2.contourArea)
(x,y),radius=cv2.minEnclosingCircle(cnt)
#找到后在每个轮廓上画圆
cv2.circle(frame,(int(x),int(y)),int(radius)*2,
(255,0,255),2)
print('x:',x,'y:',y)
cv2.imshow('capture',frame)
if cv2.waitKey(1)==29:
break
cap.release()
cv2.destroyAllWindows()
每一句代码的解释已经在上面了,整体的思路就是先根据颜色阈值设置掩膜,有了掩膜我们就可以得到想要识别的颜色所在的区域。紧接着我们对其进行轮廓检测,找到最大的那个轮廓以排除一些干扰,最后根据轮廓信息画出其外接圆即可。
五、下面来说一下如果进行不指定颜色的颜色识别,这里我们使用的是静态图片,提供一张颜色分明的图片,我们识别出它是什么颜色。
import cv2
import numpy as np
def color_hist(img):
mask=np.zeros(img.shape[:2],dtype=np.uint8)
'''
设置掩膜,目的是只对中间这部分进行H分量的直方图统计,
不对整张图进行统计,是因为图的关键内容一般都是在中间
'''
mask[70:170,100:220]=255
'''
这里选择[0,180]是因为在HSV中H的范围是[0,179];
也即横坐标表示的是H的值,和你的尺寸,比如上面的
70.170.100.220这几个数没关系
'''
hsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
'''
计算该图像的直方图,得到的hist_mask是一维数组,长度就是180,
所以这里的object_H表示数组的某个位置
就可以理解为它就是表示0-179里的某个数,代表像素值=object_H的
像素点最多,因此就可以辨别颜色
'''
hist_mask=cv2.calcHist([hsv],[0],mask,[180],[0,180])
object_H=np.where(hist_mask==np.max(hist_mask))
print(object_H[0])
return object_H[0]
'''
根据上述计算出的像素点最多的一个H的值,也即object_H,就可以根据其范围大致估计图片的颜色
'''
def color_distinguish(object_H):
try:
if object_H>26 and object_H<34: color='yellow'
elif object_H>156 and object_H<180 : color='red'
elif object_H>100 and object_H<124: color='blue'
elif object_H>35 and object_H<77 : color='green'
elif object_H>78 and object_H<99:color=='cyan-blue'
elif object_H>6 and object_H<15: color ='orange'
else: color='None'
print(color)
return color
except:pass
if __name__=='__main__':
img=np.ones((240,320,3),dtype=np.uint8)*128
img[60:180,80:240]=[0,255,255]
object_H=color_hist(img)
color_distinguish(object_H)
cv2.imshow('image',img)
cv2.waitKey(0)
以上只是提供了颜色识别的简单思路,主要是熟悉如何在HSV颜色空间进行颜色识别。不同的场景还需要根据实际情况进行修改。
参考链接:https://www.yahboom.com/study/Pi_motion