defect_service.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import cv2
  2. import numpy as np
  3. from ..core.model_loader import get_predictor
  4. from app.utils.defect_inference.CardDefectAggregator import CardDefectAggregator
  5. from app.utils.defect_inference.arean_anylize_draw import DefectProcessor, DrawingParams
  6. from app.utils.defect_inference.AnalyzeCenter import (
  7. analyze_centering_rotated,analyze_centering_rect ,formate_center_data)
  8. from app.utils.defect_inference.DrawCenterInfo import draw_boxes_and_center_info
  9. from app.utils.defect_inference.ClassifyEdgeCorner import ClassifyEdgeCorner
  10. from app.utils.json_data_formate import formate_face_data, formate_add_edit_type
  11. from app.utils.simplify_points import SimplifyPoints
  12. from app.core.config import settings
  13. from app.core.logger import get_logger
  14. import json
  15. logger = get_logger(__name__)
  16. class DefectInferenceService:
  17. def defect_inference(self, inference_type: str, img_bgr: np.ndarray,
  18. is_draw_image=True) -> dict:
  19. """
  20. 执行卡片识别推理。
  21. Args:
  22. inference_type: 模型类型 (e.g., 'outer_box').
  23. img_bgr: 图像。
  24. Returns:
  25. 一个包含推理结果的字典。
  26. """
  27. simplifyPoints = SimplifyPoints()
  28. # 面
  29. if (inference_type == "pokemon_front_face_no_reflect_defect"
  30. or inference_type == "pokemon_front_face_reflect_defect"
  31. or inference_type == "pokemon_back_face_defect"):
  32. # 1. 获取对应的预测器实例
  33. predictor = get_predictor(inference_type)
  34. # 3. 调用我们新加的 predict_from_image 方法进行推理
  35. # result = predictor.predict_from_image(img_bgr)
  36. # 3. 实例化我们聚合器,传入预测器
  37. aggregator = CardDefectAggregator(
  38. predictor=predictor,
  39. tile_size=512,
  40. overlap_ratio=0.1, # 10% 重叠
  41. )
  42. json_data = aggregator.process_image(
  43. image=img_bgr,
  44. mode='face'
  45. )
  46. # 简化点数
  47. for shapes in json_data["shapes"]:
  48. points = shapes["points"]
  49. num1 = len(points)
  50. simplify_points = simplifyPoints.simplify_points(points)
  51. shapes["points"] = simplify_points
  52. new_num1 = len(simplify_points)
  53. logger.info(f"num: {num1}, new_num1: {new_num1}")
  54. merge_json_path = settings.TEMP_WORK_DIR / f'{inference_type}-merge.json'
  55. with open(merge_json_path, 'w', encoding='utf-8') as f:
  56. json.dump(json_data, f, ensure_ascii=False, indent=4)
  57. logger.info(f"合并结束")
  58. processor = DefectProcessor(pixel_resolution=settings.PIXEL_RESOLUTION)
  59. area_json_path = settings.TEMP_WORK_DIR / f'{inference_type}-face_result.json'
  60. if is_draw_image:
  61. drawing_params_with_rect = DrawingParams(draw_min_rect=True)
  62. drawn_image, area_json = processor.analyze_and_draw(img_bgr, json_data,
  63. drawing_params_with_rect)
  64. temp_img_path = settings.TEMP_WORK_DIR / f'{inference_type}-face_result.jpg'
  65. cv2.imwrite(temp_img_path, drawn_image)
  66. else:
  67. area_json = processor.analyze_from_json(json_data)
  68. face_json_result = formate_face_data(area_json)
  69. face_json_result = formate_add_edit_type(face_json_result)
  70. with open(area_json_path, 'w', encoding='utf-8') as f:
  71. json.dump(face_json_result, f, ensure_ascii=False, indent=2)
  72. logger.info("面的面积计算结束")
  73. return face_json_result
  74. # 边角
  75. elif (inference_type == "pokemon_front_corner_no_reflect_defect"
  76. or inference_type == "pokemon_front_corner_reflect_defect"
  77. or inference_type == "pokemon_back_corner_defect"):
  78. predictor = get_predictor(inference_type)
  79. aggregator = CardDefectAggregator(
  80. predictor=predictor,
  81. tile_size=512,
  82. overlap_ratio=0.1, # 10% 重叠
  83. )
  84. json_data = aggregator.process_image(
  85. image=img_bgr,
  86. mode='edge'
  87. )
  88. for shapes in json_data["shapes"]:
  89. points = shapes["points"]
  90. num1 = len(points)
  91. simplify_points = simplifyPoints.simplify_points(points)
  92. shapes["points"] = simplify_points
  93. new_num1 = len(simplify_points)
  94. logger.info(f"num: {num1}, new_num1: {new_num1}")
  95. # merge_json_path = settings.TEMP_WORK_DIR / f'{inference_type}-merge.json'
  96. # with open(merge_json_path, 'w', encoding='utf-8') as f:
  97. # json.dump(json_data, f, ensure_ascii=False, indent=4)
  98. # logger.info(f"合并结束")
  99. processor = DefectProcessor(pixel_resolution=settings.PIXEL_RESOLUTION)
  100. area_json_path = settings.TEMP_WORK_DIR / f'{inference_type}-corner_result.json'
  101. if is_draw_image:
  102. drawing_params_with_rect = DrawingParams(draw_min_rect=True)
  103. drawn_image, area_json = processor.analyze_and_draw(img_bgr, json_data,
  104. drawing_params_with_rect)
  105. temp_img_path = settings.TEMP_WORK_DIR / f'{inference_type}-corner_result.jpg'
  106. cv2.imwrite(temp_img_path, drawn_image)
  107. else:
  108. area_json: dict = processor.analyze_from_json(json_data)
  109. logger.info("边角缺陷面积计算结束")
  110. # 推理外框
  111. predictor_outer = get_predictor("outer_box")
  112. outer_result = predictor_outer.predict_from_image(img_bgr)
  113. classifier = ClassifyEdgeCorner(settings.PIXEL_RESOLUTION, settings.CORNER_SIZE_MM)
  114. edge_corner_data = classifier.classify_defects_location(area_json, outer_result)
  115. edge_corner_data = formate_add_edit_type(edge_corner_data)
  116. with open(area_json_path, 'w', encoding='utf-8') as f:
  117. json.dump(edge_corner_data, f, ensure_ascii=False, indent=2)
  118. logger.info("边角面积计算结束")
  119. return edge_corner_data
  120. elif inference_type == "pokemon_front_card_center" \
  121. or inference_type == "pokemon_back_card_center":
  122. predictor_inner = get_predictor(settings.DEFECT_TYPE[inference_type]['inner_box'])
  123. predictor_outer = get_predictor(settings.DEFECT_TYPE[inference_type]['outer_box'])
  124. inner_result = predictor_inner.predict_from_image(img_bgr)
  125. outer_result = predictor_outer.predict_from_image(img_bgr)
  126. # temp_inner_json_path = settings.TEMP_WORK_DIR / f'{inference_type}-inner_result.json'
  127. # temp_outer_json_path = settings.TEMP_WORK_DIR / f'{inference_type}-outer_result.json'
  128. # with open(temp_inner_json_path, 'w', encoding='utf-8') as f:
  129. # json.dump(inner_result, f, ensure_ascii=False, indent=4)
  130. # with open(temp_outer_json_path, 'w', encoding='utf-8') as f:
  131. # json.dump(outer_result, f, ensure_ascii=False, indent=4)
  132. inner_points = inner_result['shapes'][0]['points']
  133. outer_points = outer_result['shapes'][0]['points']
  134. center_result, inner_rect_box, outer_rect_box = analyze_centering_rotated(inner_points, outer_points)
  135. # logger.info(f"inner_rect_box: {type(inner_rect_box)}, {inner_rect_box}")
  136. # logger.info(f"outer_rect_box: , {outer_rect_box}")
  137. logger.info("格式化居中数据")
  138. center_result = formate_center_data(center_result,
  139. inner_result, outer_result,
  140. inner_rect_box, outer_rect_box)
  141. draw_img = draw_boxes_and_center_info(img_bgr, center_result)
  142. temp_center_img_path = settings.TEMP_WORK_DIR / f'{inference_type}-center_result.jpg'
  143. cv2.imwrite(temp_center_img_path, draw_img)
  144. temp_center_json_path = settings.TEMP_WORK_DIR / f'{inference_type}-center_result.json'
  145. with open(temp_center_json_path, 'w', encoding='utf-8') as f:
  146. json.dump(center_result, f, ensure_ascii=False, indent=2)
  147. return center_result
  148. else:
  149. return {}
  150. # inference_type: center, face, corner_edge
  151. def re_inference_from_json(self, inference_type: str, center_json: dict, defect_json: dict) -> dict:
  152. inference_type_list = ["center", "face", "corner_edge"]
  153. if inference_type not in inference_type_list:
  154. logger.error(f"inference_type 只能为{inference_type_list}, 输入为{inference_type}")
  155. raise ValueError(f"inference_type 只能为{inference_type_list}, 输入为{inference_type}")
  156. processor = DefectProcessor(pixel_resolution=settings.PIXEL_RESOLUTION)
  157. # 对于面的图, 不计算居中相关, 这里得到的center_json 应该为 {}
  158. if inference_type == "face":
  159. area_json = processor.re_analyze_from_json(defect_json)
  160. face_json_result = formate_face_data(area_json)
  161. logger.info("面缺陷面积计算结束")
  162. return face_json_result
  163. inner_result = center_json['box_result']['inner_box']
  164. outer_result = center_json['box_result']['outer_box']
  165. if inference_type == "center":
  166. inner_rect = inner_result['shapes'][0]['rect_box']
  167. outer_rect = outer_result['shapes'][0]['rect_box']
  168. center_result, inner_rect_box, outer_rect_box = analyze_centering_rect(inner_rect, outer_rect)
  169. center_result = formate_center_data(center_result,
  170. inner_result, outer_result,
  171. inner_rect_box, outer_rect_box)
  172. return center_result
  173. elif inference_type == "corner_edge":
  174. area_json: dict = processor.re_analyze_from_json(defect_json)
  175. logger.info("边角缺陷面积计算结束")
  176. # 根据外框区分边和角
  177. classifier = ClassifyEdgeCorner(settings.PIXEL_RESOLUTION, settings.CORNER_SIZE_MM)
  178. edge_corner_data = classifier.classify_defects_location(area_json, outer_result)
  179. logger.info("边角面积计算结束")
  180. return edge_corner_data
  181. else:
  182. return {}
  183. # 创建一个单例服务
  184. # defect_service = DefectInferenceService()