519 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			519 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html lang="en" >
 | |
| <head>
 | |
|     <link  rel="stylesheet" href="../static/element.css">
 | |
|     <script src="../static/vue.js"> </script>
 | |
|     <script src="../static/element.js"> </script>
 | |
| 
 | |
|     <title>公共安全技术研究中心算法集</title>
 | |
|     <style lang="scss">
 | |
|         .upload-container {
 | |
|             background-color: #d3d3d3; /* Grey background */
 | |
|             padding: 20px;
 | |
|             border-radius: 15px;
 | |
|             display: flex;
 | |
|             justify-content: space-around; /* Space between form and button */
 | |
|             align-items: center; /* Vertically center */
 | |
|             width: 80%;
 | |
|             margin: 20px auto; /* Centering the div */
 | |
|         }
 | |
|         .result-container {
 | |
|             background-color: hsl(125, 85%, 33%); /* Grey background */
 | |
|             padding: 20px;
 | |
|             border-radius: 15px;
 | |
|             display: flex;
 | |
|             justify-content: space-around; /* Space between form and button */
 | |
|             align-items: center; /* Vertically center */
 | |
|             width: 80%;
 | |
|             margin: 20px auto; /* Centering the div */
 | |
|         }
 | |
| 
 | |
|         .upload-btn-wrapper {
 | |
|             background-color: #4CAF50; /* Green background */
 | |
|             border: none;
 | |
|             color: white;
 | |
|             padding: 8px 16px;
 | |
|             text-align: center;
 | |
|             text-decoration: none;
 | |
|             display: inline-block;
 | |
|             font-size: 16px;
 | |
|             margin: 4px 2px;
 | |
|             cursor: pointer;
 | |
|             border-radius: 4px;
 | |
|         }
 | |
| 
 | |
|         .webcam-btn {
 | |
|             background-color: #4CAF50; /* Green background */
 | |
|             border: none;
 | |
|             color: white;
 | |
|             padding: 8px 16px;
 | |
|             text-align: center;
 | |
|             text-decoration: none;
 | |
|             font-size: 16px;
 | |
|             cursor: pointer;
 | |
|             border-radius: 4px;
 | |
|         }
 | |
| 
 | |
|         .file-input {
 | |
|             display: none; /* Hide the default file input */
 | |
|         }
 | |
|         .res-input {
 | |
|             width: 100;
 | |
|             font-size: large;
 | |
| 
 | |
| 
 | |
|         }
 | |
| 
 | |
|         .custom-file-label {
 | |
|             border: 2px solid whitesmoke;
 | |
|             display: inline-block;
 | |
|             padding: 6px 12px;
 | |
|             cursor: pointer;
 | |
|         }
 | |
|         .video-file-label {
 | |
|             border: 2px solid whitesmoke;
 | |
|             display: inline-block;
 | |
|             padding: 6px 12px;
 | |
|             cursor: pointer;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         .video-container {
 | |
|             width: 70%;
 | |
|             margin: 20px auto;
 | |
|             background-color: #f0f0f0;
 | |
|             border-radius: 15px;
 | |
|             box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
 | |
|             text-align: center;
 | |
|             padding: 15px;
 | |
|             margin-left: 190px;
 | |
|             height: 100%;
 | |
|         }        
 | |
|         .left-column {
 | |
|             flex: 3;
 | |
|             background-color: hsl(0, 24%, 96%); /* Grey background */
 | |
|             border-radius: 15px;
 | |
|             justify-content: space-around; /* Space between form and button */
 | |
|             align-items: center; /* Vertically center */
 | |
|         }
 | |
|         
 | |
|         .right-column {
 | |
|             flex: 1;
 | |
|             background-color: #d3d3d3; /* Grey background */
 | |
|             border-radius: 15px;
 | |
|             justify-content: space-around; /* Space between form and button */
 | |
|             align-items: center; /* Vertically center */
 | |
|             
 | |
|         }
 | |
| 
 | |
|         #bg {
 | |
|             max-width: 100%;
 | |
|             height: auto;
 | |
|             border-radius: 10px;
 | |
|         }
 | |
| 
 | |
