This commit is contained in:
zaiun xu
2026-04-13 17:13:02 +08:00
parent 6f006def64
commit c1aafc69bf
8 changed files with 580 additions and 66 deletions

View File

@@ -11,6 +11,8 @@ from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
import numpy as np
from app.logging_config import format_json_pretty
from app.settings import Settings
from app.state import MeasureSnapshot
@@ -187,12 +189,15 @@ def _safe_media_prefix(stem: str) -> str:
def _result_from_weight_prediction(data: Dict[str, Any]) -> List[Dict[str, Any]]:
"""按 track_id 聚合:体重取 max(predicted_weight_g),体长取达到 max 的那条 PLY 的 length_input (mm)。"""
"""按 track_id 聚合:对每个 track_id 的点云,取 predicted_weight_g 最大的 top5 平均值作为体重,
体长取这 top5 点云的平均 length_input (mm)。只使用通过点云分类器的好点云used_for_prediction=True"""
items = data.get("per_cloud") or data.get("per_file") or []
if not isinstance(items, list):
return []
# tid -> (max_weight_g, length_mm at max weight)
best: Dict[int, Tuple[float, float]] = {}
# tid -> list of (weight_g, length_mm) for this track
track_predictions: Dict[int, List[Tuple[float, float]]] = {}
for it in items:
if not isinstance(it, dict):
continue
@@ -202,24 +207,55 @@ def _result_from_weight_prediction(data: Dict[str, Any]) -> List[Dict[str, Any]]
tid = _parse_tid_from_ply_name(Path(str(ply)).name)
if tid is None:
continue
# 只使用通过点云分类器的好点云
if not it.get("used_for_prediction", True):
continue
try:
wg = float(it.get("predicted_weight_g", float("nan")))
except (TypeError, ValueError):
continue
if not math.isfinite(wg):
continue
try:
ln = float(it.get("length_input", float("nan")))
except (TypeError, ValueError):
ln = float("nan")
if tid not in best or wg > best[tid][0]:
best[tid] = (wg, ln)
if tid not in track_predictions:
track_predictions[tid] = []
track_predictions[tid].append((wg, ln))
out: List[Dict[str, Any]] = []
for tid in sorted(best.keys()):
wg, ln = best[tid]
if not math.isfinite(ln):
TOP_K = 5
for tid in sorted(track_predictions.keys()):
predictions = track_predictions[tid]
if not predictions:
continue
out.append({"id": tid, "weight": wg, "length": ln})
# 按重量降序排序,取 top5
predictions_sorted = sorted(predictions, key=lambda x: x[0], reverse=True)
top5 = predictions_sorted[:min(TOP_K, len(predictions_sorted))]
# 计算 top5 平均重量和平均长度
avg_weight = float(np.mean([p[0] for p in top5]))
valid_lengths = [p[1] for p in top5 if math.isfinite(p[1])]
avg_length = float(np.mean(valid_lengths)) if valid_lengths else float("nan")
if not math.isfinite(avg_length):
continue
out.append({
"id": tid,
"type": "大黄鱼",
"weight": str(round(avg_weight)),
"length": str(round(avg_length)),
"date": datetime.now(timezone.utc).strftime("%Y-%m-%d"),
})
return out