Compare commits
3 Commits
1b344aeb2e
...
6712a311f8
| Author | SHA1 | Date | |
|---|---|---|---|
| 6712a311f8 | |||
| 294b0e1abb | |||
| 1c7190bbb0 |
@@ -15,6 +15,7 @@ from db.models import get_db
|
||||
from inference.pipeline import get_pipeline
|
||||
|
||||
router = APIRouter(prefix="/api/cameras", tags=["摄像头管理"])
|
||||
router2 = APIRouter(prefix="/api/camera", tags=["摄像头状态"])
|
||||
|
||||
|
||||
class CameraUpdateRequest(BaseModel):
|
||||
@@ -163,3 +164,42 @@ def get_camera_status(camera_id: int, db: Session = Depends(get_db)):
|
||||
"last_check_time": None,
|
||||
"stream": stream_info,
|
||||
}
|
||||
|
||||
|
||||
router2 = APIRouter(prefix="/api/camera", tags=["摄像头状态"])
|
||||
|
||||
|
||||
@router2.get("/status/all")
|
||||
def get_all_camera_status(db: Session = Depends(get_db)):
|
||||
from db.crud import get_all_cameras, get_camera_status as get_status
|
||||
|
||||
cameras = get_all_cameras(db, enabled_only=False)
|
||||
pipeline = get_pipeline()
|
||||
|
||||
result = []
|
||||
for cam in cameras:
|
||||
status = get_status(db, cam.id)
|
||||
|
||||
stream = pipeline.stream_manager.get_stream(str(cam.id))
|
||||
stream_info = stream.get_info() if stream else None
|
||||
|
||||
if status:
|
||||
result.append({
|
||||
"camera_id": cam.id,
|
||||
"is_running": status.is_running,
|
||||
"fps": status.fps,
|
||||
"error_message": status.error_message,
|
||||
"last_check_time": status.last_check_time.isoformat() if status.last_check_time else None,
|
||||
"stream": stream_info,
|
||||
})
|
||||
else:
|
||||
result.append({
|
||||
"camera_id": cam.id,
|
||||
"is_running": False,
|
||||
"fps": 0.0,
|
||||
"error_message": None,
|
||||
"last_check_time": None,
|
||||
"stream": stream_info,
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
11
config.py
11
config.py
@@ -23,16 +23,17 @@ class DatabaseConfig(BaseModel):
|
||||
|
||||
|
||||
class ModelConfig(BaseModel):
|
||||
engine_path: str = "models/yolo11s.engine"
|
||||
onnx_path: str = "models/yolo11s.onnx"
|
||||
pt_model_path: str = "models/yolo11s.pt"
|
||||
engine_path: str = "models/yolo11n.engine"
|
||||
onnx_path: str = "models/yolo11n.onnx"
|
||||
pt_model_path: str = "models/yolo11n.pt"
|
||||
imgsz: List[int] = [640, 640]
|
||||
conf_threshold: float = 0.5
|
||||
iou_threshold: float = 0.45
|
||||
device: int = 0
|
||||
batch_size: int = 8
|
||||
half: bool = True
|
||||
use_onnx: bool = True
|
||||
half: bool = False
|
||||
use_onnx: bool = False
|
||||
use_trt: bool = False
|
||||
|
||||
|
||||
class StreamConfig(BaseModel):
|
||||
|
||||
@@ -24,6 +24,10 @@ const Dashboard: React.FC = () => {
|
||||
const [recentAlerts, setRecentAlerts] = useState<Alert[]>([]);
|
||||
const [cameraStatus, setCameraStatus] = useState<any[]>([]);
|
||||
|
||||
const handleViewSnapshot = (alert: Alert) => {
|
||||
window.open(`/api/alarms/${alert.id}/snapshot`, '_blank');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchStats();
|
||||
fetchAlerts();
|
||||
@@ -139,7 +143,7 @@ const Dashboard: React.FC = () => {
|
||||
description={formatTime(alert.created_at)}
|
||||
/>
|
||||
{alert.snapshot_path && (
|
||||
<Button type="link" size="small">
|
||||
<Button type="link" size="small" onClick={() => handleViewSnapshot(alert)}>
|
||||
查看截图
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -49,6 +49,10 @@ class ONNXEngine:
|
||||
return img
|
||||
|
||||
def postprocess(self, output: np.ndarray, orig_img: np.ndarray) -> List[Results]:
|
||||
import torch
|
||||
import numpy as np
|
||||
from ultralytics.engine.results import Boxes as BoxesObj, Results
|
||||
|
||||
c, n = output.shape
|
||||
output = output.T
|
||||
|
||||
@@ -74,6 +78,9 @@ class ONNXEngine:
|
||||
orig_h, orig_w = orig_img.shape[:2]
|
||||
scale_x, scale_y = orig_w / self.imgsz[1], orig_h / self.imgsz[0]
|
||||
|
||||
if len(indices) == 0:
|
||||
return [Results(orig_img=orig_img, path="", names={0: "person"})]
|
||||
|
||||
filtered_boxes = []
|
||||
for idx in indices:
|
||||
if idx >= len(boxes):
|
||||
@@ -82,30 +89,30 @@ class ONNXEngine:
|
||||
x1, y1, x2, y2 = box
|
||||
w, h = x2 - x1, y2 - y1
|
||||
filtered_boxes.append([
|
||||
int(x1 * scale_x),
|
||||
int(y1 * scale_y),
|
||||
int(w * scale_x),
|
||||
int(h * scale_y),
|
||||
float(x1 * scale_x),
|
||||
float(y1 * scale_y),
|
||||
float(w * scale_x),
|
||||
float(h * scale_y),
|
||||
float(scores[idx]),
|
||||
int(classes[idx])
|
||||
])
|
||||
|
||||
from ultralytics.engine.results import Boxes as BoxesObj
|
||||
if filtered_boxes:
|
||||
box_tensor = torch.tensor(filtered_boxes)
|
||||
boxes_obj = BoxesObj(
|
||||
box_tensor,
|
||||
orig_shape=(orig_h, orig_w)
|
||||
)
|
||||
result = Results(
|
||||
orig_img=orig_img,
|
||||
path="",
|
||||
names={0: "person"},
|
||||
boxes=boxes_obj
|
||||
)
|
||||
return [result]
|
||||
box_array = np.array(filtered_boxes, dtype=np.float32)
|
||||
else:
|
||||
box_array = np.zeros((0, 6), dtype=np.float32)
|
||||
|
||||
return [Results(orig_img=orig_img, path="", names={0: "person"})]
|
||||
boxes_obj = BoxesObj(
|
||||
torch.from_numpy(box_array),
|
||||
orig_shape=(orig_h, orig_w)
|
||||
)
|
||||
result = Results(
|
||||
orig_img=orig_img,
|
||||
path="",
|
||||
names={0: "person"},
|
||||
boxes=boxes_obj
|
||||
)
|
||||
return [result]
|
||||
|
||||
def inference(self, images: List[np.ndarray]) -> List[Results]:
|
||||
if not images:
|
||||
@@ -183,29 +190,21 @@ class TensorRTEngine:
|
||||
self.context = self.engine.create_execution_context()
|
||||
|
||||
self.stream = torch.cuda.Stream(device=self.device)
|
||||
self.batch_size = 1
|
||||
|
||||
for i in range(self.engine.num_io_tensors):
|
||||
name = self.engine.get_tensor_name(i)
|
||||
dtype = self.engine.get_tensor_dtype(name)
|
||||
shape = list(self.engine.get_tensor_shape(name))
|
||||
|
||||
if dtype == trt.float16:
|
||||
buffer = torch.zeros(shape, dtype=torch.float16, device=self.device)
|
||||
else:
|
||||
buffer = torch.zeros(shape, dtype=torch.float32, device=self.device)
|
||||
|
||||
if self.engine.get_tensor_mode(name) == trt.TensorIOMode.INPUT:
|
||||
if -1 in shape:
|
||||
shape = [self.batch_size if d == -1 else d for d in shape]
|
||||
if dtype == trt.float16:
|
||||
buffer = torch.zeros(shape, dtype=torch.float16, device=self.device)
|
||||
else:
|
||||
buffer = torch.zeros(shape, dtype=torch.float32, device=self.device)
|
||||
self.input_buffer = buffer
|
||||
self.input_name = name
|
||||
else:
|
||||
if -1 in shape:
|
||||
shape = [self.batch_size if d == -1 else d for d in shape]
|
||||
if dtype == trt.float16:
|
||||
buffer = torch.zeros(shape, dtype=torch.float16, device=self.device)
|
||||
else:
|
||||
buffer = torch.zeros(shape, dtype=torch.float32, device=self.device)
|
||||
self.output_buffers.append(buffer)
|
||||
if self.output_name is None:
|
||||
self.output_name = name
|
||||
@@ -215,8 +214,6 @@ class TensorRTEngine:
|
||||
stream_handle = torch.cuda.current_stream(self.device).cuda_stream
|
||||
self.context.set_optimization_profile_async(0, stream_handle)
|
||||
|
||||
self.batch_size = 1
|
||||
|
||||
def preprocess(self, frame: np.ndarray) -> torch.Tensor:
|
||||
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
img = cv2.resize(img, self.imgsz)
|
||||
@@ -247,9 +244,6 @@ class TensorRTEngine:
|
||||
self.input_name, input_tensor.contiguous().data_ptr()
|
||||
)
|
||||
|
||||
input_shape = list(input_tensor.shape)
|
||||
self.context.set_input_shape(self.input_name, input_shape)
|
||||
|
||||
torch.cuda.synchronize(self.stream)
|
||||
self.context.execute_async_v3(self.stream.cuda_stream)
|
||||
torch.cuda.synchronize(self.stream)
|
||||
@@ -336,6 +330,10 @@ class Boxes:
|
||||
self.orig_shape = orig_shape
|
||||
self.is_track = is_track
|
||||
|
||||
@property
|
||||
def ndim(self) -> int:
|
||||
return self.data.ndim
|
||||
|
||||
@property
|
||||
def xyxy(self):
|
||||
if self.is_track:
|
||||
@@ -369,35 +367,15 @@ class YOLOEngine:
|
||||
self,
|
||||
model_path: Optional[str] = None,
|
||||
device: int = 0,
|
||||
use_trt: bool = True,
|
||||
use_trt: bool = False,
|
||||
):
|
||||
self.use_trt = False
|
||||
self.onnx_engine = None
|
||||
self.trt_engine = None
|
||||
self.model = None
|
||||
self.device = device
|
||||
config = get_config()
|
||||
|
||||
if use_trt:
|
||||
try:
|
||||
self.trt_engine = TensorRTEngine(device=device)
|
||||
self.trt_engine.warmup()
|
||||
self.use_trt = True
|
||||
print("TensorRT引擎加载成功")
|
||||
return
|
||||
except Exception as e:
|
||||
print(f"TensorRT加载失败: {e}")
|
||||
|
||||
try:
|
||||
onnx_path = config.model.onnx_path
|
||||
if os.path.exists(onnx_path):
|
||||
self.onnx_engine = ONNXEngine(device=device)
|
||||
self.onnx_engine.warmup()
|
||||
print("ONNX引擎加载成功")
|
||||
return
|
||||
else:
|
||||
print(f"ONNX模型不存在: {onnx_path}")
|
||||
except Exception as e:
|
||||
print(f"ONNX加载失败: {e}")
|
||||
self.config = config
|
||||
|
||||
try:
|
||||
pt_path = model_path or config.model.pt_model_path
|
||||
@@ -409,26 +387,17 @@ class YOLOEngine:
|
||||
raise FileNotFoundError(f"PT文件无效或不存在: {pt_path}")
|
||||
except Exception as e:
|
||||
print(f"PyTorch加载失败: {e}")
|
||||
raise RuntimeError("所有模型加载方式均失败")
|
||||
raise RuntimeError("无法加载模型")
|
||||
|
||||
def __call__(self, frame: np.ndarray, **kwargs) -> List[Results]:
|
||||
if self.use_trt and self.trt_engine:
|
||||
if self.model is not None:
|
||||
try:
|
||||
return self.trt_engine.inference_single(frame)
|
||||
return self.model(frame, imgsz=self.config.model.imgsz, conf=self.config.model.conf_threshold, iou=self.config.model.iou_threshold, **kwargs)
|
||||
except Exception as e:
|
||||
print(f"TensorRT推理失败,切换到ONNX: {e}")
|
||||
self.use_trt = False
|
||||
if self.onnx_engine:
|
||||
return self.onnx_engine.inference_single(frame)
|
||||
elif self.model:
|
||||
return self.model(frame, imgsz=get_config().model.imgsz, **kwargs)
|
||||
else:
|
||||
return []
|
||||
elif self.onnx_engine:
|
||||
return self.onnx_engine.inference_single(frame)
|
||||
else:
|
||||
results = self.model(frame, imgsz=get_config().model.imgsz, **kwargs)
|
||||
return results
|
||||
print(f"PyTorch推理失败: {e}")
|
||||
|
||||
print("警告: 模型不可用,返回空结果")
|
||||
return []
|
||||
|
||||
def __del__(self):
|
||||
if self.trt_engine:
|
||||
|
||||
@@ -7,6 +7,7 @@ from collections import deque
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from config import get_config
|
||||
@@ -322,20 +323,23 @@ class InferencePipeline:
|
||||
print("推理pipeline已停止")
|
||||
|
||||
def get_status(self) -> Dict[str, Any]:
|
||||
return {
|
||||
result = {
|
||||
"running": self.running,
|
||||
"camera_count": len(self.camera_threads),
|
||||
"cameras": {
|
||||
cid: {
|
||||
"running": self.camera_stop_events[cid] is not None and not self.camera_stop_events[cid].is_set(),
|
||||
"fps": self.get_camera_fps(cid),
|
||||
"frame_time": self.camera_frame_times.get(cid).isoformat() if self.camera_frame_times.get(cid) else None,
|
||||
}
|
||||
for cid in self.camera_threads
|
||||
},
|
||||
"cameras": {},
|
||||
"event_queue_size": len(self.event_queue),
|
||||
}
|
||||
|
||||
for cid in self.camera_threads:
|
||||
frame_time = self.camera_frame_times.get(cid)
|
||||
result["cameras"][str(cid)] = {
|
||||
"is_running": self.camera_stop_events[cid] is not None and not self.camera_stop_events[cid].is_set(),
|
||||
"fps": self.get_camera_fps(cid),
|
||||
"last_check_time": frame_time.isoformat() if frame_time else None,
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
_pipeline: Optional[InferencePipeline] = None
|
||||
|
||||
|
||||
106
logs/app.log
106
logs/app.log
@@ -133,3 +133,109 @@
|
||||
2026-01-21 13:18:55,795 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 13:18:55,809 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 13:19:08,492 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:01:21,015 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:01:21,257 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:03:48,547 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:03:48,563 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:04:01,197 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:04:20,191 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:04:20,414 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:05:48,342 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:05:48,355 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:06:00,984 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:07:24,065 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:07:24,222 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:08:10,073 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:08:10,088 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:08:22,715 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:09:05,249 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:09:05,480 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:11:29,491 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:11:29,513 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:11:42,900 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:14:04,974 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:14:05,161 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:14:41,203 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:14:41,220 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:14:54,380 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:15:30,975 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:15:31,180 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:16:24,472 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:16:24,485 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:16:37,611 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:17:01,178 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:17:01,420 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:18:00,008 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:18:00,022 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:18:13,126 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:18:13,128 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:18:21,683 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:20:04,985 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:20:04,999 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:20:18,151 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:21:24,782 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:21:24,927 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:22:48,064 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:22:48,078 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:23:01,270 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:23:13,509 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:23:13,628 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:24:16,374 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:24:16,386 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:24:29,425 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:24:42,751 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:24:42,846 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:25:25,549 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:25:25,562 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:25:38,636 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:26:02,871 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:26:03,124 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:26:45,885 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:26:45,899 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:26:59,042 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:27:26,873 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:27:26,980 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:31:38,376 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:31:38,390 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:31:51,594 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:32:17,471 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:32:17,536 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:32:53,841 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:32:53,855 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:33:06,946 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:34:30,645 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:34:30,818 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:38:24,673 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:38:24,685 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:38:37,183 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:39:04,359 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:39:04,486 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:40:07,246 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:40:07,259 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:40:19,745 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 14:40:33,742 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 14:40:33,863 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 14:41:27,191 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 14:41:27,205 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 14:41:39,701 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 15:03:14,674 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 15:03:14,688 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 15:03:27,230 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 15:06:28,976 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 15:06:28,990 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 15:06:41,537 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 15:06:41,539 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 15:06:49,686 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 15:07:27,870 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 15:07:27,884 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 15:07:40,380 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 15:07:58,160 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 15:07:58,299 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 15:08:28,521 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 15:08:28,533 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 15:08:41,019 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
2026-01-21 15:09:16,894 - security_monitor - INFO - 正在关闭系统...
|
||||
2026-01-21 15:09:17,139 - security_monitor - INFO - 系统已关闭
|
||||
2026-01-21 15:09:41,042 - security_monitor - INFO - 启动安保异常行为识别系统
|
||||
2026-01-21 15:09:41,055 - security_monitor - INFO - 数据库初始化完成
|
||||
2026-01-21 15:09:53,555 - security_monitor - INFO - 推理Pipeline启动,活跃摄像头数: 2
|
||||
|
||||
35
main.py
35
main.py
@@ -11,15 +11,28 @@ os.environ["TENSORRT_DISABLE_MYELIN"] = "1"
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi import FastAPI, HTTPException, Depends
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, StreamingResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from prometheus_client import start_http_server
|
||||
|
||||
from db.models import get_db
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from ultralytics.engine.results import Boxes as UltralyticsBoxes
|
||||
|
||||
def _patch_boxes_ndim():
|
||||
if not hasattr(UltralyticsBoxes, 'ndim'):
|
||||
@property
|
||||
def ndim(self):
|
||||
return self.data.ndim
|
||||
UltralyticsBoxes.ndim = ndim
|
||||
_patch_boxes_ndim()
|
||||
|
||||
from api.alarm import router as alarm_router
|
||||
from api.camera import router as camera_router
|
||||
from api.camera import router as camera_router, router2 as camera_status_router
|
||||
from api.roi import router as roi_router
|
||||
from api.sync import router as sync_router
|
||||
from config import get_config, load_config
|
||||
@@ -82,6 +95,7 @@ app.add_middleware(
|
||||
)
|
||||
|
||||
app.include_router(camera_router)
|
||||
app.include_router(camera_status_router)
|
||||
app.include_router(roi_router)
|
||||
app.include_router(alarm_router)
|
||||
app.include_router(sync_router)
|
||||
@@ -134,6 +148,23 @@ async def get_snapshot_base64(camera_id: int):
|
||||
return {"image": base64.b64encode(buffer).decode("utf-8")}
|
||||
|
||||
|
||||
@app.get("/api/alarms/{alarm_id}/snapshot")
|
||||
async def get_alarm_snapshot(alarm_id: int, db: Session = Depends(get_db)):
|
||||
from db.models import Alarm
|
||||
|
||||
alarm = db.query(Alarm).filter(Alarm.id == alarm_id).first()
|
||||
if not alarm:
|
||||
raise HTTPException(status_code=404, detail="告警不存在")
|
||||
|
||||
if not alarm.snapshot_path:
|
||||
raise HTTPException(status_code=404, detail="该告警没有截图")
|
||||
|
||||
if not os.path.exists(alarm.snapshot_path):
|
||||
raise HTTPException(status_code=404, detail="截图文件不存在")
|
||||
|
||||
return FileResponse(alarm.snapshot_path, media_type="image/jpeg")
|
||||
|
||||
|
||||
@app.get("/api/camera/{camera_id}/detect")
|
||||
async def get_detection_with_overlay(camera_id: int):
|
||||
pipeline = get_pipeline()
|
||||
|
||||
Reference in New Issue
Block a user