|         .status-message {
 | |
|             text-align: center;
 | |
|             margin-top: 20px;
 | |
|             font-size: 18px;
 | |
|             padding: 10px;
 | |
|             border-radius: 5px;
 | |
|             width: 80%;
 | |
|             margin-left: auto;
 | |
|             margin-right: auto;
 | |
|         }
 | |
| 
 | |
|         .success {
 | |
|             color: #155724; /* Dark green */
 | |
|             background-color: #d4edda; /* Light green */
 | |
|             border: 1px solid #c3e6cb;
 | |
|         }
 | |
| 
 | |
|         .error {
 | |
|             color: #721c24; /* Dark red */
 | |
|             background-color: #f8d7da; /* Light red */
 | |
|             border: 1px solid #f5c6cb;
 | |
|         }
 | |
| 
 | |
|         .webcam-btn-active {
 | |
|         background-color: #dc3545; /* Red background */
 | |
|         }
 | |
| 
 | |
|         .mode-txet {
 | |
|             background-color: #1208a7; /* Green background */
 | |
|             border: none;
 | |
|             color: white;
 | |
|             padding: 8px 16px;
 | |
|             text-align: center;
 | |
|             text-decoration: none;
 | |
|             font-size: 16px;
 | |
|             cursor: pointer;
 | |
|             border-radius: 4px;
 | |
|         }
 | |
| 
 | |
|         .select-text {
 | |
|             border: none;
 | |
|             color: rgb(8, 8, 8);
 | |
|             padding: 8px 16px;
 | |
|             text-align: center;
 | |
|             text-decoration: none;
 | |
|             font-size: 16px;
 | |
|             cursor: pointer;
 | |
|             border-radius: 4px;
 | |
|         }
 | |
|         .left-align {
 | |
|             text-align: left;
 | |
|           }
 | |
|           .el-row {
 | |
|             margin-bottom: 20px;
 | |
|         }
 | |
|         .el-col {
 | |
|             border-radius: 4px;
 | |
|         }
 | |
|         .bg-purple-dark {
 | |
|             background: #99a9bf;
 | |
|         }
 | |
|         .bg-purple {
 | |
|             background: #d3dce6;
 | |
|         }
 | |
|         .bg-purple-light {
 | |
|             font-size: 50px;
 | |
|             background: #e5e9f2;
 | |
|         }
 | |
|         .grid-content {
 | |
|             border-radius: 4px;
 | |
|             min-height: 36px;
 | |
|         }
 | |
|         .row-bg {
 | |
|             padding: 10px 0;
 | |
|             background-color: #f9fafc;
 | |
|         }
 | |
|         .custom-input .el-input__inner {
 | |
| 
 | |
|             height: 60px; /* 设置输入部分的高度 */
 | |
|         }
 | |
|         .custom-input {
 | |
|             
 | |
|             height: 60px; /* 设置输入部分的高度 */
 | |
|             font-size: 50px;
 | |
|         }
 | |
| 
 | |
| 
 | |
|     </style>
 | |
| </head>
 | |
| <body>
 | |
|     <!-- <div class="upload-container">
 | |
|         <form id="upload-form" enctype="multipart/form-data">
 | |
|             <button type="button"  class="mode-txet">模式1</button>
 | |
|             <label class="custom-file-label" for="file-input">选择文件</label>
 | |
|             <input id="file-input" class="file-input" type="file" name="file">
 | |
|             <button type="button" onclick="uploadFile()" class="upload-btn-wrapper">上传</button>
 | |
|         </form>
 | |
|         <form id="rtsp-form" enctype="multipart/form-data">
 | |
|             <button type="button"  class="mode-txet">模式2</button>
 | |
|             <button id="turn-off-webcam-btn" onclick="openWebcam()" class="webcam-btn">相机RTSP</button>
 | |
|         </form> -->
 | |
| 
 | |
|         <div class="upload-container" id="el-up">
 | |
|             <h2>算法配置</h2>
 | |
|             <form id="selection-form">
 | |
|                 <button type="button"  class="mode-txet">算法选择</button>
 | |
|                 <select id="dropdown_alg" name="dropdown_alg"  class="select-text">
 | |
|                 <option value="行人检测">行人检测</option>
 | |
