csv_read.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import os
  2. import csv
  3. import json
  4. import shutil
  5. import math
  6. from typing import List, Union, Dict
  7. # === 文件夹配置 ===
  8. csv_folder = r"\\192.168.50.222\share\zyh\master_dataset\pokou\remark_251104\params" # CSV 文件夹
  9. json_folder = r"\\192.168.50.222\share\zyh\master_dataset\pokou\total" # JSON 和图片文件夹
  10. output_folder = r"\\192.168.50.222\share\zyh\master_dataset\pokou\251115\csvjson" # 输出文件夹
  11. os.makedirs(output_folder, exist_ok=True)
  12. def compute_arc_ends(points: List[List[float]]) -> List[List[float]]:
  13. if len(points) != 3:
  14. return [[0,0],[0,0]]
  15. p1, p2, p3 = points
  16. x1, y1 = p1
  17. x2, y2 = p2
  18. x3, y3 = p3
  19. # --- 圆心 ---
  20. A = 2*(x2-x1)
  21. B = 2*(y2-y1)
  22. C = x2**2+y2**2-x1**2-y1**2
  23. D = 2*(x3-x2)
  24. E = 2*(y3-y2)
  25. F = x3**2+y3**2-x2**2-y2**2
  26. denom = A*E - B*D
  27. if denom == 0:
  28. return [p1, p3]
  29. cx = (C*E - F*B)/denom
  30. cy = (A*F - D*C)/denom
  31. angles = [math.atan2(y-cy, x-cx) for x,y in points]
  32. def angle_diff(a1,a2):
  33. diff = (a2-a1)%(2*math.pi)
  34. if diff>math.pi: diff=2*math.pi-diff
  35. return diff
  36. pairs = [(0,1),(0,2),(1,2)]
  37. max_diff=-1
  38. end_pair=(0,1)
  39. for i,j in pairs:
  40. diff=angle_diff(angles[i],angles[j])
  41. if diff>max_diff:
  42. max_diff=diff
  43. end_pair=(i,j)
  44. return [points[end_pair[0]], points[end_pair[1]]]
  45. # === 工具函数:匹配点到最近椭圆 ===
  46. def match_point_to_ellipse(point: List[float], ellipses: List[Dict]) -> int:
  47. """
  48. 根据点匹配到最近的椭圆
  49. point: [x,y]
  50. ellipses: list of dict,每个包含 cx,cy
  51. return: ellipse_index
  52. """
  53. x, y = point
  54. min_dist = float('inf')
  55. match_idx = -1
  56. for i, e in enumerate(ellipses):
  57. cx, cy = e['cx'], e['cy']
  58. dist = math.hypot(x - cx, y - cy)
  59. if dist < min_dist:
  60. min_dist = dist
  61. match_idx = i
  62. return match_idx
  63. # === 读取 CSV,构建文件名到椭圆参数映射 ===
  64. csv_ellipse_map = {} # filename -> list of ellipse params
  65. for csv_file in os.listdir(csv_folder):
  66. if not csv_file.endswith(".csv"):
  67. continue
  68. csv_path = os.path.join(csv_folder, csv_file)
  69. with open(csv_path, "r", encoding="utf-8-sig") as f:
  70. reader = csv.DictReader(f)
  71. for row in reader:
  72. filename = row["filename"].strip()
  73. shape_str = row["region_shape_attributes"]
  74. try:
  75. shape_data = json.loads(shape_str)
  76. except json.JSONDecodeError:
  77. shape_data = json.loads(shape_str.replace('""', '"'))
  78. if filename not in csv_ellipse_map:
  79. csv_ellipse_map[filename] = []
  80. csv_ellipse_map[filename].append(shape_data)
  81. # === 遍历 JSON 文件 ===
  82. for json_file in os.listdir(json_folder):
  83. if not json_file.endswith(".json"):
  84. continue
  85. json_path = os.path.join(json_folder, json_file)
  86. filename = json_file.replace(".json", ".jpg")
  87. img_path = os.path.join(json_folder, filename)
  88. if not os.path.exists(img_path):
  89. print(f"?? Image not found for {filename}")
  90. continue
  91. if filename not in csv_ellipse_map:
  92. print(f"?? CSV ellipse not found for {filename}")
  93. continue
  94. with open(json_path, "r", encoding="utf-8") as jf:
  95. data = json.load(jf)
  96. if "shapes" not in data:
  97. data["shapes"] = []
  98. # 收集所有 arc 单点
  99. arc_points = [s["points"][0] for s in data["shapes"]
  100. if s.get("label")=="arc" and "points" in s and len(s["points"])==1]
  101. # 根据 CSV 椭圆匹配分组
  102. ellipses = csv_ellipse_map[filename]
  103. ellipse_point_map = {i: [] for i in range(len(ellipses))}
  104. for pt in arc_points:
  105. idx = match_point_to_ellipse(pt, ellipses)
  106. ellipse_point_map[idx].append(pt)
  107. # 打印匹配到两个及以上椭圆的图片信息
  108. active_ellipses = [i for i, pts in ellipse_point_map.items() if len(pts) >= 1]
  109. if len(active_ellipses) >= 2:
  110. print(f"Image {filename} matches {len(active_ellipses)} ellipses")
  111. # 构造新的 arc_shape
  112. new_arc_shapes = []
  113. for idx, pts in ellipse_point_map.items():
  114. if len(pts) != 3:
  115. print(f"?? {filename} ellipse {idx} points not equal 3, got {len(pts)}")
  116. ends = [[0,0],[0,0]]
  117. else:
  118. ends = compute_arc_ends(pts)
  119. e = ellipses[idx]
  120. arc_shape = {
  121. "label": "arc",
  122. "points": pts,
  123. "params": [e.get("cx",0), e.get("cy",0), e.get("rx",0), e.get("ry",0), e.get("theta",0)],
  124. "ends": ends,
  125. "group_id": None,
  126. "description": "",
  127. "difficult": False,
  128. "shape_type": "arc",
  129. "flags": {},
  130. "attributes": {}
  131. }
  132. new_arc_shapes.append(arc_shape)
  133. # 保留非 arc shapes
  134. remaining_shapes = [s for s in data["shapes"] if s.get("label") != "arc"]
  135. data["shapes"] = remaining_shapes + new_arc_shapes
  136. # 保存 JSON
  137. output_json = os.path.join(output_folder, json_file)
  138. with open(output_json, "w", encoding="utf-8") as jf:
  139. json.dump(data, jf, ensure_ascii=False, indent=2)
  140. # 复制图片
  141. shutil.copy2(img_path, os.path.join(output_folder, filename))
  142. print(f"Saved merged JSON and image for: {filename}")
  143. print("\nAll done! Final JSONs and images saved in:", output_folder)