haminhtien99 před 5 měsíci
revize
98441f9b72
72 změnil soubory, kde provedl 521 přidání a 0 odebrání
  1. 2 0
      .gitignore
  2. 65 0
      README.md
  3. binární
      camera_calibration/calib_data/original/MultiMatrix.npz
  4. 67 0
      camera_calibration/calibration.py
  5. 71 0
      camera_calibration/capture_images.py
  6. 53 0
      camera_calibration/capture_images_without_showing.py
  7. binární
      camera_calibration/images/original/image0.png
  8. binární
      camera_calibration/images/original/image1.png
  9. binární
      camera_calibration/images/original/image10.png
  10. binární
      camera_calibration/images/original/image11.png
  11. binární
      camera_calibration/images/original/image12.png
  12. binární
      camera_calibration/images/original/image13.png
  13. binární
      camera_calibration/images/original/image14.png
  14. binární
      camera_calibration/images/original/image15.png
  15. binární
      camera_calibration/images/original/image16.png
  16. binární
      camera_calibration/images/original/image17.png
  17. binární
      camera_calibration/images/original/image18.png
  18. binární
      camera_calibration/images/original/image19.png
  19. binární
      camera_calibration/images/original/image2.png
  20. binární
      camera_calibration/images/original/image20.png
  21. binární
      camera_calibration/images/original/image21.png
  22. binární
      camera_calibration/images/original/image22.png
  23. binární
      camera_calibration/images/original/image23.png
  24. binární
      camera_calibration/images/original/image24.png
  25. binární
      camera_calibration/images/original/image25.png
  26. binární
      camera_calibration/images/original/image26.png
  27. binární
      camera_calibration/images/original/image27.png
  28. binární
      camera_calibration/images/original/image28.png
  29. binární
      camera_calibration/images/original/image29.png
  30. binární
      camera_calibration/images/original/image3.png
  31. binární
      camera_calibration/images/original/image30.png
  32. binární
      camera_calibration/images/original/image31.png
  33. binární
      camera_calibration/images/original/image32.png
  34. binární
      camera_calibration/images/original/image33.png
  35. binární
      camera_calibration/images/original/image34.png
  36. binární
      camera_calibration/images/original/image35.png
  37. binární
      camera_calibration/images/original/image36.png
  38. binární
      camera_calibration/images/original/image37.png
  39. binární
      camera_calibration/images/original/image38.png
  40. binární
      camera_calibration/images/original/image39.png
  41. binární
      camera_calibration/images/original/image4.png
  42. binární
      camera_calibration/images/original/image5.png
  43. binární
      camera_calibration/images/original/image6.png
  44. binární
      camera_calibration/images/original/image7.png
  45. binární
      camera_calibration/images/original/image8.png
  46. binární
      camera_calibration/images/original/image9.png
  47. binární
      chessboard.png
  48. 25 0
      default_config.py
  49. 131 0
      distance_estimation/camera_position.py
  50. 96 0
      distance_estimation/distance_single.py
  51. 11 0
      generate_markers/generate.py
  52. binární
      generate_markers/markers/marker_0.png
  53. binární
      generate_markers/markers/marker_1.png
  54. binární
      generate_markers/markers/marker_10.png
  55. binární
      generate_markers/markers/marker_11.png
  56. binární
      generate_markers/markers/marker_12.png
  57. binární
      generate_markers/markers/marker_13.png
  58. binární
      generate_markers/markers/marker_14.png
  59. binární
      generate_markers/markers/marker_15.png
  60. binární
      generate_markers/markers/marker_16.png
  61. binární
      generate_markers/markers/marker_17.png
  62. binární
      generate_markers/markers/marker_18.png
  63. binární
      generate_markers/markers/marker_19.png
  64. binární
      generate_markers/markers/marker_2.png
  65. binární
      generate_markers/markers/marker_3.png
  66. binární
      generate_markers/markers/marker_4.png
  67. binární
      generate_markers/markers/marker_5.png
  68. binární
      generate_markers/markers/marker_6.png
  69. binární
      generate_markers/markers/marker_7.png
  70. binární
      generate_markers/markers/marker_8.png
  71. binární
      generate_markers/markers/marker_9.png
  72. binární
      requirements.txt

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+.venv/
+__pycache__/