|                 <option value="物体检测">物体检测</option>
 | |
|                 <option value="人脸识别">人脸识别</option>
 | |
|                 <option value="OCR">OCR</option>
 | |
|                 </select>
 | |
|                 <button type="button" onclick="submitForm()" class="webcam-btn">确定</button>
 | |
|             </form>
 | |
| 
 | |
|             <form id="selection-form">
 | |
|                 <button type="button" class="mode-txet">摄像机选择</button>
 | |
|                 <select id="dropdown_cam" name="dropdown_cam" class="select-text">
 | |
|                     
 | |
|                 </select>
 | |
|                 <button type="button" onclick="submitCamera()" class="webcam-btn">确定</button>
 | |
|                 
 | |
|             </form>
 | |
| 
 | |
|             <form id="selection-form">
 | |
|                 <button type="button"  class="mode-txet">绊线选择</button>
 | |
|                 <select id="dropdown" name="dropdown"  class="select-text">
 | |
|                 <option value="绊线1">绊线1</option>
 | |
|                 <option value="绊线2">绊线2</option>
 | |
|                 <option value="绊线3">绊线3</option>
 | |
|                 </select>
 | |
|                 <button type="button" onclick="submitForm()" class="webcam-btn">确定</button>
 | |
|             </form>
 | |
| 
 | |
|         </div>
 | |
| 
 | |
|         <div class="upload-container">
 | |
|             <h2>输入源选择</h2>
 | |
|             <form id="upload-form" enctype="multipart/form-data">
 | |
|                 <button type="button"  class="mode-txet">模式1</button>
 | |
|                 <label class="custom-file-label" for="file-input">选择图片或视频</label>
 | |
|                 <input id="file-input" class="file-input" type="file" name="file">
 | |
|                 <button type="button" onclick="uploadFile()" class="upload-btn-wrapper">上传</button>
 | |
|             </form>
 | |
|             <div class="left-align">
 | |
|                 <button type="button" class="mode-txet">模式2</button>
 | |
|                 <button id="turn-off-webcam-btn" onclick="openWebcam()" class="webcam-btn">打开相机RTSP</button>
 | |
|             </div>
 | |
| 
 | |
|         </div>
 | |
| 
 | |
| 
 | |
| 
 | |
|     <div id="upload-status">
 | |
| 
 | |
|     </div>
 | |
|     <div id="message-container" class="status-message"></div>
 | |
| 
 | |
|     <!-- 将检测结果显示在页面上 -->
 | |
|     <div id="fff"> 
 | |
|         <el-row>
 | |
|             <el-col :span="16"><div class="grid-content bg-purple">
 | |
|                 <img id="bg" src="{{url_for('video_feed')}}"> 
 | |
|             </div></el-col>
 | |
|             <el-col :span="8"><div class="grid-content bg-purple-light">
 | |
|                 检到结果:<el-input v-model="numPeople" class="custom-input" ></el-input>
 | |
|                 <!-- 准确率为:<el-input v-model="accuracy" class="custom-input" ></el-input>      -->
 | |
|             </div></el-col>
 | |
|           </el-row>
 | |
|     
 | |
|     </div>
 | |
| 
 | |
| 
 | |
|     <script>
 | |
