开源一个完全免费的全本地运行的视觉模型Next.JS系统
- 其他
- 10天前
- 13热度
- 0评论
实时视觉分析系统概述
系统简介
实时视觉分析系统是一个基于浏览器的实时监控平台,用于检测和管理视频流中的目标。该系统采用轻量级的目标检测模型(EfficientDet-Lite0)在客户端进行目标识别,并通过威胁等级配置实现告警闭环。
技术栈与架构
1. 主要技术
- Next.js App Router: 负责页面路由和 API Routes。
- React Hooks: 处理摄像头状态、检测状态和页面交互。
- TypeScript: 提供类型约束,增强开发体验。
- Ant Design: 构建后台管理界面。
- MediaPipe Object Detector: 实现浏览器端目标检测。
- EfficientDet-Lite0: 轻量级目标检测模型。
- MySQL: 存储威胁配置、截图、历史记录和摄像头配置。
2. 主要功能模块
系统主要分为五个页面:
/ - 实时视觉分析首页
/history - 历史记录
/threats - 威胁管理
/snapshots - 截图管理
/cameras - 摄像头管理详细功能介绍
1. 浏览器摄像头采集
通过浏览器的 MediaDevices.getUserMedia API 获取视频流,并设置相关参数以优化性能和兼容性。如果用户拒绝权限,系统会显示相应的错误提示。
const stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
facingMode: "environment",
width: { ideal: 1280 },
height: { ideal: 720 }
}
});2. MediaPipe 模型加载
目标检测模型通过动态导入在浏览器端加载,确保服务端渲染阶段不会访问浏览器 API。
const detector = await ObjectDetector.createFromOptions(vision, {
baseOptions: {
modelAssetPath: "/models/efficientdet_lite0_uint8.tflite"
},
maxResults: 20,
runningMode: "VIDEO",
scoreThreshold: 0.45
});3. 实时检测与节流处理
为减少浏览器主线程压力,目标检测间隔设置为大约每700ms执行一次。
const DETECTION_INTERVAL_MS = 700;
intervalRef.current = window.setInterval(detectOnce, DETECTION_INTERVAL_MS);4. 检测结果处理
MediaPipe 返回的检测结果会被转换成项目统一的数据结构,并使用中文名称进行显示。
export type DetectedObject = {
id: string;
label: string;
displayName: string;
score: number;
box?: {
x: number;
y: number;
width: number;
height: number;
};
};5. 威胁等级配置
系统支持为不同目标设置威胁等级,并根据这些配置决定是否需要告警。威胁级别包括 none、low、medium、high 和 critical。
type ThreatLevel = "none" | "low" | "medium" | "high" | "critical";默认威胁配置在 lib/db.ts 中定义:
const defaultConfigs = [
["person", "行人", "medium", "检测到人员进入监控区域", 1],
["car", "车辆", "low", "检测到车辆经过", 1],
["truck", "卡车", "medium", "检测到货运车辆进入区域", 1],
["knife", "刀具", "critical", "检测到刀具,高危告警", 1],
// 其他配置
];总结
实时视觉分析系统利用轻量级目标检测模型和威胁等级配置实现了高效的视频监控功能。通过优化的摄像头采集、节流处理以及中文显示支持,该系统为用户提供了一套完整的监控解决方案。
以上内容概括了实时视觉分析系统的架构和技术栈,并详细介绍了各个主要功能模块的具体实现。通过这些技术应用和优化措施,用户可以高效地进行视频流中的目标检测与管理。
9. 告警提醒
当系统检测到威胁目标时,它会立即弹出警告通知来提示用户潜在的安全隐患:
notification.warning({
message: primaryThreat.config.alertMessage,
description: `${primaryThreat.config.displayName} / ${
THREAT_META[primaryThreat.config.threatLevel].label
}危 / ${Math.round(primaryThreat.object.score * 100)}%`,
placement: "topRight"
});为了防止同一威胁目标在短时间内连续触发告警,系统实施了去重机制:
const lastNoticeAt = lastNoticeRef.current[key] ?? 0;
if (now - lastNoticeAt < 6000) {
return;
}
lastNoticeRef.current[key] = now;这确保了一个威胁目标在6秒内不会重复提醒,从而减少用户干扰并专注于新的安全事件。
10. 告警截图生成
为了更直观地展示告警信息,系统会使用 Canvas 技术截取当前视频帧,并绘制出告警框和文字:
const canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const context = canvas.getContext("2d");
context.drawImage(video, 0, 0, canvas.width, canvas.height);接下来,系统会在截图上添加目标框以及相关信息:
context.strokeStyle = color;
context.fillStyle = color;
context.strokeRect(x, y, width, height);
context.fillRect(x, Math.max(0, y - 30), context.measureText(label).width + 18, 28);
context.fillStyle = "#fff";
context.fillText(label, x + 8, Math.max(0, y - 25));在截图的顶部,系统还会添加告警信息和时间戳:
context.fillStyle = "rgba(0, 0, 0, 0.7)";
context.fillRect(0, 0, canvas.width, 52);
context.fillStyle = "#ffffff";
context.fillText(`${config.alertMessage} / ${timeLabel}`, 18, 15);最后,截图会被转换为 Base64 格式并提交到后端:
imageData: canvas.toDataURL("image/jpeg", 0.86)为了防止短时间内连续生成大量截图文件,系统还设置了截图冷却时间:
const SNAPSHOT_COOLDOWN_MS = 12000;11. 历史记录管理
项目不仅存储每一帧的检测结果,还会详细记录目标出现和消失的时间。每当新的威胁对象进入画面时,系统会创建一条历史记录:
const response = await fetch("/api/history", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
cameraId: currentCamera?.id ?? null,
cameraName: currentCamera?.name ?? "本地摄像头",
objectLabel: label,
displayName: config?.displayName || object.displayName,
threatLevel: config?.enabled ? config.threatLevel : "none",
confidence: object.score
})
});当目标离开画面时,系统会更新该记录的离场时间和最高置信度:
fetch(`/api/history/${record.id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ confidence: record.confidence })
});这有助于后端计算目标在画面中停留的时长,并进行进一步的数据分析。
12. 数据库连接与建表
数据库连接和配置逻辑位于 lib/db.ts 文件:
function createPool() {
return mysql.createPool({
host: process.env.MYSQL_HOST ?? "127.0.0.1",
port: Number(process.env.MYSQL_PORT ?? 3306),
user: process.env.MYSQL_USER ?? "root",
password: process.env.MYSQL_PASSWORD ?? "123456",
database: DATABASE_NAME,
waitForConnections: true,
connectionLimit: 10,
namedPlaceholders: true,
timezone: "+08:00"
});
}数据库的名称为:
const DATABASE_NAME = "vision_analysis_system";项目启动时会自动创建所需数据库,保证数据存储的基础架构:
await bootstrapConnection.query(
`CREATE DATABASE IF NOT EXISTS \`${DATABASE_NAME}\`
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci`
);系统中包含多个关键的数据库表结构定义:
CREATE TABLE IF NOT EXISTS threat_configs (...);
CREATE TABLE IF NOT EXISTS threat_snapshots (...);
CREATE TABLE IF NOT EXISTS system_events (...);
CREATE TABLE IF NOT EXISTS cameras (...);
CREATE TABLE IF NOT EXISTS detection_records (...);这些表格存储了威胁配置、告警截图数据、系统事件等信息。项目还提供了独立的 SQL 文件:
database/vision_analysis_system.sql用户可以通过以下命令手动导入数据库文件到 MySQL 中:
mysql -u root -p < database/vision_analysis_system.sql13. 后端 API 设计
该项目使用了 Next.js 的 API Routes 功能来构建后端接口。例如,截图保存功能的 API 路径定义为 app/api/snapshots/route.ts。
前端向 /api/snapshots 发送 POST 请求时会触发以下代码段:
const response = await fetch("/api/snapshots", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
objectLabel: config.objectLabel,
displayName: config.displayName,
threatLevel: config.threatLevel,
alertMessage: config.alertMessage,
confidence: object.score,
imageData: canvas.toDataURL("image/jpeg", 0.86),
detectedObjects: objects
})
});后端接收到请求后,会将截图数据存储到 MySQL 数据库中:
await db.query(
`
INSERT INTO threat_snapshots
(object_label, display_name, threat_level, alert_message, confidence, image_data, detected_objects)
VALUES
(:objectLabel, :displayName, :threatLevel, :alertMessage, :confidence, :imageData, CAST(:detectedObjects AS JSON))
`,
{
objectLabel,
displayName,
threatLevel,
alertMessage,
confidence,
imageData,
detectedObjects: JSON.stringify(payload.detectedObjects ?? [])
}
);这种设计使得前端页面和后端接口都能在同一个 Next.js 项目中运行,简化了部署与维护流程。
14. 页面与响应式设计
项目的用户界面采用 Ant Design 组件库搭建,并通过全局 CSS 实现深色科技风格。整个布局分为顶部导航、实时视频显示区域以及右侧信息展示区:
<div className="monitor-layout">
<Card className="video-card monitor-video-card">
<div className="video-shell">
<video ref={videoRef} autoPlay muted playsInline />
<div className="detection-layer">
{/* 目标框 */}
</div>
</div>
</Card>
<aside className="monitor-sidebar">
{/* 统计信息、检测结果、模型信息、最近截图 */}
</aside>
</div>在桌面端,界面采用左右布局模式:
.monitor-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(300px, 360px);
gap: 16px;
}而在移动设备上,则转为单列布局:
@media (max-width: 1023px) {
.monitor-layout {
grid-template-columns: 1fr;
}
}这样可以确保在桌面端视频画面占据主要区域,而手机端的内容则自然地向下排列。
15. 项目总结
实时视觉分析系统通过 MediaPipe Object Detector 和 EfficientDet-Lite0 模型实现在浏览器中的本地推理功能。这种设计不仅满足了摄像头视频流的检测需求,并且增加了威胁等级配置、告警截图生成、历史记录管理和摄像头管理等高级特性。
从技术实现的角度来看,该系统综合运用了多种前端和后端技术栈,包括浏览器摄像头 API、WebAssembly 本地推理能力、React Hooks 状态管理机制、Canvas 绘图功能以及 Next.js API 路由设计。这样的整体架构不仅清晰明确,而且非常适合用作计算机视觉、前端 AI 开发、智能监控系统及本地化目标检测领域的学习项目或毕业设计案例。
该项目的核心优势在于其能够在普通浏览器中实时执行复杂的视觉分析任务;无需依赖云端服务接口,并且具有部署简便、成本低廉、保护隐私性和良好的扩展性等特点。