基于yolo的视频检测分析

基于yolo的视频检测分析

分步骤实现视频处理、目标检测与追踪、动作分析、计数逻辑,然后整合成API

完整的解决方案,包含视频分析逻辑和API封装,使用Python、YOLOv8和FastAPI实现代码如下:

python代码实现

import os
import uuid
import json
from datetime import datetime
from fastapi import FastAPI, UploadFile, BackgroundTasks
from fastapi.responses import JSONResponse
from pydantic import BaseModel
import cv2
import numpy as np
from ultralytics import YOLO
from collections import defaultdict# 初始化FastAPI应用
app = FastAPI(title="Smart Retail Cabinet API")# 配置参数
CONFIG = {"upload_folder": "uploads","result_folder": "results","model_path": "yolov8n_custom.pt",  # 自定义训练的商品检测模型"shelf_roi": [(100, 50), (600, 400)],  # 货架区域坐标"hand_roi": [(0, 400), (800, 600)],   # 手部操作区域坐标"frame_skip": 5,                      # 跳帧处理间隔"confidence_threshold": 0.7
}# 数据库模拟(实际应使用数据库)
processing_queue = {}
results_db = {}# 定义数据模型
class ProcessingRequest(BaseModel):task_id: strstatus: strresult: dict = None# 工具函数
def create_folders():os.makedirs(CONFIG['upload_folder'], exist_ok=True)os.makedirs(CONFIG['result_folder'], exist_ok=True)def save_upload_file(file: UploadFile) -> str:task_id = str(uuid.uuid4())file_path = os.path.join(CONFIG['upload_folder'], f"{task_id}.mp4")with open(file_path, "wb") as buffer:buffer.write(file.file.read())return task_id, file_path# 核心分析逻辑
class CabinetAnalyzer:def __init__(self):self.model = YOLO(CONFIG['model_path'])self.track_history = defaultdict(list)self.inventory = defaultdict(int)self.current_in_shelf = set()def is_in_region(self, box, region):x1, y1, x2, y2 = boxrx1, ry1 = region[0]rx2, ry2 = region[1]return (rx1 < (x1+x2)/2 < rx2) and (ry1 < (y1+y2)/2 < ry2)def analyze_video(self, video_path: str):cap = cv2.VideoCapture(video_path)frame_count = 0event_log = []while cap.isOpened():success, frame = cap.read()if not success:breakframe_count += 1if frame_count % CONFIG['frame_skip'] != 0:continue# 运行目标检测与追踪results = self.model.track(frame, persist=True,conf=CONFIG['confidence_threshold'],verbose=False)if results[0].boxes.id is None:continue# 解析检测结果boxes = results[0].boxes.xyxy.cpu().numpy()track_ids = results[0].boxes.id.int().cpu().tolist()class_ids = results[0].boxes.cls.int().tolist()confidences = results[0].boxes.conf.float().tolist()current_frame_objects = set()for box, track_id, cls_id, conf in zip(boxes, track_ids, class_ids, confidences):# 判断物体位置in_shelf = self.is_in_region(box, CONFIG['shelf_roi'])in_hand = self.is_in_region(box, CONFIG['hand_roi'])# 更新追踪历史self.track_history[track_id].append({"frame": frame_count,"position": box.tolist(),"in_shelf": in_shelf,"in_hand": in_hand,"class_id": cls_id})current_frame_objects.add(track_id)# 检测放入/取出事件if len(self.track_history[track_id]) > 10:first_state = self.track_history[track_id][-10]current_state = self.track_history[track_id][-1]if first_state["in_shelf"] and current_state["in_hand"]:event_log.append({"type": "TAKE","track_id": track_id,"class_id": cls_id,"frame": frame_count})self.inventory[cls_id] += 1elif first_state["in_hand"] and current_state["in_shelf"]:event_log.append({"type": "RETURN","track_id": track_id,"class_id": cls_id,"frame": frame_count})self.inventory[cls_id] -= 1# 清理旧的追踪记录for track_id in list(self.track_history.keys()):if track_id not in current_frame_objects:del self.track_history[track_id]# 更新货架状态self.current_in_shelf = current_frame_objectscap.release()return {"inventory_changes": dict(self.inventory),"event_log": event_log,"total_frames": frame_count}# API端点
@app.post("/analyze")
async def create_analysis_task(file: UploadFile, background_tasks: BackgroundTasks):create_folders()task_id, video_path = save_upload_file(file)processing_queue[task_id] = {"status": "queued","start_time": datetime.now().isoformat()}background_tasks.add_task(run_analysis, task_id, video_path)return JSONResponse({"task_id": task_id,"status_url": f"/status/{task_id}"})@app.get("/status/{task_id}")
def get_task_status(task_id: str):if task_id not in processing_queue and task_id not in results_db:return JSONResponse({"error": "Task not found"}, status_code=404)if task_id in results_db:return results_db[task_id]return processing_queue[task_id]async def run_analysis(task_id: str, video_path: str):try:processing_queue[task_id]["status"] = "processing"analyzer = CabinetAnalyzer()result = analyzer.analyze_video(video_path)# 转换为商品名称class_names = analyzer.model.namesfinal_result = {"items": [{"product": class_names[cls_id],"quantity": quantity} for cls_id, quantity in result["inventory_changes"].items() if quantity > 0],"analysis_time": datetime.now().isoformat(),"metadata": {"duration_frames": result["total_frames"],"events_count": len(result["event_log"])}}# 保存结果result_file = os.path.join(CONFIG['result_folder'], f"{task_id}.json")with open(result_file, "w") as f:json.dump(final_result, f)results_db[task_id] = {"status": "completed","result": final_result,"result_url": f"/results/{task_id}"}except Exception as e:results_db[task_id] = {"status": "failed","error": str(e)}finally:if task_id in processing_queue:del processing_queue[task_id]@app.get("/results/{task_id}")
def get_analysis_result(task_id: str):if task_id not in results_db:return JSONResponse({"error": "Result not found"}, status_code=404)result_file = os.path.join(CONFIG['result_folder'], f"{task_id}.json")with open(result_file) as f:result_data = json.load(f)return JSONResponse(result_data)if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)

