无人监控视频输出卡顿状态

设计思路,如下:

          1.通过采集卡将视频信号输出到个人PC中

          2.PC按设置好的时间,视频属性分片保存

          3.将步骤2中的视频,按预处理要求,得到待计算的视频片段

          4.使用SSIM算法计算预处理后的视频,将计算得到的数据存放在硬盘中

          5.WEB端,分页按时间倒序展示,视屏卡顿情况

          6.循环执行上述1~5步骤,直到视频输出结束

          ps:根据视频的质量的不同,计算时间和硬盘空间要求也要具体区分准备

代码A,实现了视频采集,预处理和计算的阶梯循环运行

#################################### 代码A ################################import time
import multiprocessing
import cv2
from skimage.metrics import structural_similarity as ssim
import matplotlib.pyplot as plt
import osclass LagAnalysis():# 文件名称file_name = 0# 单文件最大时长 单位秒file_time = 900# 文件记录最大数量file_max = 3# 文件分辨率大小file_resolution_ratio = (640, 480)# 文件帧率单位file_frame_rate = 60# 原始文件路径file_o_path = os.getcwd() + "\\original"# 预处理文件路径file_p_path = os.getcwd() + "\\pretreatment"# 解析结果文件路径file_r_path = os.getcwd() + "\\result"def record(self):# 初始化摄像头cap = cv2.VideoCapture(0)  # 0 通常是默认摄像头的标识# 检查摄像头是否成功打开if not cap.isOpened():print("无法打开摄像头")exit()# 设置视频编码格式和输出视频文件fourcc = cv2.VideoWriter_fourcc(*'XVID')name = self.file_nameout_file = "original/output_" + str(name) + ".avi"out = cv2.VideoWriter(out_file, fourcc, self.file_frame_rate, self.file_resolution_ratio)flag = 0# 单文件包含最大帧数flag1 = self.file_time * self.file_frame_rate# 循环捕获视频帧while cap.isOpened() and name < self.file_max:ret, frame = cap.read()if ret:if flag < flag1:# 写入帧到输出视频文件out.write(frame)flag = flag + 1else:out.release()flag = 0name = name + 1if name < self.file_max:out_file = "original/output_" + str(name) + ".avi"out = cv2.VideoWriter(out_file, fourcc, self.file_frame_rate, self.file_resolution_ratio)else:break# 释放资源cap.release()out.release()cv2.destroyAllWindows()def pretreatment(self, x, y, width, height, f):# 预处理视频函数index = f.find("/")out_file = "pretreatment/" + f[index + 1:]fourcc = cv2.VideoWriter_fourcc(*'XVID')cap = cv2.VideoCapture(f)out = cv2.VideoWriter(out_file, fourcc, self.file_frame_rate, (width, height))# 检查视频是否成功打开if not cap.isOpened():print("Error: Could not open video.")exit()# 通过循环读取视频的每一帧while True:# 读取下一帧,ret是一个布尔值,表示是否成功读取# frame是读取到的帧,如果读取失败,则为Noneret, frame = cap.read()# 如果正确读取帧,进行处理if ret:# 展示帧# cv2.imshow('Frame', frame)cropped_image = frame[y:y + height, x:x + width]# cv2.imshow('Cropped Image', cropped_image)out.write(cropped_image)# time.sleep(10)else:# 如果读取帧失败,退出循环breakcap.release()out.release()cv2.destroyAllWindows()def calculate(self, width, height, f):# 预处理视频函数index = f.find("/")index1 = f.find(".")out_file = "result/" + f[index + 1:index1] + ".txt"# fourcc = cv2.VideoWriter_fourcc(*'XVID')fourcc = cv2.VideoWriter_fourcc(*'XVID')cap = cv2.VideoCapture(f)# 检查视频是否成功打开if not cap.isOpened():print("Error: Could not open video.")exit()ret, frame = cap.read()old_frame = frame# 打开文件进行写入with open(out_file, 'w') as file:# 通过循环读取视频的每一帧while True:# 读取下一帧,ret是一个布尔值,表示是否成功读取# frame是读取到的帧,如果读取失败,则为Noneret, frame = cap.read()# 如果正确读取帧,进行处理if ret:score, diff = self.compare_images(old_frame, frame)file.write(str(score))file.write("\n")else:# 如果读取帧失败,退出循环breakcap.release()cv2.destroyAllWindows()file.close()def compare_images(self, imageA, imageB):# 转换图片为灰度grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)# 计算SSIMscore, diff = ssim(grayA, grayB, full=True)diff = (diff * 255).astype("uint8")return score, diffdef show_images(self, imageA, imageB, diff):fig, axes = plt.subplots(1, 3, figsize=(20, 8))ax = axes.ravel()ax[0].imshow(imageA, cmap=plt.cm.gray)ax[0].set_title('Image A')ax[1].imshow(imageB, cmap=plt.cm.gray)ax[1].set_title('Image B')ax[2].imshow(diff, cmap=plt.cm.gray)ax[2].set_title('Difference')for a in ax:a.axis('off')plt.show()def listen1(self):# 监听指定目录下是否有新的待预处理的文件name = self.file_nameflag = 0o_name = ""next_name = ""while name < self.file_max and flag < self.file_max:file_list = [file for file in os.listdir(self.file_o_path) ifos.path.isfile(os.path.join(self.file_o_path, file))]print(file_list)next_name = "output_" + str(name + 1) + ".avi"o_name = "original/output_" + str(name) + ".avi"if next_name in file_list:self.pretreatment(0, 0, 640, 240, o_name)name = name + 1if name == self.file_max-1:flag = flag + 1time.sleep(self.file_time)self.pretreatment(0, 0, 640, 240, o_name)def listen2(self):# 监听指定目录下是否有新的待计算的预处理文件name = self.file_nameflag = 0o_name = ""next_name = ""while name < self.file_max and flag < self.file_max:file_list = [file for file in os.listdir(self.file_p_path) ifos.path.isfile(os.path.join(self.file_p_path, file))]print(file_list)next_name = "output_" + str(name + 1) + ".mp4"o_name = "pretreatment/output_" + str(name) + ".mp4"if next_name in file_list:self.calculate(640, 240, o_name)name = name + 1if name == self.file_max-1:flag = flag + 1# time.sleep(self.file_time)self.calculate(640, 240, o_name)if __name__ == "__main__":a = LagAnalysis()process = multiprocessing.Process(target=a.listen1)process.start()process1 = multiprocessing.Process(target=a.listen2)process1.start()a.record()# process.join()process1.join()

