Skip to content

Commit 3a99967

Browse files
Merge branch 'main' of github.com:luxonis/depthai
2 parents a920f79 + 251296f commit 3a99967

33 files changed

+1113
-655
lines changed

calibrate.py

Lines changed: 90 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -27,72 +27,39 @@
2727
red = (255, 0, 0)
2828
green = (0, 255, 0)
2929

30-
if hasattr(dai.CameraBoardSocket, 'CAM_A'):
31-
stringToCam = {
32-
'RGB' : dai.CameraBoardSocket.CAM_A,
33-
'LEFT' : dai.CameraBoardSocket.CAM_B,
34-
'RIGHT' : dai.CameraBoardSocket.CAM_C,
35-
'CAM_A' : dai.CameraBoardSocket.CAM_A,
36-
'CAM_B' : dai.CameraBoardSocket.CAM_B,
37-
'CAM_C' : dai.CameraBoardSocket.CAM_C,
38-
'CAM_D' : dai.CameraBoardSocket.CAM_D,
39-
'CAM_E' : dai.CameraBoardSocket.CAM_E,
40-
'CAM_F' : dai.CameraBoardSocket.CAM_F,
41-
'CAM_G' : dai.CameraBoardSocket.CAM_G,
42-
'CAM_H' : dai.CameraBoardSocket.CAM_H
43-
}
44-
camToString = {
45-
dai.CameraBoardSocket.CAM_A : 'RGB' ,
46-
dai.CameraBoardSocket.CAM_B : 'LEFT' ,
47-
dai.CameraBoardSocket.CAM_C : 'RIGHT',
48-
dai.CameraBoardSocket.CAM_A : 'CAM_A',
49-
dai.CameraBoardSocket.CAM_B : 'CAM_B',
50-
dai.CameraBoardSocket.CAM_C : 'CAM_C',
51-
dai.CameraBoardSocket.CAM_D : 'CAM_D',
52-
dai.CameraBoardSocket.CAM_E : 'CAM_E',
53-
dai.CameraBoardSocket.CAM_F : 'CAM_F',
54-
dai.CameraBoardSocket.CAM_G : 'CAM_G',
55-
dai.CameraBoardSocket.CAM_H : 'CAM_H'
56-
}
57-
else:
58-
stringToCam = {
59-
'RGB': dai.CameraBoardSocket.RGB,
60-
'LEFT': dai.CameraBoardSocket.LEFT,
61-
'RIGHT': dai.CameraBoardSocket.RIGHT,
62-
'AUTO': dai.CameraBoardSocket.AUTO,
63-
'CAM_A' : dai.CameraBoardSocket.RGB,
64-
'CAM_B' : dai.CameraBoardSocket.LEFT,
65-
'CAM_C' : dai.CameraBoardSocket.RIGHT
66-
}
67-
68-
camToString = {
69-
# dai.CameraBoardSocket.RGB : 'RGB' ,
70-
# dai.CameraBoardSocket.LEFT : 'LEFT' ,
71-
# dai.CameraBoardSocket.RIGHT : 'RIGHT',
72-
# dai.CameraBoardSocket.AUTO : 'AUTO',
73-
dai.CameraBoardSocket.RGB : 'CAM_A',
74-
dai.CameraBoardSocket.LEFT : 'CAM_B',
75-
dai.CameraBoardSocket.RIGHT : 'CAM_C',
76-
}
30+
31+
stringToCam = {
32+
'RGB' : dai.CameraBoardSocket.CAM_A,
33+
'LEFT' : dai.CameraBoardSocket.CAM_B,
34+
'RIGHT' : dai.CameraBoardSocket.CAM_C,
35+
'CAM_A' : dai.CameraBoardSocket.CAM_A,
36+
'CAM_B' : dai.CameraBoardSocket.CAM_B,
37+
'CAM_C' : dai.CameraBoardSocket.CAM_C,
38+
'CAM_D' : dai.CameraBoardSocket.CAM_D,
39+
'CAM_E' : dai.CameraBoardSocket.CAM_E,
40+
'CAM_F' : dai.CameraBoardSocket.CAM_F,
41+
'CAM_G' : dai.CameraBoardSocket.CAM_G,
42+
'CAM_H' : dai.CameraBoardSocket.CAM_H
43+
}
7744

7845

