jf-open-pro-traffic-heatmap

内容来源:clawhub · 原始地址 · 查看安装指南

原始内容


name: jf-open-pro-traffic-heatmap description: 室内人流热力图分析技能。通过杰峰摄像头定时抓拍 + 本地 YOLOv8 头部检测,生成圆形高斯模糊热力图叠加的交互式 HTML 报告。支持 10 分钟粒度流量趋势、空间利用率分析和客流计数统计。 metadata: version: 1.4.1 author: User category: analytics tags: - 热力图 - 人流分析 - 杰峰 - 监控 - 客流统计 - 头部检测 - 定时任务 triggers: - 热力图 - 人流分析 - 客流统计 - 空间利用率 - 流量报告 - 热力图报告 - 人头检测 - 热力图怎么用 - 热力图使用指南 prerequisites: - Python 3.8+ - pip install opencv-python numpy ultralytics matplotlib - 已安装杰峰相关技能(jf-open-pro-capture, jf-open-pro-device-status, jf-open-pro-device-list)


Traffic Heatmap — 人流热力图分析

技能描述

分析室内空间人流,通过杰峰摄像头抓图 + 本地 YOLOv8m 头部检测模型,生成圆形高斯模糊热力图叠加的交互式 HTML 报告。支持 10 分钟粒度流量趋势、空间利用率分析和客流计数统计。可配合 QoderWork 定时任务实现自动化采集与 IM 推送。

触发词

热力图 / 人流分析 / 客流统计 / 空间利用率 / 流量报告 / 人头检测 / 热力图怎么用 / 使用指南

依赖技能

本技能依赖以下已有杰峰技能来完成设备操作,不要自行实现设备通信

依赖技能 用途
jf-open-pro-capture 设备抓图(单设备/批量)
jf-open-pro-device-status 查询设备在线状态
jf-open-pro-device-list 查询已绑定设备列表

前置条件

环境变量

由杰峰技能统一管理(JF_UUID, JF_APP_KEY, JF_APP_SECRET, JF_MOVE_CARD 等),本技能无需额外配置。

Python 依赖

pip install opencv-python numpy ultralytics matplotlib

注意:不需要 requests,设备通信由杰峰技能处理。

检测模型

使用 YOLOv8m 头部检测模型models/head-yolov8m.pt,约 50MB),基于 SCUT-HEAD 数据集训练,单类别 {0: 'head'}

模型来源:https://github.com/Abcfsa/YOLOv8_head_detector (medium.pt)

下载地址(如模型文件缺失可手动或自动下载):

文件 大小 下载地址
head-yolov8m.pt (medium) ~50 MB https://github.com/Abcfsa/YOLOv8_head_detector/raw/main/medium.pt
head-yolov8s.pt (nano) ~6 MB https://github.com/Abcfsa/YOLOv8_head_detector/raw/main/nano.pt

下载后放入 models/ 目录并重命名为 head-yolov8m.pthead-yolov8s.ptdetect.pyload_model() 在本地未找到模型时会自动尝试从上述地址下载。

模型查找路径按优先级从高到低:

  1. models/head-yolov8m.pt
  2. models/head-yolov8s.pt
  3. data/models/head-yolov8m.pt
  4. data/models/head-yolov8s.pt

如无头部模型权重且下载失败,脚本会抛出异常并提示手动下载地址,不会回退到 COCO 检测器。

配置文件

config/cameras.json 存储本技能使用的摄像头列表和检测参数:

{
  "cameras": [
    {
      "id": "a717e75986337093",
      "name": "办公室-主区域",
      "password": "",
      "grid_cols": 24,
      "grid_rows": 14
    }
  ],
  "settings": {
    "capture_interval_minutes": 5,
    "confidence_threshold": 0.4,
    "image_retention_days": 7
  }
}
  • id: 摄像头唯一标识(杰峰设备 ID)
  • name: 用户定义的显示名称
  • grid_cols/grid_rows: 热力图网格密度(默认 24x14,每格约 80x77 像素,适合 1920x1080 画面)
  • capture_interval_minutes: 建议采集间隔(仅供 Agent 参考)
  • confidence_threshold: 头部检测最低置信度(默认 0.4,平衡召回与误检)

数据隔离

每个会话使用独立的数据目录,避免不同会话的数据互相污染。

通过 --data-dir 参数指定会话数据目录,数据库、抓拍图片、报告输出全部存储在该目录下:

{data_dir}/
  data/
    traffic_heatmap.db    # 独立的 SQLite 数据库
    captures/             # 独立的抓拍归档
      {YYYYMMDD}/
    outputs/              # 独立的报告输出
      report.html
      summary.txt