|         new Vue({
 | |
|             el: '#fff',
 | |
|             data() {
 | |
|                 return{
 | |
|                     numPeople:0,
 | |
|                     accuracy: 1,
 | |
|                 }
 | |
|                 }, 
 | |
|             // 获取检测的人数和检测的准确率
 | |
|             mounted() {
 | |
|                 var that = this
 | |
|                 fetch('/use_webcam')
 | |
|                     .then(response => {
 | |
|                         const reader = response.body.getReader();
 | |
|                         const decoder = new TextDecoder('utf-8');
 | |
| 
 | |
|                         function readStream() {
 | |
|                         let buffer = '';
 | |
|                         let jsonEndIndex; // 声明 jsonEndIndex 变量
 | |
| 
 | |
|                         return reader.read().then(({ done, value }) => {
 | |
|                             if (done) {
 | |
|                             console.log('Stream ended');
 | |
|                             return;
 | |
|                             }
 | |
| 
 | |
|                             buffer += decoder.decode(value);
 | |
| 
 | |
|                             const numPeopleIndex = buffer.indexOf('--num_people');
 | |
|                             
 | |
|                             if (numPeopleIndex !== -1) {
 | |
|                             const jsonStartIndex = buffer.indexOf('\r\n\r\n', numPeopleIndex) + 4;
 | |
|                             jsonEndIndex = buffer.indexOf('\r\n\r\n', jsonStartIndex); // 移除 const
 | |
| 
 | |
|                             const json = buffer.slice(jsonStartIndex, jsonEndIndex);
 | |
| 
 | |
|                             try {
 | |
|                                 //console.log(JSON.parse(json))
 | |
|                                 const { num_people } = JSON.parse(json);
 | |
|                                 that.numPeople = num_people
 | |
|                                 //console.log(that.numPeople);
 | |
|                             } catch (error) {
 | |
|                                 that.numPeople = 0
 | |
|                                 console.error('Invalid JSON:', error);
 | |
|                             }
 | |
|                             }
 | |
| 
 | |
|                             const accuracyIndex = buffer.indexOf('--accuracy');
 | |
|                             if (accuracyIndex !== -1) {
 | |
|                             const jsonStartIndex = buffer.indexOf('\r\n\r\n', accuracyIndex) + 4;
 | |
|                             jsonEndIndex = buffer.indexOf('\r\n\r\n', jsonStartIndex); // 移除 const
 | |
| 
 | |
|                             const json = buffer.slice(jsonStartIndex, jsonEndIndex);
 | |
| 
 | |
|                             try {
 | |
|                                 //console.log(JSON.parse(json))
 | |
|                                 const { accuracy } = JSON.parse(json);
 | |
|                                 that.accuracy = accuracy
 | |
|                                 //console.log(that.accuracy);
 | |
|                             } catch (error) {
 | |
|                                 that.accuracy = 0
 | |
|                                 console.error("Invalid JSON:", error);
 | |
|                             }
 | |
|                             }
 | |
| 
 | |
| 
 | |
|                             // 剩余的数据继续读取
 | |
|                             buffer = buffer.slice(jsonEndIndex + 4);
 | |
|                             return readStream();
 | |
|                         });
 | |
|                         }
 | |
| 
 | |
|                         return readStream();
 | |
|                     })
 | |
|                     .catch(error => console.error('Error:', error));
 | |
|             },
 | |
| 
 | |
| 
 | |
| 
 | |
|         })
 | |
| 
 | |
|                 // Update the label text with the selected file name
 | |
|         document.getElementById('file-input').onchange = function () {
 | |
|         document.querySelector('.custom-file-label').textContent = this.files[0].name;
 | |
|         };
 | |
| 
 | |
|         function loadVideoFeed() {
 | |
|             var videoFeed = document.getElementById('bg');
 | |
|             videoFeed.src = "{{ url_for('video_feed') }}?" + new Date().getTime();
 | |
|         }
 | |
