camera_position_and_log.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ''' Camera position estimation from center marker '''
  2. import cv2
  3. from cv2 import aruco
  4. import numpy as np
  5. import math
  6. import sys
  7. import os
  8. sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
  9. from default_config import *
  10. visualization = True
  11. # save
  12. output = 'distance_estimation/logs'
  13. if not os.path.exists(output):
  14. os.makedirs(output)
  15. log_file = os.path.join(output, f'log_{len(os.listdir(output)):03d}.txt')
  16. with open(log_file, 'w') as f:
  17. f.write('x,y,z,roll,pitch,yaw\n')
  18. # Tải dữ liệu hiệu chuẩn camera, phù hợp với độ phân giải ban đầu
  19. calib_data_path = f"camera_calibration/calib_data/{set_resolution}/MultiMatrix.npz"
  20. calib_data = np.load(calib_data_path)
  21. print('resolution:', set_resolution)
  22. cam_mat = calib_data["camMatrix"]
  23. dist_coef = calib_data["distCoef"]
  24. marker_dict = aruco.getPredefinedDictionary(aruco.DICT_7X7_50)
  25. param_markers = aruco.DetectorParameters()
  26. cap = cv2.VideoCapture(0)
  27. # Thay đổi độ phân giải phù hợp với yêu cầu ban đầu
  28. new_height = RESOLUTION_STANDARDS[set_resolution]
  29. new_width, new_height = change_resolution(cap,new_height)
  30. print(f'Resolution camera {new_width}x{new_height}')
  31. fps = cap.get(cv2.CAP_PROP_FPS)
  32. print(f"Frames per second: {fps}")
  33. # convert rotation matrix to euler angles (degrees)
  34. def rotationMatrixEulerAngles(rotMatrix):
  35. assert rotMatrix.shape == (3, 3), "Ma trận quay phải có kích thước 3x3"
  36. sy = math.sqrt(rotMatrix[0, 0]* rotMatrix[0, 0] + rotMatrix[1, 0]*rotMatrix[1, 0])
  37. singular = sy < 1e-6
  38. if not singular:
  39. x = math.atan2(rotMatrix[2, 1], rotMatrix[2, 2])
  40. x = np.round(np.degrees(x))
  41. y = math.atan2(-rotMatrix[2, 0], sy)
  42. y = np.round(np.degrees(y))
  43. z = math.atan2(rotMatrix[1, 0], rotMatrix[0, 0])
  44. z = np.round(np.degrees(z))
  45. else:
  46. x = math.atan2(rotMatrix[1, 0], rotMatrix[0, 0])
  47. x = np.round(np.degrees(x))
  48. y = math.atan2(-rotMatrix[2, 0], sy)
  49. y = np.round(np.degrees(y))
  50. z = 0
  51. return np.array([x, y, z])
  52. while True:
  53. ret, frame = cap.read()
  54. center_y, center_x = frame.shape[0]//2, frame.shape[1]//2
  55. cv2.drawMarker(frame, (center_x, center_y), (0,0,255), markerType=cv2.MARKER_CROSS, markerSize=10, thickness=1, line_type=cv2.LINE_AA)
  56. if not ret:
  57. break
  58. gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  59. marker_corners, marker_IDs, reject = aruco.detectMarkers(
  60. gray_frame, marker_dict, parameters=param_markers
  61. )
  62. if marker_corners:
  63. rVec, tVec, _ = aruco.estimatePoseSingleMarkers(
  64. marker_corners, MARKER_SIZE, cam_mat, dist_coef
  65. )
  66. total_markers = range(0, marker_IDs.size)
  67. markers = {}
  68. for ids, corners, i in zip(marker_IDs, marker_corners, total_markers):
  69. corners = corners.reshape(4, 2)
  70. corners = corners.astype(int)
  71. top_right = corners[0].ravel()
  72. top_left = corners[1].ravel()
  73. bottom_right = corners[2].ravel()
  74. bottom_left = corners[3].ravel()
  75. # Chuyển đổi rVec thành ma trận quay R
  76. R, _ = cv2.Rodrigues(rVec[i])
  77. # Tính toán tọa độ các điểm của marker so với camera
  78. object_points = np.array([
  79. [-MARKER_SIZE / 2, MARKER_SIZE / 2, 0],
  80. [MARKER_SIZE / 2, MARKER_SIZE / 2, 0],
  81. [MARKER_SIZE / 2, -MARKER_SIZE / 2, 0],
  82. [-MARKER_SIZE / 2, -MARKER_SIZE / 2, 0]
  83. ])
  84. marker_points_camera = R @ object_points.T + tVec[i].reshape(3, 1)
  85. marker_points_camera = marker_points_camera.T
  86. distance = np.linalg.norm(tVec[i][0])
  87. # Draw the pose of the marker
  88. point = cv2.drawFrameAxes(frame, cam_mat, dist_coef, rVec[i], tVec[i], 4, 4)
  89. R, _ = cv2.Rodrigues(rVec[i]) # Chuyển rVec sang ma trận quay
  90. # R_inv = R.T # Lấy nghịch đảo của ma trận quay (tức là R^T nếu R là trực giao)
  91. # position = - R_inv @ tVec[i].reshape(3, 1) # Tính vị trí camera trong hệ marker
  92. # position = position.reshape(3,)
  93. position =np.array([-tVec[i][0][0], tVec[i][0][1], tVec[i][0][2]])
  94. position += default_positions[ids[0]]
  95. angles = rotationMatrixEulerAngles(R.T)
  96. markers[f'marker {ids[0]}'] = np.hstack((position, angles))
  97. if visualization:
  98. cv2.putText(
  99. frame,
  100. f"id: {ids[0]}",
  101. top_right,
  102. cv2.FONT_HERSHEY_PLAIN,
  103. 1.3,
  104. (0, 0, 255), 2, cv2.LINE_AA
  105. )
  106. # Nếu marker trung tâm (marker 0) xuất hiện thì chỉ cần lấy vị trí so với marker này
  107. if 'marker 0' in markers.keys():
  108. cam_position = markers['marker 0']
  109. # Nếu không, xét trung bình các marker
  110. else:
  111. cam_position = np.array([0., 0., 0., 0., 0., 0.])
  112. for v in markers.values():
  113. cam_position += v
  114. cam_position /= len(markers)
  115. with open(log_file, 'a') as f:
  116. line = ','.join(f'{i:.1f}' for i in cam_position.tolist()) +'\n'
  117. f.write(line)
  118. print(','.join(f'{i:.1f}' for i in cam_position.tolist()))
  119. if visualization:
  120. cv2.putText(
  121. frame,
  122. ','.join(f'{i:.1f}' for i in cam_position[:3].tolist()),
  123. (10, 20),
  124. cv2.FONT_HERSHEY_PLAIN,
  125. 1.,
  126. (0, 255, 0), 1, cv2.LINE_AA
  127. )
  128. cv2.putText(
  129. frame,
  130. ','.join(f'{i:.1f}' for i in cam_position[3:].tolist()),
  131. (10, 40),
  132. cv2.FONT_HERSHEY_PLAIN,
  133. 1.,
  134. (0, 0, 255), 1, cv2.LINE_AA
  135. )
  136. if visualization:
  137. cv2.imshow("frame", frame)
  138. key = cv2.waitKey(1)
  139. if key == ord("q"):
  140. break
  141. cap.release()
  142. if visualization:
  143. cv2.destroyAllWindows()