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