129 lines
4.2 KiB
Python
129 lines
4.2 KiB
Python
# realtime_from_gui_logic.py
|
||
import cv2
|
||
import time
|
||
import threading
|
||
from threading import Lock
|
||
import obb_angle # 确保可导入
|
||
|
||
# =============== 完全复制自你 GUI 中验证有效的 VideoStream ===============
|
||
class VideoStream:
|
||
def __init__(self, rtsp_url, name="Stream"):
|
||
self.rtsp_url = rtsp_url
|
||
self.name = name
|
||
self.cap = None
|
||
self.frame = None
|
||
self.timestamp = 0
|
||
self.lock = Lock()
|
||
self.running = False
|
||
self.thread = None
|
||
|
||
def start(self):
|
||
self.running = True
|
||
self.thread = threading.Thread(target=self.update, args=(), daemon=True)
|
||
self.thread.start()
|
||
return self
|
||
|
||
def update(self):
|
||
while self.running:
|
||
if self.cap is None or not self.cap.isOpened():
|
||
print(f"[{self.name}] 正在连接 RTSP: {self.rtsp_url}")
|
||
try:
|
||
# 关键:显式使用 CAP_FFMPEG
|
||
self.cap = cv2.VideoCapture(self.rtsp_url, cv2.CAP_FFMPEG)
|
||
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||
self.cap.set(cv2.CAP_PROP_TCP_NODELAY, 1)
|
||
# 可选:强制设置解码器(某些平台需要)
|
||
# self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('H', '2', '6', '4'))
|
||
except Exception as e:
|
||
print(f"[{self.name}] 连接失败: {e}")
|
||
time.sleep(1)
|
||
continue
|
||
|
||
ret, frame = self.cap.read()
|
||
if ret:
|
||
with self.lock:
|
||
self.frame = frame.copy()
|
||
self.timestamp = time.time()
|
||
else:
|
||
print(f"[{self.name}] 读取失败,准备重连...")
|
||
if self.cap:
|
||
self.cap.release()
|
||
self.cap = None
|
||
time.sleep(1)
|
||
|
||
def read(self):
|
||
with self.lock:
|
||
if self.frame is not None and (time.time() - self.timestamp) < 1.5:
|
||
return self.frame.copy()
|
||
else:
|
||
return None
|
||
|
||
def stop(self):
|
||
self.running = False
|
||
if self.thread is not None:
|
||
self.thread.join(timeout=2)
|
||
if self.cap is not None:
|
||
self.cap.release()
|
||
print(f"[{self.name}] 视频流已停止")
|
||
|
||
|
||
# =============== 主程序 ===============
|
||
if __name__ == "__main__":
|
||
RTSP_URL = "rtsp://admin:XJ123456@192.168.250.60:554/streaming/channels/101"
|
||
MODEL_PATH = "./obb.rknn"
|
||
|
||
# 设置 obb_angle 行为
|
||
obb_angle.DRAW_RESULT = True
|
||
obb_angle.SAVE_PATH = None
|
||
|
||
# 启动流(和 GUI 完全一致)
|
||
stream = VideoStream(RTSP_URL, "Camera01").start()
|
||
print("🚀 使用 GUI 验证过的实时流逻辑启动...")
|
||
|
||
last_time = time.time()
|
||
window_name = "Realtime OBB - From GUI Logic"
|
||
cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
|
||
cv2.resizeWindow(window_name, 800, 600) # 宽 800,高 600
|
||
|
||
try:
|
||
while True:
|
||
frame = stream.read()
|
||
if frame is None:
|
||
time.sleep(0.01)
|
||
continue
|
||
|
||
# 上下翻转
|
||
frame = cv2.flip(frame, 0)
|
||
|
||
# 推理
|
||
angle_result, vis_frame = obb_angle.detect_two_box_angle(MODEL_PATH, frame)
|
||
|
||
# 打印角度
|
||
if angle_result is not None:
|
||
if isinstance(angle_result, (list, tuple)) and len(angle_result) >= 2:
|
||
a1, a2 = angle_result[0], angle_result[1]
|
||
diff = abs(a1 - a2)
|
||
diff = min(diff, 360 - diff)
|
||
print(f"Box1: {a1:.1f}°, Box2: {a2:.1f}°, 夹角: {diff:.1f}°")
|
||
else:
|
||
print(f"角度: {angle_result:.1f}°")
|
||
else:
|
||
print("未检测到目标")
|
||
|
||
# 显示(窗口已提前创建并设好大小)
|
||
cv2.imshow(window_name, vis_frame)
|
||
|
||
# FPS 估算0
|
||
curr_time = time.time()
|
||
fps = 1.0 / (curr_time - last_time + 1e-6)
|
||
last_time = curr_time
|
||
print(f"FPS: {fps:.1f}")
|
||
if cv2.waitKey(1) == ord('q'):
|
||
|
||
break
|
||
|
||
except KeyboardInterrupt:
|
||
pass
|
||
finally:
|
||
stream.stop()
|
||
cv2.destroyAllWindows() |