feat: 2.17.18
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
id: t11
|
id: t11
|
||||||
name: t11
|
name: t11
|
||||||
version: 2.17.15
|
version: 2.17.18
|
||||||
author: t11
|
author: t11
|
||||||
icon: ''
|
icon: ''
|
||||||
desc: t11
|
desc: t11
|
||||||
|
|||||||
+1
-26
@@ -8,15 +8,6 @@ import threading
|
|||||||
import config
|
import config
|
||||||
from logger_manager import logger_manager
|
from logger_manager import logger_manager
|
||||||
|
|
||||||
_USE_CV = False
|
|
||||||
try:
|
|
||||||
import cv2
|
|
||||||
import numpy as np
|
|
||||||
from maix import image as _maix_image
|
|
||||||
_USE_CV = True
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CameraManager:
|
class CameraManager:
|
||||||
"""相机管理器(单例)"""
|
"""相机管理器(单例)"""
|
||||||
@@ -110,23 +101,7 @@ class CameraManager:
|
|||||||
with self._camera_lock:
|
with self._camera_lock:
|
||||||
if self._camera is None:
|
if self._camera is None:
|
||||||
self.init_camera()
|
self.init_camera()
|
||||||
frame = self._camera.read()
|
return self._camera.read()
|
||||||
if frame is not None and _USE_CV:
|
|
||||||
try:
|
|
||||||
v_flip = getattr(config, 'CAMERA_V_FLIP', False)
|
|
||||||
h_mirror = getattr(config, 'CAMERA_H_MIRROR', False)
|
|
||||||
if v_flip or h_mirror:
|
|
||||||
img_cv = _maix_image.image2cv(frame, False, False)
|
|
||||||
if v_flip and h_mirror:
|
|
||||||
img_cv = cv2.flip(img_cv, -1)
|
|
||||||
elif v_flip:
|
|
||||||
img_cv = cv2.flip(img_cv, 0)
|
|
||||||
elif h_mirror:
|
|
||||||
img_cv = cv2.flip(img_cv, 1)
|
|
||||||
frame = _maix_image.cv2image(img_cv, False, False)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return frame
|
|
||||||
|
|
||||||
def show(self, image):
|
def show(self, image):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ LOCAL_FILENAME = APP_DIR + "/main_tmp.py"
|
|||||||
# 相机初始化分辨率(CameraManager / main.py 使用)
|
# 相机初始化分辨率(CameraManager / main.py 使用)
|
||||||
CAMERA_WIDTH = 640
|
CAMERA_WIDTH = 640
|
||||||
CAMERA_HEIGHT = 480
|
CAMERA_HEIGHT = 480
|
||||||
CAMERA_V_FLIP = True # 摄像头垂直翻转(上下颠倒时设为 True)
|
|
||||||
CAMERA_H_MIRROR = True # 摄像头水平镜像(左右反了时设为 True)
|
|
||||||
|
|
||||||
# 三角形检测缩图比例:默认按相机最长边缩到 1/2(性能更稳;可按需调整)
|
# 三角形检测缩图比例:默认按相机最长边缩到 1/2(性能更稳;可按需调整)
|
||||||
# 取值范围建议 (0.25 ~ 1.0];1.0 表示不缩图
|
# 取值范围建议 (0.25 ~ 1.0];1.0 表示不缩图
|
||||||
@@ -329,16 +327,16 @@ MAX_CMD_THREADS = 10 # 并发命令线程上限(防止服务器下
|
|||||||
|
|
||||||
# ==================== 图像保存配置 ====================
|
# ==================== 图像保存配置 ====================
|
||||||
SAVE_IMAGE_ENABLED = True # 是否保存图像(True=保存,False=不保存)
|
SAVE_IMAGE_ENABLED = True # 是否保存图像(True=保存,False=不保存)
|
||||||
SAVE_IMAGE_ON_FAILURE = False # 检测失败时是否强制保存图像(供调试测试用)
|
SAVE_IMAGE_ON_FAILURE = True # 检测失败时是否强制保存图像(供调试测试用)
|
||||||
PHOTO_DIR = "/root/phot" # 照片存储目录
|
PHOTO_DIR = "/root/phot" # 照片存储目录
|
||||||
MAX_IMAGES = 1000
|
MAX_IMAGES = 1000
|
||||||
SAVE_RAW_IMAGE_ENABLED = True # 额外保存完整原始帧(不画框、不画点、不裁剪)
|
SAVE_RAW_IMAGE_ENABLED = False # 额外保存完整原始帧(不画框、不画点、不裁剪)
|
||||||
RAW_IMAGE_DIR = PHOTO_DIR + "/raw"
|
RAW_IMAGE_DIR = PHOTO_DIR + "/raw"
|
||||||
RAW_IMAGE_MAX_IMAGES = MAX_IMAGES
|
RAW_IMAGE_MAX_IMAGES = MAX_IMAGES
|
||||||
# Stage2 调试目录(默认 PHOTO_DIR/stage2_roi)内 JPEG 最多保留张数;None 表示与 MAX_IMAGES 相同
|
# Stage2 调试目录(默认 PHOTO_DIR/stage2_roi)内 JPEG 最多保留张数;None 表示与 MAX_IMAGES 相同
|
||||||
TRIANGLE_BLACK_YOLO_STAGE2_ROI_MAX_IMAGES = None
|
TRIANGLE_BLACK_YOLO_STAGE2_ROI_MAX_IMAGES = None
|
||||||
|
|
||||||
SHOW_CAMERA_PHOTO_WHILE_SHOOTING = True # 是否在拍摄时显示摄像头图像(True=显示,False=不显示),建议在连着USB测试过程中打开
|
SHOW_CAMERA_PHOTO_WHILE_SHOOTING = False # 是否在拍摄时显示摄像头图像(True=显示,False=不显示),建议在连着USB测试过程中打开
|
||||||
|
|
||||||
# ==================== OTA配置 ====================
|
# ==================== OTA配置 ====================
|
||||||
MAX_BACKUPS = 5
|
MAX_BACKUPS = 5
|
||||||
|
|||||||
@@ -385,11 +385,11 @@ def cmd_str():
|
|||||||
pressure_max = adc_val
|
pressure_max = adc_val
|
||||||
if len(pressure_buf) >= PRESSURE_BATCH_SIZE:
|
if len(pressure_buf) >= PRESSURE_BATCH_SIZE:
|
||||||
_flush_pressure_buf("batch")
|
_flush_pressure_buf("batch")
|
||||||
# 突变增量检测:压力增量大于300时触发
|
# 突变增量检测:压力增量大于400时触发
|
||||||
# 触发后需等气压降到触发值以下才重新检测增量
|
# 触发后需等气压降到触发值以下才重新检测增量
|
||||||
if adc_val < trigger_adc_val :
|
if adc_val < trigger_adc_val :
|
||||||
enable_check = True
|
enable_check = True
|
||||||
if (adc_val - last_adc_val) > 500 and enable_check:
|
if (adc_val - last_adc_val) > 200 and enable_check:
|
||||||
hardware_manager.start_idle_timer() # 重新计时
|
hardware_manager.start_idle_timer() # 重新计时
|
||||||
last_adc_trigger = current_time
|
last_adc_trigger = current_time
|
||||||
trigger_adc_val = adc_val # 记录触发时的气压值
|
trigger_adc_val = adc_val # 记录触发时的气压值
|
||||||
|
|||||||
+28
-4
@@ -59,6 +59,7 @@ def analyze_shot(frame, laser_point=None):
|
|||||||
"""
|
"""
|
||||||
logger = logger_manager.logger
|
logger = logger_manager.logger
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
yellow_algorithm_ms = 0.0
|
||||||
|
|
||||||
# ── Step 1: 确定激光点 ────────────────────────────────────────────────────
|
# ── Step 1: 确定激光点 ────────────────────────────────────────────────────
|
||||||
laser_point_method = None
|
laser_point_method = None
|
||||||
@@ -74,7 +75,11 @@ def analyze_shot(frame, laser_point=None):
|
|||||||
logger.info(f"[算法] 使用校准值: {laser_manager.laser_point}")
|
logger.info(f"[算法] 使用校准值: {laser_manager.laser_point}")
|
||||||
else:
|
else:
|
||||||
# 动态模式:先做一次无激光点检测以估算距离,再推算激光点
|
# 动态模式:先做一次无激光点检测以估算距离,再推算激光点
|
||||||
|
_t_yellow = time_std.perf_counter()
|
||||||
|
try:
|
||||||
_, _, _, _, best_radius1_temp, _ = detect_circle_v3(frame, None)
|
_, _, _, _, best_radius1_temp, _ = detect_circle_v3(frame, None)
|
||||||
|
finally:
|
||||||
|
yellow_algorithm_ms += (time_std.perf_counter() - _t_yellow) * 1000.0
|
||||||
distance_m_first = estimate_distance(best_radius1_temp) if best_radius1_temp else None
|
distance_m_first = estimate_distance(best_radius1_temp) if best_radius1_temp else None
|
||||||
if distance_m_first and distance_m_first > 0:
|
if distance_m_first and distance_m_first > 0:
|
||||||
laser_point = laser_manager.calculate_laser_point_from_distance(distance_m_first)
|
laser_point = laser_manager.calculate_laser_point_from_distance(distance_m_first)
|
||||||
@@ -119,6 +124,7 @@ def analyze_shot(frame, laser_point=None):
|
|||||||
"laser_point": laser_point, "laser_point_method": laser_point_method,
|
"laser_point": laser_point, "laser_point_method": laser_point_method,
|
||||||
"offset_method": "yellow_ellipse" if ellipse_params else "yellow_circle",
|
"offset_method": "yellow_ellipse" if ellipse_params else "yellow_circle",
|
||||||
"distance_method": "yellow_radius",
|
"distance_method": "yellow_radius",
|
||||||
|
"yellow_algorithm_ms": float(yellow_algorithm_ms),
|
||||||
}
|
}
|
||||||
if yolo_roi_xyxy is not None:
|
if yolo_roi_xyxy is not None:
|
||||||
out["yolo_roi_xyxy"] = yolo_roi_xyxy
|
out["yolo_roi_xyxy"] = yolo_roi_xyxy
|
||||||
@@ -126,9 +132,12 @@ def analyze_shot(frame, laser_point=None):
|
|||||||
|
|
||||||
if not use_tri:
|
if not use_tri:
|
||||||
# 三角形未配置,直接跑圆形检测
|
# 三角形未配置,直接跑圆形检测
|
||||||
return _build_circle_result(
|
_t_yellow = time_std.perf_counter()
|
||||||
detect_circle_v3(frame, laser_point, img_cv=img_cv)
|
try:
|
||||||
)
|
cdata = detect_circle_v3(frame, laser_point, img_cv=img_cv)
|
||||||
|
finally:
|
||||||
|
yellow_algorithm_ms += (time_std.perf_counter() - _t_yellow) * 1000.0
|
||||||
|
return _build_circle_result(cdata)
|
||||||
|
|
||||||
# ── Step 4: 先独占跑三角形,超时或失败后再跑圆形(不与圆心并行,避免抢 CPU)──
|
# ── Step 4: 先独占跑三角形,超时或失败后再跑圆形(不与圆心并行,避免抢 CPU)──
|
||||||
roi_xyxy = None
|
roi_xyxy = None
|
||||||
@@ -281,6 +290,7 @@ def analyze_shot(frame, laser_point=None):
|
|||||||
"laser_point": laser_point, "laser_point_method": laser_point_method,
|
"laser_point": laser_point, "laser_point_method": laser_point_method,
|
||||||
"offset_method": tri.get("offset_method") or "triangle_homography",
|
"offset_method": tri.get("offset_method") or "triangle_homography",
|
||||||
"distance_method": tri.get("distance_method") or "pnp_triangle",
|
"distance_method": tri.get("distance_method") or "pnp_triangle",
|
||||||
|
"yellow_algorithm_ms": float(yellow_algorithm_ms),
|
||||||
"tri_markers": tri.get("markers", []),
|
"tri_markers": tri.get("markers", []),
|
||||||
"tri_markers_completed": tri.get("markers_completed", []),
|
"tri_markers_completed": tri.get("markers_completed", []),
|
||||||
"tri_homography": tri.get("homography"),
|
"tri_homography": tri.get("homography"),
|
||||||
@@ -300,8 +310,12 @@ def analyze_shot(frame, laser_point=None):
|
|||||||
logger.warning(f"[TRI] 超时 {tri_timeout_s:.2f}s 仍未结束,启动圆心算法(三角形仍在后台)")
|
logger.warning(f"[TRI] 超时 {tri_timeout_s:.2f}s 仍未结束,启动圆心算法(三角形仍在后台)")
|
||||||
|
|
||||||
# 三角形超时或失败 → 跑圆心;圆心跑完后再检查三角形是否已结束
|
# 三角形超时或失败 → 跑圆心;圆心跑完后再检查三角形是否已结束
|
||||||
|
try:
|
||||||
|
_t_yellow = time_std.perf_counter()
|
||||||
try:
|
try:
|
||||||
cdata = detect_circle_v3(frame, laser_point, img_cv=img_cv)
|
cdata = detect_circle_v3(frame, laser_point, img_cv=img_cv)
|
||||||
|
finally:
|
||||||
|
yellow_algorithm_ms += (time_std.perf_counter() - _t_yellow) * 1000.0
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[CIRCLE] 圆形检测异常: {e}")
|
logger.error(f"[CIRCLE] 圆形检测异常: {e}")
|
||||||
cdata = (frame, None, None, None, None, None)
|
cdata = (frame, None, None, None, None, None)
|
||||||
@@ -337,10 +351,15 @@ def process_shot(adc_val):
|
|||||||
|
|
||||||
# Classify only the current shot frame; never reuse a previous result.
|
# Classify only the current shot frame; never reuse a previous result.
|
||||||
target_class_result = None
|
target_class_result = None
|
||||||
|
yolo_target_ms = 0.0
|
||||||
try:
|
try:
|
||||||
from target_roi_yolo import try_get_target_class_from_yolo
|
from target_roi_yolo import try_get_target_class_from_yolo
|
||||||
|
|
||||||
|
_t_yolo_target = time_std.perf_counter()
|
||||||
|
try:
|
||||||
target_class_result = try_get_target_class_from_yolo(frame, logger=logger)
|
target_class_result = try_get_target_class_from_yolo(frame, logger=logger)
|
||||||
|
finally:
|
||||||
|
yolo_target_ms = (time_std.perf_counter() - _t_yolo_target) * 1000.0
|
||||||
if logger:
|
if logger:
|
||||||
logger.info(f"[YOLO-TARGET] 当前箭业务结果: {target_class_result}")
|
logger.info(f"[YOLO-TARGET] 当前箭业务结果: {target_class_result}")
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -370,6 +389,7 @@ def process_shot(adc_val):
|
|||||||
laser_point_method = analysis_result["laser_point_method"]
|
laser_point_method = analysis_result["laser_point_method"]
|
||||||
offset_method = analysis_result.get("offset_method", "yellow_circle")
|
offset_method = analysis_result.get("offset_method", "yellow_circle")
|
||||||
distance_method = analysis_result.get("distance_method", "yellow_radius")
|
distance_method = analysis_result.get("distance_method", "yellow_radius")
|
||||||
|
yellow_algorithm_ms = float(analysis_result.get("yellow_algorithm_ms", 0.0) or 0.0)
|
||||||
tri_markers = analysis_result.get("tri_markers", [])
|
tri_markers = analysis_result.get("tri_markers", [])
|
||||||
tri_markers_completed = analysis_result.get("tri_markers_completed", [])
|
tri_markers_completed = analysis_result.get("tri_markers_completed", [])
|
||||||
tri_homography = analysis_result.get("tri_homography")
|
tri_homography = analysis_result.get("tri_homography")
|
||||||
@@ -419,7 +439,9 @@ def process_shot(adc_val):
|
|||||||
"r": 20.0, # 保留字段(服务端当前忽略,物理外环半径 cm)
|
"r": 20.0, # 保留字段(服务端当前忽略,物理外环半径 cm)
|
||||||
"target_class": target_label,
|
"target_class": target_label,
|
||||||
"target_class_confidence": (
|
"target_class_confidence": (
|
||||||
float(target_confidence) if target_confidence is not None else None
|
round(float(target_confidence), 2)
|
||||||
|
if target_confidence is not None
|
||||||
|
else None
|
||||||
),
|
),
|
||||||
"d": round((distance_m or 0.0) * 100),
|
"d": round((distance_m or 0.0) * 100),
|
||||||
"d_laser": round((laser_distance_m or 0.0) * 100),
|
"d_laser": round((laser_distance_m or 0.0) * 100),
|
||||||
@@ -431,6 +453,8 @@ def process_shot(adc_val):
|
|||||||
"target_y": float(y),
|
"target_y": float(y),
|
||||||
"offset_method": offset_method,
|
"offset_method": offset_method,
|
||||||
"distance_method": distance_method,
|
"distance_method": distance_method,
|
||||||
|
"yellow_algorithm_ms": round(yellow_algorithm_ms, 2),
|
||||||
|
"yolo_target_ms": round(float(yolo_target_ms), 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
if ellipse_params:
|
if ellipse_params:
|
||||||
|
|||||||
+1
-1
@@ -4,6 +4,6 @@
|
|||||||
应用版本号
|
应用版本号
|
||||||
每次 OTA 更新时,只需要更新这个文件中的版本号
|
每次 OTA 更新时,只需要更新这个文件中的版本号
|
||||||
"""
|
"""
|
||||||
VERSION = '2.17.15'
|
VERSION = '2.17.18'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user