algorithm_system_server/index copy.html

571 lines
20 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 id="app">
<div class="upload-container" id="el-up">
<h2>算法配置</h2>
<form id="selection-form">
<button type="button" class="mode-txet">算法选择</button>
<el-select v-model="selectValue" placeholder="行人检测">
<el-option
v-for="item in options"
:key="item[0]"
:label="item[1]"
:value="item[1]">
</el-option>
</el-select>
<el-button type="success" @click="submitForm"> 确定</el-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> -->
<el-button @click="uploadFile">上传</el-button>
</form>
<div class="left-align">
<el-row>
<button type="button" class="mode-txet">模式2</button>
<el-button ref="webcam-btn" id="turn-on-webcam-btn" @click="openWebcam()" type="primary">打开相机RTSP</el-button>
</el-row>
</div>
</div>
<div id="upload-status">
</div>
<div id="message-container" class="status-message"></div>
<!-- 将检测结果显示在页面上 -->
<div>
<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>
</div></el-col>
</el-row>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return{
numPeople:100,
accuracy: 1,
getUseCam: false,
getUseVideo: false,
options: [],
selectValue: ''
}
},
created() {
this.fetchAlgData()
},
methods: {
openWebcam() {
var webcamBtn = document.getElementById('turn-on-webcam-btn');
var videoFeed = document.getElementById('bg');
var formData = new FormData();
var that = this
if (webcamBtn.innerHTML === '打开相机RTSP') {
that.getUseCam = true;
//console.log(that.getUseCam+'相机RTSP');
videoFeed.src = "{{ url_for('use_webcam') }}?" + new Date().getTime();
webcamBtn.innerHTML = '关闭相机RTSP';
webcamBtn.classList.add('webcam-btn-active');
} else {
that.getUseCam = false;
videoFeed.src = ''; // Turn off the webcam
that.numPeople = 100;
webcamBtn.innerHTML = '相机RTSP';
//console.log(that.getUseCam+'相机1RTSP');
webcamBtn.classList.remove('webcam-btn-active');
}
if(that.getUseCam == true){
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 || that.getUseCam == false) {
that.numPeople = 100;
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);
}
}
// 剩余的数据继续读取
buffer = buffer.slice(jsonEndIndex + 4);
return readStream();
});
}
return readStream();
})
.catch(error => console.error('Error:', error)
);
}
},
async fetchAlgData() {
const response = await fetch('/getSqlAlg', {method:'Get'});
const data = await response.json();
this.options = data;
this.selectValue = this.options[0][1];
},
submitForm() {
// console.log(this.selectValue);
var formData = new FormData();
formData.append('selectAlgorithm',this.selectValue);
fetch('/getSelectAlgorithm', {
method: 'POST',
body: formData
}).then(response => {
if (!response.ok) {
return response.text().then(text => { throw new Error(text || 'Response not OK') });
}
})
},
uploadFile() {
var formData = new FormData();
var fileInput = document.getElementById('file-input');
var that = this;
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')) {
that.loadVideoFeed();
}
})
.catch(error => {
showMessage('Upload failed: ' + error.message, true);
});
} else {
showMessage('Please select a file first.', true);
}
},
loadVideoFeed() {
var that = this;
var videoFeed = document.getElementById('bg');
videoFeed.src = "{{ url_for('video_feed') }}?" + new Date().getTime();
that.getUseVideo = true;
// console.log(that.getUseVideo)
if(that.getUseVideo == true){
fetch('/video_feed')
.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 || that.getUseVideo == false) {
that.numPeople = 100;
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);
}
}
// 剩余的数据继续读取
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 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);
}
</script>
</body>
</html>