在计算机视觉领域,颜色识别是最基础却极具实用价值的技术之一。想象一下,你能否用摄像头自动识别并标记出视野中的红色消防栓或蓝色停车标志?这正是我们今天要实现的智能工具。不同于简单的代码演示,本文将带你从零构建一个完整的可执行程序,包含参数调节界面和跨平台打包方案。
颜色识别的关键在于理解HSV色彩模型。与常见的RGB模式不同,HSV(Hue色相, Saturation饱和度, Value明度)更接近人类感知颜色的方式:
python复制# HSV颜色范围定义示例
lower_red = np.array([0, 50, 100]) # 色相(0-10), 饱和度(50-255), 明度(100-255)
upper_red = np.array([10, 255, 255])
为什么选择HSV?
常见颜色的HSV范围参考:
| 颜色 | H范围 | S范围 | V范围 |
|---|---|---|---|
| 红色 | 0-10 | >50 | >100 |
| 蓝色 | 100-124 | >50 | >100 |
| 绿色 | 35-80 | >50 | >50 |
提示:实际环境中,建议通过滑块动态调整这些阈值,后文将介绍具体实现方法
优秀的项目需要清晰的模块划分。我们采用面向对象设计,将功能分解为独立类:
python复制class ColorDetector:
def __init__(self):
self.hsv_ranges = {
'red': ([0,50,100], [10,255,255]),
'blue': ([100,50,100], [124,255,255])
}
def process_frame(self, frame):
"""主处理流程"""
results = {}
for color, (lower, upper) in self.hsv_ranges.items():
mask = self._create_mask(frame, lower, upper)
contours = self._find_contours(mask)
if contours:
results[color] = contours
return results
def _create_mask(self, frame, lower, upper):
"""创建颜色掩膜"""
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
return cv2.inRange(hsv, np.array(lower), np.array(upper))
def _find_contours(self, mask):
"""寻找轮廓"""
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
return contours if len(contours) > 0 else None
关键改进点:
PySimpleGUI让我们快速构建专业界面:
python复制import PySimpleGUI as sg
# 颜色阈值滑块布局
color_controls = [
[sg.Text('红色H_min'), sg.Slider((0,180), 0, 1, orientation='h', key='-RED_H_MIN-')],
[sg.Text('红色H_max'), sg.Slider((0,180), 10, 1, orientation='h', key='-RED_H_MAX-')],
# 更多滑块...
]
layout = [
[sg.Column([[sg.Image(filename='', key='-IMAGE-')]]),
sg.Column(color_controls)],
[sg.Button('Exit'), sg.Button('Save Settings')]
]
window = sg.Window('Color Detector', layout, finalize=True)
实时更新逻辑:
python复制while True:
event, values = window.read(timeout=20)
if event == sg.WIN_CLOSED:
break
# 从滑块获取当前阈值
detector.hsv_ranges['red'][0][0] = int(values['-RED_H_MIN-'])
# 更新其他参数...
# 处理并显示帧
frame = camera.get_frame()
processed = detector.process_frame(frame)
window['-IMAGE-'].update(data=cv2.imencode('.png', frame)[1].tobytes())
4.1 光照适应方案
cv2.xphoto.createSimpleWB().balanceWhite(frame)cv2.equalizeHist()4.2 多线程处理
避免GUI卡顿的经典模式:
python复制from threading import Thread
from queue import Queue
class CameraStream:
def __init__(self):
self.queue = Queue(maxsize=1)
self.running = False
def start(self):
self.running = True
Thread(target=self._update, daemon=True).start()
def _update(self):
while self.running:
if not self.queue.full():
ret, frame = cap.read()
if ret:
self.queue.put(frame)
4.3 常见问题排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 识别不稳定 | 阈值范围过大 | 缩小H范围,增加S/V下限 |
| 误识别背景 | 反光或相似色 | 添加形态学开运算 |
| 帧率低下 | 处理复杂度高 | 降低分辨率或优化算法 |
5.1 使用PyInstaller打包
创建spec文件:
python复制# build.spec
a = Analysis(['main.py'],
pathex=['/project_path'],
binaries=[],
datas=[('icon.png', '.')],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz,...)
构建命令:
bash复制pyinstaller --onefile --windowed --icon=icon.ico main.spec
5.2 扩展思路
完整项目代码已托管至GitHub仓库(示例链接),包含:
在实际部署到停车场监控系统时,建议将HSV阈值存储在JSON配置文件中,便于现场调整。对于需要识别10米外交通标志的场景,可以尝试以下参数组合:
json复制{
"blue": {
"lower": [100, 150, 60],
"upper": [124, 255, 255]
},
"red": {
"lower": [0, 120, 80],
"upper": [10, 255, 255]
}
}