前言
本专栏旨在学习记录OpenCV的各种基础知识和常用函数的用法,共八节基础内容已全部记录完毕。最后一篇文章将进入OpenCV的简单实战——各种颜色识别,在本篇文章中,我将详细记录使用OpenCV进行颜色识别的完整代码及代码分析,并上传OpenCV的所有基础内容及实战项目的源码。
一、代码展示
首先展示该实战项目的完整代码:
import cv2
import numpy as np
def color_detection(frame):
# 定义颜色范围(在HSV颜色空间中)
lower_red = np.array([0, 100, 100])
upper_red = np.array([10, 255, 255])
lower_blue = np.array([110, 100, 100])
upper_blue = np.array([130, 255, 255])
lower_green = np.array([50, 100, 100])
upper_green = np.array([70, 255, 255])
# 将帧转换为HSV颜色空间
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 根据颜色范围创建掩膜
red_mask = cv2.inRange(hsv_frame, lower_red, upper_red)
blue_mask = cv2.inRange(hsv_frame, lower_blue, upper_blue)
green_mask = cv2.inRange(hsv_frame, lower_green, upper_green)
# 对掩膜进行形态学操作,以去除噪声
kernel = np.ones((5, 5), np.uint8)
red_mask = cv2.morphologyEx(red_mask, cv2.MORPH_OPEN, kernel)
blue_mask = cv2.morphologyEx(blue_mask, cv2.MORPH_OPEN, kernel)
green_mask = cv2.morphologyEx(green_mask, cv2.MORPH_OPEN, kernel)
# 在原始帧中找到颜色区域并绘制方框
contours, _ = cv2.findContours(red_mask + blue_mask + green_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
color = ""
if cv2.contourArea(contour) > 500: # 设置最小区域面积以排除噪声
if np.any(red_mask[y:y+h, x:x+w]):
color = "红色"
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
elif np.any(blue_mask[y:y+h, x:x+w]):
color = "蓝色"
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
elif np.any(green_mask[y:y+h, x:x+w]):
color = "绿色"
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(frame, color, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
return frame
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
# 读取摄像头帧
ret, frame = cap.read()
# 进行颜色识别
result = color_detection(frame)
# 显示结果帧
cv2.imshow("Color Detection", result)
# 按下 'q' 键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头和关闭窗口
cap.release()
cv2.destroyAllWindows()
接下来,我们将对这段代码进行详细分析
二、战前准备
想要完成颜色识别的实战项目,除了掌握本专栏所记录的所有基础内容之外,还得熟悉以下知识:
(一)创建数组
创建数组并不是opencv库中的内容,而是numpy库中的内容。创建数组在进行颜色检测等方面十分重要,通常可以通过创建一个三元数组来确定颜色的范围,例如RGB、HSV等。
使用numpy库创建数组的函数如下:
np.array([a, b, c]) # 创建一个(a, b, c)的数组
其中a、b、c为常数,在本实战项目中可以设置为颜色的HSV颜色空间数值
(二)HSV颜色空间
HSV颜色空间由三个分量组成:色相(Hue)、饱和度(Saturation)和明度(Value)。通过调整这些分量的值,我们可以选择特定的颜色范围,HSV具体含义如下:
-
色相(Hue):色相值表示颜色在颜色轮上的位置。不同的颜色在色相上有不同的取值范围。例如,红色的色相值约为0-10或160-180,蓝色的色相值约为110-130,绿色的色相值约为50-70。根据所需识别的颜色,选择相应的色相范围。
-
饱和度(Saturation):饱和度值表示颜色的纯度或鲜艳程度。较高的饱和度值表示颜色更加鲜艳,而较低的饱和度值表示颜色较为灰暗。根据实际场景中颜色的饱和度,选择适当的饱和度范围。
-
明度(Value):明度值表示颜色的亮度或明暗程度。较高的明度值表示颜色较亮,而较低的明度值表示颜色较暗。根据实际场景中颜色的明度,选择适当的明度范围。
这些值是根据经验和实验进行调整的,以获得最佳的颜色识别效果。我们可以根据具体的应用场景和需求进行调整,以适应不同的颜色识别任务。在实际使用中,我们可能需要进行多次尝试和调整,以找到最适合需求的颜色范围。
对于每种颜色(红色、蓝色和绿色),我们使用np.array()
函数创建了一个包含三个元素的NumPy数组。这些元素分别代表HSV颜色空间中的色相、饱和度和明度的下限和上限。
例如,对于红色,我们将色相的下限设置为0,上限设置为10。这意味着我们将识别色相值在0到10之间的红色。饱和度和明度的下限设置为100,上限设置为255,以确保我们只识别饱和度和明度较高的红色。代码如下:
lower_red = np.array([0, 100, 100])
upper_red = np.array([10, 255, 255])
(三)创建掩膜
在进行颜色识别时,我们通过创建掩膜的方法来将图像进行二值化,即非黑即白,通过创建颜色掩膜,可以将图像中的特定颜色范围提取出来,让摄像头对目标颜色更为敏感。
我们使用cv2.inRange()
函数来创建颜色掩膜。它会根据指定的颜色范围,将图像中在范围内的像素设置为255(白色),而其他像素则设置为0(黑色)
cv2.inRange(src, lowerb, upperb)
其中三个参数分别为:
(1)“src”, 输入图像,可以是灰度图像或彩色图像
(2)“lowerb”, 下限阈值,用于指定要提取的像素的最小值
(3)“upperb”, 上限阈值,用于指定要提取的像素的最大值
例如,创建红色掩膜的代码如下:
red_mask = cv2.inRange(hsv_frame, lower_red, upper_red)
# lower_red = np.array([0, 100, 100])
# upper_red = np.array([10, 255, 255])
三、完整代码分析
(1)我们首先导入该项目所要用到的库
import cv2
import numpy as np
(2)然后创建一个子函数用于进行颜色识别,其中,参数frame代表的是摄像头获取的帧,即待处理的图像
def color_detection(frame):
(3)在颜色识别函数中,我们先用np.array()函数创建红色、绿色、蓝色在HSV颜色空间中的阈值范围
lower_red = np.array([0, 100, 100])
upper_red = np.array([10, 255, 255])
lower_blue = np.array([110, 100, 100])
upper_blue = np.array([130, 255, 255])
lower_green = np.array([50, 100, 100])
upper_green = np.array([70, 255, 255])
(4)使用cv2.cvtColor()函数将帧转换为HSV颜色空间
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
(5)根据颜色范围使用cv2.inRange()函数创建掩膜
red_mask = cv2.inRange(hsv_frame, lower_red, upper_red)
blue_mask = cv2.inRange(hsv_frame, lower_blue, upper_blue)
green_mask = cv2.inRange(hsv_frame, lower_green, upper_green)
(6)对掩膜进行形态学操作,以去除噪声
kernel = np.ones((5, 5), np.uint8)
red_mask = cv2.morphologyEx(red_mask, cv2.MORPH_OPEN, kernel)
blue_mask = cv2.morphologyEx(blue_mask, cv2.MORPH_OPEN, kernel)
green_mask = cv2.morphologyEx(green_mask, cv2.MORPH_OPEN, kernel)
(7)将前面创建的红、绿、蓝三个掩膜进行相加,并将相加的结果作为输入图,寻找颜色的轮廓
contours, _ = cv2.findContours(red_mask + blue_mask + green_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
(8)得到轮廓列表countours后进行遍历(循环),提取出轮廓列表中的所有轮廓值,并记录为countour
for contour in contours:
(9)可以使用cv2.boundingRect()函数计算每一个轮廓(contour)的边界框,该函数将得到x、y、w、h四个返回值,其中:(x, y)
是矩形框左上角的坐标,w
是矩形框的宽度,h
是矩形框的高度。
x, y, w, h = cv2.boundingRect(contour)
(10)用if语句设置最小区域面积以排除噪声,即当目标颜色区域太小时不显示
if cv2.contourArea(contour) > 500:
(11)用if语句判断识别到的颜色处于哪个HSV颜色空间阈值内,并使用cv2.rectangle()函数绘制对应颜色的方框圈住目标颜色,再用cv2.putText()函数进行颜色注释。
例如:red_mask[y:y+h, x:x+w]表示从红色掩膜中提取出与当前轮廓对应的区域(切片操作)。如果在该区域中存在非零值(即存在红色像素),则条件为真,表示当前轮廓属于红色区域。
本段代码十分重要,是颜色识别的核心判断,请反复琢磨代码,确保自己十分清晰判断原理和绘制矩形方法。如果对该判断原理不够熟悉,可以自行复习一下python的if语句和opencv的图像基础操作。
if np.any(red_mask[y:y+h, x:x+w]):
color = "红色"
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
elif np.any(blue_mask[y:y+h, x:x+w]):
color = "蓝色"
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
elif np.any(green_mask[y:y+h, x:x+w]):
color = "绿色"
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(frame, color, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
(12)返回帧
return frame
(13)打开摄像头
cap = cv2.VideoCapture(0)
(14)进入主循环
while True:
# 读取摄像头帧
ret, frame = cap.read()
# 进行颜色识别
result = color_detection(frame)
# 显示结果帧
cv2.imshow("Color Detection", result)
# 按下 'q' 键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头和关闭窗口
cap.release()
cv2.destroyAllWindows()
四、总结
该OpenCV实战项目全部分析完毕,本专栏到此也全部结束