提交
This commit is contained in:
parent
167524b758
commit
dd695cfcca
@ -16,6 +16,10 @@ from flask_cors import CORS
|
||||
import sqlite3
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from flask_socketio import SocketIO, emit
|
||||
import cv2
|
||||
import base64
|
||||
import configparser
|
||||
|
||||
# 添加当前目录到Python路径
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
@ -40,10 +44,16 @@ logger = logging.getLogger(__name__)
|
||||
# 创建Flask应用
|
||||
app = Flask(__name__)
|
||||
app.config['SECRET_KEY'] = 'body-balance-detection-system-2024'
|
||||
socketio = SocketIO(app, cors_allowed_origins='*', async_mode='threading')
|
||||
|
||||
# 启用CORS支持
|
||||
CORS(app, origins=['http://localhost:3000', 'http://localhost:3001', 'file://*'])
|
||||
|
||||
# 读取RTSP配置
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__), 'config.ini'), encoding='utf-8')
|
||||
rtsp_url = config.get('CAMERA', 'rtsp_url', fallback=None)
|
||||
|
||||
# 全局变量
|
||||
db_manager = None
|
||||
device_manager = None
|
||||
@ -51,6 +61,8 @@ detection_engine = None
|
||||
data_processor = None
|
||||
current_detection = None
|
||||
detection_thread = None
|
||||
rtsp_thread = None
|
||||
rtsp_running = False
|
||||
|
||||
def init_app():
|
||||
"""初始化应用"""
|
||||
@ -612,19 +624,57 @@ if __name__ == '__main__':
|
||||
# 初始化应用
|
||||
init_app()
|
||||
|
||||
# 启动Flask服务
|
||||
# 启动Flask+SocketIO服务
|
||||
logger.info('启动后端服务...')
|
||||
app.run(
|
||||
host='127.0.0.1',
|
||||
port=5000,
|
||||
debug=False,
|
||||
threaded=True
|
||||
socketio.run(app,
|
||||
host=config.get('SERVER', 'host', fallback='127.0.0.1'),
|
||||
port=config.getint('SERVER', 'port', fallback=5000),
|
||||
debug=config.getboolean('APP', 'debug', fallback=False),
|
||||
allow_unsafe_werkzeug=True
|
||||
)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info('服务被用户中断')
|
||||
except Exception as e:
|
||||
logger.error(f'服务启动失败: {e}')
|
||||
sys.exit(1)
|
||||
finally:
|
||||
logger.info('后端服务已停止')
|
||||
logger.info('后端服务已停止')
|
||||
|
||||
# ==================== WebSocket 实时推送RTSP帧 ====================
|
||||
|
||||
def generate_rtsp_frames():
|
||||
global rtsp_running
|
||||
cap = cv2.VideoCapture(rtsp_url)
|
||||
if not cap.isOpened():
|
||||
logger.error(f'无法打开RTSP流: {rtsp_url}')
|
||||
return
|
||||
rtsp_running = True
|
||||
while rtsp_running:
|
||||
ret, frame = cap.read()
|
||||
if not ret:
|
||||
logger.warning('RTSP读取帧失败,尝试重连...')
|
||||
cap.release()
|
||||
time.sleep(1)
|
||||
cap = cv2.VideoCapture(rtsp_url)
|
||||
continue
|
||||
_, buffer = cv2.imencode('.jpg', frame)
|
||||
jpg_as_text = base64.b64encode(buffer).decode('utf-8')
|
||||
socketio.emit('rtsp_frame', {'image': jpg_as_text})
|
||||
time.sleep(1/15) # 推送帧率可调
|
||||
cap.release()
|
||||
|
||||
@socketio.on('start_rtsp')
|
||||
def handle_start_rtsp():
|
||||
global rtsp_thread, rtsp_running
|
||||
if rtsp_thread and rtsp_thread.is_alive():
|
||||
emit('rtsp_status', {'status': 'already_running'})
|
||||
return
|
||||
rtsp_thread = threading.Thread(target=generate_rtsp_frames)
|
||||
rtsp_thread.start()
|
||||
emit('rtsp_status', {'status': 'started'})
|
||||
|
||||
@socketio.on('stop_rtsp')
|
||||
def handle_stop_rtsp():
|
||||
global rtsp_running
|
||||
rtsp_running = False
|
||||
emit('rtsp_status', {'status': 'stopped'})
|
@ -39,3 +39,7 @@ secret_key = 026efbf83a2fe101f168780740da86bf1c9260625458e6782738aa9cf18f8e37
|
||||
session_timeout = 3600
|
||||
max_login_attempts = 5
|
||||
|
||||
|
||||
[CAMERA]
|
||||
rtsp_url = rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101
|
||||
|
||||
|
@ -265,7 +265,7 @@ const formatDate = (date) => {
|
||||
|
||||
const loadPatients = async () => {
|
||||
try {
|
||||
const response = await patientAPI.getList()
|
||||
const response = await patientAPI.getPatients()
|
||||
if (response.success) {
|
||||
patients.value = response.data
|
||||
}
|
||||
|
@ -142,13 +142,13 @@
|
||||
<el-table-column prop="rotLeft" label="左" min-width="60" align="center"/>
|
||||
<el-table-column prop="rotRight" label="右" min-width="60" align="center"/>
|
||||
</el-table-column>
|
||||
<el-table-column label="最大旋转角" align="center">
|
||||
<el-table-column prop="rotLeft" label="左" min-width="60" align="center"/>
|
||||
<el-table-column prop="rotRight" label="右" min-width="60" align="center"/>
|
||||
<el-table-column label="最大倾斜角" align="center">
|
||||
<el-table-column prop="tiltLeft" label="左" min-width="60" align="center"/>
|
||||
<el-table-column prop="tiltRight" label="右" min-width="60" align="center"/>
|
||||
</el-table-column>
|
||||
<el-table-column label="最大旋转角" align="center">
|
||||
<el-table-column prop="rotLeft" label="左" min-width="60" align="center"/>
|
||||
<el-table-column prop="rotRight" label="右" min-width="60" align="center"/>
|
||||
<el-table-column label="最大仰视角" align="center">
|
||||
<el-table-column prop="pitchDown" label="下" min-width="60" align="center"/>
|
||||
<el-table-column prop="pitchUp" label="上" min-width="60" align="center"/>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
@ -289,7 +289,7 @@
|
||||
<div class="module-title">视频</div>
|
||||
</div>
|
||||
</div>
|
||||
<video src="@/assets/1.mp4" autoplay style="width: 100%;height: 268px;"></video>
|
||||
<img :src="rtspImgSrc" alt="RTSP视频流" style="width: 100%;height: 268px;object-fit:contain;background:#000;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -298,15 +298,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
ArrowLeft,
|
||||
UserFilled,
|
||||
Clock,
|
||||
Grid,
|
||||
Edit
|
||||
} from '@element-plus/icons-vue'
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { wsManager } from '@/services/api'
|
||||
const router = useRouter()
|
||||
|
||||
const isStart = ref(false)
|
||||
@ -325,6 +319,41 @@ const handleBack = () => {
|
||||
// 可添加路由跳转逻辑
|
||||
console.log('返回上一页')
|
||||
}
|
||||
const rtspImgSrc = ref('')
|
||||
let ws = null
|
||||
|
||||
onMounted(() => {
|
||||
// 使用Socket.IO连接
|
||||
if (window.electronAPI) {
|
||||
window.electronAPI.getBackendUrl().then(url => {
|
||||
// 使用wsManager连接
|
||||
wsManager.connect(url)
|
||||
|
||||
// 监听连接成功事件
|
||||
wsManager.on('connect', () => {
|
||||
console.log('WebSocket连接成功')
|
||||
wsManager.emit('start_rtsp', {})
|
||||
})
|
||||
|
||||
// 监听RTSP帧数据
|
||||
wsManager.on('rtsp_frame', (data) => {
|
||||
if (data.image) {
|
||||
rtspImgSrc.value = 'data:image/jpeg;base64,' + data.image
|
||||
}
|
||||
})
|
||||
|
||||
// 监听连接错误
|
||||
wsManager.on('connect_error', (error) => {
|
||||
console.error('WebSocket连接失败:', error)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
// 停止RTSP并断开连接
|
||||
wsManager.emit('stop_rtsp', {})
|
||||
wsManager.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
Loading…
Reference in New Issue
Block a user