aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/ArUcoMarkers/ArUcoTracker.py
blob: f5adb4ca2eaed611497b027d249ba3463489b51c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/env python

import numpy
import cv2 as cv
import cv2.aruco as aruco

# Built-in ArUco dictionaries from OpenCV library
ARUCO_DICT = {
    'DICT_4X4_50': aruco.DICT_4X4_50,
    'DICT_4X4_100': aruco.DICT_4X4_100,
    'DICT_4X4_250': aruco.DICT_4X4_250,
    'DICT_4X4_1000': aruco.DICT_4X4_1000,
    'DICT_5X5_50': aruco.DICT_5X5_50,
    'DICT_5X5_100': aruco.DICT_5X5_100,
    'DICT_5X5_250': aruco.DICT_5X5_250,
    'DICT_5X5_1000': aruco.DICT_5X5_1000,
    'DICT_6X6_50': aruco.DICT_6X6_50,
    'DICT_6X6_100': aruco.DICT_6X6_100,
    'DICT_6X6_250': aruco.DICT_6X6_250,
    'DICT_6X6_1000': aruco.DICT_6X6_1000,
    'DICT_7X7_50': aruco.DICT_7X7_50,
    'DICT_7X7_100': aruco.DICT_7X7_100,
    'DICT_7X7_250': aruco.DICT_7X7_250,
    'DICT_7X7_1000': aruco.DICT_7X7_1000,
    'DICT_ARUCO_ORIGINAL': aruco.DICT_ARUCO_ORIGINAL
}

class ArUcoTracker():
    """Track ArUco markers into a frame."""

    def __init__(self, aruco_dictionary_name, marker_length, camera):
        """Define which markers library to track and their size:
        - DICT_4X4_50
        - DICT_4X4_100
        - DICT_4X4_250
        - DICT_4X4_1000
        - DICT_5X5_50
        - DICT_5X5_100
        - DICT_5X5_250
        - DICT_5X5_1000
        - DICT_6X6_50
        - DICT_6X6_100
        - DICT_6X6_250
        - DICT_6X6_1000
        - DICT_7X7_50
        - DICT_7X7_100
        - DICT_7X7_250
        - DICT_7X7_1000
        - DICT_ARUCO_ORIGINAL
        """

        # check aruco dictionary name
        if ARUCO_DICT.get(aruco_dictionary_name, None) is None:
            raise NameError(f'Bad ArUco dictionnary name: {aruco_dictionary_name}')

        # load ArUco dictionary
        self.__aruco_dict = aruco.Dictionary_get(ARUCO_DICT[aruco_dictionary_name])

        # define marker length in centimeter
        self.__marker_length = marker_length

        # define camera
        self.__camera = camera

        # setup ArUco detection parameters
        self.__aruco_param = aruco.DetectorParameters_create()
        self.__aruco_param.cornerRefinementMethod = aruco.CORNER_REFINE_CONTOUR

        # define tracked markers data
        self.__markers_corners = []
        self.__markers_ids = []
        self.__rvecs = []
        self.__tvecs = []
        self.__points = []

        # define tracked board data
        self.__board = None
        self.__board_corners_number = 0
        self.__board_corners = []
        self.__board_corners_ids = []

    def __del__(self):
        pass

    def track(self, frame, estimate_pose = True):
        """Track ArUco markers in frame."""

        # DON'T MIRROR FRAME : it makes the markers detection to fail
        
        # detect markers from gray picture
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        self.__markers_corners, self.__markers_ids, rejectedPoints = aruco.detectMarkers(gray, self.__aruco_dict, parameters = self.__aruco_param)

        if len(self.__markers_corners) > 0 and estimate_pose:

            # markers pose estimation
            self.__rvecs, self.__tvecs, self.__points = aruco.estimatePoseSingleMarkers(self.__markers_corners, self.__marker_length, self.__camera.get_K(), self.__camera.get_D()) 

        else:

            self.__rvecs = []
            self.__tvecs = []
            self.__points = []

    def track_board(self, frame, board, expected_markers_number):
        """Track ArUco markers board in frame setting up the number of detected markers needed to agree detection."""

        # DON'T MIRROR FRAME : it makes the markers detection to fail
        
        # detect markers from gray picture
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        self.__markers_corners, self.__markers_ids, rejectedPoints = aruco.detectMarkers(gray, self.__aruco_dict, parameters = self.__aruco_param)

         # if all board markers are detected
        if self.get_markers_number() == expected_markers_number:

            self.__board = board
            self.__board_corners_number, self.__board_corners, self.__board_corners_ids = aruco.interpolateCornersCharuco(self.__markers_corners, self.__markers_ids, gray, self.__board.get_model())

        else:

            self.__board = None
            self.__board_corners_number = 0
            self.__board_corners = []
            self.__board_corners_ids = []

    def draw(self, frame):
        """Draw tracked markers in frame."""

        # draw detected markers square
        if len(self.__markers_corners) > 0:

            aruco.drawDetectedMarkers(frame, self.__markers_corners, self.__markers_ids)

            # draw marker axis if pose has been estimated
            if len(self.__rvecs) > 0:

                for (i, marker_id) in enumerate(self.__markers_ids):

                    aruco.drawAxis(frame, self.__camera.get_K(), self.__camera.get_D(), self.__rvecs[i], self.__tvecs[i], self.__marker_length)

    def draw_board(self, frame):
        """Draw tracked board corners in frame."""

        if self.__board != None:

            cv.drawChessboardCorners(frame, ((self.__board.get_size()[0] - 1 ), (self.__board.get_size()[1] - 1)), self.__board_corners, True)

    def get_markers_number(self):
        """Get tracked markers number."""
        return len(self.__markers_corners)

    def get_markers_ids(self):
        """Get tracked markers identifers."""
        return self.__markers_ids

    def get_marker_corners(self, i):
        """Get marker i corners."""
        return self.__markers_corners[i]

    def get_marker_rotation(self, i):
        """Get marker i rotation vector."""
        return self.__rvecs[i]

    def get_marker_translation(self, i):
        """Get marker i translation vector."""
        return self.__tvecs[i]

    def get_marker_points(self, i):
        """Get marker i points."""
        return self.__points[i]

    def get_board_corners_number(self):
        """Get tracked board corners number."""
        return self.__board_corners_number

    def get_board_corners_ids(self):
        """Get tracked board corners identifiers."""
        return self.__board_corners_ids

    def get_board_corners(self):
        """Get tracked board corners."""
        return self.__board_corners