代码B,实现了后端获取计算结果的分页功能

// 代码B
const express = require('express');
const fs = require('fs');
const path = require('path');const app = express();
const port = 3000;
// const txtDirectory = path.join(__dirname, 'txt_files'); // Adjust this path to your txt files directory
const txtDirectory = path.join("D:/others/python/ts_autotest/private/", 'result');app.use(express.static('public'));app.get('/files', (req, res) => {const page = parseInt(req.query.page) || 1;const limit = parseInt(req.query.limit) || 20;fs.readdir(txtDirectory, (err, files) => {if (err) {return res.status(500).json({ error: 'Failed to read directory' });}const txtFiles = files.filter(file => file.endsWith('.txt'));const totalFiles = txtFiles.length;const totalPages = Math.ceil(totalFiles / limit);const startIndex = (page - 1) * limit;const endIndex = Math.min(startIndex + limit, totalFiles);const selectedFiles = txtFiles.slice(startIndex, endIndex);const fileDataPromises = selectedFiles.map(file => {const filePath = path.join(txtDirectory, file);return new Promise((resolve, reject) => {fs.readFile(filePath, 'utf-8', (err, data) => {if (err) {return reject(err);}const parsedData = data.split('\n').map(Number);resolve({ fileName: file, data: parsedData });});});});Promise.all(fileDataPromises).then(fileData => res.json({ files: fileData, totalPages })).catch(err => res.status(500).json({ error: 'Failed to read files' }));});
});app.listen(port, () => {console.log(`Server is running at http://localhost:${port}`);
});

