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> |