mask.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import os
  2. import json
  3. import shutil
  4. import numpy as np
  5. import cv2
  6. from scipy.optimize import leastsq
  7. from tqdm import tqdm
  8. def calc_R(x, y, xc, yc):
  9. return np.sqrt((x - xc) ** 2 + (y - yc) ** 2)
  10. def f(c, x, y):
  11. Ri = calc_R(x, y, *c)
  12. return Ri - Ri.mean()
  13. def fit_arc_and_create_mask(points, shape, point_step_deg=0.5, radius=2):
  14. x_data = points[:, 0]
  15. y_data = points[:, 1]
  16. center_estimate = np.mean(x_data), np.mean(y_data)
  17. center, _ = leastsq(f, center_estimate, args=(x_data, y_data))
  18. xc, yc = center
  19. Ri = calc_R(x_data, y_data, xc, yc)
  20. R = Ri.mean()
  21. # 极角
  22. angles = np.arctan2(points[:, 1] - yc, points[:, 0] - xc)
  23. start_angle = np.min(angles)
  24. end_angle = np.max(angles)
  25. # 确保角度顺序正确
  26. if end_angle - start_angle > np.pi:
  27. start_angle, end_angle = end_angle, start_angle + 2 * np.pi
  28. arc_angles = np.arange(start_angle, end_angle, np.deg2rad(point_step_deg))
  29. arc_points = np.stack([
  30. xc + R * np.cos(arc_angles),
  31. yc + R * np.sin(arc_angles)
  32. ], axis=-1).astype(np.int32)
  33. # 不返回mask了,直接返回点列表
  34. return None, arc_points.tolist()
  35. def build_shapes_from_points(points, label="arc"):
  36. points_np = np.array(points)
  37. if points_np.shape[0] < 3:
  38. return []
  39. xs = points_np[:, 0]
  40. ys = points_np[:, 1]
  41. shape = {
  42. "label": label,
  43. "points": points,
  44. "shape_type": "polygon",
  45. "flags": {},
  46. "xmin": int(xs.min()),
  47. "ymin": int(ys.min()),
  48. "xmax": int(xs.max()),
  49. "ymax": int(ys.max())
  50. }
  51. return [shape]
  52. def process_folder_labelme(input_dir, output_dir, point_step_deg=0.5, radius=2):
  53. os.makedirs(output_dir, exist_ok=True)
  54. for file_name in tqdm(os.listdir(input_dir)):
  55. if not file_name.endswith(".json"):
  56. continue
  57. json_path = os.path.join(input_dir, file_name)
  58. image_path = json_path.replace(".json", ".jpg")
  59. if not os.path.exists(image_path):
  60. print(f"图像不存在,跳过:{image_path}")
  61. continue
  62. with open(json_path, "r") as f:
  63. label_data = json.load(f)
  64. points_list = [item['points'][0] for item in label_data['shapes'] if item['label'] == 'arc']
  65. if len(points_list) != 3:
  66. print(f"{file_name} 中 arc 点数不足 3,跳过")
  67. continue
  68. image = cv2.imread(image_path)
  69. h, w = image.shape[:2]
  70. points = np.array(points_list)
  71. _, arc_points = fit_arc_and_create_mask(points, (h, w), point_step_deg, radius)
  72. shapes = build_shapes_from_points(arc_points, label="arc")
  73. if len(shapes) == 0:
  74. print(f"{file_name} 拟合失败,跳过")
  75. continue
  76. output_json = {
  77. "version": "5.0.1",
  78. "flags": {},
  79. "shapes": shapes,
  80. "imagePath": os.path.basename(image_path),
  81. "imageHeight": h,
  82. "imageWidth": w
  83. }
  84. base_name = os.path.splitext(os.path.basename(image_path))[0]
  85. out_json_path = os.path.join(output_dir, base_name + ".json")
  86. out_img_path = os.path.join(output_dir, base_name + ".jpg")
  87. with open(out_json_path, "w") as f:
  88. json.dump(output_json, f, indent=4)
  89. shutil.copy(image_path, out_img_path)
  90. print(f"\n✅ 所有 arc 区域已保存为 labelme 格式(图像 + json)到目录:{output_dir}")
  91. # ===== 修改为你自己的输入输出路径 =====
  92. input_dir = r"G:\python_ws_g\data\arc"
  93. output_dir = r"G:\python_ws_g\data\arcout"
  94. point_step_deg = 0.5
  95. draw_radius = 2
  96. if __name__ == "__main__":
  97. process_folder_labelme(input_dir, output_dir, point_step_deg, draw_radius)