CardScorer.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import json
  2. from typing import List, Dict, Any, Tuple
  3. class CardScorer:
  4. """
  5. 它从一个JSON配置文件加载评分规则,并根据输入的卡片数据计算分数。
  6. """
  7. def __init__(self, config_path: str):
  8. try:
  9. with open(config_path, 'r', encoding='utf-8') as f:
  10. self.config = json.load(f)
  11. self.base_score = self.config.get("base_score", 10.0)
  12. except FileNotFoundError:
  13. raise ValueError(f"配置文件未找到: {config_path}")
  14. except json.JSONDecodeError:
  15. raise ValueError(f"配置文件格式错误: {config_path}")
  16. def _get_score_from_tiers(self, value: float, rules: List[List[Any]]) -> float:
  17. """
  18. 一个通用的辅助函数,根据分层规则查找值对应的分数。
  19. """
  20. for tier in rules:
  21. threshold, score = tier
  22. if threshold == "inf" or value < threshold:
  23. return float(score)
  24. return 0.0 # 如果没有匹配的规则,不扣分
  25. def calculate_defect_score(self, aspect: str, defect_data: Dict[str, List[float]]) -> float:
  26. """
  27. 一个通用的缺陷计分函数,用于计算角、边、表面的加权分数。
  28. 'corners', 'edges', 'face'
  29. """
  30. aspect_config = self.config[aspect]
  31. total_deduction = 0.0
  32. weighted_scores = {}
  33. # 1. 计算每种缺陷类型的总扣分
  34. for defect_type, values in defect_data.items():
  35. if defect_type not in aspect_config['rules']:
  36. continue
  37. rules = aspect_config['rules'][defect_type]
  38. # 累加所有同类型缺陷的扣分
  39. type_deduction = sum(self._get_score_from_tiers(v, rules) for v in values)
  40. weighted_scores[defect_type] = type_deduction
  41. # 2. 根据权重/系数计算最终扣分
  42. weights = aspect_config.get(f"{self.current_face}_weights") or aspect_config.get("coefficients")
  43. if not weights:
  44. raise ValueError(f"在配置中未找到 '{aspect}' 的权重/系数")
  45. for defect_type, score in weighted_scores.items():
  46. total_deduction += score * weights.get(defect_type, 1.0)
  47. return total_deduction
  48. def calculate_centering_score(self, card_type: str, center_data: dict) -> float:
  49. """
  50. 计算居中度分数。
  51. card_type 为 front或 back
  52. """
  53. if card_type != "front" and card_type != "back":
  54. raise TypeError("calculate_centering_score:card_type 只能为 front 或 back")
  55. centering_config = self.config['centering'][card_type]
  56. rules = centering_config['rules']
  57. coefficients = centering_config['coefficients']
  58. center_left = center_data['inference_result']['center_inference']['center_left']
  59. center_right = center_data['inference_result']['center_inference']['center_right']
  60. center_top = center_data['inference_result']['center_inference']['center_top']
  61. center_bottom = center_data['inference_result']['center_inference']['center_bottom']
  62. # 将比例转换为用于查找规则的单个最大值
  63. h_lookup_val = 51
  64. v_lookup_val = 52
  65. h_deduction = self._get_score_from_tiers(h_lookup_val, rules) * coefficients['horizontal']
  66. v_deduction = self._get_score_from_tiers(v_lookup_val, rules) * coefficients['vertical']
  67. print(h_deduction, v_deduction)
  68. return h_deduction + v_deduction
  69. if __name__ == '__main__':
  70. # 1. 初始化评分器,加载规则
  71. scorer = CardScorer(r"C:\Code\ML\Project\CheckCardBoxAndDefectServer\app\core\scoring_config.json")
  72. center_data_path = r"C:\Code\ML\Project\CheckCardBoxAndDefectServer\_temp_work\pokemon_card_center-center_result.json"
  73. with open(center_data_path, 'r', encoding='utf-8') as f:
  74. center_data = json.load(f)
  75. center_score = scorer.calculate_centering_score("front", center_data)
  76. print(center_score)