main.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import cv2
  2. import os
  3. import sys
  4. sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
  5. import time
  6. import glob
  7. import json
  8. import argparse
  9. import pickle
  10. import matplotlib.pyplot as plt
  11. from datetime import datetime
  12. import numpy as np
  13. import scipy.io as sio
  14. from scipy.io import savemat, loadmat
  15. np.random.seed(42)
  16. from src.utils import binarize, get_meshgrid, get_world_points, get_camera_points, get_screen_points, write_point_cloud, \
  17. get_white_mask, get_world_points_from_mask, get_meshgrid_contour, post_process
  18. from src.phase import extract_phase, unwrap_phase
  19. from src.recons import reconstruction_cumsum
  20. from src.calibration import calibrate_world, calibrate_screen, map_screen_to_world
  21. from src.vis import plot_coords
  22. from src.eval import get_eval_result, find_notch
  23. def list_directories(path):
  24. # List all items in the given directory and filter only directories
  25. return [item for item in os.listdir(path) if os.path.isdir(os.path.join(path, item))]
  26. def parse_args():
  27. parser = argparse.ArgumentParser(description="")
  28. parser.add_argument("--img_path", type=str, default='D:\\file\\20240913-data\\20240913105234292')
  29. parser.add_argument("--camera_path", type=str, default='D:\\file\\标定数据\\标定数据0913\\calibration_0913')
  30. parser.add_argument("--screen_path", type=str, default='D:\\file\\screen0920')
  31. parser.add_argument("--cfg", type=str, default="config/cfg_3freq_wafer.json")
  32. #parser.add_argument("--cfg", type=str, default="D:\code\pmdrecons-python\config\cfg_3freq_wafer.json")
  33. parser.add_argument("--save_path", type=str, default="debug")
  34. parser.add_argument("--grid_spacing", type=int, default=1)
  35. parser.add_argument("--debug", action='store_true')
  36. parser.add_argument("--smooth", action='store_true')
  37. parser.add_argument("--align", action='store_true')
  38. parser.add_argument("--denoise", action='store_true')
  39. args = parser.parse_args()
  40. return args
  41. def main(cfg, img_folder, camera_path, screen_path, save_path, grid_spacing, debug):
  42. n_cam = 4
  43. num_freq = cfg['num_freq']
  44. start_time = time.time()
  45. #debug = True
  46. print(f"开始执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  47. print("\n1. 相机标定")
  48. preprocess_start = time.time()
  49. camera_subdir = list_directories(camera_path)
  50. camera_subdir.sort()
  51. assert len(camera_subdir) == 4, f"found {len(camera_subdir)} cameras, should be 4"
  52. cam_para_path = os.path.join(camera_path, "cam_params.pkl")
  53. if os.path.exists(cam_para_path):
  54. with open(cam_para_path, 'rb') as pkl_file:
  55. cam_params = pickle.load(pkl_file)
  56. else:
  57. cam_params = []
  58. for i in range(n_cam):
  59. cam_img_path = glob.glob(os.path.join(camera_path, camera_subdir[i], "*.bmp"))
  60. cam_img_path.sort()
  61. cam_param_raw = calibrate_world(cam_img_path, i, cfg['world_chessboard_size'], cfg['world_square_size'], debug=False)
  62. cam_params.append(cam_param_raw)
  63. with open(cam_para_path, 'wb') as pkl_file:
  64. pickle.dump(cam_params, pkl_file)
  65. preprocess_end = time.time()
  66. print(f" 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  67. print(f" 耗时: {preprocess_end - preprocess_start:.2f} 秒")
  68. # import pdb; pdb.set_trace()
  69. print("\n2. 屏幕标定")
  70. screen_cal_start = time.time()
  71. screen_img_path = glob.glob(os.path.join(screen_path, "*.bmp"))
  72. screen_para_path = os.path.join(screen_path, "screen_params.pkl")
  73. if os.path.exists(screen_para_path):
  74. with open(screen_para_path, 'rb') as pkl_file:
  75. screen_params = pickle.load(pkl_file)[0]
  76. else:
  77. screen_params = calibrate_screen(screen_img_path, cam_params[0]['camera_matrix'], cam_params[0]['distortion_coefficients'], cfg['screen_chessboard_size'], cfg['screen_square_size'], debug=True)
  78. with open(screen_para_path, 'wb') as pkl_file:
  79. pickle.dump([screen_params], pkl_file)
  80. screen_to_world = map_screen_to_world(screen_params, cam_params[0])
  81. screen_cal_end = time.time()
  82. print(f" 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  83. print(f" 耗时: {screen_cal_end - screen_cal_start:.2f} 秒")
  84. print("\n3. 相位提取,相位展开")
  85. phase_start = time.time()
  86. x_uns, y_uns = [], []
  87. binary_masks = []
  88. for cam_id in range(n_cam):
  89. white_path = os.path.join(img_folder, f'{cam_id}_frame_24.bmp')
  90. binary = get_white_mask(white_path)
  91. binary_masks.append(binary)
  92. phases = extract_phase(img_folder, cam_id, binary, cam_params[cam_id]['camera_matrix'], cam_params[cam_id]['distortion_coefficients'], num_freq=num_freq)
  93. x_un, y_un = unwrap_phase(phases, save_path, num_freq, debug=False)
  94. x_uns.append(x_un)
  95. y_uns.append(y_un)
  96. phase_end = time.time()
  97. print(f" 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  98. print(f" 耗时: {phase_end - phase_start:.2f} 秒")
  99. print("\n4. 获得不同坐标系下点的位置")
  100. get_point_start = time.time()
  101. total_cloud_point = np.empty((0, 3))
  102. for i in range(n_cam):
  103. if i > 5:
  104. continue
  105. contours_point = get_meshgrid_contour(binary_masks[i], grid_spacing, save_path, debug=False)
  106. world_points = get_world_points(contours_point, cam_params[i], grid_spacing, cfg['d'], save_path, debug=debug)
  107. camera_points, u_p, v_p = get_camera_points(world_points, cam_params[i], save_path, i, debug=debug)
  108. point_data = {'x_w': world_points[:, 0], 'y_w': world_points[:, 1], 'z_w': world_points[:, 2],
  109. 'x_c': camera_points[:, 0], 'y_c': camera_points[:, 1], 'z_c': camera_points[:, 2],
  110. 'u_p': u_p, 'v_p': v_p}
  111. screen_points = get_screen_points(point_data, x_uns[i], y_uns[i], screen_params, screen_to_world, cfg, save_path, i, debug=debug)
  112. #plot_coords(world_points, camera_points, screen_points)
  113. z, smoothed, aligned, denoise = reconstruction_cumsum(world_points, camera_points, screen_points, save_path, i, debug=debug, smooth=args.smooth, align=args.align, denoise=args.denoise)
  114. write_point_cloud(os.path.join(img_folder, str(i) + '_cloudpoint.txt'), world_points[:, 0], world_points[:, 1], 1000 * denoise[:,2])
  115. total_cloud_point = np.vstack([total_cloud_point, np.column_stack((denoise[:, 0], denoise[:, 1], 1000 * denoise[:,2]))])
  116. print('point cloud has been written in file')
  117. write_point_cloud(os.path.join(img_folder, 'cloudpoint.txt'), total_cloud_point[:, 0], total_cloud_point[:, 1], total_cloud_point[:,2])
  118. if debug:
  119. fig = plt.figure()
  120. ax = fig.add_subplot(111, projection='3d')
  121. # 提取 x, y, z 坐标
  122. x_vals = total_cloud_point[:, 0]
  123. y_vals = total_cloud_point[:, 1]
  124. z_vals = total_cloud_point[:, 2]
  125. # 绘制3D点云
  126. ax.scatter(x_vals, y_vals, z_vals, c=z_vals, cmap='viridis', marker='o')
  127. # 设置轴标签和标题
  128. ax.set_xlabel('X (mm)')
  129. ax.set_ylabel('Y (mm)')
  130. ax.set_zlabel('Z (mm)')
  131. ax.set_title('3D Point Cloud Visualization')
  132. plt.show()
  133. get_point_end = time.time()
  134. print(f" 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  135. print(f" 耗时: {get_point_end - get_point_start:.2f} 秒")
  136. print("\n5. 后处理")
  137. post_process_start = time.time()
  138. post_process(args.img_path, debug)
  139. post_process_end = time.time()
  140. print(f" 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  141. print(f" 耗时: {post_process_end - post_process_start:.2f} 秒")
  142. print("\n6. 评估")
  143. eval_start = time.time()
  144. point_cloud_path = os.path.join(img_folder, str(i) + '_cloudpoint.txt')
  145. json_path = os.path.join(img_folder, str(i) + 'result.json')
  146. theta_notch = 0
  147. get_eval_result(point_cloud_path, json_path, theta_notch)
  148. post_process(args.img_path, debug)
  149. eval_end = time.time()
  150. print(f" 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  151. print(f" 耗时: {eval_end - eval_start:.2f} 秒")
  152. return True
  153. if __name__ == '__main__':
  154. start_time = time.time()
  155. args = parse_args()
  156. img_folder = args.img_path
  157. cfg = json.load(open(args.cfg, 'r'))
  158. if not os.path.exists(args.save_path):
  159. os.makedirs(args.save_path)
  160. args.smooth = True
  161. args.align = True
  162. args.denoise = True
  163. args.debug = 0
  164. main(cfg, img_folder, args.camera_path, args.screen_path, args.save_path, args.grid_spacing, args.debug)
  165. end_time = time.time()
  166. print(f"总运行时间: {end_time - start_time:.2f} 秒")