系统架构说明:

  • API接口层:

/analyze:接收视频上传并启动后台分析任务

/status/{task_id}:查询任务状态

/results/{task_id}:获取分析结果

  • 视频分析核心模块:

使用YOLOv8进行实时目标检测与追踪

基于空间位置的状态机判断取放行为

多帧验证机制确保事件准确性

  • 数据流处理:
sequenceDiagramparticipant Clientparticipant APIparticipant Analyzerparticipant StorageClient->>API: POST /analyze (video.mp4)API->>Storage: 保存视频文件API->>Analyzer: 启动后台任务Analyzer->>Analyzer: 视频帧处理Analyzer->>Storage: 保存分析结果Client->>API: GET /status/123API->>Client: 返回处理状态Client->>API: GET /results/123API->>Client: 返回JSON结果

使用方法:

  • 启动服务:
uvicorn main:app --reload
  • 调用API:
# 上传视频
curl -X POST -F "file=@test.mp4" http://localhost:8000/analyze# 响应示例
{"task_id": "550e8400-e29b-41d4-a716-446655440000","status_url": "/status/550e8400-e29b-41d4-a716-446655440000"
}# 查询结果
curl http://localhost:8000/results/550e8400-e29b-41d4-a716-446655440000# 响应示例
{"items": [{"product": "coca_cola", "quantity": 2},{"product": "pringles", "quantity": 1}],"analysis_time": "2024-01-20T14:30:00","metadata": {"duration_frames": 300,"events_count": 3}
}

优化建议:

  • 模型优化:

使用TensorRT加速推理

量化模型到INT8精度