7946
camToMonoRes = {
80-
'OV7251' : dai.MonoCameraProperties.SensorResolution.THE_480_P,
81-
'OV9*82' : dai.MonoCameraProperties.SensorResolution.THE_800_P,
82-
'OV9282' : dai.MonoCameraProperties.SensorResolution.THE_800_P,
83-
'AR0234' : dai.MonoCameraProperties.SensorResolution.THE_1200_P,
84-
}
47+
'OV7251' : dai.MonoCameraProperties.SensorResolution.THE_480_P,
48+
'OV9*82' : dai.MonoCameraProperties.SensorResolution.THE_800_P,
49+
'OV9282' : dai.MonoCameraProperties.SensorResolution.THE_800_P,
50+
'AR0234' : dai.MonoCameraProperties.SensorResolution.THE_1200_P,
51+
}
8552

8653
camToRgbRes = {
87-
'IMX378' : dai.ColorCameraProperties.SensorResolution.THE_4_K,
88-
'IMX214' : dai.ColorCameraProperties.SensorResolution.THE_4_K,
89-
'OV9*82' : dai.ColorCameraProperties.SensorResolution.THE_800_P,
90-
'OV9282' : dai.ColorCameraProperties.SensorResolution.THE_800_P,
91-
'OV9782' : dai.ColorCameraProperties.SensorResolution.THE_800_P,
92-
'IMX582' : dai.ColorCameraProperties.SensorResolution.THE_12_MP,
93-
'AR0234' : dai.ColorCameraProperties.SensorResolution.THE_1200_P,
94-
'IMX296' : dai.ColorCameraProperties.SensorResolution.THE_1440X1080,
95-
}
54+
'IMX378' : dai.ColorCameraProperties.SensorResolution.THE_4_K,
55+
'IMX214' : dai.ColorCameraProperties.SensorResolution.THE_4_K,
56+
'OV9*82' : dai.ColorCameraProperties.SensorResolution.THE_800_P,
57+
'OV9282' : dai.ColorCameraProperties.SensorResolution.THE_800_P,
58+
'OV9782' : dai.ColorCameraProperties.SensorResolution.THE_800_P,
59+
'IMX582' : dai.ColorCameraProperties.SensorResolution.THE_12_MP,
60+
'AR0234' : dai.ColorCameraProperties.SensorResolution.THE_1200_P,
61+
'IMX296' : dai.ColorCameraProperties.SensorResolution.THE_1440X1080,
62+
}
9663

9764
def create_blank(width, height, rgb_color=(0, 0, 0)):
9865
"""Create new image(numpy array) filled with certain color in RGB"""
@@ -164,25 +131,32 @@ def parse_args():
164131
help="Invert horizontal axis of the camera for the display")
165132
# parser.add_argument("-ep", "--maxEpiploarError", default="1.0", type=float, required=False,
166133
# help="Sets the maximum epiploar allowed with rectification")
167-
parser.add_argument("-cm", "--cameraMode", default="perspective", type=str,
168-
required=False, help="Choose between perspective and Fisheye")
134+
parser.add_argument("-cm", "--cameraModel", default="", choices=["perspective", "fisheye"], type=str,
135+
required=False, help="Overwrite the camera model specified in board config file. Choose between perspective and fisheye.")
169136
parser.add_argument("-rlp", "--rgbLensPosition", default=-1, type=int,
170137
required=False, help="Set the manual lens position of the camera for calibration")
171-
parser.add_argument("-fps", "--fps", default=10, type=int,
172-
required=False, help="Set capture FPS for all cameras. Default: %(default)s")
173138
parser.add_argument("-cd", "--captureDelay", default=5, type=int,
174139
required=False, help="Choose how much delay to add between pressing the key and capturing the image. Default: %(default)s")
175140
parser.add_argument("-d", "--debug", default=False, action="store_true", help="Enable debug logs.")
176141
parser.add_argument("-fac", "--factoryCalibration", default=False, action="store_true",
177142
help="Enable writing to Factory Calibration.")
178143
parser.add_argument("-osf", "--outputScaleFactor", type=float, default=0.5,
179144
help="set the scaling factor for output visualization. Default: 0.5.")
145+
parser.add_argument('-fps', '--framerate', type=float, default=10,
146+
help="FPS to set for all cameras. Default: %(default)s")
180147
parser.add_argument("-sync", "--minSyncTime", type=float, default=0.2,
181-
help="set the minimum time enforced between frames to keep synchronization. Default: 0.2.")
148+
help="set the minimum time enforced between frames to keep synchronization. Default: %(default)s.")
182149
parser.add_argument("-q", "--minQueueDepth", type=int, default=4,
183-
help="set the minimum queue depth for syncing before retrieving synced frames. Default: 1.")
184-
185-
150+
help="set the minimum queue depth for syncing before retrieving synced frames. Default: %(default)s.")
151+
parser.add_argument('-scp', '--saveCalibPath', type=str, default="",
152+
help="Save calibration file to this path")
153+
parser.add_argument('-dst', '--datasetPath', type=str, default="dataset",
154+
help="Path to dataset used for processing images")
155+
parser.add_argument('-mt', '--mouseTrigger', default=False, action="store_true",
156+
help="Enable mouse trigger for image capture")
157+
parser.add_argument('-l', '--traceLevel', type=int, default=2,
158+
help="Set the debug trace level. Default: %(default)s.")
159+
186160
options = parser.parse_args()
187161