+ 65 - 0
README.md

@@ -0,0 +1,65 @@
+# LANDING_SPACE
+
+Thuật toán hạ cánh và điều hướng drone dựa trên ArUco marker
+
+## Tải xuống git này và cài đặt các tài nguyên cần thiết
+
+```bash
+git clone https://git.vnai.xyz/haminhtien99/landing_space
+cd landing_space
+pip install -r requirements.txt
+```
+
+## Cài đặt các giá trị ban đầu cho marker
+
+Di chuyển tới file [`default_config.py`](default_config.py), thay đổi các giá trị sau
+
+```python
+MARKER_SIZE=5
+set_resolution='original'
+```
+
+
+
+## Hiệu chuẩn camera:
+
+Để thực hiện hiệu chuẩn, cần phải chụp ảnh bàn cờ `chessboard.jpg` được in trên giấy với nhiều góc độ khác nhau
+
+`python camera_calibration/capture_images.py`
+
+- Nhấn phím "s" để chụp ảnh, nhấn "q" để kết thúc.
+- Ảnh sẽ được lưu vào thư mục con của thư mục `camera_calibration/images`, tương ứng với giá trị `set_resolution` được đặt ban đầu.
+
+`python camera_calibration/capture_images_without_showing.py`, tương tự bên trên
+
+- Ảnh sẽ được tự động lưu vào thư mục `camera_calibration/images` sau mỗi 5 giây.
+- Nhấn tổ hợp phím `Ctrl` + `C` để thoát chương trình
+
+`python camera_calibration/calibration.py`
+
+- Thông số hiệu chuẩn của camera sẽ được lưu vào thư mục `camera_calibration/calib_data`.
+
+## Dữ liệu hiệu chuẩn
+Dữ liệu hiệu chuẩn camera lưu tại tệp .npz. Dữ liệu này bao gồm:
+
+- camMatrix: Ma trận camera, chứa các tham số nội tại của camera.
+- distCoef: Các hệ số biến dạng của camera.
+- rVector: Vector xoay của từng ảnh dùng để hiệu chuẩn.
+- tVector: Vector tịnh tiến của từng ảnh hiệu chuẩn.
+
+## Tạo mã Aruco:
+
+- Tạo tùy ý 20 mã marker. Chạy `python generate_markers/generate.py`.
+- Có thể thay đổi loại marker tùy ý, trong bài toán này sử dụng loại 7x7 (`aruco.DICT_7X7_50`)
+
+
+## Ước lượng vị trí marker so với camera:
+- Chạy `distance_estimation/distance_single.py` để in kết quả đầu ra kèm kết quả hình ảnh;
+- Hoặc chạy `distance_estimation/distance_single_without_showing.py` để in kết quả đầu ra.
+
+## Ước lượng vị trí camera (Hiện không khả dụng):
+`python distance_estimation/camera_position.py`
+- Ược lượng vị trí camera trong bản đồ tạo bởi các marker được xác định trước
+- Phương pháp này tính toán vị trí camera từ vector tVec, không sử dụng ma trận nghịch đảo của ma trận xoay (vốn yêu cầu mặt phẳng camera luôn song song với mặt phẳng của marker).
+- Các script này sẽ hiển thị vị trí tương đối của camera so với marker_2 đặt ở trung tâm vùng hạ cánh. `x, y, z, roll, pitch, yaw` sẽ được hiển thị trên màn hình.
+- Nhấn phím `q` để kết thúc, thoát video

binární
camera_calibration/calib_data/original/MultiMatrix.npz


+ 67 - 0
camera_calibration/calibration.py

