|
@@ -8,11 +8,13 @@ import time
|
|
|
import json
|
|
import json
|
|
|
import threading
|
|
import threading
|
|
|
import queue
|
|
import queue
|
|
|
|
|
+import tempfile
|
|
|
import requests
|
|
import requests
|
|
|
import http.client
|
|
import http.client
|
|
|
import mimetypes
|
|
import mimetypes
|
|
|
from typing import Optional, Dict, Any, List
|
|
from typing import Optional, Dict, Any, List
|
|
|
from dataclasses import dataclass
|
|
from dataclasses import dataclass
|
|
|
|
|
+from datetime import datetime
|
|
|
from enum import Enum
|
|
from enum import Enum
|
|
|
from codecs import encode
|
|
from codecs import encode
|
|
|
|
|
|
|
@@ -80,6 +82,12 @@ class EventPusher:
|
|
|
self.api_port = self.config.get('api_port', 8583)
|
|
self.api_port = self.config.get('api_port', 8583)
|
|
|
self.use_https = self.config.get('use_https', True)
|
|
self.use_https = self.config.get('use_https', True)
|
|
|
|
|
|
|
|
|
|
+ # 基础 URL(优先使用配置中的 base_url)
|
|
|
|
|
+ self.base_url = self.config.get('base_url')
|
|
|
|
|
+ if not self.base_url:
|
|
|
|
|
+ protocol = 'https' if self.use_https else 'http'
|
|
|
|
|
+ self.base_url = f"{protocol}://{self.api_host}:{self.api_port}"
|
|
|
|
|
+
|
|
|
# 上传接口
|
|
# 上传接口
|
|
|
self.upload_url = self.config.get('upload_url', '/api/resource/oss/upload')
|
|
self.upload_url = self.config.get('upload_url', '/api/resource/oss/upload')
|
|
|
self.event_url = self.config.get('event_url', '/api/system/event')
|
|
self.event_url = self.config.get('event_url', '/api/system/event')
|
|
@@ -180,6 +188,82 @@ class EventPusher:
|
|
|
self.push_event(event)
|
|
self.push_event(event)
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
|
|
|
+ def upload_numpy_image(self, image: np.ndarray) -> Optional[str]:
|
|
|
|
|
+ """
|
|
|
|
|
+ 将 numpy 图片上传到 OSS
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ image: numpy 图像数组
|
|
|
|
|
+
|
|
|
|
|
+ Returns:
|
|
|
|
|
+ 图片URL或None
|
|
|
|
|
+ """
|
|
|
|
|
+ if image is None:
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ temp_path = None
|
|
|
|
|
+ try:
|
|
|
|
|
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as f:
|
|
|
|
|
+ temp_path = f.name
|
|
|
|
|
+
|
|
|
|
|
+ cv2.imwrite(temp_path, image)
|
|
|
|
|
+ url = self._upload_image(temp_path)
|
|
|
|
|
+ return url
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"上传 numpy 图片失败: {e}")
|
|
|
|
|
+ return None
|
|
|
|
|
+ finally:
|
|
|
|
|
+ if temp_path:
|
|
|
|
|
+ try:
|
|
|
|
|
+ os.remove(temp_path)
|
|
|
|
|
+ except Exception:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ def push_tracking_capture(self, batch_time: float, captures: List[dict]):
|
|
|
|
|
+ """
|
|
|
|
|
+ 推送一轮多目标跟踪抓拍事件
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ batch_time: 批次时间戳
|
|
|
|
|
+ captures: 抓拍记录列表
|
|
|
|
|
+
|
|
|
|
|
+ Returns:
|
|
|
|
|
+ 响应对象或None
|
|
|
|
|
+ """
|
|
|
|
|
+ payload = {
|
|
|
|
|
+ "eventType": "TRACKING_CAPTURE",
|
|
|
|
|
+ "eventTime": datetime.fromtimestamp(batch_time).isoformat(),
|
|
|
|
|
+ "deviceId": self.config.get("device_id"),
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "captureCount": len(captures),
|
|
|
|
|
+ "captures": captures,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ url = f"{self.base_url}{self.event_url}"
|
|
|
|
|
+ return self._post(url, payload)
|
|
|
|
|
+
|
|
|
|
|
+ def _post(self, url: str, json_data: dict):
|
|
|
|
|
+ """
|
|
|
|
|
+ 发送 POST 请求
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ url: 请求URL
|
|
|
|
|
+ json_data: JSON数据
|
|
|
|
|
+
|
|
|
|
|
+ Returns:
|
|
|
|
|
+ 响应对象或None
|
|
|
|
|
+ """
|
|
|
|
|
+ for attempt in range(self.retry_count):
|
|
|
|
|
+ try:
|
|
|
|
|
+ response = requests.post(url, json=json_data, verify=False, timeout=10)
|
|
|
|
|
+ return response
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"POST 请求异常 (尝试 {attempt + 1}/{self.retry_count}): {e}")
|
|
|
|
|
+ if attempt < self.retry_count - 1:
|
|
|
|
|
+ time.sleep(self.retry_delay)
|
|
|
|
|
+
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
def _worker(self):
|
|
def _worker(self):
|
|
|
"""工作线程"""
|
|
"""工作线程"""
|
|
|
while self.running:
|
|
while self.running:
|