基于此篇文章做得简单的修改 OpenCV---颜色识别_opencv 颜色识别-CSDN博客
修改内容主要有两点
- 之前文章中只测量中心点一点的颜色,该文章会测量更大区域的颜色(也就是对区域内的颜色取均值)
- 之前文章文章只对 红黄绿蓝紫粉 六种颜色进行识别,该文章会对 赤橙黄绿青蓝紫粉黑白 十种颜色进行识别(不是特别精准)
目录
[1 hsv的基本了解](#1 hsv的基本了解)
[1.1 色调 H](#1.1 色调 H)
[1.2 饱和度 S](#1.2 饱和度 S)
[1.3 值 V](#1.3 值 V)
[2 hsv在opencv中的数字化](#2 hsv在opencv中的数字化)
[3 识别单张图像](#3 识别单张图像)
[4 摄像头识别](#4 摄像头识别)
1 hsv的基本了解
HSV分为三个参数。
- H的意思是hue,翻译成中文是色调
- S的意思是saturation,翻译成中文是饱和度
- V的意思是value,翻译成中文是值
1.1 色调 H
色调 是分辨 赤橙黄绿青蓝紫 这些的。在我们的调色盘上来看可以理解为横坐标,比如我现在左上角的色调是0

右上角的色调是359

对于中间来讲不同的色调就是不同的颜色

1.2 饱和度 S
饱和度可以理解为 明亮度。在我们的调色盘来看可以理解为纵坐标。比如我左上角的饱和度是100

左下角的饱和度是0

越往下(饱和度越低)你可以理解为这个颜色就越浅

1.3 值 V
值可以理解为黑暗度。在调色盘上可以我们最右侧的这个条。当前我们的值是100

拉到最下,值就会变成0

可以理解为值越小,越暗。并且值的优先级高于饱和度
2 hsv在opencv中的数字化
opencv有opencv自己的数字化规则,注意千万不要用画图的这个值。在美术中画图的这三个值或许是正确的,但在opencv中不是

我们写这样一个代码,作用是把hsv的值转变为RGB值
python
import cv2
import numpy as np
def nothing(x):
pass
cv2.namedWindow("frame")
cv2.createTrackbar("H","frame",0,179,nothing)
cv2.createTrackbar("S","frame",0,255,nothing)
cv2.createTrackbar("V","frame",0,255,nothing)
img_hsv = np.zeros((250,500,3),np.uint8)
while True:
h = cv2.getTrackbarPos("H","frame")
s = cv2.getTrackbarPos("S","frame")
v = cv2.getTrackbarPos("V","frame")
img_hsv[:] = (h,s,v)
img_bgr = cv2.cvtColor(img_hsv,cv2.COLOR_HSV2BGR)
cv2.imshow("frame",img_bgr)
key = cv2.waitKey(1)
if key == 27:
break
cv2.destroyAllWindows()
为了更好地找到对应关系,我们搞了个滚动条。我们发现0是红色

179的时候也是红色
- 这里的179是测出来的,你可以将H的最大值设置为255,你发现179之后就是橘黄色了

那么我们现在其实可以和画图中的H值找到联系了,画图中H的下限是0,上限是359,一共360个值。opencv中的下限是0,上限是179,一共是180个值。那么我们合理推断一下,opencv的H值是画图中H值的一般。我们测试一下,果然是这样

S就是255对100,0对0
V也是255对100,0对0
综上所述opencv中的H值是画图中的 1/2
S值是画图中的 2.55 倍,V值是画图中的 2.55倍
颜色 | 画图中的H值 | opencv中的H值 |
---|---|---|
红色 | 0-15 and 325-359 | 0-8 and 163-179 |
橙色 | 15-50 | 8-25 |
黄色 | 50-70 | 25-35 |
绿色 | 70-155 | 35-78 |
青色 | 155-185 | 78-93 |
蓝色 | 185-255 | 93-128 |
紫色 | 255-300 | 128-150 |
粉色 | 300-325 | 150-163 |
需要注意的是我们这种判定的方式是有局限性的,因为我们只使用H值进行判断。
我们举一个反例,当H为120,S,V都为255时,我们看到这是一个明显的蓝色

当我们减低S值后,发现这个颜色就很像紫色了

如果你想要更加精准的判断,你可以把HSV的所有情况都搞一个区间,那样就比较麻烦,我目前的案例只对特征明显的颜色进行识别
如果判断黑色和白色,我们就不能通过H值进行判断了,我们简单弄一下,比如我们认为V值在20以下,就算黑色了

当然对于不同的H、S值也是有所不同,比如下面的颜色就更像是墨绿色

判断白色,比如我们认为S值在20以下就是白色了

3 识别单张图像
width_margin的意思是宽度边缘,height_margin的意思是高度边缘,如果乘0就代表没有边缘,我们检测的绿色框子区域内的颜色
python
import cv2
frame = cv2.imread('white.png')
width = frame.shape[1]
height = frame.shape[0]
width_margin = int(width * 0)
height_margin = int(height * 0)
point_list = []
for i in range(width_margin,width-width_margin):
for j in range(height_margin,height-height_margin):
point_list.append((i,j))
# print(len(point_list))
imghsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
average_hue_value = 0
average_saturation_value = 0
average_value_value = 0
for i in point_list:
average_hue_value = average_hue_value + imghsv[i[1],i[0]][0]
average_saturation_value = average_saturation_value + imghsv[i[1],i[0]][1]
average_value_value = average_value_value + imghsv[i[1],i[0]][2]
# print(average_hue_value)
average_hue_value = int(average_hue_value/len(point_list))
average_saturation_value = int(average_saturation_value/len(point_list))
average_value_value = int(average_value_value/len(point_list))
print(average_hue_value)
print(average_saturation_value)
print(average_value_value)
color = ''
if average_value_value < 20:
color = 'black'
elif average_saturation_value < 20:
color = 'white'
elif average_hue_value <= 8 or average_hue_value > 163:
color = 'red'
elif average_hue_value > 8 and average_hue_value <= 25:
color = 'orange'
elif average_hue_value > 25 and average_hue_value <= 35:
color = 'yellow'
elif average_hue_value > 35 and average_hue_value <= 78:
color = 'green'
elif average_hue_value > 78 and average_hue_value <= 93:
color = 'cyan'
elif average_hue_value > 93 and average_hue_value <= 128:
color = 'blue'
elif average_hue_value > 128 and average_hue_value <= 150:
color = 'purple'
elif average_hue_value > 150 and average_hue_value <= 163:
color = 'pink'
cv2.rectangle(frame, (width_margin, height_margin), (width-width_margin, height-height_margin), (0, 255, 0), 3)
cv2.putText(frame,color,(20,20),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2)
cv2.imshow("capture", frame)
cv2.waitKey(0)
cv2.destroyAllWindows()


静态图像相对校准(当然需要是人类能识别出来的颜色,随便找一张没有主体颜色的图给人类,人类也是分不清的)
4 摄像头识别
对于摄像头来讲就没有这么准了,需要根据自己的摄像头对判断的数值区间再进行一些调整
python
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
width = 640
height = 480
width_margin = int(width * 0.4)
height_margin = int(height * 0.4)
point_list = []
for i in range(width_margin,width-width_margin):
for j in range(height_margin,height-width_margin):
point_list.append((i,j))
# print(point_list)
# print(len(point_list))
while True:
ret, frame = cap.read()
if ret:
frame = cv2.resize(frame, (width, height))
imghsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
average_hue_value = 0
average_saturation_value = 0
average_value_value = 0
for i in point_list:
average_hue_value = average_hue_value + imghsv[i[1], i[0]][0]
average_saturation_value = average_saturation_value + imghsv[i[1], i[0]][1]
average_value_value = average_value_value + imghsv[i[1], i[0]][2]
# print(average_hue_value)
average_hue_value = int(average_hue_value / len(point_list))
average_saturation_value = int(average_saturation_value / len(point_list))
average_value_value = int(average_value_value / len(point_list))
print('average_hue_value',average_hue_value)
print('average_saturation_value',average_saturation_value)
print('average_value_value',average_value_value)
color = ''
if average_value_value < 20:
color = 'black'
elif average_saturation_value < 20:
color = 'white'
elif average_hue_value <= 8 or average_hue_value > 163:
color = 'red'
elif average_hue_value > 8 and average_hue_value <= 25:
color = 'orange'
elif average_hue_value > 25 and average_hue_value <= 35:
color = 'yellow'
elif average_hue_value > 35 and average_hue_value <= 78:
color = 'green'
elif average_hue_value > 78 and average_hue_value <= 93:
color = 'cyan'
elif average_hue_value > 93 and average_hue_value <= 128:
color = 'blue'
elif average_hue_value > 128 and average_hue_value <= 150:
color = 'purple'
elif average_hue_value > 150 and average_hue_value <= 163:
color = 'pink'
cv2.rectangle(frame, (width_margin, height_margin), (width-width_margin, height-height_margin), (0, 255, 0), 3)
cv2.putText(frame,color,(20,20),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2)
cv2.imshow("capture", frame)
k = cv2.waitKey(1)
if k == ord(' '):
break
cap.release()
cv2.destroyAllWindows()