颜色识别系统是运行在 Windows 本机的颜色采集与识别系统。V1.4.0 提供可交付的 onedir EXE, 最终用户不需要安装 Python、Node.js 或 npm。
V1.4.0 新增本地 SQLite 上传日志、图片预览、颜色参数记录和日志留存策略。
V1.4.0 保留前端启动与摄像头初始化解耦。即使没有摄像头、摄像头被占用或运行中断开, FastAPI 与 Vue 页面仍会正常启动,并显示可恢复的 Camera 状态。
V1.4.0 继续使用单一纯色块展示颜色识别结果,并以本地文件形式保存日志图片。
为保持既有安装路径和升级兼容性,发布目录与可执行文件仍使用
ColorVision / ColorVision.exe 作为技术文件名;界面和文档中的正式名称统一为
“颜色识别系统”。
完整流程:
双击 ColorVision.exe
-> 启动本地 FastAPI
-> 托管 Vue 生产页面
-> 自动打开默认浏览器
-> 初始化 CameraService 并检测摄像头
-> 摄像头实时画面
-> 拍照与 ROI 框选
-> RGB / LAB / HEX
-> Mock 或真实 API 上传
发布目录:
dist/ColorVision/
├── ColorVision.exe
├── README.md
└── _internal/
使用步骤:
- 保持整个
ColorVision目录完整,不要只复制 EXE。 - 双击
ColorVision.exe。 - 等待默认浏览器自动打开
http://127.0.0.1:8000/。 - 系统会自动检测并打开第一台可用摄像头;没有设备时可切换到 Mock Camera。
- 点击“拍照”,在图片上拖动 ROI。
- 点击“识别颜色”,查看 RGB、LAB 和 HEX。
- 点击“上传服务器”完成 Mock 或真实 API 上传。
- 在“日志”页面查看北京时间、上传图片、ROI 图片和颜色参数。
- 在“设置”页面点击“退出颜色识别系统”可正确释放摄像头并关闭服务。
重复双击 EXE 时,程序会检测现有服务并提示颜色识别系统已经在运行。
第一次运行会在 EXE 同级生成:
ColorVision/
├── config/
│ └── config.json
└── data/
├── captures/
├── results/
└── logs/
├── colorvision.db
├── colorvision.log
└── images/
默认配置:
{
"api_url": "http://127.0.0.1:9000/api/color",
"token": "",
"camera_id": "CAM-001",
"auto_upload": false,
"mock_mode": true,
"timeout": 10.0,
"port": 8000,
"image_retention_days": 0,
"max_image_count": 0,
"log_enabled": true,
"log_image_storage_enabled": true,
"log_retention_days": 0,
"max_log_count": 0
}配置说明:
api_url:真实上传 API 地址。token:以Authorization: Bearer <token>发送,可为空。camera_id:上传数据中的设备标识。auto_upload:颜色识别完成后自动上传。mock_mode:true时不访问外部服务器。timeout:外部 API 超时时间,单位秒。port:本地服务端口,修改后需要重启 EXE。image_retention_days:拍摄图片保留天数,设为0时不按时间清理。max_image_count:拍摄图片最大保留数量,设为0时不按数量清理。log_enabled:上传成功后是否写入本地上传日志。log_image_storage_enabled:日志是否在本机保存上传原图和识别区域图。log_retention_days:日志保留天数,设为0时不按时间清理。max_log_count:日志最大条数,设为0时不按数量清理。
也可以使用环境变量指定其他配置文件:
$env:COLORVISION_CONFIG = "D:\ColorVisionData\config.json"CameraService 支持以下状态:
| 状态 | 含义 | 页面操作 |
|---|---|---|
initializing |
正在检测或初始化 | 等待 |
available |
真实摄像头已打开 | 实时预览、拍照 |
not_found |
未检测到摄像头 | 重新检测、使用 Mock |
open_failed |
摄像头存在但无法打开 | 重新检测、使用 Mock |
busy |
设备可能被其他程序占用 | 重新检测、使用 Mock |
disconnected |
运行中设备断开 | 重新连接、使用 Mock |
read_failed |
当前帧读取失败 | 重新检测、使用 Mock |
mock |
Mock Camera 正在运行 | 拍照、切回真实摄像头 |
重新检测和重连会先释放旧 VideoCapture,再枚举设备并重新打开,所有生命周期操作会串行执行,
避免快速重复点击造成重复打开或资源泄漏。
设备只有连续读取到尺寸有效且包含可见内容的视频帧后才会进入 available;仅
VideoCapture.isOpened() 成功不会被判定为可用摄像头。Windows 摄像头驱动在无设备时
可能打开占位视频源并持续返回全黑帧,因此连续全黑或近全黑画面会被视为无效帧。
这两项是独立功能:
- Mock Camera:代替摄像头提供动态测试画面,不依赖 USB 摄像头。
- Mock Upload:
mock_mode=true时模拟上传服务器响应,不访问外部 API。
当前配置文件中的 mock_mode 仍只控制上传行为。Mock Camera 由页面按钮或 Camera API 控制。
当前版本不启用软件端白平衡、曝光增益或灰度世界校正。摄像头驱动负责自动白平衡和曝光, 避免软件二次校正与设备校正叠加后产生不可重复的颜色偏移。采集到的 BGR 图像按设备输出的 sRGB 图像处理,再按 BGR → RGB → CIELAB 的标准顺序转换。
ROI 采样先排除过暗和过亮像素,再用中位数/MAD 去除局部高光、阴影或 JPEG 噪声等离群点, 最后对剩余像素取均值。该流程用于提高同一颜色在不同照片中的一致性,不做主观“增强颜色”。 CIELAB 使用 float32 sRGB 和 D65 白点计算,避免 OpenCV uint8 LAB 的量化与偏移误差。
如果后续需要标准色卡级别的绝对色差报告,应在固定光源下锁定摄像头白平衡和曝光,并使用 经过认证的标准色卡建立设备级校准矩阵;这些步骤尚未加入当前配置流程。
Mock 上传模式:
{
"mock_mode": true
}页面会显示类似:
{
"success": true,
"message": "Mock upload success",
"request_id": "MOCK-20260914-0001"
}真实 API 模式:
{
"api_url": "http://your-server/api/color",
"token": "your-token",
"mock_mode": false,
"timeout": 10
}上传使用 multipart/form-data,包含:
original_imageroi_imagergblabhexroicamera_idtimestamp
后端会处理超时、HTTP 状态码、无效 JSON 和网络异常。
前端主导航依次为“工作台”“日志”“设置”。上传成功后,日志页按北京时间 (UTC+8,精确到秒)倒序显示:
- 上传原图
- 颜色识别区域图
- RGB、CIELAB、HEX 和 ROI 参数
- Camera ID、上传模式和请求 ID
日志数据只保存在本机:
data/logs/colorvision.db # SQLite 日志索引,仅包含结构化参数
data/logs/images/ # 原图和识别区域图
首次启动自动创建 upload_logs 表和上述图片目录,不写入任何初始数据。
应用不会把日志上传到外部服务器;关闭“保存日志图片”后,后续日志只保留
颜色参数。日志页支持单条删除和全部清空,设置页可配置保留天数与最大条数。
日志位置:
data/logs/colorvision.log
日志包含:
- 服务启动与停止
- 摄像头扫描、打开与关闭
- 拍照文件保存
- ROI 颜色分析
- Mock 或真实 API 上传
- 配置迁移与错误
- 未处理异常
EXE 为无控制台窗口模式,正常运行不会持续弹出控制台日志。
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
Set-Location .\frontend
npm install
Set-Location ..同时启动 FastAPI 和 Vite:
.\scripts\dev.ps1也可以使用生产式统一入口:
python backend/main.py该入口默认绑定 127.0.0.1:8000,不使用 --reload,并直接托管
frontend/dist。
开发接口文档:
http://127.0.0.1:8000/docs
Vite 开发服务器仍可用于前端热更新:
Set-Location .\frontend
npm run dev开发服务器地址为 http://127.0.0.1:5173。这是唯一仍使用 5173 的场景。
运行全部测试、真实摄像头测试和前端生产构建:
.\scripts\test.ps1跳过摄像头:
.\scripts\test.ps1 -SkipCamera测试覆盖:
- 健康检查、Swagger 和 Vue 托管
- 纯红、纯绿、纯蓝、白色、黑色
- RGB、LAB、HEX 范围、通道顺序和标准 sRGB/D65 基准值
- 含局部高光与噪声的 ROI 稳健采样
- ROI 零尺寸和越界校验
- 配置默认值、持久化和旧字段迁移
- Mock 上传响应
- 无摄像头、设备占用和运行中断开状态
- 640×480、1280×720、1920×1080 分辨率元数据
- Windows DSHOW/MSMF 摄像头后端选择
- PyInstaller 外部配置、打包资源和前端静态资源路径
- Mock Camera 拍照、存储与静态预览
- 真实摄像头拍照、存储与静态预览
.\scripts\build.ps1构建流程:
- 执行 Vue TypeScript 检查和
npm run build。 - 校验
frontend/dist/index.html和frontend/dist/assets是否完整。 - 使用
colorvision.spec收集后端、OpenCV、Python 依赖、Vue 资源和 Windows 版本信息。 - 在
build/release-staging中生成 PyInstaller onedir 目录。 - 校验 staging 内的 EXE 和 Vue 资源。
- 生成版本化 ZIP,并只替换
dist/ColorVision中的程序文件。 - 保留已有
config/和data/。
输出:
dist/ColorVision/ColorVision.exe
dist/ColorVision-v1.4.0-win-x64.zip
ZIP 文件名自动读取 backend.__version__,升级版本后无需手工修改构建脚本。
只构建前端:
.\scripts\build.ps1 -FrontendOnly项目使用 onedir,不使用 onefile。稳定性优先于单文件体积。
| 方法 | 路径 | 功能 |
|---|---|---|
| GET | /api/health |
健康状态 |
| GET、PUT | /api/config |
读取或保存配置 |
| GET | /api/camera/list |
枚举摄像头 |
| GET | /api/camera/status |
摄像头状态 |
| POST | /api/camera/open |
打开摄像头 |
| POST | /api/camera/detect |
释放旧设备、重新检测并打开 |
| POST | /api/camera/reconnect |
重连指定或首台可用摄像头 |
| POST | /api/camera/mock |
切换到 Mock Camera |
| POST | /api/camera/close |
关闭摄像头 |
| GET | /api/camera/stream |
MJPEG 实时画面 |
| POST | /api/camera/capture |
拍照 |
| POST | /api/color/analyze |
ROI 颜色分析 |
| POST | /api/upload |
Mock 或真实上传 |
| GET | /api/logs |
分页读取本地上传日志 |
| DELETE | /api/logs/{id} |
删除单条日志及其图片 |
| DELETE | /api/logs |
清空全部日志及图片 |
| POST | /api/system/shutdown |
托管模式优雅退出 |
- 关闭 Windows 相机、Teams、Zoom、浏览器会议等可能占用摄像头的程序。
- 检查 Windows 设置中的“隐私和安全性 -> 相机”权限。
- 重新插拔 USB 摄像头。
- 确认没有重复运行的
ColorVision.exe。 - 查看
data/logs/colorvision.log中的摄像头错误。 - 使用 Windows“相机”应用确认设备本身可以工作。
当前版本只允许一台进程打开一台摄像头。不同时支持多摄像头并发采集。
CAMERA_OPEN_FAILED:
摄像头不存在、驱动不可用,或者已被其他程序占用。
CAMERA_DEVICE_BUSY:
摄像头可能正在被其他相机、会议或浏览器程序占用。
CAMERA_DRIVER_ERROR:
OpenCV 或摄像头驱动在打开、配置设备时发生异常。
CAMERA_DISCONNECTED:
摄像头运行过程中断开,重新连接设备后可再次检测。
CAMERA_READ_FAILED:
摄像头仍被打开,但当前帧读取失败。
CAPTURE_FAILED:
摄像头已连接,但当前帧读取失败。重新打开摄像头或重新插拔设备。
INVALID_ROI:
ROI 宽高为 0,或者选区超出原图范围。
IMAGE_READ_FAILED:
上传图片为空、格式不支持或超过 25 MB。
API_TIMEOUT:
外部 API 在配置的 timeout 时间内未响应。
API_REQUEST_FAILED:
外部 API 网络失败、返回非 2xx,或返回了无效 JSON。
端口已被其他程序占用:
关闭占用端口的程序,或者修改 config/config.json 中的 port 后重启。
Free code signing provided by SignPath.io, certificate by SignPath Foundation.
- Committers and reviewers: AbsoluteZero
- Approvers: AbsoluteZero
本项目采用 MIT License。