aboutsummaryrefslogtreecommitdiff
path: root/docs/user_guide/aruco_marker_pipeline/advanced_topics/optic_parameters_calibration.md
blob: 7bbfc636dd82c080122e77103b2cb7628afc1f5b (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
185
186
187
188
189
190
Calibrate optic parameters
==========================

A camera device have to be calibrated to compensate its optical distorsion.

![Optic parameters calibration](../../../img/optic_calibration.png)

## Print calibration board

The first step to calibrate a camera is to create an [ArUcoBoard](../../../argaze.md/#argaze.ArUcoMarker.ArUcoBoard) like in the code below:

```python
from argaze.ArUcoMarker import ArUcoMarkerDictionary, ArUcoBoard

# Create ArUco dictionary
aruco_dictionary = ArUcoMarkerDictionary.ArUcoMarkerDictionary('DICT_APRILTAG_16h5')

# Create an ArUco board of 7 columns and 5 rows with 5 cm squares with 3cm ArUco markers inside
aruco_board = ArUcoBoard.ArUcoBoard(7, 5, 5, 3, aruco_dictionary)

# Export ArUco board with 300 dpi resolution
aruco_board.save('./calibration_board.png', 300)
```

!!! note
      There is **A3_DICT_APRILTAG_16h5_3cm_35cmx25cm.pdf** file located in *./src/argaze/ArUcoMarker/utils/* folder ready to be printed on A3 paper sheet.

Let's print the calibration board before to go further.

## Capture board pictures 

Then, the calibration process needs to make many different captures of an [ArUcoBoard](../../../argaze.md/#argaze.ArUcoMarker.ArUcoBoard) through the camera and then, pass them to an [ArUcoDetector](../../../argaze.md/#argaze.ArUcoMarker.ArUcoDetector.ArUcoDetector) instance to detect board corners and store them as calibration data into an [ArUcoOpticCalibrator](../../../argaze.md/#argaze.ArUcoMarker.ArUcoOpticCalibrator) for final calibration process.

![Calibration step](../../../img/optic_calibration_step.png)

The sample of code below illustrates how to:

* load all required ArGaze objects,
* detect board corners into a Full HD camera video stream, 
* store detected corners as calibration data then, 
* once enough captures are made, process them to find optic parameters and, 
* finally, save optic parameters into a JSON file.

```python
from argaze.ArUcoMarker import ArUcoMarkerDictionary, ArUcoOpticCalibrator, ArUcoBoard, ArUcoDetector

# Create ArUco dictionary
aruco_dictionary = ArUcoMarkerDictionary.ArUcoMarkerDictionary('DICT_APRILTAG_16h5')

# Create ArUco optic calibrator
aruco_optic_calibrator = ArUcoOpticCalibrator.ArUcoOpticCalibrator()

# Create ArUco board of 7 columns and 5 rows with 5 cm squares with 3cm aruco markers inside
# Note: This board is the one expected during further board tracking
expected_aruco_board = ArUcoBoard.ArUcoBoard(7, 5, 5, 3, aruco_dictionary)

# Create ArUco detector
aruco_detector = ArUcoDetector.ArUcoDetector(dictionary=aruco_dictionary)

# Assuming that live Full HD (1920x1080) video stream is enabled
...

# Assuming there is a way to escape the while loop
...

    while video_stream.is_alive():

        # Capture image from video stream
        image = video_stream.read()

        # Detect all board corners in image
        aruco_detector.detect_board(image, expected_aruco_board, expected_aruco_board.markers_number)

        # If all board corners are detected
        if aruco_detector.board_corners_number() == expected_aruco_board.corners_number:

            # Draw board corners to show that board tracking succeeded
            aruco_detector.draw_board(image)

            # Append tracked board data for further calibration processing 
            aruco_optic_calibrator.store_calibration_data(aruco_detector.board_corners(), aruco_detector.board_corners_identifier())

# Start optic calibration processing for Full HD image resolution
print('Calibrating optic...')
optic_parameters = aruco_optic_calibrator.calibrate(expected_aruco_board, dimensions=(1920, 1080))

if optic_parameters:

    # Export optic parameters
    optic_parameters.to_json('./optic_parameters.json')

    print('Calibration succeeded: optic_parameters.json file exported.')

else:

    print('Calibration failed.')
```

Below, an optic_parameters JSON file example:

```json
{
    "rms": 0.6688921504088245,
    "dimensions": [
        1920,
        1080
    ],
    "K": [
        [
            1135.6524381415752,
            0.0,
            956.0685325355497
        ],
        [
            0.0,
            1135.9272506869524,
            560.059099810324
        ],
        [
            0.0,
            0.0,
            1.0
        ]
    ],
    "D": [
        0.01655492265003404,
        0.1985524264972037,
        0.002129965902489484,
        -0.0019528582922179365,
        -0.5792910353639452
    ]
}
```

## Load and display optic parameters

[ArUcoCamera.detector.optic_parameters](../../../argaze.md/#argaze.ArUcoMarker.ArUcoOpticCalibrator.OpticParameters) can be enabled thanks to a dedicated JSON entry.

Here is an extract from the JSON [ArUcoCamera](../../../argaze.md/#argaze.ArUcoMarker.ArUcoCamera) configuration file where optic parameters are loaded and displayed:

```json
{
    "name": "My FullHD Camera",
    "size": [1920, 1080],
    "aruco_detector": {
        "dictionary": "DICT_APRILTAG_16h5",
        "optic_parameters": {
            "rms": 0.6688921504088245,
            "dimensions": [
                1920,
                1080
            ],
            "K": [
                [
                    1135.6524381415752,
                    0.0,
                    956.0685325355497
                ],
                [
                    0.0,
                    1135.9272506869524,
                    560.059099810324
                ],
                [
                    0.0,
                    0.0,
                    1.0
                ]
            ],
            "D": [
                0.01655492265003404,
                0.1985524264972037,
                0.002129965902489484,
                -0.0019528582922179365,
                -0.5792910353639452
            ]
        }
    },
    ...
    "image_parameters": {
        ...
        "draw_optic_parameters_grid": {
            "width": 192,
            "height": 108,
            "z": 100,
            "point_size": 1,
            "point_color": [0, 0, 255]
        }
    }
```