针对具体商品优化YOLO模型

  • 系统扩展:

使用Redis存储任务队列

添加Celery分布式任务队列

实现视频分块处理

  • 安全增强:

添加JWT身份验证

限制文件上传类型和大小

实现请求频率限制

  • 功能扩展:

添加多摄像头支持

实现实时视频流分析

增加库存同步接口

该方案实现了完整的取货分析流程,并通过API提供标准化接口,适合集成到各类零售管理系统。实际部署时需要根据具体硬件配置调整视频处理参数(如frame_skip值)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/70459.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

归一化与伪彩:LabVIEW图像处理的区别

在LabVIEW的图像处理领域&#xff0c;归一化&#xff08;Normalization&#xff09;和伪彩&#xff08;Pseudo-coloring&#xff09;是两个不同的概念&#xff0c;虽然它们都涉及图像像素值的调整&#xff0c;但目的和实现方式截然不同。归一化用于调整像素值的范围&#xff0c…

MySQL8.0实现MHA高可用

一、简介 MHA&#xff08;Master HA&#xff09;是一款开源的 MySQL 的高可用程序&#xff0c;它为 MySQL 主从复制架构提供了 automating master failover 功能。MHA 在监控到 master 节点故障时&#xff0c;会提升其中拥有最新数据的 slave 节点成为新的master 节点&#xf…

记录 | WPF基础学习登录界面制作

目录 前言一、普通方式Step1 创建项目Step2 设计布局Step3 对剩余布局进行内容填充可执行代码下载 Step4 编写点击事件Step5 创建新WPF窗口Step6 简单写点Index内容Step7 跳转到Index当前代码下载 二、绑定方式绑定用户名【单向绑定】双向绑定代码提供 三、MVVM方式1&#xff1…

vivado 7 系列器件时钟

7 系列器件时钟 注释&#xff1a; 本章节以 Virtex -7 时钟源为例。 Virtex-6 的时钟资源与此类似。如果使用不同的架构&#xff0c;请参阅有关器件的 《时 钟资源指南》 [ 参照 40] 。 Virtex-6 和 Virtex-7 器件内含 32 个称为 BUFG 的全局时钟缓存。 BUFG 可满…

无须付费,安装即是完全版!

不知道大家有没有遇到过不小心删掉了电脑上超重要的文件&#xff0c;然后急得像热锅上的蚂蚁&#xff1f; 别担心&#xff0c;今天给大家带来一款超给力的数据恢复软件&#xff0c;简直就是拯救文件的“救星”&#xff01; 数据恢复 专业的恢复数据软件 这款软件的界面设计得特…

【图片合并转换PDF】如何将每个文件夹下的图片转化成PDF并合并成一个文件?下面基于C++的方式教你实现

医院在为患者进行诊断和治疗过程中&#xff0c;会产生大量的医学影像图片&#xff0c;如 X 光片、CT 扫描图、MRI 图像等。这些图片通常会按照检查时间或者检查项目存放在不同的文件夹中。为了方便医生查阅和患者病历的长期保存&#xff0c;需要将每个患者文件夹下的图片合并成…

Racecar Gym 总结

1.Racecar Gym 简介 Racecar Gym 是一个基于 PyBullet 物理引擎 的自动驾驶仿真平台&#xff0c;提供 Gymnasium&#xff08;OpenAI Gym&#xff09; 接口&#xff0c;主要用于强化学习&#xff08;Reinforcement Learning, RL&#xff09;、多智能体竞速&#xff08;Multi-Ag…

基于微信小程序的医院预约挂号系统的设计与实现

hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生…

智体链:大语言模型协作完成长上下文任务

25年1月来自Penn State U和谷歌云的论文“Chain of Agents: Large Language Models Collaborating on Long-Context Tasks”。 解决有效处理长上下文的挑战已成为大语言模型 (LLM) 的关键问题。出现了两种常见策略&#xff1a;1&#xff09;减少输入长度&#xff0c;例如通过检…

