diff --git a/core/detect_plate_process.py b/core/detect_plate_process.py index 2f287e5..a1aa2b0 100644 --- a/core/detect_plate_process.py +++ b/core/detect_plate_process.py @@ -16,7 +16,7 @@ class Config: # 你的Plate检测模型路径(相对项目根目录);若存在 best_openvino_model 会自动优先加载 MODEL_PATH = str(_ROOT / "best.pt") - CONF_THRESHOLD = 0.8 + CONF_THRESHOLD = 0.90 IOU_THRESHOLD = 0.45 # 显式 imgsz,便于 OpenVINO / CPU 控制耗时;可用环境变量 DISH_YOLO_IMGSZ 覆盖 IMGSZ = int(os.environ.get("DISH_YOLO_IMGSZ", "640")) diff --git a/core/pending_learning_ui.py b/core/pending_learning_ui.py index 0050f1c..c8c72b0 100644 --- a/core/pending_learning_ui.py +++ b/core/pending_learning_ui.py @@ -31,13 +31,43 @@ def format_predict_detail(detail): def format_dish_box_label(detail): - """将识别结果格式化为图片框上的菜品名称标签。""" + """将识别结果格式化为图片框标签。 + + 默认只显示菜名;设环境变量 DISH_SHOW_BOX_SCORES=1 时追加「似xx 检xx」。 + """ if not detail or detail.get("error"): return "识别失败" + if detail.get("is_unknown"): suggested = detail.get("suggested_category") - return f"未知·{suggested}" if suggested else "未知" - return detail.get("label") or "未知" + base = f"未知·{suggested}" if suggested else "未知" + else: + base = detail.get("label") or detail.get("name") or "未知" + + try: + from dao.settings import DISH_SHOW_BOX_SCORES + show_scores = bool(DISH_SHOW_BOX_SCORES) + except Exception: + show_scores = False + if not show_scores: + return str(base) + + def _fmt(v): + try: + return f"{float(v):.2f}" if v is not None else None + except (TypeError, ValueError): + return None + + sim = _fmt(detail.get("score")) + det = _fmt(detail.get("det_conf")) + bits = [] + if sim is not None: + bits.append(f"似{sim}") + if det is not None: + bits.append(f"检{det}") + if not bits: + return str(base) + return f"{base} {' '.join(bits)}" class PendingLearningUIMixin: diff --git a/dao/settings.py b/dao/settings.py index 80a1063..5ed3c74 100644 --- a/dao/settings.py +++ b/dao/settings.py @@ -71,6 +71,9 @@ DISH_DEVICE_STATUS_ENABLED = os.environ.get('DISH_DEVICE_STATUS_ENABLED', '1') = DISH_SYNC_ON_START = os.environ.get('DISH_SYNC_ON_START', '1') == '1' DISH_SYNC_INTERVAL = int(os.environ.get('DISH_SYNC_INTERVAL', 300)) # 默认 5 分钟 +# 识别框是否显示「似xx 检xx」(默认关;需要时 set DISH_SHOW_BOX_SCORES=1) +DISH_SHOW_BOX_SCORES = os.environ.get('DISH_SHOW_BOX_SCORES', '0') == '1' + DEBUG = True diff --git a/ui/classifier_ui.py b/ui/classifier_ui.py index e7fb1c1..21dc560 100644 --- a/ui/classifier_ui.py +++ b/ui/classifier_ui.py @@ -1759,12 +1759,8 @@ class BaseDishApp(PendingLearningUIMixin): print(f"[live] preview failed: {e}") def _live_dish_label(self, dish): - if not dish: - return "未知" - if dish.get("is_unknown"): - sug = (dish.get("suggested_category") or "").strip() - return f"未知·{sug}" if sug else "未知" - return (dish.get("label") or dish.get("name") or "未知").strip() or "未知" + from ui.pending_learning_ui import format_dish_box_label + return format_dish_box_label(dish) def _draw_live_overlay_pil(self, pil_im, dishes, sx=1.0, sy=1.0): """在已缩放预览图上画识别框:整图一次 alpha 合成,避免逐框卡顿。""" @@ -1967,6 +1963,7 @@ class BaseDishApp(PendingLearningUIMixin): boxes, auto_pending=False, crop_images=crop_arrays, + det_confs=[c.get("conf") for c in crop_items], ) self._last_detect_fp = fp self._last_live_dishes = list(dishes or []) @@ -2404,6 +2401,7 @@ class BaseDishApp(PendingLearningUIMixin): f"正在识别第 {cur} 张…", "busy" ), crop_images=crop_arrays, + det_confs=[c.get("conf") for c in crop_items], ) preview = labeled_path or visualize_save_path if preview: @@ -2523,7 +2521,9 @@ class BaseDishApp(PendingLearningUIMixin): return final_result, _, _unknown_count, labeled_path, dishes = self.run_plate_predict_batch( - save_path, cropped_file_paths, boxes, crop_images=crop_arrays, + save_path, cropped_file_paths, boxes, + crop_images=crop_arrays, + det_confs=[c.get("conf") for c in crop_items], ) preview = labeled_path or visualize_save_path self.report_recognition(save_path, dishes, preview) diff --git a/ui/pending_learning_ui.py b/ui/pending_learning_ui.py index 576834c..b4cd236 100644 --- a/ui/pending_learning_ui.py +++ b/ui/pending_learning_ui.py @@ -31,13 +31,43 @@ def format_predict_detail(detail): def format_dish_box_label(detail): - """将识别结果格式化为图片框上的菜品名称标签。""" + """将识别结果格式化为图片框标签。 + + 默认只显示菜名;设环境变量 DISH_SHOW_BOX_SCORES=1 时追加「似xx 检xx」。 + """ if not detail or detail.get("error"): return "识别失败" + if detail.get("is_unknown"): suggested = detail.get("suggested_category") - return f"未知·{suggested}" if suggested else "未知" - return detail.get("label") or "未知" + base = f"未知·{suggested}" if suggested else "未知" + else: + base = detail.get("label") or detail.get("name") or "未知" + + try: + from dao.settings import DISH_SHOW_BOX_SCORES + show_scores = bool(DISH_SHOW_BOX_SCORES) + except Exception: + show_scores = False + if not show_scores: + return str(base) + + def _fmt(v): + try: + return f"{float(v):.2f}" if v is not None else None + except (TypeError, ValueError): + return None + + sim = _fmt(detail.get("score")) + det = _fmt(detail.get("det_conf")) + bits = [] + if sim is not None: + bits.append(f"似{sim}") + if det is not None: + bits.append(f"检{det}") + if not bits: + return str(base) + return f"{base} {' '.join(bits)}" class PendingLearningUIMixin: @@ -689,6 +719,7 @@ class PendingLearningUIMixin: def run_plate_predict_batch( self, source_image_path, cropped_file_paths, boxes, progress_callback=None, auto_pending=True, crop_images=None, + det_confs=None, ): """对多个裁剪区域识别。 @@ -698,6 +729,7 @@ class PendingLearningUIMixin: cropped_file_paths: 裁剪图路径列表(可与 crop_images 二选一/并用) crop_images: 可选 BGR ndarray 列表,优先用于特征提取(免读盘) + det_confs: 可选 YOLO 检测置信度列表(与 boxes 对齐) 返回: final_result, dish_labels, unknown_count, labeled_path, dishes @@ -728,6 +760,7 @@ class PendingLearningUIMixin: if progress_callback: progress_callback(i + 1, n) box = boxes[i] if boxes and i < len(boxes) else None + det_conf = det_confs[i] if det_confs and i < len(det_confs) else None img_path = cropped_file_paths[i] if i < len(cropped_file_paths) else None try: detail = self.manager.predict_from_feature( @@ -737,12 +770,15 @@ class PendingLearningUIMixin: ) if detail.get("is_unknown"): unknown_count += 1 - dish_labels.append(format_dish_box_label(detail)) + label_src = dict(detail) + label_src["det_conf"] = det_conf + dish_labels.append(format_dish_box_label(label_src)) final_result += f"【菜品{i + 1}】{format_predict_detail(detail)}\n" dishes.append({ "index": i + 1, "label": detail.get("label"), "score": detail.get("score"), + "det_conf": det_conf, "is_unknown": bool(detail.get("is_unknown")), "suggested_category": detail.get("suggested_category"), "pending_id": detail.get("pending_id"), @@ -759,6 +795,7 @@ class PendingLearningUIMixin: "index": i + 1, "label": None, "score": None, + "det_conf": det_conf, "is_unknown": True, "suggested_category": None, "pending_id": None,