@@ -0,0 +1,67 @@
+import cv2
+import os
+import numpy as np
+
+
+
+# LỰa chọn độ phân giải bằng cách thay đổi set_resolution
+resolution = 'original'
+
+# Checker board size
+CHESS_BOARD_DIM = (9, 6)
+
+# The size of Square in the checker board.
+SQUARE_SIZE = 24  # millimeters
+
+# termination criteria
+criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
+
+
+calib_data_path = f"camera_calibration/calib_data/{resolution}"
+if not os.path.exists(calib_data_path):
+    os.makedirs(calib_data_path)
+
+# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
+obj_3D = np.zeros((CHESS_BOARD_DIM[0] * CHESS_BOARD_DIM[1], 3), np.float32)
+
+obj_3D[:, :2] = np.mgrid[0 : CHESS_BOARD_DIM[0], 0 : CHESS_BOARD_DIM[1]].T.reshape(
+    -1, 2
+)
+obj_3D *= SQUARE_SIZE
+print(obj_3D)
+
+# Arrays to store object points and image points from all the images.
+obj_points_3D = []  # 3d point in real world space
+img_points_2D = []  # 2d points in image plane.
+
+# The images directory path
+image_dir_path = f"camera_calibration/images/{resolution}"
+files = os.listdir(image_dir_path)
+for file in files:
+    print(file)
+    imagePath = os.path.join(image_dir_path, file)
+
+    image = cv2.imread(imagePath)
+    grayScale = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
+    ret, corners = cv2.findChessboardCorners(image, CHESS_BOARD_DIM, None)
+    if ret == True:
+        obj_points_3D.append(obj_3D)
+        corners2 = cv2.cornerSubPix(grayScale, corners, (3, 3), (-1, -1), criteria)
+        img_points_2D.append(corners2)
+
+        img = cv2.drawChessboardCorners(image, CHESS_BOARD_DIM, corners2, ret)
+
+cv2.destroyAllWindows()
+ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
+    obj_points_3D, img_points_2D, grayScale.shape[::-1], None, None
+)
+print("calibrated")
+
+np.savez(
+    f"{calib_data_path}/MultiMatrix",
+    camMatrix=mtx,
+    distCoef=dist,
+    rVector=rvecs,
+    tVector=tvecs,
+)
+print(f'saved to {calib_data_path}/MultiMatrix')

+ 71 - 0
camera_calibration/capture_images.py

@@ -0,0 +1,71 @@
+import cv2
+import os
+import sys
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+from default_config import *
+
+
+visualization = True
+CHESS_BOARD_DIM = (9, 6)
+criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
+
+# checking if  images dir is exist not, if not then create images directory
+image_dir_path = f"CAMERA_CALIBRATION/images/{set_resolution}"
+if not os.path.exists(image_dir_path):
+    os.makedirs(image_dir_path)
+
+
+def detect_checker_board(image, grayImage, criteria, boardDimension):
+    ret, corners = cv2.findChessboardCorners(grayImage, boardDimension)
+    if ret == True:
+        corners1 = cv2.cornerSubPix(grayImage, corners, (3, 3), (-1, -1), criteria)
+        image = cv2.drawChessboardCorners(image, boardDimension, corners1, ret)
+
+    return image, ret
+
+
+cap = cv2.VideoCapture(0)
+
+# Thay đổi độ phân giải phù hợp với yêu cầu ban đầu
+new_height = RESOLUTION_STANDARDS[set_resolution]
+new_width, new_height = change_resolution(cap,new_height)    
+print(f'Resolution camera {new_width}x{new_height}')
+
+n = 0  # image_counter
+while True:
+    _, frame = cap.read()
+    copyFrame = frame.copy()
+    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+
+    image, board_detected = detect_checker_board(frame, gray, criteria, CHESS_BOARD_DIM)
+
+    if visualization:
+        cv2.putText(
+            frame,
+            f"saved_img : {n}",
+            (30, 40),
+            cv2.FONT_HERSHEY_PLAIN,
+            1.4,
+            (0, 255, 0),
+            2,
+            cv2.LINE_AA,
+        )
+
+        cv2.imshow("frame", frame)
+        cv2.imshow("copyFrame", copyFrame)
+
+    key = cv2.waitKey(1)
+
+    if key == ord("q"):
+        break
+    if key == ord("s") and board_detected == True:
+        # storing the checker board image
+        cv2.imwrite(f"{image_dir_path}/image{n}.png", copyFrame)
+
+        print(f"saved image number {n}")
+        n += 1  # incrementing the image counter
+cap.release()
+cv2.destroyAllWindows()
+
+print("Total saved Images:", n)

