無人監控視頻輸出卡頓狀態

設計思路,如下:

? ? ? ? ? 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.pswp.cn/bicheng/21929.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21929.shtml
英文地址,請注明出處:http://en.pswp.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…

Prism 入門04,導航功能

當前章節,沿用 上一章使用Prism 框架創建的WPF 項目空模板。在上一章節,各個不同的模塊之間能夠進行切換并把內容呈現在主程序的頁面當中(其實是通過在主程序中注冊的區域去發起一個導航的請求,然后跳轉到對應的視圖。也就是實現了導航跳轉功能)。 為什么能實現導航的跳轉?…

Mybatis的一級緩存

緩存 MyBatis 包含一個非常強大的查詢緩存特性,它可以非常方便地配置和定制。MyBatis 3 中的緩存實現的很多改進都已經實現了,使得它更加強大而且易于配置。 Mybatis和Hibernate一樣&#xff0c;也有一級和二級緩存&#xff0c;同樣默認開啟的只有一級緩存&#xff0c;二級緩…

docker-compose安裝多環境apollo

下載數據庫sql文件 https://github.com/apolloconfig/apollo/blob/master/scripts/sql/src/apolloconfigdb.sql https://github.com/apolloconfig/apollo/blob/master/scripts/sql/src/apolloportaldb.sql 創建庫并導入表 #生產環境 mysql> CREATE DATABASE IF NOT EXIS…

腦部磁共振成像腫瘤分割方法(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…

擴展翡蜀定理問題

問題描述 給定一個大小為 n n n 的集合 A { a 1 , a 2 ~ a n } A\{a_1,a_2 \sim a_n\} A{a1?,a2?~an?}&#xff0c;滿足條件 gcd ( A ) 1 \text{gcd}(A)1 gcd(A)1。 O ( 1 ) O(1) O(1)時間內 求最大的 k k k &#xff0c;滿足不存在一個大小為 n n n 的非負數集合…

工廠的精益生產如此重要

什么是工廠的精益生產 精益生產&#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進行如下設計: 其中,連接器管理客戶端的連接,負責管理連接、認證鑒權等;查詢緩存則是為了加速查詢,命中則直接返回結…

Linux Shell Script 編寫入門

Linux Shell 腳本是一種強大的工具&#xff0c;能夠幫助用戶自動化任務、簡化系統管理以及提高工作效率。本文將帶您全面了解如何編寫 Linux Shell 腳本&#xff0c;并介紹一些常見的腳本編寫技巧和注意事項。 目錄 什么是 Linux ShellShell 腳本的基本結構常用 Shell 命令變…

系統介紹在線直線度測量儀的測量原理

測頭的測量原理 藍鵬光電測頭采用的是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;用于存儲相同類型的元…