使用规则:

  • Agent 在对话中执行操作时:使用当前会话的 workspace 目录作为 --data-dir,例如 C:\Users\...\workspace\{session_id}\。这样每个会话的数据完全隔离。
  • 定时任务:使用定时任务自己的 contextDirs 目录作为 --data-dir,定时任务的数据与其他会话独立。
  • 不指定 --data-dir:回退到技能安装目录(向后兼容),所有数据共享。

脚本调用示例:

# detect.py 指定数据目录
python scripts/detect.py --images {data_dir}/data/captures/{YYYYMMDD}/ \
  --config config/cameras.json \
  --db {data_dir}/data/traffic_heatmap.db \
  --data-dir {data_dir}

# run_report.py 指定数据目录
python run_report.py --data-dir {data_dir}

配置(config/cameras.json)、代码(scripts/assets/)和模型(models/)始终从技能安装目录共享,不受 --data-dir 影响。

核心工作流

工作流 0: 引导使用(首次对话 / 帮助)

触发: 用户说"热力图怎么用"、"帮我配置热力图"、"介绍一下热力图"、"使用指南",或 Agent 判断用户是首次使用本技能。

流程:

Agent 应先做一次环境检查,然后根据当前状态给出针对性的引导,而不是机械地输出固定话术。

第一步:环境检查(静默执行,不要告诉用户"我在检查")

依次检查以下项目,记录结果:

  1. 读取 config/cameras.json,看是否已有摄像头配置(cameras 列表是否为空,或只有默认占位数据)。
  2. 检查 models/ 目录下是否有 head-yolov8m.pthead-yolov8s.pt
  3. 检查当前会话的 data_dir/data/traffic_heatmap.db 是否存在(是否有历史数据)。
  4. 使用 qoder_cron 的 list action 检查是否已有热力图相关的定时任务。

第二步:根据状态引导

根据检查结果,按以下逻辑组织对话:

情况 A — 全新状态(无摄像头、无模型、无数据):

你好!我来帮你搭建人流热力图分析系统。

这个系统能做什么:
• 通过杰峰摄像头定时抓拍画面,用 AI 检测人头数量
• 生成空间热力图,直观展示哪些区域人流密集
• 支持定时自动采集,检测结果自动推送到 IM 频道(钉钉等)

搭建只需要 3 步,我来一步步带你完成:

1️⃣ 添加摄像头 — 告诉我你要监控哪个摄像头
2️⃣ 下载检测模型 — 首次使用需要下载 AI 模型(约 50MB,自动完成)
3️⃣ 试跑一次 — 抓图、检测、看效果

我们先从添加摄像头开始,好吗?说"开始"就行。

用户确认后,自动进入工作流 1(摄像头配置)。

情况 B — 有摄像头,但无模型:

已经配置好摄像头了!接下来需要下载头部检测模型。

当前摄像头:{列出已配置的摄像头名称}

模型文件约 50MB,从 GitHub 下载,首次运行检测时会自动拉取。
要现在试跑一次看看效果吗?

用户确认后,进入工作流 2(采集与检测),模型会在 load_model() 中自动下载。

情况 C — 有摄像头、有模型,但无数据:

一切就绪!你的系统配置如下:

📷 摄像头:{列出名称}
🧠 检测模型:已就绪
⏱️ 定时任务:{已配置 / 未配置}

现在可以做这些事:
• 「采集一次」— 立即抓图并检测人数
• 「生成报告」— 生成热力图 HTML 报告
• 「定时采集」— 设置自动采集和钉钉推送

建议先跑一次采集看看效果,要试试吗?

情况 D — 已有数据(老用户回来):

欢迎回来!当前状态:

📷 摄像头:{列出名称}
📊 历史数据:{数据条数} 条采集记录
⏱️ 定时任务:{已配置 / 未配置}

需要我做什么?
• 「采集一次」— 立即抓图检测
• 「生成报告」— 查看最新热力图
• 「查看摄像头」— 管理摄像头配置
• 「定时采集」— 配置自动采集推送

第三步:执行用户选择的操作

根据用户回复进入对应工作流(1~5),执行完成后回到引导末尾,简短提示下一步可以做什么。

注意事项

  • 引导对话要简洁,不要一次输出太多信息
  • 环境检查是静默的,不要列出一堆检查步骤给用户看
  • 如果用户明确说要做什么(如"帮我添加摄像头"),跳过引导直接进入对应工作流
  • 每次完成一个操作后,简短提示用户接下来可以做什么

工作流 1: 摄像头配置

触发: 用户说"添加摄像头"、"配置摄像头"、"查看摄像头列表"、"删除摄像头"