188162
# Set some extra defaults, `-brd` would override them
@@ -201,7 +175,6 @@ def parse_args():
201175
options.rgbLensPosition = 135
202176

203177
return options
204-
205178
class MessageSync:
206179
def __init__(self, num_queues, min_diff_timestamp, max_num_messages=10, min_queue_depth=3):
207180
self.num_queues = num_queues
@@ -294,6 +267,7 @@ class Main:
294267
current_polygon = 0
295268
images_captured_polygon = 0
296269
images_captured = 0
270+
camera_model = "perspective"
297271

298272
def __init__(self):
299273
global debug
@@ -379,6 +353,10 @@ def close(self):
379353
if self.device:
380354
self.device.close()
381355

356+
def mouse_event_callback(self, event, x, y, flags, param):
357+
if event == cv2.EVENT_LBUTTONDOWN:
358+
self.mouseTrigger = True
359+
382360
def is_markers_found(self, frame):
383361
marker_corners, _, _ = cv2.aruco.detectMarkers(
384362
frame, self.aruco_dictionary)
@@ -404,7 +382,7 @@ def test_camera_orientation(self, frame_l, frame_r):
404382
def create_pipeline(self):
405383
pipeline = dai.Pipeline()
406384

407-
fps = self.args.fps
385+
fps = self.args.framerate
408386
cams = {}
409387
for cam_id in self.board_config['cameras']:
410388
cam_info = self.board_config['cameras'][cam_id]
@@ -460,7 +438,7 @@ def parse_frame(self, frame, stream_name):
460438

461439
filename = calibUtils.image_filename(
462440
stream_name, self.current_polygon, self.images_captured)
463-
cv2.imwrite("dataset/{}/{}".format(stream_name, filename), frame)
441+
cv2.imwrite(f"{str(self.dataset_path)}/{stream_name}/{filename}", frame)
464442
print("py: Saved image as: " + str(filename))
465443
return True
466444

@@ -552,6 +530,7 @@ def capture_images_sync(self):
552530

553531
self.display_name = "Image Window"
554532
syncCollector = MessageSync(len(self.camera_queue.keys()), min_diff_timestamp=self.args.minSyncTime, min_queue_depth=self.args.minQueueDepth)
533+
self.mouseTrigger = False
555534

556535
# Clear events
557536
streams = self.device.getQueueEvents(list(self.camera_queue.keys()))
@@ -675,10 +654,11 @@ def capture_images_sync(self):
675654
if key == 27 or key == ord("q"):
676655
print("py: Calibration has been interrupted!")
677656
raise SystemExit(0)
678-
elif key == ord(" "):
657+
elif key == ord(" ") or self.mouseTrigger:
679658
start_timer = True
680659
prev_time = time.time()
681660
timer = self.args.captureDelay
661+
self.mouseTrigger = False
682662

683663
if start_timer == True:
684664
curr_time = time.time()
@@ -696,6 +676,10 @@ def capture_images_sync(self):
696676
7, (0, 255, 255),
697677
4, cv2.LINE_AA)
698678

679+
cv2.namedWindow(self.display_name)
680+
if self.args.mouseTrigger:
681+
cv2.setMouseCallback(self.display_name, self.mouse_event_callback)
682+
699683
cv2.imshow(self.display_name, combinedImage)
700684
tried = {}
701685
allPassed = True
@@ -941,21 +925,25 @@ def capture_images(self):
941925