+ 53 - 0
camera_calibration/capture_images_without_showing.py

@@ -0,0 +1,53 @@
+import cv2
+import os
+import sys
+import time
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+from default_config import *
+
+CHESS_BOARD_DIM = (9, 6)
+criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
+
+image_dir_path = f"CAMERA_CALIBRATION/images/{set_resolution}"
+os.makedirs(image_dir_path, exist_ok=True)
+
+def detect_checker_board(image, grayImage, criteria, boardDimension):
+    ret, corners = cv2.findChessboardCorners(grayImage, boardDimension)
+    if ret:
+        corners1 = cv2.cornerSubPix(grayImage, corners, (3, 3), (-1, -1), criteria)
+        image = cv2.drawChessboardCorners(image, boardDimension, corners1, ret)
+    return image, ret
+
+cap = cv2.VideoCapture(0)
+
+# Thay đổi độ phân giải video theo cài đặt ở file default_config.py
+new_height = RESOLUTION_STANDARDS[set_resolution]
+new_width, new_height = change_resolution(cap, new_height)    
+print(f'Resolution camera {new_width}x{new_height}')
+
+n = 0  # image counter
+MAX_IMAGES = 20  # Limit for automatic saving
+
+while True:
+    ret, frame = cap.read()
+    if not ret:
+        break
+
+    copyFrame = frame.copy()
+    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+
+    _, board_detected = detect_checker_board(frame, gray, criteria, CHESS_BOARD_DIM)
+
+    if board_detected:
+        save_path = f"{image_dir_path}/image{n}.png"
+        cv2.imwrite(save_path, copyFrame)
+        print(f"[INFO] Saved image {n} at {save_path}")
+        n += 1
+
+        if n >= MAX_IMAGES:
+            break
+        time.sleep(5)
+
+cap.release()
+print("Total saved images:", n)

binární
camera_calibration/images/original/image0.png


binární
camera_calibration/images/original/image1.png


binární
camera_calibration/images/original/image10.png


binární
camera_calibration/images/original/image11.png


binární
camera_calibration/images/original/image12.png


binární
camera_calibration/images/original/image13.png


binární
camera_calibration/images/original/image14.png


binární
camera_calibration/images/original/image15.png


binární
camera_calibration/images/original/image16.png


binární
camera_calibration/images/original/image17.png


binární
camera_calibration/images/original/image18.png


binární
camera_calibration/images/original/image19.png


binární
camera_calibration/images/original/image2.png


binární
camera_calibration/images/original/image20.png


binární
camera_calibration/images/original/image21.png


binární
camera_calibration/images/original/image22.png


binární
camera_calibration/images/original/image23.png


binární
camera_calibration/images/original/image24.png


binární
camera_calibration/images/original/image25.png


binární
camera_calibration/images/original/image26.png


binární
camera_calibration/images/original/image27.png


binární
camera_calibration/images/original/image28.png


binární
camera_calibration/images/original/image29.png


binární
camera_calibration/images/original/image3.png


binární
camera_calibration/images/original/image30.png


binární
camera_calibration/images/original/image31.png


binární
camera_calibration/images/original/image32.png


binární
camera_calibration/images/original/image33.png


binární
camera_calibration/images/original/image34.png


binární
camera_calibration/images/original/image35.png


binární
camera_calibration/images/original/image36.png


binární
camera_calibration/images/original/image37.png


binární
camera_calibration/images/original/image38.png


binární
camera_calibration/images/original/image39.png


binární
camera_calibration/images/original/image4.png