流程:

  1. 如果用户说"查看摄像头列表":读取 config/cameras.json 并展示给用户。
  2. 如果用户说"添加摄像头":
    • 使用 jf-open-pro-device-list 技能查询可用设备列表
    • 让用户选择要添加的设备(或手动输入设备 ID)
    • 询问用户给摄像头起个名字(如"入口"、"收银台")
    • 使用 jf-open-pro-device-status 验证设备是否在线
    • 将设备信息写入 config/cameras.json
  3. 如果用户说"删除摄像头":从 config/cameras.json 中移除对应条目。

工作流 2: 采集与检测

触发: 用户说"采集一次"、"收集数据"、"跑检测"

流程:

  1. 读取 config/cameras.json 获取摄像头列表。
  2. 使用 jf-open-pro-capture 技能 对所有摄像头执行批量抓图。
    • 将图片下载到 {data_dir}/data/captures/{YYYYMMDD}/ 目录
    • 图片命名格式:{camera_id}_{timestamp}.png
    • 如果某个摄像头离线,跳过并记录警告
  3. 运行头部检测脚本:
    python scripts/detect.py --images {data_dir}/data/captures/{YYYYMMDD}/ \
      --config config/cameras.json \
      --db {data_dir}/data/traffic_heatmap.db \
      --data-dir {data_dir}
    
  4. 向用户汇报检测结果摘要(每个摄像头检测到多少人)。

工作流 3: 生成报告

触发: 用户说"生成报告"、"看热力图"、"本周报告"

流程:

  1. 根据用户意图确定时间范围(默认:当天)。
  2. 运行报告生成脚本(自动查找最新背景图):
    python run_report.py --data-dir {data_dir}
    
    {data_dir} 为当前会话的数据目录。脚本会从 {data_dir}/data/ 读取数据库和抓拍图,输出 report.htmlsummary.txt{data_dir}/data/outputs/
  3. 使用 present_files 将生成的 HTML 报告呈现给用户。
  4. generate_report() 返回总结文本,可保存到 summary.txt 或直接用于 IM 推送。

工作流 4: 单独渲染热力图

触发: 用户说"看某个摄像头的热力图"

流程:

  1. 运行热力图渲染脚本:
    python scripts/heatmap.py \
      --db data/traffic_heatmap.db \
      --camera {camera_id} \
      --start {YYYY-MM-DD} \
      --end {YYYY-MM-DD} \
      --background {background_image_path} \
      --output data/outputs/heatmap_{camera_id}.png \
      --grid-cols 24 --grid-rows 14
    
  2. 展示生成的热力图 PNG。

工作流 5: 定时自动采集与推送

触发: 用户说"定时采集"、"每 N 分钟跑一次"、"自动推送报告"

流程:

  1. 引导用户确认配置(必须,不要假设):

    使用 AskUserQuestion 工具询问以下信息:

    • 采集间隔: 提供选项 5 分钟 / 10 分钟 / 15 分钟 / 30 分钟
    • 推送对象: 使用 qoder_list_channel_conversations 查询当前可用的 IM 会话列表,将会话名称作为选项供用户选择(如"钉钉-陈亮"、"钉钉-运维群"等),如果没有可用会话则提示用户先连接 IM 频道
    • 运行时段: 提供选项 全天 24 小时 / 仅工作时间 9:00-18:00 / 自定义
  2. 使用 qoder_cron 工具创建定时任务:

    schedule: { kind: "cron", expr: "*/{间隔} * * * *", tz: "Asia/Shanghai" }
    payload.message: 自然语言描述完整流水线步骤
    
  3. 定时任务的 message 应包含完整步骤:

    • 使用杰峰技能抓图
    • 运行 detect.py --data-dir {data_dir} 检测头部
    • 运行 run_report.py --data-dir {data_dir} 生成报告(自动选择最新抓图作为热力图背景)
    • 读取 summary.txt,通过 IM 频道推送给用户选择的接收人

推送方式: 统一通过 IM 频道发送消息(使用 qoder_list_channel_conversations 查找会话 + qoder_delegate_to_im 投递),不要使用 DWS 等连接器直接发钉钉消息

示例定时任务 message({用户名} 由用户选择后替换,{data_dir} 为定时任务的数据目录):

执行以下人流热力图分析任务:

技能目录: {skill_dir}
数据目录: {data_dir}

步骤 1 — 抓图
使用杰峰抓图技能对所有摄像头抓图。
环境变量: JF_UUID=xxx, JF_APP_KEY=xxx, JF_APP_SECRET=xxx, JF_MOVE_CARD=xxx
图片保存到 {data_dir}/data/captures/{今天YYYYMMDD}/ 目录,命名格式 {camera_id}_YYYYMMDDHHmmss.png