942926
def calibrate(self):
943927
print("Starting image processing")
944-
stereo_calib = calibUtils.StereoCalibration()
945-
# self.args.cameraMode = 'perspective' # hardcoded for now
946-
try:
928+
stereo_calib = calibUtils.StereoCalibration(self.args.traceLevel)
929+
930+
self.camera_model = self.board_config.get("camera_model", "perspective")
947931

932+
if self.args.cameraModel != "": # If camera model is specified in the command line, use that
933+
self.camera_model = self.args.cameraModel
934+
935+
try:
948936
# stereo_calib = StereoCalibration()
949937
print("Starting image processingxxccx")
950938
print(self.args.squaresX)
951939
status, result_config = stereo_calib.calibrate(
952940
self.board_config,
953-
self.dataset_path,
941+
str(self.dataset_path),
954942
self.args.squareSizeCm,
955943
self.args.markerSizeCm,
956944
self.args.squaresX,
957945
self.args.squaresY,
958-
self.args.cameraMode,
946+
self.camera_model,
959947
self.args.rectifiedDisp) # Turn off enable disp rectify
960948

961949
calibration_handler = dai.CalibrationHandler()
@@ -1014,6 +1002,10 @@ def prepare_calibration_handler(self, result_config, calibration_handler):
10141002
calibration_handler.setDistortionCoefficients(stringToCam[camera], cam_info['dist_coeff'])
10151003
calibration_handler.setCameraIntrinsics(stringToCam[camera], cam_info['intrinsics'], cam_info['size'][0], cam_info['size'][1])
10161004
calibration_handler.setFov(stringToCam[camera], cam_info['hfov'])
1005+
if self.camera_model == "perspective":
1006+
calibration_handler.setCameraType(stringToCam[camera], dai.CameraModel.Perspective)
1007+
elif self.camera_model == "fisheye":
1008+
calibration_handler.setCameraType(stringToCam[camera], dai.CameraModel.Fisheye)
10171009

10181010
if 'hasAutofocus' in cam_info and cam_info['hasAutofocus']:
10191011
calibration_handler.setLensPosition(stringToCam[camera], self.focus_value)
@@ -1088,7 +1080,14 @@ def flash(self, result_config):
10881080
eeepromData.version = 7
10891081
print(f'EEPROM VERSION being flashed is -> {eeepromData.version}')
10901082
mx_serial_id = self.device.getDeviceInfo().getMxId()
1091-
calib_dest_path = self.dest_path / f"{mx_serial_id}.json"
1083+
1084+
calib_dest_folder = self.dest_path
1085+
if self.args.saveCalibPath:
1086+
calib_dest_folder = Path(self.args.saveCalibPath)
1087+
calib_dest_folder.mkdir(parents=True, exist_ok=True)
1088+
1089+
calib_dest_path = calib_dest_folder / f"{mx_serial_id}.json"
1090+
10921091
calibration_handler.eepromToJsonFile(calib_dest_path)
10931092
# try:
10941093
self.device.flashCalibration2(calibration_handler)
@@ -1144,21 +1143,29 @@ def flash(self, result_config):
11441143

11451144

11461145
def run(self):
1146+
1147+
if self.args.datasetPath:
1148+
self.dataset_path = Path(self.args.datasetPath)
1149+
else:
1150+
self.dataset_path = Path("dataset").absolute()
1151+
1152+
self.dataset_path.mkdir(parents=True, exist_ok=True)
1153+
11471154
if 'capture' in self.args.mode:
11481155
try:
1149-
if Path('dataset').exists():
1150-
shutil.rmtree('dataset/')
1156+
if self.dataset_path.exists():
1157+
shutil.rmtree(str(self.dataset_path))
11511158
for cam_id in self.board_config['cameras']:
11521159
name = self.board_config['cameras'][cam_id]['name']
1153-
Path("dataset/{}".format(name)).mkdir(parents=True, exist_ok=True)
1160+
(self.dataset_path / name).mkdir(parents=True, exist_ok=True)
11541161

11551162
except OSError:
11561163
traceback.print_exc()
11571164
print("An error occurred trying to create image dataset directories!")
11581165
raise SystemExit(1)
11591166
self.show_info_frame()
11601167
self.capture_images_sync()
1161-
self.dataset_path = str(Path("dataset").absolute())
1168+
11621169
if 'process' in self.args.mode:
11631170
status, err_text, result_config = self.calibrate()
11641171
if 'flash' in self.args.mode:

charuco_11x8.pdf

-24.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)