|     
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|         function openWebcam() {
 | |
|             var webcamBtn = document.getElementById('turn-off-webcam-btn');
 | |
|             var videoFeed = document.getElementById('bg');
 | |
|             
 | |
|             if (webcamBtn.innerHTML === '相机RTSP') {
 | |
|                 videoFeed.src = "{{ url_for('use_webcam') }}?" + new Date().getTime();
 | |
|                 webcamBtn.innerHTML = '关闭相机RTSP';
 | |
|                 webcamBtn.classList.add('webcam-btn-active');
 | |
|             } else {
 | |
|                 videoFeed.src = ''; // Turn off the webcam
 | |
|                 webcamBtn.innerHTML = '相机RTSP';
 | |
|                 webcamBtn.classList.remove('webcam-btn-active');
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // 返回选择的算法
 | |
|         function submitForm() {
 | |
|             // 获取选择框的值
 | |
|             var selectedOption = document.getElementById('dropdown_alg').value;
 | |
|             
 | |
|             // 在这里执行您需要的操作,可以使用选定的选项进行相应的处理
 | |
|             alert('您选择了:' + selectedOption);
 | |
|             var formData = new FormData();
 | |
|             formData.append('selectAlgorithm',selectedOption);
 | |
|             fetch('/getSelectAlgorithm', {
 | |
|                     method: 'POST',
 | |
|                     body: formData
 | |
|                 }).then(response => {
 | |
| 
 | |
|                     if (!response.ok) {
 | |
|                         return response.text().then(text => { throw new Error(text || 'Response not OK') });
 | |
|                     }
 | |
| 
 | |
|                 })
 | |
| 
 | |
| 
 | |
|           }
 | |
|         
 | |
|         // 获取数据库的摄像头信息
 | |
|         function getCameraData() {
 | |
|             return new Promise((resolve, reject) => {
 | |
|                 fetch('/getSqlCamera', {
 | |
|                     method: 'GET',
 | |
|                 })
 | |
|                 .then(response => response.json())
 | |
|                 .then(data => {
 | |
|                     resolve(data);
 | |
|                 })
 | |
|                 .catch(error => {
 | |
|                     reject(error);
 | |
|                 });
 | |
|             });
 | |
|         }
 | |
|         // 根据摄像头信息显示摄像头的所有选项
 | |
|         getCameraData().then(data => {
 | |
|             const dropdown = document.getElementById('dropdown_cam');
 | |
|             dropdown.innerHTML = ''; // 清空现有选项
 | |
| 
 | |
|             data.forEach(optionValue => {
 | |
|                 const option = document.createElement('option');
 | |
|                 option.value = optionValue[0];
 | |
|                 option.text = optionValue[2];
 | |
|                 dropdown.appendChild(option);
 | |
|             });
 | |
|         }).catch(error => {
 | |
|             console.error('获取摄像头数据出错:', error);
 | |
|         });
 | |
|         
 | |
|         // 确定选择的摄像头,并传回后端
 | |
|         function submitCamera() {
 | |
|             var selectCamera = document.getElementById('dropdown_cam').value;
 | |
|             
 | |
|             // 在这里执行您需要的操作,可以使用选定的选项进行相应的处理
 | |
|             var formData = new FormData();
 | |
|             formData.append('camID',selectCamera);
 | |
|             fetch('/getFrontCamera', {
 | |
|                     method: 'POST',
 | |
|                     body: formData
 | |
|                 }).then(response => {
 | |
| 
 | |
|                     if (!response.ok) {
 | |
|                         return response.text().then(text => { throw new Error(text || 'Response not OK') });
 | |
|                     }
 | |
| 
 | |
|                 })
 | |
|         }
 | |
|         
 | |
|         function showMessage(message, isError = false) {
 | |
|             var messageDiv = document.getElementById('message-container');
 | |
|             messageDiv.innerHTML = message;
 | |
|             messageDiv.className = isError ? 'status-message error' : 'status-message success';
 | |
| 
 | |
|             // Hide the message after 5 seconds
 | |
|             setTimeout(() => {
 | |
|                 messageDiv.innerHTML = '';
 | |
|                 messageDiv.className = '';
 | |
|             }, 2000);
 | |
|         }
 | |
| 
 | |
|         function uploadFile() {
 | |
|             var formData = new FormData();
 | |
|             var fileInput = document.getElementById('file-input');
 | |
| 
 | |
|             if (fileInput.files.length > 0) {
 | |
|                 formData.append('file', fileInput.files[0]);
 | |
| 
 | |
|                 fetch('/upload', {
 | |
|                         method: 'POST',
 | |
|                         body: formData
 | |
|                     })
 | |
|                     .then(response => {
 | |
|                         if (!response.ok) {
 | |
|                             return response.text().then(text => { throw new Error(text || 'Response not OK') });
 | |
|                         }
 | |
|                         return response.json();
 | |
|                     })
 | |
|                     .then(result => {
 | |
|                         showMessage(result.message);
 | |
|                         if (result.message.includes('uploaded successfully')) {
 | |
|                             loadVideoFeed();
 | |
|                         }
 | |
|                     })
 | |
|                     .catch(error => {
 | |
|                         showMessage('Upload failed: ' + error.message, true);
 | |
|                     });
 | |
| 
 | |
|             } else {
 | |
|                 showMessage('Please select a file first.', true);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     </script>
 | |
| </body>
 | |
| 
 | |
| </html>
 |