binární
camera_calibration/images/original/image5.png


binární
camera_calibration/images/original/image6.png


binární
camera_calibration/images/original/image7.png


binární
camera_calibration/images/original/image8.png


binární
camera_calibration/images/original/image9.png


binární
chessboard.png


+ 25 - 0
default_config.py

@@ -0,0 +1,25 @@
+import cv2
+import os
+
+os.environ["QT_QPA_PLATFORM"] = "xcb"
+
+MARKER_SIZE = 5  # centimeters
+
+# LỰa chọn độ phân giải bằng cách thay đổi set_resolution
+set_resolution = 'original'
+RESOLUTION_STANDARDS = {'540p': 540, '720p': 720, '1080p': 1080, 'original': None}
+
+
+# Thay đổi độ phân giải phù hợp với yêu cầu ban đầu
+def change_resolution(capture: cv2.VideoCapture, new_height):
+    old_height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
+    old_width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
+
+    if new_height is not None:
+        new_width = int(old_width* new_height/old_height)
+        capture.set(cv2.CAP_PROP_FRAME_WIDTH, new_width)
+        capture.set(cv2.CAP_PROP_FRAME_HEIGHT, new_height)
+    else:
+        new_width = old_width
+        new_height = old_height
+    return (new_width, new_height)

+ 131 - 0
distance_estimation/camera_position.py