步骤 2 — 检测
设置 PYTHONIOENCODING=utf-8,运行:
python {skill_dir}/scripts/detect.py --images {data_dir}/data/captures/{今天YYYYMMDD}/ \
  --config {skill_dir}/config/cameras.json \
  --db {data_dir}/data/traffic_heatmap.db \
  --data-dir {data_dir}

步骤 3 — 生成报告
运行: python {skill_dir}/run_report.py --data-dir {data_dir}
生成 {data_dir}/data/outputs/report.html 和 summary.txt(自动选最新图片作背景)

步骤 4 — 推送
读取 {data_dir}/data/outputs/summary.txt,通过 IM 频道发送总结给「{用户名}」

脚本参考

脚本 用途 调用方式
scripts/db.py SQLite 数据层(库模块) 被其他脚本导入
scripts/detect.py YOLOv8m 头部检测 + 网格映射 CLI: --images --config --db --data-dir
scripts/heatmap.py 圆形高斯热力图渲染 CLI: --db --camera --start --end --background --output --grid-cols --grid-rows
scripts/report.py 交互式 HTML 报告生成(含总结生成) CLI: --db --config --start --end --output --backgrounds --data-dir,返回总结文本
run_report.py 报告生成入口(自动选最新背景图) CLI: --data-dir --daily,输出 report.html + summary.txt

检测策略

使用 YOLOv8m 头部检测模型(SCUT-HEAD 训练),专门针对监控场景优化:

  • 模型: head-yolov8m.pt,单类别 head,medium 规模(约 50MB)
  • 锚点: 头部 bbox 底部中心 (cx, y2),近似颈部/肩膀位置
  • 置信度阈值: 0.4(在召回率和误检率之间取得平衡)
  • 适用场景: 站立、行走、坐姿、背面、后脑勺、半遮挡人头、远距离小目标
  • 回退: 如无头部模型权重且自动下载失败,抛出异常提示手动下载,不回退到 COCO 检测器

热力图渲染

采用圆形高斯模糊渲染方式,不使用网格线:

  • 每个有数据的网格绘制一个圆形色块,半径为格子短边的 40%
  • 使用高斯模糊(kernel = radius/2)使圆形边缘柔和
  • 颜色映射使用 YlOrRd colormap(黄→橙→红),透明度 alpha=0.6
  • 无数据区域不绘制,直接显示背景画面

报告格式

交互式自包含 HTML 报告,特性包括:

  • 摄像头标签切换: 多摄像头时通过标签页切换
  • 统计卡片(6 项): 总检测人次、平均检测人次(每轮)、本小时平均人次、高峰时段、最热区域、采集轮次;网格自适应布局
  • 左右排版: 左侧热力图(1.5fr)+ 右侧 10 分钟流量柱状图(1fr)
  • 热力图: base64 嵌入 PNG,圆形色块叠加,带渐变色图例
  • 流量图表: Canvas 柱状图,按 10 分钟粒度聚合,X 轴标签旋转 -30°,峰值高亮
  • 本次总结: 可视化区域下方展示统计总结卡片,包含采集轮次、累计检测人次、高峰时段、最热区域、平均人次和流量趋势(上升/下降/平稳)
  • 采集记录摘要: 每条历史记录附带简要分析(本时段峰值 / 高于平均 / 正常水平 / 低于平均 / 未检测到人员活动)
  • 时间预设: 日/周/月快捷切换按钮

报告生成函数 generate_report() 返回总结文本字符串,调用方可将其保存或用于 IM 推送。

数据说明

SQLite 数据库 {data_dir}/data/traffic_heatmap.db 包含三张表:

  • cameras: 摄像头配置信息
  • detections: 每帧检测记录(时间戳、人数、图片路径)
  • grid_heat: 网格热力累积数据(按摄像头+网格坐标+时间窗口)

报告通过 query_grid() 聚合 grid_heat 表生成热力图,通过 query_time_series() 按 10 分钟窗口聚合生成流量趋势。

关键查询函数

函数 说明
query_grid(db, cam_id, start, end) 聚合网格数据用于热力图渲染
query_time_series(db, cam_id, start, end, interval_minutes=10) 按 N 分钟窗口聚合流量趋势
query_stats(db, cam_id, start, end) 汇总统计(总量、高峰、最热格子、轮次)
query_history(db, cam_id, start, end) 查询检测历史记录(时间戳、人数、图片路径)

错误处理

场景 处理
摄像头离线 跳过该设备,汇报部分结果
未找到头部检测模型 自动从 GitHub 下载(重试 3 次),失败则抛异常提示手动下载地址
某帧无检测结果 正常行为,不写入 grid_heat 记录
Windows CLI JSON 转义失败 改用临时 Python 脚本直接调用函数
磁盘空间不足 建议用户清理旧图片(超过 image_retention_days 的)