labelme_process.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. def convert_internal_to_labelme(image_path: str, internal_json: dict) -> dict:
  2. """
  3. 将系统内部的 detection_json/modified_json 转换为 LabelMe 格式
  4. """
  5. result = internal_json.get("result", {})
  6. img_h = result.get("imageHeight", 0)
  7. img_w = result.get("imageWidth", 0)
  8. labelme_data = {
  9. "version": "5.5.0",
  10. "flags": {},
  11. "shapes": [],
  12. "imagePath": image_path.lstrip("/\\"), # 去除开头的斜杠
  13. "imageData": None,
  14. "imageHeight": img_h,
  15. "imageWidth": img_w
  16. }
  17. # 1. 处理框 (Center Result -> Inner/Outer Box)
  18. # inner_box 放在第二个,outer_box 放在最上面
  19. center_result = result.get("center_result", {})
  20. box_result = center_result.get("box_result", {})
  21. inner_shape = None
  22. outer_shape = None
  23. # 提取 Inner Box
  24. if "inner_box" in box_result:
  25. shapes = box_result["inner_box"].get("shapes", [])
  26. if shapes and len(shapes) > 0:
  27. points = shapes[0].get("points", [])
  28. if points:
  29. inner_shape = {
  30. "label": "inner_box",
  31. "points": points,
  32. "group_id": None,
  33. "shape_type": "polygon",
  34. "flags": {}
  35. }
  36. # 提取 Outer Box
  37. if "outer_box" in box_result:
  38. shapes = box_result["outer_box"].get("shapes", [])
  39. if shapes and len(shapes) > 0:
  40. points = shapes[0].get("points", [])
  41. if points:
  42. outer_shape = {
  43. "label": "outer_box",
  44. "points": points,
  45. "group_id": None,
  46. "shape_type": "polygon",
  47. "flags": {}
  48. }
  49. # 添加到列表头部
  50. if outer_shape:
  51. labelme_data["shapes"].append(outer_shape)
  52. if inner_shape:
  53. labelme_data["shapes"].append(inner_shape)
  54. # 2. 处理缺陷 (Defects)
  55. defect_result = result.get("defect_result", {})
  56. defects = defect_result.get("defects", [])
  57. for defect in defects:
  58. shape = {
  59. "label": defect.get("label", "unknown"),
  60. "points": defect.get("points", []),
  61. "group_id": None,
  62. "description": "",
  63. "shape_type": "polygon",
  64. "flags": {},
  65. # 我们将系统特有的字段暂存到 extra_info 中,或者直接放在 shape 根目录下
  66. # LabelMe 打开时会忽略这些额外字段,但保存时通常会保留它们 (取决于版本)
  67. # 为了安全,关键信息最好也保留
  68. "system_data": {
  69. "confidence": defect.get("confidence"),
  70. "defect_type": defect.get("defect_type"),
  71. "score": defect.get("score"),
  72. "edit_type": defect.get("edit_type", "edit")
  73. }
  74. }
  75. labelme_data["shapes"].append(shape)
  76. return labelme_data
  77. def convert_labelme_to_internal(original_json: dict, labelme_json: dict) -> dict:
  78. """
  79. 将 LabelMe JSON 还原为系统内部格式结构。
  80. 注意:我们只构建 '结构',具体的面积/分数计算交给 Project 1 的重计算接口。
  81. 我们需要保留 original_json 中的一些元数据 (如 imageHeight, etc.)
  82. """
  83. # 基础结构复制
  84. new_internal = {
  85. "result": {
  86. "imageHeight": labelme_json.get("imageHeight", original_json["result"].get("imageHeight")),
  87. "imageWidth": labelme_json.get("imageWidth", original_json["result"].get("imageWidth")),
  88. "center_result": {},
  89. "defect_result": {"defects": []}
  90. }
  91. }
  92. # 准备容器
  93. defects_list = []
  94. inner_box_data = None
  95. outer_box_data = None
  96. # 遍历 LabelMe 的 shapes
  97. for shape in labelme_json.get("shapes", []):
  98. label = shape.get("label")
  99. points = shape.get("points", [])
  100. if not points:
  101. continue
  102. if label == "outer_box":
  103. # 重构 outer_box 结构
  104. outer_box_data = {
  105. "shapes": [{"label": "outer_box", "points": points, "shape_type": "polygon"}]
  106. }
  107. elif label == "inner_box":
  108. # 重构 inner_box 结构
  109. inner_box_data = {
  110. "shapes": [{"label": "inner_box", "points": points, "shape_type": "polygon"}]
  111. }
  112. else:
  113. # 这是一个缺陷
  114. # 尝试从 shape 中读取我们之前暂存的 system_data,如果没有则初始化默认值
  115. sys_data = shape.get("system_data", {})
  116. defect_obj = {
  117. "label": label,
  118. "points": points,
  119. "shape_type": "polygon",
  120. # 如果是新加的缺陷,这些可能是 None,重计算服务应该处理它
  121. "confidence": sys_data.get("confidence", 1.0),
  122. "defect_type": sys_data.get("defect_type", "face"), # 默认为 face, 服务端会重新校验
  123. "edit_type": "edit", # 标记为编辑过
  124. # score 字段由服务端计算,这里可以不传或者传旧的
  125. "score": sys_data.get("score")
  126. }
  127. defects_list.append(defect_obj)
  128. # 组装 Center Result
  129. # 只有当原始数据里有 box_result 或者 labelme 里画了 box 时才构造
  130. # 保持原有的层级结构: center_result -> box_result -> inner_box/outer_box
  131. if inner_box_data or outer_box_data:
  132. new_internal["result"]["center_result"] = {
  133. "box_result": {}
  134. }
  135. if inner_box_data:
  136. new_internal["result"]["center_result"]["box_result"]["inner_box"] = inner_box_data
  137. if outer_box_data:
  138. new_internal["result"]["center_result"]["box_result"]["outer_box"] = outer_box_data
  139. else:
  140. # 如果没有框的信息(例如面部图),保持 center_result 为空或复制原始的非 box 信息
  141. new_internal["result"]["center_result"] = {}
  142. # 组装 Defect Result
  143. new_internal["result"]["defect_result"]["defects"] = defects_list
  144. # 复制 statistics 等其他可能的字段,或者留给服务端重新生成
  145. # 建议只传核心数据,让服务端全权处理统计
  146. return new_internal