@@ -0,0 +1,131 @@
+''' Camera position estimation from center marker '''
+
+import cv2
+from cv2 import aruco
+import numpy as np
+import math
+import sys
+import os
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from default_config import *
+
+
+
+calib_data_path = f"camera_calibration/calib_data/{set_resolution}/MultiMatrix.npz"
+calib_data = np.load(calib_data_path)
+print('resolution:', set_resolution)
+
+cam_mat = calib_data["camMatrix"]
+dist_coef = calib_data["distCoef"]
+
+
+marker_dict = aruco.getPredefinedDictionary(aruco.DICT_7X7_50)
+param_markers = aruco.DetectorParameters()
+
+cap = cv2.VideoCapture(0)
+
+# Thay đổi độ phân giải phù hợp với yêu cầu ban đầu
+new_height = RESOLUTION_STANDARDS[set_resolution]
+new_width, new_height = change_resolution(cap,new_height)    
+print(f'Resolution camera {new_width}x{new_height}')
+
+fps = cap.get(cv2.CAP_PROP_FPS)
+print(f"Frames per second: {fps}")
+
+# convert rotation matrix to euler angles (degrees)
+def rotationMatrixEulerAngles(rotMatrix):
+    assert rotMatrix.shape == (3, 3), "Ma trận quay phải có kích thước 3x3"
+    sy = math.sqrt(rotMatrix[0, 0]* rotMatrix[0, 0] + rotMatrix[1, 0]*rotMatrix[1, 0])
+    singular = sy < 1e-6
+    if not singular:
+        x = math.atan2(rotMatrix[2, 1], rotMatrix[2, 2])
+        x = np.round(np.degrees(x))
+        y = math.atan2(-rotMatrix[2, 0], sy)
+        y = np.round(np.degrees(y))
+        z = math.atan2(rotMatrix[1, 0], rotMatrix[0, 0])
+        z = np.round(np.degrees(z))
+    else:
+        x = math.atan2(rotMatrix[1, 0], rotMatrix[0, 0])
+        x = np.round(np.degrees(x))
+        y = math.atan2(-rotMatrix[2, 0], sy)
+        y = np.round(np.degrees(y))
+        z = 0
+    return np.array([x, y, z])
+
+while True:
+    ret, frame = cap.read()
+
+    if not ret:
+        break
+    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+    marker_corners, marker_IDs, reject = aruco.detectMarkers(
+        gray_frame, marker_dict, parameters=param_markers
+    )
+    if marker_corners:
+        rVec, tVec, _ = aruco.estimatePoseSingleMarkers(
+            marker_corners, MARKER_SIZE, cam_mat, dist_coef
+        )
+        total_markers = range(0, marker_IDs.size)
+        markers = {}
+        for ids, corners, i in zip(marker_IDs, marker_corners, total_markers):
+            corners = corners.reshape(4, 2)
+            corners = corners.astype(int)
+            top_right = corners[0].ravel()
+            top_left = corners[1].ravel()
+            bottom_right = corners[2].ravel()
+            bottom_left = corners[3].ravel()
+    
+            # Chuyển đổi rVec thành ma trận quay R
+            R, _ = cv2.Rodrigues(rVec[i])
+        
+            # Tính toán tọa độ các điểm của marker so với camera
+            object_points = np.array([
+                [-MARKER_SIZE / 2, MARKER_SIZE / 2, 0],
+                [MARKER_SIZE / 2, MARKER_SIZE / 2, 0],
+                [MARKER_SIZE / 2, -MARKER_SIZE / 2, 0],
+                [-MARKER_SIZE / 2, -MARKER_SIZE / 2, 0]
+            ])
+            marker_points_camera = R @ object_points.T + tVec[i].reshape(3, 1)
+            marker_points_camera = marker_points_camera.T
+
+            distance = np.sqrt(
+                tVec[i][0][2] ** 2 + tVec[i][0][0] ** 2 + tVec[i][0][1] ** 2
+            )
+            # Draw the pose of the marker
+            # point = cv2.drawFrameAxes(frame, cam_mat, dist_coef, rVec[i], tVec[i], 4, 4)
+            x = -tVec[i][0][0]
+            y = tVec[i][0][1]
+            z = tVec[i][0][2]
+            pos = np.array([x, y, z])
+            angles = rotationMatrixEulerAngles(R.T)
+            if ids == 2:
+                markers['marker 2'] = np.hstack((pos,angles))
+            if ids == 0:
+                pos += np.array([-12.3, 9.1, 0])
+                markers['marker 0'] = np.hstack((pos,angles))
+            if ids == 1:
+                pos += np.array([12.3, 9.1, 0.])
+                markers['marker 1'] = np.hstack((pos,angles))
+            if ids == 3:
+                pos += np.array([-7.2, -9.1, 0.])
+                markers['marker 3'] = np.hstack((pos,angles))
+            if ids == 4:
+                pos += np.array([12.3, -5., 0.])
+                markers['marker 4'] = np.hstack((pos,angles))
+        if 'marker 2' in markers.keys():
+            x, y, z, roll, pitch, yaw = np.round(markers['marker 2'], 1)
+        else:
+            cam_position = np.array([0., 0., 0., 0., 0., 0.])
+            for v in markers.values():
+                cam_position += v
+            cam_position /= len(markers)
+            x, y, z, roll, pitch, yaw = np.round(cam_position, 1)
+        print(x, y, z, roll, pitch, yaw)
+    # cv2.imshow("frame", frame)
+    key = cv2.waitKey(1)
+    if key == ord("q"):
+        break
+cap.release()
+cv2.destroyAllWindows()

+ 96 - 0
distance_estimation/distance_single.py

