web前备份
This commit is contained in:
144
web.py
144
web.py
@@ -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
|
||||
|
||||
# 启用 OpenCL(Mali-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()
|
||||
Reference in New Issue
Block a user