代码C,实现了前端展示计算结果的折线图

<---   代码C  ---><!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Text Files to Charts</title><style>body {font-family: Arial, sans-serif;}.container {display: flex;flex-direction: column;flex-wrap: wrap;margin: 20px;}.row {display: flex;width: 100%;margin-bottom: 20px;}.chart {flex: 1;margin: 0 10px;}canvas {width: 100%;}#pagination {margin-top: 20px;text-align: center;}#pagination button {margin: 0 5px;padding: 5px 10px;}#modal {display: none;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);background: white;padding: 20px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);}#modal canvas {width: 500px;height: 300px;}</style>
</head>
<body>
<div class="container" id="container"></div>
<div id="pagination"></div><div id="modal"><button onclick="closeModal()">Close</button><canvas id="zoomChart"></canvas>
</div><!-- Include Chart.js library -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>const itemsPerPage = 20;let currentPage = 1;let totalPages = 1;async function fetchTextFiles(page) {const response = await fetch(`/files?page=${page}&limit=${itemsPerPage}`);const filesData = await response.json();return filesData;}function initializeChart(chartId, data) {const ctx = document.getElementById(chartId).getContext('2d');const chart = new Chart(ctx, {type: 'line',data: {labels: data.map((_, index) => `Point ${index + 1}`),datasets: [{label: 'Data Points',data: data,borderColor: 'rgba(75, 192, 192, 1)',borderWidth: 2,fill: false}]},options: {responsive: true,scales: {x: {beginAtZero: true},y: {beginAtZero: true}},onClick: (event, elements) => {if (elements.length > 0) {const elementIndex = elements[0].index;showModal(data, elementIndex);}}}});}function createRow(data, chartId) {const row = document.createElement('div');row.className = 'row';const chartContainer = document.createElement('div');chartContainer.className = 'chart';const canvasElement = document.createElement('canvas');canvasElement.id = chartId;chartContainer.appendChild(canvasElement);row.appendChild(chartContainer);return row;}function updatePaginationControls() {const paginationContainer = document.getElementById('pagination');paginationContainer.innerHTML = '';for (let i = 1; i <= totalPages; i++) {const button = document.createElement('button');button.textContent = i;button.disabled = i === currentPage;button.addEventListener('click', () => {currentPage = i;initializePage();});paginationContainer.appendChild(button);}}async function initializePage() {const container = document.getElementById('container');container.innerHTML = '';const filesData = await fetchTextFiles(currentPage);totalPages = filesData.totalPages;filesData.files.forEach((fileData, index) => {const row = createRow(fileData.data, `chart${index + 1}`);container.appendChild(row);initializeChart(`chart${index + 1}`, fileData.data);});updatePaginationControls();}function showModal(data, index) {const modal = document.getElementById('modal');const ctx = document.getElementById('zoomChart').getContext('2d');const zoomData = data.slice(Math.max(0, index - 5), index + 6);new Chart(ctx, {type: 'line',data: {labels: zoomData.map((_, i) => `Point ${i + 1}`),datasets: [{label: 'Zoomed Data Points',data: zoomData,borderColor: 'rgba(255, 99, 132, 1)',borderWidth: 2,fill: false}]},options: {responsive: true,scales: {x: {beginAtZero: true},y: {beginAtZero: true}}}});modal.style.display = 'block';}function closeModal() {const modal = document.getElementById('modal');modal.style.display = 'none';}document.addEventListener('DOMContentLoaded', function() {initializePage();});
</script>
</body>
</html>

项目运行成功后,刷新浏览器,页面将实时显示当前视频片段的卡顿情况(如下图)

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

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