@@ -0,0 +1,96 @@
+import cv2
+from cv2 import aruco
+import numpy as np
+import os
+import sys
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+from default_config import *
+
+visualzation = True
+
+
+calib_data_path = f"camera_calibration/calib_data/{set_resolution}/MultiMatrix.npz"
+calib_data = np.load(calib_data_path)
+print('resolution:', set_resolution)
+
+cam_mat = calib_data["camMatrix"]
+dist_coef = calib_data["distCoef"]
+
+
+marker_dict = aruco.getPredefinedDictionary(aruco.DICT_7X7_50)
+param_markers = aruco.DetectorParameters()
+
+cap = cv2.VideoCapture(0)
+
+# Thay đổi độ phân giải phù hợp với yêu cầu ban đầu
+new_height = RESOLUTION_STANDARDS[set_resolution]
+new_width, new_height = change_resolution(cap,new_height)    
+print(f'Resolution camera {new_width}x{new_height}')
+
+fps = cap.get(cv2.CAP_PROP_FPS)
+print(f"Frames per second: {fps}")
+
+while True:
+    ret, frame = cap.read()
+
+    if not ret:
+        break
+    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+    detector = cv2.aruco.ArucoDetector(marker_dict, param_markers)
+    marker_corners, marker_IDs, reject = detector.detectMarkers(gray_frame)
+    if marker_corners:
+        rVec, tVec, _ = aruco.estimatePoseSingleMarkers(
+            marker_corners, MARKER_SIZE, cam_mat, dist_coef
+        )
+        total_markers = range(0, marker_IDs.size)
+        for ids, corners, i in zip(marker_IDs, marker_corners, total_markers):
+            if visualzation:
+                cv2.polylines(
+                    frame, [corners.astype(np.int32)], True, (0, 255, 255), 4, cv2.LINE_AA
+                )
+            corners = corners.reshape(4, 2)
+            corners = corners.astype(int)
+            top_right = corners[0].ravel()
+            top_left = corners[1].ravel()
+            bottom_right = corners[2].ravel()
+            bottom_left = corners[3].ravel()
+
+            distance = np.linalg.norm(tVec[i][0])
+            x = tVec[i][0][0]
+            y = tVec[i][0][1]
+            z = tVec[i][0][2]
+
+            # Draw the pose of the marker
+            if visualzation:
+                point = cv2.drawFrameAxes(frame, cam_mat, dist_coef, rVec[i], tVec[i], 4, 4)
+                cv2.putText(
+                    frame,
+                    f"id: {ids[0]} Dist: {distance: .2f}",
+                    top_right,
+                    cv2.FONT_HERSHEY_PLAIN,
+                    1.3,
+                    (0, 0, 255),
+                    2,
+                    cv2.LINE_AA,
+                )
+                cv2.putText(
+                    frame,
+                    f"x:{x: .1f} y: {y: .1f} ",
+                    bottom_right,
+                    cv2.FONT_HERSHEY_PLAIN,
+                    1.0,
+                    (0, 0, 255),
+                    2,
+                    cv2.LINE_AA,
+                )
+            print(f"Marker {ids[0]}: x = {x: .1f}, y = {y: .1f} , z = {z: .1f}, distance = {distance: .2f}")
+    if visualzation:
+        cv2.imshow("frame", frame)
+        key = cv2.waitKey(1)
+        if key == ord("q"):
+            break
+cap.release()
+
+if visualzation:
+    cv2.destroyAllWindows()

+ 11 - 0
generate_markers/generate.py

@@ -0,0 +1,11 @@
+import cv2 as cv
+from cv2 import aruco
+
+marker_dict = aruco.getPredefinedDictionary(aruco.DICT_7X7_50)
+
+MARKER_SIZE = 400  # pixels
+
+for id in range(5):
+    marker_image = aruco.generateImageMarker(marker_dict, id, MARKER_SIZE)
+    cv.imwrite(f"markers/marker_{id}.png", marker_image)
+

binární
generate_markers/markers/marker_0.png


binární
generate_markers/markers/marker_1.png


binární
generate_markers/markers/marker_10.png


binární
generate_markers/markers/marker_11.png


binární
generate_markers/markers/marker_12.png


binární
generate_markers/markers/marker_13.png


binární
generate_markers/markers/marker_14.png


binární
generate_markers/markers/marker_15.png


binární
generate_markers/markers/marker_16.png


binární
generate_markers/markers/marker_17.png


binární
generate_markers/markers/marker_18.png


binární
generate_markers/markers/marker_19.png


binární
generate_markers/markers/marker_2.png


binární
generate_markers/markers/marker_3.png


binární
generate_markers/markers/marker_4.png


binární
generate_markers/markers/marker_5.png


binární
generate_markers/markers/marker_6.png


binární
generate_markers/markers/marker_7.png


binární
generate_markers/markers/marker_8.png


binární
generate_markers/markers/marker_9.png


binární
requirements.txt