37
37
38
38
import cv2
39
39
import argparse
40
- import depthai as dai
41
40
import collections
42
41
import time
43
42
from itertools import cycle
44
43
from pathlib import Path
44
+ import sys
45
+ import cam_test_gui
46
+ import signal
47
+
45
48
46
49
def socket_type_pair (arg ):
47
50
socket , type = arg .split (',' )
48
- if not (socket in ['rgb' , 'left' , 'right' , 'camd' ]): raise ValueError ("" )
49
- if not (type in ['m' , 'mono' , 'c' , 'color' ]): raise ValueError ("" )
51
+ if not (socket in ['rgb' , 'left' , 'right' , 'camd' ]):
52
+ raise ValueError ("" )
53
+ if not (type in ['m' , 'mono' , 'c' , 'color' ]):
54
+ raise ValueError ("" )
50
55
is_color = True if type in ['c' , 'color' ] else False
51
56
return [socket , is_color ]
52
57
58
+
53
59
parser = argparse .ArgumentParser ()
54
60
parser .add_argument ('-cams' , '--cameras' , type = socket_type_pair , nargs = '+' ,
55
- default = [['rgb' , True ], ['left' , False ], ['right' , False ], ['camd' , True ]],
61
+ default = [['rgb' , True ], ['left' , False ],
62
+ ['right' , False ], ['camd' , True ]],
56
63
help = "Which camera sockets to enable, and type: c[olor] / m[ono]. "
57
64
"E.g: -cams rgb,m right,c . Default: rgb,c left,m right,m camd,c" )
58
65
parser .add_argument ('-mres' , '--mono-resolution' , type = int , default = 800 , choices = {480 , 400 , 720 , 800 },
@@ -71,8 +78,25 @@ def socket_type_pair(arg):
71
78
help = "Make OpenCV windows resizable. Note: may introduce some artifacts" )
72
79
parser .add_argument ('-tun' , '--camera-tuning' , type = Path ,
73
80
help = "Path to custom camera tuning database" )
81
+ parser .add_argument ('-d' , '--device' , default = "" , type = str ,
82
+ help = "Optional MX ID of the device to connect to." )
83
+
84
+ parser .add_argument ('-ctimeout' , '--connection-timeout' , default = 30000 ,
85
+ help = "Connection timeout in ms. Default: %(default)s (sets DEPTHAI_CONNECTION_TIMEOUT environment variable)" )
86
+
87
+ parser .add_argument ('-btimeout' , '--boot-timeout' , default = 30000 ,
88
+ help = "Boot timeout in ms. Default: %(default)s (sets DEPTHAI_BOOT_TIMEOUT environment variable)" )
89
+
74
90
args = parser .parse_args ()
75
91
92
+ # Set timeouts before importing depthai
93
+ os .environ ["DEPTHAI_CONNECTION_TIMEOUT" ] = str (args .connection_timeout )
94
+ os .environ ["DEPTHAI_BOOT_TIMEOUT" ] = str (args .boot_timeout )
95
+ import depthai as dai
96
+
97
+ if len (sys .argv ) == 1 :
98
+ cam_test_gui .main ()
99
+
76
100
cam_list = []
77
101
cam_type_color = {}
78
102
print ("Enabled cameras:" )
@@ -85,24 +109,24 @@ def socket_type_pair(arg):
85
109
print ("DepthAI path:" , dai .__file__ )
86
110
87
111
cam_socket_opts = {
88
- 'rgb' : dai .CameraBoardSocket .RGB , # Or CAM_A
89
- 'left' : dai .CameraBoardSocket .LEFT , # Or CAM_B
90
- 'right' : dai .CameraBoardSocket .RIGHT , # Or CAM_C
91
- 'camd' : dai .CameraBoardSocket .CAM_D ,
112
+ 'rgb' : dai .CameraBoardSocket .RGB , # Or CAM_A
113
+ 'left' : dai .CameraBoardSocket .LEFT , # Or CAM_B
114
+ 'right' : dai .CameraBoardSocket .RIGHT , # Or CAM_C
115
+ 'camd' : dai .CameraBoardSocket .CAM_D ,
92
116
}
93
117
94
118
cam_socket_to_name = {
95
- 'RGB' : 'rgb' ,
96
- 'LEFT' : 'left' ,
119
+ 'RGB' : 'rgb' ,
120
+ 'LEFT' : 'left' ,
97
121
'RIGHT' : 'right' ,
98
122
'CAM_D' : 'camd' ,
99
123
}
100
124
101
125
rotate = {
102
- 'rgb' : args .rotate in ['all' , 'rgb' ],
103
- 'left' : args .rotate in ['all' , 'mono' ],
126
+ 'rgb' : args .rotate in ['all' , 'rgb' ],
127
+ 'left' : args .rotate in ['all' , 'mono' ],
104
128
'right' : args .rotate in ['all' , 'mono' ],
105
- 'camd' : args .rotate in ['all' , 'rgb' ],
129
+ 'camd' : args .rotate in ['all' , 'rgb' ],
106
130
}
107
131
108
132
mono_res_opts = {
@@ -134,9 +158,11 @@ def __init__(self, window_size=30):
134
158
self .fps = 0
135
159
136
160
def update (self , timestamp = None ):
137
- if timestamp == None : timestamp = time .monotonic ()
161
+ if timestamp == None :
162
+ timestamp = time .monotonic ()
138
163
count = len (self .dq )
139
- if count > 0 : self .fps = count / (timestamp - self .dq [0 ])
164
+ if count > 0 :
165
+ self .fps = count / (timestamp - self .dq [0 ])
140
166
self .dq .append (timestamp )
141
167
142
168
def get (self ):
@@ -145,7 +171,7 @@ def get(self):
145
171
# Start defining a pipeline
146
172
pipeline = dai .Pipeline ()
147
173
# Uncomment to get better throughput
148
- #pipeline.setXLinkChunkSize(0)
174
+ # pipeline.setXLinkChunkSize(0)
149
175
150
176
control = pipeline .createXLinkIn ()
151
177
control .setStreamName ('control' )
@@ -159,21 +185,21 @@ def get(self):
159
185
cam [c ] = pipeline .createColorCamera ()
160
186
cam [c ].setResolution (color_res_opts [args .color_resolution ])
161
187
cam [c ].setIspScale (1 , args .isp_downscale )
162
- #cam[c].initialControl.setManualFocus(85) # TODO
188
+ # cam[c].initialControl.setManualFocus(85) # TODO
163
189
cam [c ].isp .link (xout [c ].input )
164
190
else :
165
191
cam [c ] = pipeline .createMonoCamera ()
166
192
cam [c ].setResolution (mono_res_opts [args .mono_resolution ])
167
193
cam [c ].out .link (xout [c ].input )
168
194
cam [c ].setBoardSocket (cam_socket_opts [c ])
169
195
# Num frames to capture on trigger, with first to be discarded (due to degraded quality)
170
- #cam[c].initialControl.setExternalTrigger(2, 1)
171
- #cam[c].initialControl.setStrobeExternal(48, 1)
172
- #cam[c].initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.INPUT)
196
+ # cam[c].initialControl.setExternalTrigger(2, 1)
197
+ # cam[c].initialControl.setStrobeExternal(48, 1)
198
+ # cam[c].initialControl.setFrameSyncMode(dai.CameraControl.FrameSyncMode.INPUT)
173
199
174
- #cam[c].initialControl.setManualExposure(15000, 400) # exposure [us], iso
200
+ # cam[c].initialControl.setManualExposure(15000, 400) # exposure [us], iso
175
201
# When set, takes effect after the first 2 frames
176
- #cam[c].initialControl.setManualWhiteBalance(4000) # light temperature in K, 1000..12000
202
+ # cam[c].initialControl.setManualWhiteBalance(4000) # light temperature in K, 1000..12000
177
203
control .out .link (cam [c ].inputControl )
178
204
if rotate [c ]:
179
205
cam [c ].setImageOrientation (dai .CameraImageOrientation .ROTATE_180_DEG )
@@ -183,13 +209,26 @@ def get(self):
183
209
if args .camera_tuning :
184
210
pipeline .setCameraTuningBlobPath (str (args .camera_tuning ))
185
211
212
+ def exit_cleanly (signum , frame ):
213
+ print ("Exiting cleanly" )
214
+ cv2 .destroyAllWindows ()
215
+ sys .exit (0 )
216
+
217
+ signal .signal (signal .SIGINT , exit_cleanly )
218
+
219
+
186
220
# Pipeline is defined, now we can connect to the device
187
- with dai .Device (pipeline ) as device :
188
- #print('Connected cameras:', [c.name for c in device.getConnectedCameras()])
221
+ device = dai .Device .getDeviceByMxId (args .device )
222
+ dai_device_args = [pipeline ]
223
+ if device [0 ]:
224
+ dai_device_args .append (device [1 ])
225
+ with dai .Device (* dai_device_args ) as device :
226
+ # print('Connected cameras:', [c.name for c in device.getConnectedCameras()])
189
227
print ('Connected cameras:' )
190
228
cam_name = {}
191
229
for p in device .getConnectedCameraFeatures ():
192
- print (f' -socket { p .socket .name :6} : { p .sensorName :6} { p .width :4} x { p .height :4} focus:' , end = '' )
230
+ print (
231
+ f' -socket { p .socket .name :6} : { p .sensorName :6} { p .width :4} x { p .height :4} focus:' , end = '' )
193
232
print ('auto ' if p .hasAutofocus else 'fixed' , '- ' , end = '' )
194
233
print (* [type .name for type in p .supportedTypes ])
195
234
cam_name [cam_socket_to_name [p .socket .name ]] = p .sensorName
@@ -237,9 +276,12 @@ def get(self):
237
276
dotIntensity = 0
238
277
floodIntensity = 0
239
278
240
- awb_mode = cycle ([item for name , item in vars (dai .CameraControl .AutoWhiteBalanceMode ).items () if name .isupper ()])
241
- anti_banding_mode = cycle ([item for name , item in vars (dai .CameraControl .AntiBandingMode ).items () if name .isupper ()])
242
- effect_mode = cycle ([item for name , item in vars (dai .CameraControl .EffectMode ).items () if name .isupper ()])
279
+ awb_mode = cycle ([item for name , item in vars (
280
+ dai .CameraControl .AutoWhiteBalanceMode ).items () if name .isupper ()])
281
+ anti_banding_mode = cycle ([item for name , item in vars (
282
+ dai .CameraControl .AntiBandingMode ).items () if name .isupper ()])
283
+ effect_mode = cycle ([item for name , item in vars (
284
+ dai .CameraControl .EffectMode ).items () if name .isupper ()])
243
285
244
286
ae_comp = 0
245
287
ae_lock = False
@@ -252,34 +294,43 @@ def get(self):
252
294
chroma_denoise = 0
253
295
control = 'none'
254
296
255
- print ("Cam:" , * [' ' + c .ljust (8 ) for c in cam_list ], "[host | capture timestamp]" )
297
+ print ("Cam:" , * [' ' + c .ljust (8 )
298
+ for c in cam_list ], "[host | capture timestamp]" )
256
299
257
300
capture_list = []
258
301
while True :
259
302
for c in cam_list :
260
- pkt = q [c ].tryGet ()
303
+ try :
304
+ pkt = q [c ].tryGet ()
305
+ except Exception as e :
306
+ print (e )
307
+ exit_cleanly (0 , 0 )
261
308
if pkt is not None :
262
309
fps_host [c ].update ()
263
310
fps_capt [c ].update (pkt .getTimestamp ().total_seconds ())
264
311
frame = pkt .getCvFrame ()
265
312
if c in capture_list :
266
313
width , height = pkt .getWidth (), pkt .getHeight ()
267
314
capture_file_name = ('capture_' + c + '_' + cam_name [c ]
268
- + '_' + str (width ) + 'x' + str (height )
269
- + '_exp_' + str (int (pkt .getExposureTime ().total_seconds ()* 1e6 ))
270
- + '_iso_' + str (pkt .getSensitivity ())
271
- + '_lens_' + str (pkt .getLensPosition ())
272
- + '_' + capture_time
273
- + '_' + str (pkt .getSequenceNum ())
274
- + ".png"
275
- )
315
+ + '_' + str (width ) + 'x' + str (height )
316
+ + '_exp_' +
317
+ str (int (
318
+ pkt .getExposureTime ().total_seconds ()* 1e6 ))
319
+ + '_iso_' + str (pkt .getSensitivity ())
320
+ + '_lens_' +
321
+ str (pkt .getLensPosition ())
322
+ + '_' + capture_time
323
+ + '_' + str (pkt .getSequenceNum ())
324
+ + ".png"
325
+ )
276
326
print ("\n Saving:" , capture_file_name )
277
327
cv2 .imwrite (capture_file_name , frame )
278
328
capture_list .remove (c )
279
329
280
330
cv2 .imshow (c , frame )
281
331
print ("\r FPS:" ,
282
- * ["{:6.2f}|{:6.2f}" .format (fps_host [c ].get (), fps_capt [c ].get ()) for c in cam_list ],
332
+ * ["{:6.2f}|{:6.2f}" .format (fps_host [c ].get (),
333
+ fps_capt [c ].get ()) for c in cam_list ],
283
334
end = '' , flush = True )
284
335
285
336
key = cv2 .waitKey (1 )
@@ -297,26 +348,33 @@ def get(self):
297
348
elif key == ord ('f' ):
298
349
print ("Autofocus enable, continuous" )
299
350
ctrl = dai .CameraControl ()
300
- ctrl .setAutoFocusMode (dai .CameraControl .AutoFocusMode .CONTINUOUS_VIDEO )
351
+ ctrl .setAutoFocusMode (
352
+ dai .CameraControl .AutoFocusMode .CONTINUOUS_VIDEO )
301
353
controlQueue .send (ctrl )
302
354
elif key == ord ('e' ):
303
355
print ("Autoexposure enable" )
304
356
ctrl = dai .CameraControl ()
305
357
ctrl .setAutoExposureEnable ()
306
358
controlQueue .send (ctrl )
307
359
elif key in [ord (',' ), ord ('.' )]:
308
- if key == ord (',' ): lensPos -= LENS_STEP
309
- if key == ord ('.' ): lensPos += LENS_STEP
360
+ if key == ord (',' ):
361
+ lensPos -= LENS_STEP
362
+ if key == ord ('.' ):
363
+ lensPos += LENS_STEP
310
364
lensPos = clamp (lensPos , lensMin , lensMax )
311
365
print ("Setting manual focus, lens position: " , lensPos )
312
366
ctrl = dai .CameraControl ()
313
367
ctrl .setManualFocus (lensPos )
314
368
controlQueue .send (ctrl )
315
369
elif key in [ord ('i' ), ord ('o' ), ord ('k' ), ord ('l' )]:
316
- if key == ord ('i' ): expTime -= EXP_STEP
317
- if key == ord ('o' ): expTime += EXP_STEP
318
- if key == ord ('k' ): sensIso -= ISO_STEP
319
- if key == ord ('l' ): sensIso += ISO_STEP
370
+ if key == ord ('i' ):
371
+ expTime -= EXP_STEP
372
+ if key == ord ('o' ):
373
+ expTime += EXP_STEP
374
+ if key == ord ('k' ):
375
+ sensIso -= ISO_STEP
376
+ if key == ord ('l' ):
377
+ sensIso += ISO_STEP
320
378
expTime = clamp (expTime , expMin , expMax )
321
379
sensIso = clamp (sensIso , sensMin , sensMax )
322
380
print ("Setting manual exposure, time: " , expTime , "iso: " , sensIso )
@@ -356,21 +414,33 @@ def get(self):
356
414
floodIntensity = 0
357
415
device .setIrFloodLightBrightness (floodIntensity )
358
416
elif key >= 0 and chr (key ) in '34567890[]' :
359
- if key == ord ('3' ): control = 'awb_mode'
360
- elif key == ord ('4' ): control = 'ae_comp'
361
- elif key == ord ('5' ): control = 'anti_banding_mode'
362
- elif key == ord ('6' ): control = 'effect_mode'
363
- elif key == ord ('7' ): control = 'brightness'
364
- elif key == ord ('8' ): control = 'contrast'
365
- elif key == ord ('9' ): control = 'saturation'
366
- elif key == ord ('0' ): control = 'sharpness'
367
- elif key == ord ('[' ): control = 'luma_denoise'
368
- elif key == ord (']' ): control = 'chroma_denoise'
417
+ if key == ord ('3' ):
418
+ control = 'awb_mode'
419
+ elif key == ord ('4' ):
420
+ control = 'ae_comp'
421
+ elif key == ord ('5' ):
422
+ control = 'anti_banding_mode'
423
+ elif key == ord ('6' ):
424
+ control = 'effect_mode'
425
+ elif key == ord ('7' ):
426
+ control = 'brightness'
427
+ elif key == ord ('8' ):
428
+ control = 'contrast'
429
+ elif key == ord ('9' ):
430
+ control = 'saturation'
431
+ elif key == ord ('0' ):
432
+ control = 'sharpness'
433
+ elif key == ord ('[' ):
434
+ control = 'luma_denoise'
435
+ elif key == ord (']' ):
436
+ control = 'chroma_denoise'
369
437
print ("Selected control:" , control )
370
438
elif key in [ord ('-' ), ord ('_' ), ord ('+' ), ord ('=' )]:
371
439
change = 0
372
- if key in [ord ('-' ), ord ('_' )]: change = - 1
373
- if key in [ord ('+' ), ord ('=' )]: change = 1
440
+ if key in [ord ('-' ), ord ('_' )]:
441
+ change = - 1
442
+ if key in [ord ('+' ), ord ('=' )]:
443
+ change = 1
374
444
ctrl = dai .CameraControl ()
375
445
if control == 'none' :
376
446
print ("Please select a control first using keys 3..9 0 [ ]" )
0 commit comments