相关文章

聊天机器人的实践过程

一、语聊机器人 OpenAI 的爆火&#xff0c;到如今也才一年多的时间&#xff0c;然而在过去的一年中&#xff0c;生成式AI的落地场景几乎 80%都是 ChatBot 的形式&#xff0c;那么今天这篇文章我们就来聊一下&#xff0c;生成式AI和IM能擦出怎么样的火花&#xff1f;以及各种场…

p13idea的其他操作

1 导入模块 错误示范&#xff1a; 正确示范&#xff1a; 2 删除模块 必须用delete才能删除干净&#xff0c;用remove删了之后还要回到文件里面把它删除掉

有钱还系统源码 人人还众筹还钱模式还贷系统源码

盈利模式&#xff1a; 1.系统里直推400 2.间推得200 3.升级是隔代匹配200 4.漏单直接设置归系统 5.九级匹配不到直接归平台 有钱还平台新注册会员&#xff0c;即新入的负债者要分9次分别资助先来的11名负债者每人200元&#xff0c;这笔资助不是一次性给到对方&#xff0c…

Mybatis的一级缓存

缓存 MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis 3 中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。 Mybatis和Hibernate一样&#xff0c;也有一级和二级缓存&#xff0c;同样默认开启的只有一级缓存&#xff0c;二级缓…

脑部磁共振成像肿瘤分割方法(MATLAB 2018)

近年脑肿瘤发病率呈上升趋势&#xff0c;约占全身肿瘤的5%&#xff0c;占儿童肿瘤的70%。CT、MRI等多种影像检查方法可用于检测脑肿瘤&#xff0c;其中MRI应用于脑肿瘤成像效果最佳。精准的脑肿瘤分割是病情诊断、手术规划及后期治疗的必备条件&#xff0c;既往研究者对脑部肿瘤…

Python知识点12---Python的I/O操作

提前说一点&#xff1a;如果你是专注于Python开发&#xff0c;那么本系列知识点只是带你入个门再详细的开发点就要去看其他资料了&#xff0c;而如果你和作者一样只是操作其他技术的Python API那就足够了。 Python的流(I/O)操作&#xff0c;最简单的其实就是输入和输出&#x…

工厂的精益生产如此重要

什么是工厂的精益生产 精益生产&#xff08;Lean Manufacturing&#xff09;是一种起源于20世纪50年代日本丰田汽车公司的生产管理哲学。它的核心理念是通过消除生产过程中的浪费&#xff0c;优化流程&#xff0c;提高效率&#xff0c;从而实现成本降低和质量提升。精益生产不仅…

VRTK4.0学习——(二)

手柄绑定以及显示 1.导入CameraRigs.UnityXRPluginFramework 和 CameraRigs.TrackedAlias 预设&#xff0c;将CameraRigs.UnityXRPluginFramework拖入CameraRigs.TrackedAlias的Elements中即可&#xff0c;运行软件后即可看到手柄了 注&#xff1a;如果无法看到手柄&#xff…

MySQL:MySQL执行一条SQL查询语句的执行过程

当多个客户端同时连接到MySQL,用SQL语句去增删改查数据,针对查询场景,MySQL要保证尽可能快地返回客户端结果。 了解了这些需求场景,我们可能会对MySQL进行如下设计: 其中,连接器管理客户端的连接,负责管理连接、认证鉴权等;查询缓存则是为了加速查询,命中则直接返回结…

系统介绍在线直线度测量仪的测量原理

测头的测量原理 蓝鹏光电测头采用的是CCD成像法测量&#xff0c;CCD成像法是指将被测物放置在物方远心光路系统中进行成像&#xff0c;并利用成像位置的CCD芯片接收成像信息进行尺寸测量的方法。该测量方法的优点主要有两个&#xff1a;一是成像边界清晰&#xff0c;光电信号可…

从墙的功能出发 -分析欧特克Revit和广联达数维的差别

