card_rectify_and_center.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import cv2
  2. import numpy as np
  3. import copy
  4. from ..core.model_loader import get_predictor
  5. from app.utils.defect_inference.img_rectify_and_center import (
  6. FryCardProcessParams, FryCardProcessor, CenterMode, FillMode)
  7. from app.core.config import settings
  8. from app.core.logger import get_logger
  9. import json
  10. logger = get_logger(__name__)
  11. class CardRectifyAndCenter:
  12. def __init__(self):
  13. self.inference_type = "outer_box"
  14. self.outer_box_model = get_predictor(self.inference_type)
  15. def _keep_max_prob_shape(self, json_data: dict) -> dict:
  16. """
  17. 辅助函数:过滤掉低置信度的框,只保留 probability 最大的那一个。
  18. """
  19. if not json_data or 'shapes' not in json_data or not json_data['shapes']:
  20. return json_data
  21. shapes = json_data['shapes']
  22. # 如果只有一个,直接返回
  23. if len(shapes) == 1:
  24. return json_data
  25. logger.info(f"检测到 {len(shapes)} 个外框,开始筛选最大置信度目标...")
  26. # 使用 max 函数找出 probability 最大的 shape
  27. # x.get('probability', 0) 确保如果字段不存在默认为0
  28. best_shape = max(shapes, key=lambda x: x.get('probability', 0))
  29. logger.info(f"筛选结果: 保留置信度为 {best_shape.get('probability')} 的目标,"
  30. f"丢弃了其他 {len(shapes) - 1} 个目标。")
  31. # 重新赋值给 shapes,保持列表结构
  32. json_data['shapes'] = [best_shape]
  33. # 同时更新 num 数量,保持数据一致性
  34. if 'num' in json_data:
  35. json_data['num'] = 1
  36. return json_data
  37. def rectify_and_center(self, img_bgr: np.ndarray) -> tuple[np.ndarray, dict]:
  38. """
  39. 修改返回值: (final_image, rectified_json)
  40. """
  41. # 1. 设置处理参数
  42. params = FryCardProcessParams(
  43. debug_level="detail",
  44. label_name="outer_box",
  45. center_mode=CenterMode.BOUNDING_RECT,
  46. fill_mode=FillMode.BLACK
  47. )
  48. # 2. 初始化处理器
  49. processor = FryCardProcessor()
  50. # 3. 原始外框推理
  51. seg_json = self.outer_box_model.predict_from_image(img_bgr)
  52. seg_json = self._keep_max_prob_shape(seg_json)
  53. # 4. 执行处理,获取图像和变换矩阵
  54. final_image, matrix = processor.process_image_with_json(img_bgr, seg_json, params)
  55. # 5. 生成变换后的 JSON 数据
  56. rectified_json = copy.deepcopy(seg_json)
  57. if matrix is not None and 'shapes' in rectified_json:
  58. logger.info("正在将原始外框坐标映射到转正后的坐标系...")
  59. for shape in rectified_json['shapes']:
  60. original_points = shape.get('points', [])
  61. if original_points:
  62. # 使用矩阵变换点
  63. new_points = processor.transform_points_with_matrix(original_points, matrix)
  64. shape['points'] = new_points
  65. # 清除可能存在的 rect_box,确保后续逻辑重新计算最小外接矩形
  66. if 'rect_box' in shape:
  67. del shape['rect_box']
  68. temp_img_path = settings.TEMP_WORK_DIR / "rectify_center_img.jpg"
  69. if final_image is not None:
  70. cv2.imwrite(temp_img_path, final_image)
  71. return final_image, rectified_json