java s7接收Byte字节,接收word转16位二进制

1图&#xff1a; 2.图&#xff1a; try {List list getNameList();//接收base64S7Connector s7Connector S7ConnectorFactory.buildTCPConnector().withHost("192.168.46.52").withPort(102).withTimeout(1000) //连接超时时间.withRack(0).withSlot(3).build()…

机器学习在癌症分子亚型分类中的应用

学习笔记&#xff1a;机器学习在癌症分子亚型分类中的应用——Cancer Cell 研究解析 1. 文章基本信息 标题&#xff1a;Classification of non-TCGA cancer samples to TCGA molecular subtypes using machine learning发表期刊&#xff1a;Cancer Cell发表时间&#xff1a;20…

Redis --- 使用HyperLogLog实现UV(访客量)

UV 和 PV 是网站或应用数据分析中的常用指标&#xff0c;用于衡量用户活跃度和页面访问量。 UV (Unique Visitor 独立访客)&#xff1a; 指的是在一定时间内访问过网站或应用的独立用户数量。通常根据用户的 IP 地址、Cookies 或用户 ID 等来唯一标识一个用户。示例&#xff1…

大学资产管理系统中的下载功能设计与实现

大学资产管理系统是高校信息化建设的重要组成部分&#xff0c;它负责记录和管理学校内所有固定资产的信息。随着信息技术的发展&#xff0c;下载功能成为提高资产管理效率的关键环节之一。 系统架构的设计是实现下载功能的基础。一个良好的系统架构能够确保数据的高效传输和存储…

Vue 3 中的 el-tooltip 详解:语法、示例及与其他框架对比

目录 前言1. 基本知识2. 实战Demo 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. 基本知识 el-tooltip 是 Element Plus&#xff08;Vue 3 组件库&#xff09;中的一个用于提示的组件&#xff0c;它可以在…

Day 31 卡玛笔记

这是基于代码随想录的每日打卡 491. 非递减子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0…

docker /var/lib/docker/overlay2目录把磁盘空间占满问题

1、查看服务器磁盘空间 df -h果然100%了,docker系统文件把磁盘空间占满了。 2、进入overlay2目录&#xff0c;查找那个容器工作目录占用最高 cd /var/lib/docker/overlay2du -h --max-depth1详见下图 好家伙占用110G&#xff01;复制目录名称2c3c48ccac533c5d4a366d45a19bb9…

02vue3实战-----项目目录详解

02vue3实战-----项目目录详解 1.目录完整结构2.extensions.json文件3.node_modules文件夹4.public文件夹5.src文件夹6.文件.gitignore7.文件env.d.ts8.文件index.html9.文件package-lock.json和文件package.json10.文件README.md11.文件vite.config.ts12.文件tsconfig.json和文…

【蓝桥杯嵌入式】4_key:单击+长按+双击

全部代码网盘自取 链接&#xff1a;https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码&#xff1a;3ii2 1、电路图 将4个按键的引脚设置为input&#xff0c;并将初始状态设置为Pull-up&#xff08;上拉输入&#xff09; 为解决按键抖动的问题&#xff0c;我们…

qt部分核心机制

作业 1> 手动将登录项目实现&#xff0c;不要使用拖拽编程 并且&#xff0c;当点击登录按钮时&#xff0c;后台会判断账号和密码是否相等&#xff0c;如果相等给出登录成功的提示&#xff0c;并且关闭当前界面&#xff0c;发射一个跳转信号&#xff0c;如果登录失败&#…

Spring Boot启动内嵌tocmat原理

要研究Spring Boot启动内嵌tomcat的原理&#xff0c;就需要先了解一下Spring Boot自动配置的过程&#xff0c;首先简要的梳理一下springboot自动配置的步骤。 一、SpringBoot自动配置 当SpringBoot应用启动时&#xff0c;EnableAutoConfiguration注解被激活&#xff0c;该注解…