欧特克&#xff08;Autodesk&#xff09;在三维建模软件领域的影响力是有目共睹的&#xff0c;它是行业的头部产商&#xff0c;拥有众多的高质量的三维设计软件&#xff0c;涵盖了建筑设计、机械设计与制造和电影文娱行业。Revit是其发布的建筑三维建模软件&#xff0c;也是BIM…

如何用个人电脑搭建一台本地服务器,并部署项目到服务器详细教程(Ubuntu镜像)

前言 VirtualBox虚拟机软件是一款强大、免费且开源的虚拟化工具&#xff0c;它允许用户在单一物理机器上同时运行多个操作系统。他对比VMware就是更轻量级的虚拟机软件&#xff0c;而且操作更简单。 下载地址&#xff1a;Download_Old_Builds_7_0 – Oracle VM VirtualBox …

SpringMVC日期格式处理 分页条件查询

实现日期格式处理 实现分页条件查询&#xff1a; 分页条件查询 和 查询所有 是两个不同的方法&#xff0c;使用同一个mapper的查询功能&#xff0c;但是两个不同的业务方法 ​​​​​​​

24年西藏事业单位报名详细流程

✨各位姐妹们注意啦&#xff01;24西藏事业单位公告已出&#xff0c;本次计划公开招聘8⃣9⃣9⃣人即日起开始报名&#xff0c;想要上岸的姐妹们要抓紧了哦✊趁着还有时间赶紧开卷&#xff01;&#xff01;&#xff01; &#x1f308;24西藏事业单位招聘考试&#xff1a; &…

k8s练习--StorageClass详细解释与应用

文章目录 前言StorageClass是什么 一、实验目的配置过程 二、实验环境实验步骤一、配置网络存储NFS&#xff1a;1.主机基础配置2.配置 NFS: 二、开启rbac权限:三、创建nfs-deployment.yaml四、创建storageclass资源五、验证&#xff1a;1&#xff0e;创建PVC验证2.创建一个pod验…

C++青少年简明教程:数组

C青少年简明教程&#xff1a;数组 C数组是一种存储固定大小连续元素的数据结构。数组中的每个元素都有一个索引&#xff0c;通过索引可以访问或修改数组中的元素。 在C中&#xff0c;数组中的元素数据类型必须一致。数组是一个连续的内存区域&#xff0c;用于存储相同类型的元…

期权懂带你懂50etf认沽期权和认购期权有什么区别?

今天带你了解期权懂带你懂50etf认沽期权和认购期权有什么区别&#xff1f;在金融市场中&#xff0c;期权是一种允许持有者在未来某个时间以特定价格买入或卖出基础资产的金融衍生品。 50etf认沽期权和认购期权有什么区别&#xff1f; 50ETF认沽期权和认购期权的主要区别在于它…

聚类算法—DBSCAN算法

文章目录 DBSCAN算法基本概念1个核心思想&#xff1a;基于密度2个算法参数&#xff1a;邻域半径R和最少点数目minpoints3种点的类别&#xff1a;核心点&#xff0c;边界点和噪声点4种点的关系&#xff1a;密度直达&#xff0c;密度可达&#xff0c;密度相连&#xff0c;非密度相…

Spi Pwm Tim 对比分析

spi SPI时序图 (spi是主从机 所以主机需要从机数据 需要主极先喊从机 把从机喊答应了 才能开始读从机的数据&#xff09; cpol时钟极性 和cpha时钟相位分析 1.cpha为高&#xff0c;cpol为高&#xff0c;则偶数上升沿有效 2.cpha为高&#xff0c;cpol为低&#xff0c;则偶数…

JVM之【GC-垃圾清除算法】

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集算法主要分为以下几种&#xff1a; 标记-清除算法&#xff08;Mark-Sweep&#xff09;复制算法&#xff08;Copying&#xff09;标记-整理算法&#xff08;Mark-Compact&#xff09;分代收集算法&#xff08;Generational C…