前言
在计算机视觉和图像处理领域,颜色识别是一项基础而重要的技术。无论是交通标志识别、工业分拣还是美颜滤镜开发,都离不开对特定颜色的处理。本文将带你全面掌握使用OpenCV进行颜色识别的关键技术,包含完整的代码实现和原理讲解。
一、颜色空间基础
1.1 RGB颜色空间
在图像处理中,最常见的就是RGB颜色空间。RGB颜色空间是我们接触最多的颜色空间,是一种用于表示和显示彩色图像的一种颜色模型。RGB代表红色(Red)、绿色(Green)和蓝色(Blue),这三种颜色通过不同强度的光的组合来创建其他颜色,广泛应用于我们的生活中,比如电视、电脑显示屏以及上面实验中所介绍的RGB彩色图。
RGB颜色模型基于笛卡尔坐标系,如下图所示,RGB原色值位于3个角上,二次色青色、红色和黄色位于另外三个角上,黑色位于原点处,白色位于离原点最远的角上。因为黑色在RGB三通道中表现为(0,0,0),所以映射到这里就是原点;而白色是(255,255,255),所以映射到这里就是三个坐标为最大值的点。
RGB颜色空间可以产生大约1600万种(255*255*255)颜色,几乎包括了世界上的所有颜色,也就是说可以使用RGB颜色空间来生成任意一种颜色。
RGB(红绿蓝)是最常见的颜色模型,采用加色法原理:
你可以使用OpenCV的cv.add()函数把两幅图像相加,或者可以简单地通过numpy操作添加两个图像,如res = img1 + img2。两个图像应该具有相同的大小和类型。
1.2 颜色加法
OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加是模运算
import cv2
import numpy as np
x = np.uint([80])
y = np.uint([200])
print(cv2.add(x,y)) #[[255]]
print(x+y) #[[24]]
运算类型 | 计算过程 | 预期输出 |
---|---|---|
cv2.add(x,y) | 80+200=280→饱和截断到255 | [[255]] |
x + y | 80+200=280→模256得24 | [[24]] |
import cv2
import numpy as np
# 导入两张图片
img1 = cv2.imread("./src/pig.png")
img2 = cv2.imread("./src/lawn.png")
img3 = img1 + img2
cv2.imshow("img3windows",img3)
cv2.waitKey(0)
# 分别使用opencv(顶点255)、numpy(256取模)相加
print(cv2.add(img1,img2)
print(img1+img2)
注意:OpenCV中图像以BGR顺序存储,与常规RGB顺序不同,这也是上面红色的像素值是(0,0,255)而不是(255,0,0)的原因。
颜色加权加法
这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。图像混合的计算公式如下:
g(x) = (1−α)f0(x) + αf1(x)
通过修改 α 的值(0 → 1),可以实现非常炫酷的混合。
现在我们把两幅图混合在一起。第一幅图的权重是0.7,第二幅图的权重是0.3。函数cv2.addWeighted()可以按下面的公式对图片进行混合操作。
dst = α⋅img1 + β⋅img2 + γ
这里γ取为零。
# 加权加法
import cv2
import numpy as np
# 1 读取图像
image1 = cv2.imread("./pig.png")
image2 = cv2.imread("./lawn.png")
# 2 图像混合
image3 = cv2.addWeighted(image1,0.7,image2,0.3,0)
cv2.imshow("image3",image3)
cv2.waitKey(0)
1.2 HSV颜色空间
HSV(色调Hue:表示颜色的种类 如红色、绿色、蓝色等 、饱和度Saturation:表示颜色的纯度或强度 如红色越纯,饱和度就越高 、明度Value:表示颜色的明暗程度,如黑色比白色亮度低 )更接近人类对颜色的感知:
分量 | 范围 | 描述 |
---|---|---|
H | 0-180 | 色调(OpenCV中为0-180) |
S | 0-255 | 饱和度 |
V | 0-255 | 明度 |
二、颜色识别关键技术
2.1 创建颜色掩膜
def color_mask(image, lower, upper):
"""创建颜色掩膜"""
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
return mask
2.2 常用颜色HSV范围
三、完整颜色识别流程
3.1 基础实现
def detect_color(image, color='red'):
"""检测特定颜色区域"""
# 颜色范围定义
color_ranges = {
'red': ([0,43,46], [10,255,255]),
'green': ([35,43,46], [77,255,255]),
'blue': ([100,43,46], [124,255,255])
}
lower, upper = color_ranges.get(color, ([0,0,0], [179,255,255]))
lower = np.array(lower)
upper = np.array(upper)
# 转换HSV并创建掩膜
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
# 应用掩膜
result = cv2.bitwise_and(image, image, mask=mask)
return mask, result
3.2 进阶优化
形态学处理:消除噪点
kernel = np.ones((5,5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
轮廓检测:标记颜色区域
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
if cv2.contourArea(cnt) > 500: # 过滤小区域
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(image, (x,y), (x+w,y+h), (0,255,0), 2)
四、实战案例:交通灯识别
def traffic_light_detection(image):
# 检测红色
red_mask, _ = detect_color(image, 'red')
# 检测绿色
green_mask, _ = detect_color(image, 'green')
# 判断哪个颜色更显著
red_pixels = cv2.countNonZero(red_mask)
green_pixels = cv2.countNonZero(green_mask)
if red_pixels > green_pixels and red_pixels > 1000:
return "红灯"
elif green_pixels > red_pixels and green_pixels > 1000:
return "绿灯"
else:
return "无信号"
五、常见问题解答
Q1:为什么颜色识别不准确?
A:可能原因:
-
光照条件变化 - 尝试自适应阈值或调整V通道范围
-
反光/阴影 - 使用形态学处理消除噪点
-
HSV范围不合适 - 使用动态调整工具确定准确范围
Q2:如何提高识别速度?
A:
-
缩小处理图像尺寸
-
限定ROI区域
-
使用GPU加速(cv2.UMat)
结语
掌握颜色识别技术是计算机视觉开发的重要基础。本文从原理到实践详细讲解了OpenCV颜色处理的全流程,建议读者动手实践各个示例,并根据实际需求进行调整优化。欢迎在评论区交流遇到的问题和心得!