web前备份

This commit is contained in:
2025-12-23 09:18:32 +08:00
parent d8b28c238b
commit 4961794bf5
26 changed files with 1124 additions and 232 deletions

144
web.py
View File

@@ -12,6 +12,18 @@ sys.path.append(os.path.dirname(__file__)) # 确保能导入 py_utils
from py_utils.coco_utils import COCO_test_helper
from py_utils.rknn_executor import RKNN_model_container # 假设使用 RKNN
from mjpeg_streamer import MJPEGServer
from multiprocessing import Pool, Manager
import cv2
# 启用 OpenCLMali-G610
if cv2.ocl.haveOpenCL():
cv2.ocl.setUseOpenCL(True)
print("✅ OpenCL is ON — using Mali-G610 GPU for acceleration")
else:
print("⚠️ OpenCL not available")
# ------YOLO 配置-----------
@@ -30,6 +42,30 @@ with open(ANCHORS_FILE, 'r') as f:
ANCHORS = np.array(values).reshape(3, -1, 2).tolist()
import threading
import numpy as np
class SharedFrameBuffer:
def __init__(self):
self._frame = None
self._lock = threading.Lock()
self._has_frame = False
def update(self, frame: np.ndarray):
"""主线程调用:更新最新帧"""
with self._lock:
self._frame = frame.copy()
self._has_frame = True
def get_frame(self):
"""YUYV 线程调用:获取最新帧"""
with self._lock:
if self._has_frame and self._frame is not None:
return True, self._frame.copy()
else:
return False, None
# ---------- YOLO 处理函数 ----------
def filter_boxes(boxes, box_confidences, box_class_probs):
box_confidences = box_confidences.reshape(-1)
@@ -44,6 +80,7 @@ def filter_boxes(boxes, box_confidences, box_class_probs):
return boxes, classes, scores
def nms_boxes(boxes, scores):
x = boxes[:, 0]
y = boxes[:, 1]
@@ -125,6 +162,7 @@ def post_process(input_data, anchors):
boxes, classes, scores = filter_boxes(boxes, scores, classes_conf)
nboxes, nclasses, nscores = [], [], []
for c in set(classes):
inds = np.where(classes == c)
b = boxes[inds]
@@ -207,11 +245,12 @@ class MultiCameraBirdView:
print("[INFO] 初始化摄像头...")
for name in self.names:
cap = cv2.VideoCapture(self.which_cameras[name], cv2.CAP_ANY)
cap = cv2.VideoCapture(self.which_cameras[name], cv2.CAP_V4L2)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"YUYV"))
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 最小缓冲,降低延迟
# cap.set(cv2.CAP_PROP_FPS, 30) # 设置帧率为 30 FPS
if not cap.isOpened():
print(f"[ERROR] 无法打开 {name} 摄像头 (设备 {self.which_cameras[name]})", file=sys.stderr)
self.running = False
@@ -239,6 +278,8 @@ class MultiCameraBirdView:
except Exception as e:
print(f"[ERROR] YOLO 模型加载失败: {e}")
self.yolo_model = None
self.shared_buffer = SharedFrameBuffer() # 👈 新增
def overlay_alert(self, birdview_img):
"""在鸟瞰图上叠加半透明红色预警区域"""
@@ -265,6 +306,7 @@ class MultiCameraBirdView:
return blended
def detect_persons(self, image):
"""使用YOLO模型检测图像中的人体"""
if self.yolo_model is None:
return image, [], []
@@ -280,7 +322,7 @@ class MultiCameraBirdView:
new_shape=(IMG_SIZE[1], IMG_SIZE[0]),
pad_color=pad_color
)
img_preprocessed = cv2.cvtColor(img_preprocessed, cv2.COLOR_BGR2RGB)
# img_preprocessed = cv2.cvtColor(img_preprocessed, cv2.COLOR_BGR2RGB)
# 推理
outputs = self.yolo_model.run([np.expand_dims(img_preprocessed, 0)])
@@ -354,7 +396,7 @@ class MultiCameraBirdView:
return frame
def process_frame_undistort(self, frame, model):
"""只处理一次:去畸变 + 投影 + 翻转"""
"""只处理一次:去畸变"""
frame = model.undistort(frame)
return frame
@@ -366,20 +408,18 @@ class MultiCameraBirdView:
while self.running:
raw_frames = {}
processed_frames = []
valid = True
for i, (cap, model, name) in enumerate(zip(self.caps, self.camera_models, self.names)):
ret, frame = cap.read()
if not ret or frame is None:
print(f"[WARN] 跳过 {name}")
valid = False
break
raw_frames[name] = frame.copy()
raw_frames[name] = frame
# self.shared_buffer.update(raw_frames[current_view])
p_frame = self.process_frame_once(frame, model)
processed_frames.append(p_frame)
if not valid or len(processed_frames) != 4:
continue
# 更新鸟瞰图
self.birdview.update_frames(processed_frames)
@@ -394,6 +434,7 @@ class MultiCameraBirdView:
)
# 在单路图像上进行人体检测
frame_count += 1
if frame_count % detection_interval == 0 and self.yolo_model is not None:
single_img, person_boxes, person_scores = self.detect_persons(single_img)
@@ -401,7 +442,7 @@ class MultiCameraBirdView:
# 根据检测结果自动触发预警
if person_boxes:
# 可以根据人体的位置和数量来触发预警
# 这里简单示例:只要检测到人就触发当前视图的预警
self.alerts[current_view] = True
# 重置其他视图的预警
for view in self.alerts:
@@ -411,11 +452,10 @@ class MultiCameraBirdView:
# 没有检测到人,清除所有预警
for view in self.alerts:
self.alerts[view] = False
birdview_img = self.birdview.image.copy()
# 叠加预警区域
birdview_with_alert = self.overlay_alert(birdview_img)
birdview_with_alert = self.overlay_alert(self.birdview.image)
# 拼接显示左侧鸟瞰图1/3右侧单路2/3
h_display, w_display = 720, 1280
@@ -426,10 +466,13 @@ class MultiCameraBirdView:
single_resized = cv2.resize(single_img, (w_single, h_display))
display = np.hstack((bird_resized, single_resized))
# 在显示窗口上添加状态信息
info_text = f"View: {current_view} | Persons detected: {len(person_boxes) if 'person_boxes' in locals() else 0}"
cv2.putText(display, info_text, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
# info_text = f"View: {current_view} | Persons detected: {len(person_boxes) if 'person_boxes' in locals() else 0}"
# cv2.putText(display, info_text, (10, 30),
# cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
# 全屏显示
cv2.namedWindow('Video', cv2.WND_PROP_FULLSCREEN)
@@ -437,33 +480,33 @@ class MultiCameraBirdView:
cv2.imshow("Video", display)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
self.running = False
break
elif key == ord('1'):
current_view = "front"
elif key == ord('2'):
current_view = "back"
elif key == ord('3'):
current_view = "left"
elif key == ord('4'):
current_view = "right"
# 新增:预警控制
elif key == ord('5'):
self.alerts["front"] = True
elif key == ord('6'):
self.alerts["back"] = True
elif key == ord('7'):
self.alerts["left"] = True
elif key == ord('8'):
self.alerts["right"] = True
elif key == ord('0'):
# 清除所有预警
for k in self.alerts:
self.alerts[k] = False
elif key == ord('d'):
# 手动触发一次检测
single_img, person_boxes, person_scores = self.detect_persons(single_img)
# if key == ord('q'):
# self.running = False
# break
# elif key == ord('1'):
# current_view = "front"
# elif key == ord('2'):
# current_view = "back"
# elif key == ord('3'):
# current_view = "left"
# elif key == ord('4'):
# current_view = "right"
# # 新增:预警控制
# elif key == ord('5'):
# self.alerts["front"] = True
# elif key == ord('6'):
# self.alerts["back"] = True
# elif key == ord('7'):
# self.alerts["left"] = True
# elif key == ord('8'):
# self.alerts["right"] = True
# elif key == ord('0'):
# # 清除所有预警
# for k in self.alerts:
# self.alerts[k] = False
# elif key == ord('d'):
# # 手动触发一次检测
# single_img, person_boxes, person_scores = self.detect_persons(single_img)
for cap in self.caps:
cap.release()
@@ -478,12 +521,21 @@ def main():
print(" 0 : 清除所有预警")
print(" d : 手动触发人体检测")
print(" q : 退出程序")
multi_cam = MultiCameraBirdView()
# ===== 启动视频流 =====
try:
from mjpeg_streamer import MJPEGServer
mjpeg_server = MJPEGServer(multi_cam.shared_buffer, host="0.0.0.0", port=8080)
mjpeg_server.start()
except Exception as e:
print(f"[WARN] YUYV 流启动失败: {e}")
if multi_cam.running:
multi_cam.run()
else:
print("[ERROR] 摄像头初始化失败")
if __name__ == "__main__":
main()