From 165abff5242994d842197735608285c3552d2de1 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Fri, 1 Oct 2021 21:11:24 +0300 Subject: [PATCH 01/28] Add simple IR register control for OAK-D-Pro. Need to install: sudo apt install python3-tk --- depthai_demo.py | 43 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 3 ++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index 8922dc283..1dbfb01cd 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -7,6 +7,8 @@ import platform import numpy as np +import PySimpleGUI as sg +import threading from depthai_helpers.arg_manager import parseArgs from depthai_helpers.config_manager import ConfigManager, DEPTHAI_ZOO, DEPTHAI_VIDEOS @@ -136,8 +138,49 @@ def fn(value): nnManager.countLabel(conf.getCountLabel(nnManager)) pm.setNnManager(nnManager) +def ir_handler(dev): + # Initial setup + #dev.irWriteReg(0x01, 0x89) + #dev.irWriteReg(0x01, 0x89) + + layout = [ + [ sg.Text('Reg:'), sg.InputText('0x', size=(5,1), key='InRegW'), + sg.Text('Value:'), sg.InputText('0x', size=(5,1), key='InValW'), + sg.Button('Write')], + [ sg.Text('Reg:'), sg.InputText('0x', size=(5,1), key='InRegR'), + sg.Button('Read'), sg.Text('->', key='TextValR')], + ] + + window = sg.Window('IR Control', layout) + + while True: + event, values = window.read() + print('EVENT :', event) + print('VALUES:', values) + if event in (sg.WIN_CLOSED, 'Cancel'): + break + if event == 'Write': + reg = int(values['InRegW'], 0) + val = int(values['InValW'], 0) + print('Write', reg, '->', val) + dev.irWriteReg(reg, val) + if event == 'Read': + reg = int(values['InRegR'], 0) + val = hex(dev.irReadReg(reg)) + window['TextValR'].update(val) + print('Read', reg, '->', val) + print() + + window.close() + exit() + +def start_ir_handler(dev): + t = threading.Thread(target=ir_handler, args=(dev,)) + t.start() + # Pipeline is defined, now we can connect to the device with dai.Device(pm.pipeline.getOpenVINOVersion(), deviceInfo, usb2Mode=conf.args.usbSpeed == "usb2") as device: + start_ir_handler(device) if deviceInfo.desc.protocol == dai.XLinkProtocol.X_LINK_USB_VSC: print("USB Connection speed: {}".format(device.getUsbSpeed())) conf.adjustParamsToDevice(device) diff --git a/requirements.txt b/requirements.txt index fca990d9c..ac153ae98 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ +PySimpleGUI requests==2.24.0 argcomplete==1.12.1 -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ -depthai==2.10.0.0.dev+7a0749a61597c086c5fd6e579618ae33accec8df +depthai==2.10.0.0.dev+f70ea7fac8cd722b62f7d4628099ef828b3ca5ba From da8765ff81b26c8ff09e6f09e44fa7bb1a85ef54 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Sat, 2 Oct 2021 13:59:14 +0300 Subject: [PATCH 02/28] IR projector handler: more GUI controls --- depthai_demo.py | 45 +------ depthai_helpers/ir_handler.py | 236 ++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+), 43 deletions(-) create mode 100644 depthai_helpers/ir_handler.py diff --git a/depthai_demo.py b/depthai_demo.py index 1dbfb01cd..e1ff18d5f 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -7,9 +7,8 @@ import platform import numpy as np -import PySimpleGUI as sg -import threading +from depthai_helpers import ir_handler from depthai_helpers.arg_manager import parseArgs from depthai_helpers.config_manager import ConfigManager, DEPTHAI_ZOO, DEPTHAI_VIDEOS from depthai_helpers.version_check import checkDepthaiVersion @@ -138,49 +137,9 @@ def fn(value): nnManager.countLabel(conf.getCountLabel(nnManager)) pm.setNnManager(nnManager) -def ir_handler(dev): - # Initial setup - #dev.irWriteReg(0x01, 0x89) - #dev.irWriteReg(0x01, 0x89) - - layout = [ - [ sg.Text('Reg:'), sg.InputText('0x', size=(5,1), key='InRegW'), - sg.Text('Value:'), sg.InputText('0x', size=(5,1), key='InValW'), - sg.Button('Write')], - [ sg.Text('Reg:'), sg.InputText('0x', size=(5,1), key='InRegR'), - sg.Button('Read'), sg.Text('->', key='TextValR')], - ] - - window = sg.Window('IR Control', layout) - - while True: - event, values = window.read() - print('EVENT :', event) - print('VALUES:', values) - if event in (sg.WIN_CLOSED, 'Cancel'): - break - if event == 'Write': - reg = int(values['InRegW'], 0) - val = int(values['InValW'], 0) - print('Write', reg, '->', val) - dev.irWriteReg(reg, val) - if event == 'Read': - reg = int(values['InRegR'], 0) - val = hex(dev.irReadReg(reg)) - window['TextValR'].update(val) - print('Read', reg, '->', val) - print() - - window.close() - exit() - -def start_ir_handler(dev): - t = threading.Thread(target=ir_handler, args=(dev,)) - t.start() - # Pipeline is defined, now we can connect to the device with dai.Device(pm.pipeline.getOpenVINOVersion(), deviceInfo, usb2Mode=conf.args.usbSpeed == "usb2") as device: - start_ir_handler(device) + ir_handler.start_ir_handler(device) if deviceInfo.desc.protocol == dai.XLinkProtocol.X_LINK_USB_VSC: print("USB Connection speed: {}".format(device.getUsbSpeed())) conf.adjustParamsToDevice(device) diff --git a/depthai_helpers/ir_handler.py b/depthai_helpers/ir_handler.py new file mode 100644 index 000000000..1e93c7ab7 --- /dev/null +++ b/depthai_helpers/ir_handler.py @@ -0,0 +1,236 @@ +import PySimpleGUI as sg +import threading + +def ir_handler(dev): + # Enable Register (0x01) + strobe_opts = {'level': 0, 'edge': 1} + strobe_type = 0 # default 0 + mode_opts = {'standby': 0, 'irdrive': 1, 'torch': 2, 'flash': 3} + mode = 1 # default 0 + enable = {} + enable['Led1'] = 0 # default 0 + enable['Led2'] = 0 # default 0 + enable['TxPin'] = 0 # default 1 + enable['Strobe'] = 1 # default 0 + enable['TorchTempPin'] = 0 # default 0 + + # IVFM Register (0x02) + uvlo_en = 0 # default 0 + ivfm_level = 0 # 0..7 = 2.9..3.6V, default 0 + ivfm_hyst_en = 0 # 1 = 50mV, default 0 + ivfm_mode = 1 # 0-disabled, 1-stop_and_hold, 2-down_mode, 3-up_and_down, default 1 + + # LED1/LED2 Flash/Torch Brightness Register (0x03,0x04,0x05,0x06) + # Note: LED2 override (set together with LED1) not enabled + # Set raw values (0..127) + brightness = {} + brightness['FlashLed1'] = 0 + brightness['FlashLed2'] = 0 + brightness['TorchLed1'] = 0 + brightness['TorchLed2'] = 0 + + # Boost Configuration Register (0x07) + led_short_fault_detect_en = 1 # default 1 + boost_mode_opts = {'normal': 0, 'pass': 1} + boost_mode = 0 # default 0 + boost_freq_opts = {'2MHz': 0, '4MHz': 1} + boost_freq = 0 # default 0 + boost_limit_opts = {'1.9A': 0, '2.8A': 1} + boost_limit = 1 # default 1 + + # Timing Configuration Register (0x08) + torch_ramp_time = 1 # 0-no_ramp, 1=1ms, 2=32ms, 3=64ms,... 7=1024ms, default 1 + # Note a flash timeout event requires reconfig - not handled yet + flash_timeout = 10 # 0..9 = 10..100ms, 10..15 = 150..400ms, default 10 + + # TEMP Register (0x09) + torch_polarity = 0 # 0-high, 1-low, default 0 + ntc_open_fault_en = 0 # default 0 + ntc_short_fault_en = 0 # default 0 + temp_volt_thresh = 4 # 0..7 = 0.2..0.9V, default 4 = 0.6V + torch_temp_sel = 0 # 0-torch, 1-temp, default 0 + + def is_flash_en(): return mode in (1, 3) + def is_torch_en(): return mode == 2 + def brightness_text(modeLed): + v = brightness[modeLed] + if modeLed.startswith('Flash'): + return '{:8.3f} mA'.format(v * 11.725 + 10.9) \ + + ('' if is_flash_en() else ' - Disabled') + else: + return '{:7.3f} mA'.format(v * 1.4 + 0.977) \ + + ('' if is_torch_en() else ' - Disabled') + def flash_timeout_text(): + return str((10*(flash_timeout+1)) if (flash_timeout<10) else (50*(flash_timeout-7))) + ' ms' + + def set_enable(): + v = (enable['TxPin'] << 7 | strobe_type << 6 | enable['Strobe'] << 5 + | enable['TorchTempPin'] << 4 | mode << 2 | enable['Led2'] << 1 | enable['Led1']) + dev.irWriteReg(0x01, v) + def set_ivfm(): + v = uvlo_en << 6 | ivfm_level << 3 | ivfm_hyst_en << 2 | ivfm_mode + dev.irWriteReg(0x02, v) + def set_brightness(modeLed): + regs = { + 'FlashLed1': 0x03, + 'FlashLed2': 0x04, + 'TorchLed1': 0x05, + 'TorchLed2': 0x06, + } + dev.irWriteReg(regs[modeLed], brightness[modeLed]) + def set_boost(): + v = led_short_fault_detect_en << 3 | boost_mode << 2 | boost_freq << 1 | boost_limit + dev.irWriteReg(0x07, v) + def set_timing(): + v = torch_ramp_time << 4 | flash_timeout + dev.irWriteReg(0x08, v) + def set_temp(): + v = (torch_polarity << 6 | ntc_open_fault_en << 5 | ntc_short_fault_en << 4 + | temp_volt_thresh << 1 | torch_temp_sel) + dev.irWriteReg(0x09, v) + + set_ivfm() + set_brightness('FlashLed1') + set_brightness('FlashLed2') + set_brightness('TorchLed1') + set_brightness('TorchLed2') + set_boost() + set_timing() + set_temp() + set_enable() + + sg.theme('Default1') + + layoutEnable = [ + [sg.Frame('Mode', [ + [sg.Radio('Standby', 'Rmode', key='standby', default=(mode==0), enable_events=True)], + [sg.Radio('IR Drive', 'Rmode', key='irdrive', default=(mode==1), enable_events=True)], + [sg.Radio('Torch', 'Rmode', key='torch', default=(mode==2), enable_events=True)], + [sg.Radio('Flash', 'Rmode', key='flash', default=(mode==3), enable_events=True)], + ]), + sg.Column([ + [sg.Checkbox('TX Pin Enable', key='TxPin', default=enable['TxPin'], enable_events=True)], + [sg.Checkbox('TORCH/TEMP Pin Enable', key='TorchTempPin', default=enable['TorchTempPin'], enable_events=True)], + [sg.Checkbox('STROBE Enable:', key='Strobe', default=enable['Strobe'], enable_events=True), + sg.Radio('Level', 'Rstr', key='level', default=(strobe_type==0), enable_events=True), + sg.Radio('Edge', 'Rstr', key='edge', default=(strobe_type==1), enable_events=True), + ], + ]), + ], + ] + + layoutBoostTiming = [ + [sg.Frame('Boost', [ + [sg.Text('Mode:'), + sg.Radio('Normal', 'RBm', key='normal', default=(boost_mode==0), enable_events=True), + sg.Radio('Pass only', 'RBm', key='pass', default=(boost_mode==1), enable_events=True)], + [sg.Text('Frequency:'), + sg.Radio('2 MHz', 'RBfreq', key='2MHz', default=(boost_freq==0), enable_events=True), + sg.Radio('4 MHz', 'RBfreq', key='4MHz', default=(boost_freq==1), enable_events=True)], + [sg.Text('Current limit:'), + sg.Radio('1.9 A', 'RBlimit', key='1.9A', default=(boost_limit==0), enable_events=True), + sg.Radio('2.8 A', 'RBlimit', key='2.8A', default=(boost_limit==1), enable_events=True)], + ]), + sg.Frame('Flash timeout duration', [ + [sg.Slider(range=(0, 15), default_value=flash_timeout, orientation='h', + enable_events=True, key='FlashTimeout')], + [sg.Text(flash_timeout_text(), key='TextFlashTimeout')], + ]), + ], + ] + + layoutLed1 = [ + [sg.Checkbox('Enable', default=enable['Led1'], enable_events=True, key='Led1')], + [sg.Text('Flash:'), + sg.Slider(range=(0, 127), default_value=brightness['FlashLed1'], orientation='h', + size=(25, 18), enable_events=True, key='FlashLed1'), + sg.Text(brightness_text('FlashLed1'), key='TextFlashLed1') + ], + [sg.Text('Torch:'), + sg.Slider(range=(0, 127), default_value=brightness['TorchLed1'], orientation='h', + size=(25, 18), enable_events=True, key='TorchLed1'), + sg.Text(brightness_text('TorchLed1'), key='TextTorchLed1') + ], + ] + + layoutLed2 = [ + [sg.Checkbox('Enable', default=enable['Led2'], enable_events=True, key='Led2')], + [sg.Text('Flash:'), + sg.Slider(range=(0, 127), default_value=brightness['FlashLed2'], orientation='h', + size=(25, 18), enable_events=True, key='FlashLed2'), + sg.Text(brightness_text('FlashLed2'), key='TextFlashLed2') + ], + [sg.Text('Torch:'), + sg.Slider(range=(0, 127), default_value=brightness['TorchLed2'], orientation='h', + size=(25, 18), enable_events=True, key='TorchLed2'), + sg.Text(brightness_text('TorchLed2'), key='TextTorchLed2') + ], + ] + + layoutRegCtrl = [ + [sg.Text('Reg:'), sg.InputText('0x', size=(10,1), key='InRegW'), + sg.Text('Value:'), sg.InputText('0x', size=(10,1), key='InValW'), + sg.Button('Write')], + [sg.Text('Reg:'), sg.InputText('0x', size=(10,1), key='InRegR'), + sg.Button('Read'), sg.Text('...', key='TextValR')], + ] + + layoutMain = [ + layoutEnable, + layoutBoostTiming, + [sg.Frame('LED1 / Flood IR', layoutLed1)], + [sg.Frame('LED2 / Laser Pattern Projector', layoutLed2)], + [sg.Frame('LM3644 Register Control', layoutRegCtrl)], + ] + + window = sg.Window('IR Control', layoutMain) + + while True: + event, values = window.read() + #print('==EV', event, values) + if event == sg.WIN_CLOSED: + break + if event == 'Write': + reg = int(values['InRegW'], 0) + val = int(values['InValW'], 0) + dev.irWriteReg(reg, val) + if event == 'Read': + reg = int(values['InRegR'], 0) + val = hex(dev.irReadReg(reg)) + window['TextValR'].update(val) + if event in ('FlashLed1', 'FlashLed2', 'TorchLed1', 'TorchLed2'): + brightness[event] = int(values[event]) + window['Text' + event].update(brightness_text(event)) + set_brightness(event) + if event == 'FlashTimeout': + flash_timeout = int(values['FlashTimeout']) + window['TextFlashTimeout'].update(flash_timeout_text()) + set_timing() + if event in ('Led1', 'Led2', 'Strobe', 'TxPin', 'TorchTempPin'): + enable[event] = values[event] + set_enable() + if event in ('standby', 'irdrive', 'torch', 'flash'): + mode = mode_opts[event] + set_enable() + for e in ('FlashLed1', 'FlashLed2', 'TorchLed1', 'TorchLed2'): + window['Text' + e].update(brightness_text(e)) + if event in ('level', 'edge'): strobe_type = strobe_opts[event]; set_enable() + if event in ('normal', 'pass'): boost_mode = boost_mode_opts[event]; set_boost() + if event in ('2MHz', '4MHz'): boost_freq = boost_freq_opts[event]; set_boost() + if event in ('1.9A', '2.8A'): boost_limit = boost_limit_opts[event]; set_boost() + + window.close() + exit() + +if 0: # Change to 1 to enable stub GUI test (no device connection) + class IrStub(): + def irWriteReg(self, reg, value): + print("IR STUB write:", hex(reg), hex(value)) + def irReadReg(self, reg): + print("IR STUB read :", hex(reg)) + return 0 + ir_handler(IrStub()) + +def start_ir_handler(dev): + t = threading.Thread(target=ir_handler, args=(dev,)) + t.start() From 3d539e643dd49334cfabe16306e1bff81ce9a0d1 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Mon, 4 Oct 2021 19:46:25 +0300 Subject: [PATCH 03/28] Add basic manual exposure/gain control for Mono cameras. Usage: Control: key[dec/inc] min..max exposure time: I O 1..33000 [us] sensitivity iso: K L 100..1600 Note: need to have an OpenCV display window in focus when pressing the keys --- depthai_demo.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/depthai_demo.py b/depthai_demo.py index e1ff18d5f..238f19b3c 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -154,14 +154,18 @@ def fn(value): dispMultiplier=conf.dispMultiplier, mouseTracker=True, lowBandwidth=conf.lowBandwidth, scale=conf.args.scale, sync=conf.args.sync, fpsHandler=fps) + pm.nodes.monoControl = pm.pipeline.createXLinkIn() + pm.nodes.monoControl.setStreamName("monoControl") if conf.leftCameraEnabled: pm.createLeftCam(monoRes, conf.args.monoFps, orientation=conf.args.cameraOrientation.get(Previews.left.name), xout=Previews.left.name in conf.args.show and (conf.getModelSource() != "left" or not conf.args.sync) ) + pm.nodes.monoControl.out.link(pm.nodes.monoLeft.inputControl) if conf.rightCameraEnabled: pm.createRightCam(monoRes, conf.args.monoFps, orientation=conf.args.cameraOrientation.get(Previews.right.name), xout=Previews.right.name in conf.args.show and (conf.getModelSource() != "right" or not conf.args.sync) ) + pm.nodes.monoControl.out.link(pm.nodes.monoRight.inputControl) if conf.rgbCameraEnabled: pm.createColorCam(nnManager.inputSize if conf.useNN else conf.previewSize, rgbRes, conf.args.rgbFps, orientation=conf.args.cameraOrientation.get(Previews.color.name), fullFov=not conf.args.disableFullFovNn, xout=Previews.color.name in conf.args.show and (conf.getModelSource() != "color" or not conf.args.sync) @@ -246,6 +250,21 @@ def createQueueCallback(queueName): sbbRois = [] callbacks.onSetup(**locals()) + # Manual exposure/focus set step + EXP_STEP = 500 # us + ISO_STEP = 50 + + expTime = 10000 + expMin = 1 + expMax = 33000 + + sensIso = 800 + sensMin = 100 + sensMax = 1600 + + def clamp(num, v0, v1): + return max(v0, min(num, v1)) + try: while True: fps.nextIter() @@ -323,6 +342,17 @@ def showFramesCallback(frame, name): elif key == ord('m'): nextFilter = next(medianFilters) pm.updateDepthConfig(device, median=nextFilter) + elif key in [ord('i'), ord('o'), ord('k'), ord('l')]: + if key == ord('i'): expTime -= EXP_STEP + if key == ord('o'): expTime += EXP_STEP + if key == ord('k'): sensIso -= ISO_STEP + if key == ord('l'): sensIso += ISO_STEP + expTime = clamp(expTime, expMin, expMax) + sensIso = clamp(sensIso, sensMin, sensMax) + print("Setting manual exposure, time: ", expTime, "iso: ", sensIso) + ctrl = dai.CameraControl() + ctrl.setManualExposure(expTime, sensIso) + device.getInputQueue("monoControl").send(ctrl) finally: if conf.useCamera and encManager is not None: encManager.close() From 5b4a9e36f204eb8f90e2cf40e031826e42e18b69 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Thu, 18 Nov 2021 04:14:16 +0200 Subject: [PATCH 04/28] Add log wrapper for IR ops --- depthai_helpers/ir_handler.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/depthai_helpers/ir_handler.py b/depthai_helpers/ir_handler.py index 1e93c7ab7..b4d5005ec 100644 --- a/depthai_helpers/ir_handler.py +++ b/depthai_helpers/ir_handler.py @@ -232,5 +232,19 @@ def irReadReg(self, reg): ir_handler(IrStub()) def start_ir_handler(dev): - t = threading.Thread(target=ir_handler, args=(dev,)) + class IrLogWrapper: + def __init__(self, dev): + self.dev = dev + self.idx = 1 + def irWriteReg(self, reg, value): + print(f'===== Op{self.idx:3}: dev.irWriteReg({hex(reg)}, {hex(value)})') + self.dev.irWriteReg(reg, value) + self.idx += 1 + def irReadReg(self, reg): + value = self.dev.irReadReg(reg) + print(f'===== Op{self.idx:3}: dev.irReadReg({hex(reg)}) -> {hex(value)}') + self.idx += 1 + return value + + t = threading.Thread(target=ir_handler, args=(IrLogWrapper(dev),)) t.start() From ca6f7a349dae0dd1490766ec53556ea644899495 Mon Sep 17 00:00:00 2001 From: Sachin Date: Tue, 23 Nov 2021 13:12:57 -0800 Subject: [PATCH 05/28] Added OpenCV to requirements --- requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/requirements.txt b/requirements.txt index ac153ae98..98bf7164a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,12 @@ PySimpleGUI requests==2.24.0 argcomplete==1.12.1 +opencv-python==4.5.4.58 ; platform_machine != "aarch64" and platform_machine != "armv6l" and platform_machine != "armv7l" and python_version == "3.10" +opencv-python==4.5.1.48 ; platform_machine != "aarch64" and platform_machine != "armv6l" and platform_machine != "armv7l" and python_version != "3.10" +opencv-contrib-python==4.5.4.58 ; platform_machine != "aarch64" and platform_machine != "armv6l" and platform_machine != "armv7l" and python_version == "3.10" +opencv-contrib-python==4.5.1.48 ; platform_machine != "aarch64" and platform_machine != "armv6l" and platform_machine != "armv7l" and python_version != "3.10" +opencv-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "armv7l" +opencv-contrib-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "armv7l" -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ depthai==2.10.0.0.dev+f70ea7fac8cd722b62f7d4628099ef828b3ca5ba From d5709bca9dc0fb6cecd737123ecec1fee4305654 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Wed, 1 Dec 2021 01:42:22 +0200 Subject: [PATCH 06/28] Update depthai version to depthai-python `oak-d-pro_develop` --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 98bf7164a..9b651f334 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,4 @@ opencv-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "a opencv-contrib-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "armv7l" -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ -depthai==2.10.0.0.dev+f70ea7fac8cd722b62f7d4628099ef828b3ca5ba +depthai==2.13.2.0.dev+164ad70f9ba08306d0a035824771bac28a8aa48a From 2820b011b76b388ce529aafa3a8389ffd7f7a982 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Thu, 30 Dec 2021 18:38:22 +0200 Subject: [PATCH 07/28] Update depthai version to depthai-python `oak-d-pro_develop` --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9b651f334..dd146c2b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,4 @@ opencv-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "a opencv-contrib-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "armv7l" -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ -depthai==2.13.2.0.dev+164ad70f9ba08306d0a035824771bac28a8aa48a +depthai==2.13.3.0.dev+985331f0bb59433a9dd46c0f8efaa7940182e040 From 7de1b30a92e0d305250e3dda81c9064e264f0696 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Mon, 17 Jan 2022 19:34:06 +0200 Subject: [PATCH 08/28] Update depthai to work with OAK-D-Pro-W. Notes: To use color, the mono resolution should also be bumped as: python3 depthai_demo.py -monor 800 -s color left right depth To use a lower mono resolution, disable color: python3 depthai_demo.py -cam right -s left right depth TODO: currently the IR COntrol GUI only supports the IR dot-projector attached in the right connector, and need to use the "LED1 / Flood IR" in the GUI to control it. The GUI will be updated next to use the newly introduced API that can control all projectors/illuminators: device.setIrLaserDotProjectorBrightness(100) # mA device.setIrFloodLightBrightness(250) # mA --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dd146c2b7..557cb8eea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,4 @@ opencv-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "a opencv-contrib-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "armv7l" -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ -depthai==2.13.3.0.dev+985331f0bb59433a9dd46c0f8efaa7940182e040 +depthai==depthai==2.14.1.0.dev+1d7d9e21435df48a2c69ff923e9b01cd07d0f420 From bb6c0afbd382651b63fa1168f61754d2b4349d1e Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Mon, 17 Jan 2022 20:01:17 +0200 Subject: [PATCH 09/28] Fix a typo in requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 557cb8eea..c47ca1b27 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,4 @@ opencv-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "a opencv-contrib-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machine == "armv7l" -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ -depthai==depthai==2.14.1.0.dev+1d7d9e21435df48a2c69ff923e9b01cd07d0f420 +depthai==2.14.1.0.dev+1d7d9e21435df48a2c69ff923e9b01cd07d0f420 From 2c21d9bf9a268100350db990903ca62557cfea15 Mon Sep 17 00:00:00 2001 From: Sachin Date: Tue, 25 Jan 2022 18:47:50 -0800 Subject: [PATCH 10/28] Updated with board config files --- resources/boards/BW1098OBC.json | 1 - resources/boards/OAK-D-PRO-W.json | 13 +++++++++++++ resources/boards/OAK-D-PRO.json | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 resources/boards/OAK-D-PRO-W.json create mode 100644 resources/boards/OAK-D-PRO.json diff --git a/resources/boards/BW1098OBC.json b/resources/boards/BW1098OBC.json index 4de5a48ad..4356ef31d 100644 --- a/resources/boards/BW1098OBC.json +++ b/resources/boards/BW1098OBC.json @@ -10,4 +10,3 @@ "left_to_rgb_distance_cm": 3.75 } } - diff --git a/resources/boards/OAK-D-PRO-W.json b/resources/boards/OAK-D-PRO-W.json new file mode 100644 index 000000000..f2fe5f629 --- /dev/null +++ b/resources/boards/OAK-D-PRO-W.json @@ -0,0 +1,13 @@ +{ + "board_config": + { + "name": "OAK-D-PRO-W", + "revision": "R2M1E2", + "swap_left_and_right_cameras": true, + "left_fov_deg": 127.0, + "rgb_fov_deg": 127.0, + "left_to_right_distance_cm": 7.5, + "left_to_rgb_distance_cm": 3.75 + } +} + diff --git a/resources/boards/OAK-D-PRO.json b/resources/boards/OAK-D-PRO.json new file mode 100644 index 000000000..f248c0eae --- /dev/null +++ b/resources/boards/OAK-D-PRO.json @@ -0,0 +1,13 @@ +{ + "board_config": + { + "name": "OAK-D-PRO", + "revision": "R2M1E2", + "swap_left_and_right_cameras": true, + "left_fov_deg": 71.86, + "rgb_fov_deg": 68.7938, + "left_to_right_distance_cm": 7.5, + "left_to_rgb_distance_cm": 3.75 + } +} + From b72c6f01c53df983dd1c70e4f0dee929ce9f7b7e Mon Sep 17 00:00:00 2001 From: Sachin Guruswamy <43363595+saching13@users.noreply.github.com> Date: Wed, 26 Jan 2022 20:46:37 -0800 Subject: [PATCH 11/28] Update resources/boards/OAK-D-PRO-W.json Co-authored-by: Luxonis-David <75903226+Luxonis-David@users.noreply.github.com> --- resources/boards/OAK-D-PRO-W.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/boards/OAK-D-PRO-W.json b/resources/boards/OAK-D-PRO-W.json index f2fe5f629..1b0e64c12 100644 --- a/resources/boards/OAK-D-PRO-W.json +++ b/resources/boards/OAK-D-PRO-W.json @@ -2,7 +2,7 @@ "board_config": { "name": "OAK-D-PRO-W", - "revision": "R2M1E2", + "revision": "R3M1E3", "swap_left_and_right_cameras": true, "left_fov_deg": 127.0, "rgb_fov_deg": 127.0, From 33f00c5e2e7aca985261d4112a236bd6ba5a8e8b Mon Sep 17 00:00:00 2001 From: Sachin Guruswamy <43363595+saching13@users.noreply.github.com> Date: Wed, 26 Jan 2022 20:46:43 -0800 Subject: [PATCH 12/28] Update resources/boards/OAK-D-PRO.json Co-authored-by: Luxonis-David <75903226+Luxonis-David@users.noreply.github.com> --- resources/boards/OAK-D-PRO.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/boards/OAK-D-PRO.json b/resources/boards/OAK-D-PRO.json index f248c0eae..c73e744e9 100644 --- a/resources/boards/OAK-D-PRO.json +++ b/resources/boards/OAK-D-PRO.json @@ -2,7 +2,7 @@ "board_config": { "name": "OAK-D-PRO", - "revision": "R2M1E2", + "revision": "R3M1E3", "swap_left_and_right_cameras": true, "left_fov_deg": 71.86, "rgb_fov_deg": 68.7938, From 944bda501a5404e49c36435861b211659e380fe7 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Thu, 24 Feb 2022 13:12:12 +0200 Subject: [PATCH 13/28] Update to latest release: 2.15.0.0, with support for OAK-D-Pro --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index f1d69376f..7afdb9665 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,5 +10,5 @@ opencv-contrib-python==4.4.0.46 ; platform_machine == "armv6l" or platform_machi -e ./depthai_sdk --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-depthai-data-local/wheels/ pyqt5>5,<5.15.6 ; platform_machine != "armv6l" and platform_machine != "armv7l" and platform_machine != "aarch64" ---extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ -depthai==2.14.1.0.dev+27fa4519f289498e84768ab5229a1a45efb7e4df +# --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-snapshot-local/ +depthai==2.15.0.0 From e5b0f7a4ed19626f25dbc8107719fc8da49c7d7c Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Thu, 24 Feb 2022 13:13:08 +0200 Subject: [PATCH 14/28] Temporarily change `-gt` : "auto" -> "cv", as the sliders will be added first to CV GUI --- depthai_helpers/arg_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index d295f0980..1a618a060 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -119,7 +119,7 @@ def parseArgs(): "If set to \"high\", the output streams will stay uncompressed\n" "If set to \"low\", the output streams will be MJPEG-encoded\n" "If set to \"auto\" (default), the optimal bandwidth will be selected based on your connection type and speed") - parser.add_argument('-gt', '--guiType', type=str, default="auto", choices=["auto", "qt", "cv"], help="Specify GUI type of the demo. \"cv\" uses built-in OpenCV display methods, \"qt\" uses Qt to display interactive GUI. \"auto\" will use OpenCV for Raspberry Pi and Qt for other platforms") + parser.add_argument('-gt', '--guiType', type=str, default="cv", choices=["auto", "qt", "cv"], help="Specify GUI type of the demo. \"cv\" uses built-in OpenCV display methods, \"qt\" uses Qt to display interactive GUI. \"auto\" will use OpenCV for Raspberry Pi and Qt for other platforms") parser.add_argument('-usbs', '--usbSpeed', type=str, default="usb3", choices=["usb2", "usb3"], help="Force USB communication speed. Default: %(default)s") parser.add_argument('-enc', '--encode', type=_comaSeparated(default=30.0, cast=float), nargs="+", default=[], help="Define which cameras to encode (record) \n" From 853d85c59b1fc55b8d80e55c3043d1ccfa156bf8 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Thu, 24 Feb 2022 13:40:54 +0200 Subject: [PATCH 15/28] Remove low-level IR control `ir_handler.py`, no longer supported with latest API --- depthai_helpers/ir_handler.py | 250 ---------------------------------- 1 file changed, 250 deletions(-) delete mode 100644 depthai_helpers/ir_handler.py diff --git a/depthai_helpers/ir_handler.py b/depthai_helpers/ir_handler.py deleted file mode 100644 index b4d5005ec..000000000 --- a/depthai_helpers/ir_handler.py +++ /dev/null @@ -1,250 +0,0 @@ -import PySimpleGUI as sg -import threading - -def ir_handler(dev): - # Enable Register (0x01) - strobe_opts = {'level': 0, 'edge': 1} - strobe_type = 0 # default 0 - mode_opts = {'standby': 0, 'irdrive': 1, 'torch': 2, 'flash': 3} - mode = 1 # default 0 - enable = {} - enable['Led1'] = 0 # default 0 - enable['Led2'] = 0 # default 0 - enable['TxPin'] = 0 # default 1 - enable['Strobe'] = 1 # default 0 - enable['TorchTempPin'] = 0 # default 0 - - # IVFM Register (0x02) - uvlo_en = 0 # default 0 - ivfm_level = 0 # 0..7 = 2.9..3.6V, default 0 - ivfm_hyst_en = 0 # 1 = 50mV, default 0 - ivfm_mode = 1 # 0-disabled, 1-stop_and_hold, 2-down_mode, 3-up_and_down, default 1 - - # LED1/LED2 Flash/Torch Brightness Register (0x03,0x04,0x05,0x06) - # Note: LED2 override (set together with LED1) not enabled - # Set raw values (0..127) - brightness = {} - brightness['FlashLed1'] = 0 - brightness['FlashLed2'] = 0 - brightness['TorchLed1'] = 0 - brightness['TorchLed2'] = 0 - - # Boost Configuration Register (0x07) - led_short_fault_detect_en = 1 # default 1 - boost_mode_opts = {'normal': 0, 'pass': 1} - boost_mode = 0 # default 0 - boost_freq_opts = {'2MHz': 0, '4MHz': 1} - boost_freq = 0 # default 0 - boost_limit_opts = {'1.9A': 0, '2.8A': 1} - boost_limit = 1 # default 1 - - # Timing Configuration Register (0x08) - torch_ramp_time = 1 # 0-no_ramp, 1=1ms, 2=32ms, 3=64ms,... 7=1024ms, default 1 - # Note a flash timeout event requires reconfig - not handled yet - flash_timeout = 10 # 0..9 = 10..100ms, 10..15 = 150..400ms, default 10 - - # TEMP Register (0x09) - torch_polarity = 0 # 0-high, 1-low, default 0 - ntc_open_fault_en = 0 # default 0 - ntc_short_fault_en = 0 # default 0 - temp_volt_thresh = 4 # 0..7 = 0.2..0.9V, default 4 = 0.6V - torch_temp_sel = 0 # 0-torch, 1-temp, default 0 - - def is_flash_en(): return mode in (1, 3) - def is_torch_en(): return mode == 2 - def brightness_text(modeLed): - v = brightness[modeLed] - if modeLed.startswith('Flash'): - return '{:8.3f} mA'.format(v * 11.725 + 10.9) \ - + ('' if is_flash_en() else ' - Disabled') - else: - return '{:7.3f} mA'.format(v * 1.4 + 0.977) \ - + ('' if is_torch_en() else ' - Disabled') - def flash_timeout_text(): - return str((10*(flash_timeout+1)) if (flash_timeout<10) else (50*(flash_timeout-7))) + ' ms' - - def set_enable(): - v = (enable['TxPin'] << 7 | strobe_type << 6 | enable['Strobe'] << 5 - | enable['TorchTempPin'] << 4 | mode << 2 | enable['Led2'] << 1 | enable['Led1']) - dev.irWriteReg(0x01, v) - def set_ivfm(): - v = uvlo_en << 6 | ivfm_level << 3 | ivfm_hyst_en << 2 | ivfm_mode - dev.irWriteReg(0x02, v) - def set_brightness(modeLed): - regs = { - 'FlashLed1': 0x03, - 'FlashLed2': 0x04, - 'TorchLed1': 0x05, - 'TorchLed2': 0x06, - } - dev.irWriteReg(regs[modeLed], brightness[modeLed]) - def set_boost(): - v = led_short_fault_detect_en << 3 | boost_mode << 2 | boost_freq << 1 | boost_limit - dev.irWriteReg(0x07, v) - def set_timing(): - v = torch_ramp_time << 4 | flash_timeout - dev.irWriteReg(0x08, v) - def set_temp(): - v = (torch_polarity << 6 | ntc_open_fault_en << 5 | ntc_short_fault_en << 4 - | temp_volt_thresh << 1 | torch_temp_sel) - dev.irWriteReg(0x09, v) - - set_ivfm() - set_brightness('FlashLed1') - set_brightness('FlashLed2') - set_brightness('TorchLed1') - set_brightness('TorchLed2') - set_boost() - set_timing() - set_temp() - set_enable() - - sg.theme('Default1') - - layoutEnable = [ - [sg.Frame('Mode', [ - [sg.Radio('Standby', 'Rmode', key='standby', default=(mode==0), enable_events=True)], - [sg.Radio('IR Drive', 'Rmode', key='irdrive', default=(mode==1), enable_events=True)], - [sg.Radio('Torch', 'Rmode', key='torch', default=(mode==2), enable_events=True)], - [sg.Radio('Flash', 'Rmode', key='flash', default=(mode==3), enable_events=True)], - ]), - sg.Column([ - [sg.Checkbox('TX Pin Enable', key='TxPin', default=enable['TxPin'], enable_events=True)], - [sg.Checkbox('TORCH/TEMP Pin Enable', key='TorchTempPin', default=enable['TorchTempPin'], enable_events=True)], - [sg.Checkbox('STROBE Enable:', key='Strobe', default=enable['Strobe'], enable_events=True), - sg.Radio('Level', 'Rstr', key='level', default=(strobe_type==0), enable_events=True), - sg.Radio('Edge', 'Rstr', key='edge', default=(strobe_type==1), enable_events=True), - ], - ]), - ], - ] - - layoutBoostTiming = [ - [sg.Frame('Boost', [ - [sg.Text('Mode:'), - sg.Radio('Normal', 'RBm', key='normal', default=(boost_mode==0), enable_events=True), - sg.Radio('Pass only', 'RBm', key='pass', default=(boost_mode==1), enable_events=True)], - [sg.Text('Frequency:'), - sg.Radio('2 MHz', 'RBfreq', key='2MHz', default=(boost_freq==0), enable_events=True), - sg.Radio('4 MHz', 'RBfreq', key='4MHz', default=(boost_freq==1), enable_events=True)], - [sg.Text('Current limit:'), - sg.Radio('1.9 A', 'RBlimit', key='1.9A', default=(boost_limit==0), enable_events=True), - sg.Radio('2.8 A', 'RBlimit', key='2.8A', default=(boost_limit==1), enable_events=True)], - ]), - sg.Frame('Flash timeout duration', [ - [sg.Slider(range=(0, 15), default_value=flash_timeout, orientation='h', - enable_events=True, key='FlashTimeout')], - [sg.Text(flash_timeout_text(), key='TextFlashTimeout')], - ]), - ], - ] - - layoutLed1 = [ - [sg.Checkbox('Enable', default=enable['Led1'], enable_events=True, key='Led1')], - [sg.Text('Flash:'), - sg.Slider(range=(0, 127), default_value=brightness['FlashLed1'], orientation='h', - size=(25, 18), enable_events=True, key='FlashLed1'), - sg.Text(brightness_text('FlashLed1'), key='TextFlashLed1') - ], - [sg.Text('Torch:'), - sg.Slider(range=(0, 127), default_value=brightness['TorchLed1'], orientation='h', - size=(25, 18), enable_events=True, key='TorchLed1'), - sg.Text(brightness_text('TorchLed1'), key='TextTorchLed1') - ], - ] - - layoutLed2 = [ - [sg.Checkbox('Enable', default=enable['Led2'], enable_events=True, key='Led2')], - [sg.Text('Flash:'), - sg.Slider(range=(0, 127), default_value=brightness['FlashLed2'], orientation='h', - size=(25, 18), enable_events=True, key='FlashLed2'), - sg.Text(brightness_text('FlashLed2'), key='TextFlashLed2') - ], - [sg.Text('Torch:'), - sg.Slider(range=(0, 127), default_value=brightness['TorchLed2'], orientation='h', - size=(25, 18), enable_events=True, key='TorchLed2'), - sg.Text(brightness_text('TorchLed2'), key='TextTorchLed2') - ], - ] - - layoutRegCtrl = [ - [sg.Text('Reg:'), sg.InputText('0x', size=(10,1), key='InRegW'), - sg.Text('Value:'), sg.InputText('0x', size=(10,1), key='InValW'), - sg.Button('Write')], - [sg.Text('Reg:'), sg.InputText('0x', size=(10,1), key='InRegR'), - sg.Button('Read'), sg.Text('...', key='TextValR')], - ] - - layoutMain = [ - layoutEnable, - layoutBoostTiming, - [sg.Frame('LED1 / Flood IR', layoutLed1)], - [sg.Frame('LED2 / Laser Pattern Projector', layoutLed2)], - [sg.Frame('LM3644 Register Control', layoutRegCtrl)], - ] - - window = sg.Window('IR Control', layoutMain) - - while True: - event, values = window.read() - #print('==EV', event, values) - if event == sg.WIN_CLOSED: - break - if event == 'Write': - reg = int(values['InRegW'], 0) - val = int(values['InValW'], 0) - dev.irWriteReg(reg, val) - if event == 'Read': - reg = int(values['InRegR'], 0) - val = hex(dev.irReadReg(reg)) - window['TextValR'].update(val) - if event in ('FlashLed1', 'FlashLed2', 'TorchLed1', 'TorchLed2'): - brightness[event] = int(values[event]) - window['Text' + event].update(brightness_text(event)) - set_brightness(event) - if event == 'FlashTimeout': - flash_timeout = int(values['FlashTimeout']) - window['TextFlashTimeout'].update(flash_timeout_text()) - set_timing() - if event in ('Led1', 'Led2', 'Strobe', 'TxPin', 'TorchTempPin'): - enable[event] = values[event] - set_enable() - if event in ('standby', 'irdrive', 'torch', 'flash'): - mode = mode_opts[event] - set_enable() - for e in ('FlashLed1', 'FlashLed2', 'TorchLed1', 'TorchLed2'): - window['Text' + e].update(brightness_text(e)) - if event in ('level', 'edge'): strobe_type = strobe_opts[event]; set_enable() - if event in ('normal', 'pass'): boost_mode = boost_mode_opts[event]; set_boost() - if event in ('2MHz', '4MHz'): boost_freq = boost_freq_opts[event]; set_boost() - if event in ('1.9A', '2.8A'): boost_limit = boost_limit_opts[event]; set_boost() - - window.close() - exit() - -if 0: # Change to 1 to enable stub GUI test (no device connection) - class IrStub(): - def irWriteReg(self, reg, value): - print("IR STUB write:", hex(reg), hex(value)) - def irReadReg(self, reg): - print("IR STUB read :", hex(reg)) - return 0 - ir_handler(IrStub()) - -def start_ir_handler(dev): - class IrLogWrapper: - def __init__(self, dev): - self.dev = dev - self.idx = 1 - def irWriteReg(self, reg, value): - print(f'===== Op{self.idx:3}: dev.irWriteReg({hex(reg)}, {hex(value)})') - self.dev.irWriteReg(reg, value) - self.idx += 1 - def irReadReg(self, reg): - value = self.dev.irReadReg(reg) - print(f'===== Op{self.idx:3}: dev.irReadReg({hex(reg)}) -> {hex(value)}') - self.idx += 1 - return value - - t = threading.Thread(target=ir_handler, args=(IrLogWrapper(dev),)) - t.start() From 9f29741ca4dea86db60242492c82e45a5080332b Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Thu, 24 Feb 2022 13:41:48 +0200 Subject: [PATCH 16/28] Add sliders for IR dot-projector and flood-illuminator control with CV GUI --- depthai_demo.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/depthai_demo.py b/depthai_demo.py index af0ed3571..1afe08982 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -472,6 +472,13 @@ def _createQueueCallback(self, queueName): if self._conf.args.stereoLrCheck: Trackbars.createTrackbar('LR-check threshold', queueName, self.LRCT_MIN, self.LRCT_MAX, self._conf.args.lrcThreshold, lambda value: self._pm.updateDepthConfig(self._device, lrcThreshold=value)) + irDrivers = self._device.getIrDrivers() + if irDrivers: + print('IR drivers detected on OAK-D Pro:', [f'{d[0]} on bus {d[1]}' for d in irDrivers]) + Trackbars.createTrackbar('IR Laser Dot Projector [mA]', queueName, 0, 1200, 0, + lambda value: self._device.setIrLaserDotProjectorBrightness(value)) + Trackbars.createTrackbar('IR Flood Illuminator [mA]', queueName, 0, 1500, 0, + lambda value: self._device.setIrFloodLightBrightness(value)) def _updateCameraConfigs(self): parsedConfig = {} From 7990e5c1cdb27290eaa272e9e4217018706fd053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 24 Feb 2022 14:12:46 +0100 Subject: [PATCH 17/28] add QT slider and fix LRC setting --- depthai_demo.py | 11 ++-- depthai_helpers/arg_manager.py | 2 +- depthai_helpers/config_manager.py | 4 ++ .../depthai_sdk/managers/pipeline_manager.py | 29 +++++---- gui/main.py | 10 +++- gui/views/DepthProperties.qml | 60 +++++++++++++++++++ gui/views/root.qml | 1 + 7 files changed, 98 insertions(+), 19 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 1afe08982..57f9abe92 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -697,6 +697,7 @@ def onSetup(self, instance): else: self.signals.setDataSignal.emit(["countLabels", []]) self.signals.setDataSignal.emit(["depthEnabled", self.conf.useDepth]) + self.signals.setDataSignal.emit(["irEnabled", self.conf.irEnabled(instance._device)]) self.signals.setDataSignal.emit(["statisticsAccepted", self.instance.metrics is not None]) self.signals.setDataSignal.emit(["modelChoices", sorted(self.conf.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) @@ -774,8 +775,8 @@ def restartDemo(self): self.stop() self.start() - def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrc=None, lrcThreshold=None): - self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrc=lrc, lrcThreshold=lrcThreshold) + def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None, irLaser=None, irFlood=None): + self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold, irLaser=irLaser, irFlood=irFlood) if median is not None: if median == dai.MedianFilter.MEDIAN_OFF: self.updateArg("stereoMedianSize", 0, False) @@ -789,8 +790,6 @@ def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrc=None, lr self.updateArg("disparityConfidenceThreshold", dct, False) if sigma is not None: self.updateArg("sigma", sigma, False) - if lrc is not None: - self.updateArg("stereoLrCheck", lrc, False) if lrcThreshold is not None: self.updateArg("lrcThreshold", lrcThreshold, False) @@ -822,7 +821,7 @@ def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturat self._demoInstance._updateCameraConfigs() - def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, extended=None): + def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, extended=None, lrc=None): if depthFrom is not None: self.updateArg("minDepth", depthFrom) if depthTo is not None: @@ -831,6 +830,8 @@ def guiOnDepthSetupUpdate(self, depthFrom=None, depthTo=None, subpixel=None, ext self.updateArg("subpixel", subpixel) if extended is not None: self.updateArg("extendedDisparity", extended) + if lrc is not None: + self.updateArg("stereoLrCheck", lrc) def guiOnCameraSetupUpdate(self, name, fps=None, resolution=None): if fps is not None: diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index 1a618a060..d295f0980 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -119,7 +119,7 @@ def parseArgs(): "If set to \"high\", the output streams will stay uncompressed\n" "If set to \"low\", the output streams will be MJPEG-encoded\n" "If set to \"auto\" (default), the optimal bandwidth will be selected based on your connection type and speed") - parser.add_argument('-gt', '--guiType', type=str, default="cv", choices=["auto", "qt", "cv"], help="Specify GUI type of the demo. \"cv\" uses built-in OpenCV display methods, \"qt\" uses Qt to display interactive GUI. \"auto\" will use OpenCV for Raspberry Pi and Qt for other platforms") + parser.add_argument('-gt', '--guiType', type=str, default="auto", choices=["auto", "qt", "cv"], help="Specify GUI type of the demo. \"cv\" uses built-in OpenCV display methods, \"qt\" uses Qt to display interactive GUI. \"auto\" will use OpenCV for Raspberry Pi and Qt for other platforms") parser.add_argument('-usbs', '--usbSpeed', type=str, default="usb3", choices=["usb2", "usb3"], help="Force USB communication speed. Default: %(default)s") parser.add_argument('-enc', '--encode', type=_comaSeparated(default=30.0, cast=float), nargs="+", default=[], help="Define which cameras to encode (record) \n" diff --git a/depthai_helpers/config_manager.py b/depthai_helpers/config_manager.py index 477376206..bc3aac059 100644 --- a/depthai_helpers/config_manager.py +++ b/depthai_helpers/config_manager.py @@ -70,6 +70,10 @@ def getModelSource(self): if self.args.camera == "color": return "color" + def irEnabled(self, device): + drivers = device.getIrDrivers() + return len(drivers) > 0 + def getModelName(self): if self.args.cnnModel: return self.args.cnnModel diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index fabeb2216..73363d4f1 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -386,7 +386,7 @@ def updateRightCamConfig(self, device, exposure=None, sensitivity=None, saturati self._updateCamConfig(self._rightConfig, Previews.right.name, device, exposure, sensitivity, saturation, contrast, brightness, sharpness) self._rightConfigInputQueue.send(self._rightConfig) - def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrc=None, lrcThreshold=None): + def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThreshold=None, irLaser=None, irFlood=None): """ Updates :obj:`depthai.node.StereoDepth` node config @@ -398,18 +398,23 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrc=None, sigma (int, Optional): Sigma value for bilateral filter (0..65535). If set to :code:`0`, the filter will be disabled. lrc (bool, Optional): Enables or disables Left-Right Check mode lrcThreshold (int, Optional): Sets the Left-Right Check threshold value (0..10) + irLaser (int, Optional): Sets the IR laser dot projector brightness (0..1200) + irFlood (int, Optional): Sets the IR flood illuminator light brightness (0..1500) """ - if dct is not None: - self._depthConfig.costMatching.confidenceThreshold = dct - if sigma is not None: - self._depthConfig.postProcessing.bilateralSigmaValue = sigma - if median is not None: - self._depthConfig.postProcessing.median = median - if lrcThreshold is not None: - self._depthConfig.algorithmControl.leftRightCheckThreshold = lrcThreshold - if lrc is not None: - self._depthConfig.algorithmControl.enableLeftRightCheck = lrc - self._depthConfigInputQueue.send(self._depthConfig) + if any([dct, sigma, median, lrcThreshold]): + if dct is not None: + self._depthConfig.costMatching.confidenceThreshold = dct + if sigma is not None: + self._depthConfig.postProcessing.bilateralSigmaValue = sigma + if median is not None: + self._depthConfig.postProcessing.median = median + if lrcThreshold is not None: + self._depthConfig.algorithmControl.leftRightCheckThreshold = lrcThreshold + self._depthConfigInputQueue.send(self._depthConfig) + if irLaser is not None: + device.setIrLaserDotProjectorBrightness(irLaser) + if irFlood is not None: + device.setIrFloodLightBrightness(irFlood) def addNn(self, nn, xoutNnInput=False, xoutSbb=False): """ diff --git a/gui/main.py b/gui/main.py index 6fc5670f4..e99511cd2 100644 --- a/gui/main.py +++ b/gui/main.py @@ -166,7 +166,7 @@ def toggleExtendedDisparity(self, state): @pyqtSlot(bool) def toggleLeftRightCheck(self, state): - instance.guiOnDepthConfigUpdate(lrc=state) + instance.guiOnDepthSetupUpdate(lrc=state) @pyqtSlot(int) def setDisparityConfidenceThreshold(self, value): @@ -189,6 +189,14 @@ def setMedianFilter(self, state): value = getattr(dai.MedianFilter, state) instance.guiOnDepthConfigUpdate(median=value) + @pyqtSlot(int) + def setIrLaserDotProjector(self, value): + instance.guiOnDepthConfigUpdate(irLaser=value) + + @pyqtSlot(int) + def setIrFloodIlluminator(self, value): + instance.guiOnDepthConfigUpdate(irFlood=value) + # @QmlElement class ColorCamBridge(QObject): diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index ca575dc33..9b068fc1f 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -333,7 +333,67 @@ ListView { font.family: "Courier" } + Text { + id: textirlaserdot + x: 360 + y: 290 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("IR Laser Dot Projector [mA]") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Slider { + id: irlaserdotslider + enabled: irEnabled + x: 361 + y: 310 + width: 198 + height: 27 + stepSize: 1 + to: 1200 + value: 10 + from: 0 + onValueChanged: { + depthBridge.setIrLaserDotProjector(value) + } + } + Text { + id: textirfloodilluminator + x: 360 + y: 350 + width: 200 + height: 25 + color: "#ffffff" + text: qsTr("IR Flood Illuminator [mA]") + font.pixelSize: 18 + horizontalAlignment: Text.AlignHCenter + font.styleName: "Regular" + font.weight: Font.Medium + font.family: "Courier" + } + + Slider { + id: irfloodslider + enabled: irEnabled + x: 361 + y: 370 + width: 198 + height: 27 + stepSize: 1 + to: 1500 + value: 10 + from: 0 + onValueChanged: { + depthBridge.setIrFloodIlluminator(value) + } + } } } /*##^## diff --git a/gui/views/root.qml b/gui/views/root.qml index 4c4e1a16b..b8ccacf66 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -73,6 +73,7 @@ ApplicationWindow { property var monoResolutionChoices property var restartRequired property var deviceChoices + property var irEnabled: false property var depthEnabled: true property var statisticsAccepted: true property var runningApp From 23182a149c1c18131f5ad2400335cdc24edb93b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 24 Feb 2022 15:10:19 +0100 Subject: [PATCH 18/28] add value indicators --- gui/views/DepthProperties.qml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 9b068fc1f..0fe8dc2ff 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -357,13 +357,25 @@ ListView { height: 27 stepSize: 1 to: 1200 - value: 10 + value: 0 from: 0 onValueChanged: { depthBridge.setIrLaserDotProjector(value) } } + Text { + id: irlaserdotslidervalue + x: 566 + y: 315 + width: 17 + height: 20 + color: "#ffffff" + text: irlaserdotslider.value + font.pixelSize: 12 + rotation: 0 + } + Text { id: textirfloodilluminator x: 360 @@ -388,12 +400,24 @@ ListView { height: 27 stepSize: 1 to: 1500 - value: 10 + value: 0 from: 0 onValueChanged: { depthBridge.setIrFloodIlluminator(value) } } + + Text { + id: irfloodslidervalue + x: 566 + y: 375 + width: 17 + height: 20 + color: "#ffffff" + text: irfloodslider.value + font.pixelSize: 12 + rotation: 0 + } } } /*##^## From b8af7a487515b816055841bec1b571e0a579fe39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 24 Feb 2022 15:28:33 +0100 Subject: [PATCH 19/28] fix dct and value setting of LRC value --- depthai_demo.py | 1 + depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py | 4 ++-- gui/views/DepthProperties.qml | 1 + gui/views/root.qml | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 57f9abe92..ab6783c51 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -698,6 +698,7 @@ def onSetup(self, instance): self.signals.setDataSignal.emit(["countLabels", []]) self.signals.setDataSignal.emit(["depthEnabled", self.conf.useDepth]) self.signals.setDataSignal.emit(["irEnabled", self.conf.irEnabled(instance._device)]) + self.signals.setDataSignal.emit(["lrc", self.conf.args.stereoLrCheck]) self.signals.setDataSignal.emit(["statisticsAccepted", self.instance.metrics is not None]) self.signals.setDataSignal.emit(["modelChoices", sorted(self.conf.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 73363d4f1..8f3629dd4 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -268,13 +268,13 @@ def createDepth(self, dct=245, median=dai.MedianFilter.KERNEL_7x7, sigma=0, lr=F self.nodes.stereo.initialConfig.setBilateralFilterSigma(sigma) self.nodes.stereo.initialConfig.setLeftRightCheckThreshold(lrcThreshold) - self._depthConfig = self.nodes.stereo.initialConfig.get() - # self.nodes.stereo.setRuntimeModeSwitch(True) self.nodes.stereo.setLeftRightCheck(lr) self.nodes.stereo.setExtendedDisparity(extended) self.nodes.stereo.setSubpixel(subpixel) + self._depthConfig = self.nodes.stereo.initialConfig.get() + # Create mono left/right cameras if we haven't already if not hasattr(self.nodes, 'monoLeft'): raise RuntimeError("Left mono camera not initialized. Call createLeftCam(res, fps) first!") diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 0fe8dc2ff..87aced55f 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -65,6 +65,7 @@ ListView { id: switch1 x: 0 y: 187 + checked: lrc text: qsTr("Left Right Check") transformOrigin: Item.Center font.family: "Courier" diff --git a/gui/views/root.qml b/gui/views/root.qml index b8ccacf66..690d238d1 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -78,6 +78,8 @@ ApplicationWindow { property var statisticsAccepted: true property var runningApp + property bool lrc: false + AppBridge { id: appBridge } From 041d2c6c86770c55cc6abb9f5b08cb644051cea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 24 Feb 2022 20:59:48 +0100 Subject: [PATCH 20/28] add better exit codes handling --- depthai_demo.py | 30 +++++++++++++++++++++++------- depthai_helpers/supervisor.py | 30 ++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index ab6783c51..f3e50cd46 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import atexit +import signal import sys if sys.version_info[0] < 3: @@ -318,7 +320,7 @@ def run(self): self.onSetup(self) try: - while not self._device.isClosed() and self.shouldRun(): + while self.shouldRun() and hasattr(self, "_device") and not self._device.isClosed(): self._fps.nextIter() self.onIter(self) self.loop() @@ -332,10 +334,13 @@ def run(self): finally: self.stop() - def stop(self): - print("Stopping demo...") - self._device.close() - del self._device + def stop(self, *args, **kwargs): + + if hasattr(self, "_device"): + print("Stopping demo...") + self._device.close() + del self._device + self._fps.printStatus() self._pm.closeDefaultQueues() if self._conf.useCamera: self._pv.closeQueues() @@ -347,7 +352,6 @@ def stop(self): self._sbbOut.close() if self._logOut is not None: self._logOut.close() - self._fps.printStatus() self.onTeardown(self) timer = time.monotonic() @@ -759,6 +763,7 @@ def stop(self, wait=True): current_mxid = self._demoInstance._device.getMxId() else: current_mxid = self.confManager.args.deviceId + self.worker.running = False self.worker.signals.exitSignal.emit() self.threadpool.waitForDone(10000) @@ -776,6 +781,10 @@ def restartDemo(self): self.stop() self.start() + def stopGui(self, *args, **kwargs): + self.stop(wait=False) + self.app.quit() + def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None, irLaser=None, irFlood=None): self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold, irLaser=irLaser, irFlood=irFlood) if median is not None: @@ -987,12 +996,19 @@ def guiOnToggleDisparity(self, value): if self.selectedPreview not in updated: self.selectedPreview = updated[0] self.updateArg("show", updated) - GuiApp().start() + app = GuiApp() + signal.signal(signal.SIGINT, app.stopGui) + signal.signal(signal.SIGTERM, app.stopGui) + atexit.register(app.stopGui) + app.start() def runOpenCv(): confManager = prepareConfManager(args) demo = Demo() + signal.signal(signal.SIGINT, demo.stop) + signal.signal(signal.SIGTERM, demo.stop) + atexit.register(demo.stop) demo.run_all(confManager) diff --git a/depthai_helpers/supervisor.py b/depthai_helpers/supervisor.py index 4d92695a3..2826ae968 100644 --- a/depthai_helpers/supervisor.py +++ b/depthai_helpers/supervisor.py @@ -1,5 +1,7 @@ +import atexit import importlib.util import os +import signal import subprocess import sys import time @@ -21,6 +23,13 @@ def removeArg(name, withValue=True): class Supervisor: + child = None + + def __init__(self): + signal.signal(signal.SIGINT, self.cleanup) + signal.signal(signal.SIGTERM, self.cleanup) + atexit.register(self.cleanup) + def runDemo(self, args): repo_root = Path(__file__).parent.parent args.noSupervisor = True @@ -33,7 +42,11 @@ def runDemo(self, args): new_env["LD_LIBRARY_PATH"] = str(Path(importlib.util.find_spec("PyQt5").origin).parent / "Qt5/lib") new_env["DEPTHAI_INSTALL_SIGNAL_HANDLER"] = "0" try: - subprocess.check_call(' '.join([f'"{sys.executable}"', "depthai_demo.py"] + new_args), env=new_env, shell=True, cwd=repo_root) + cmd = ' '.join([f'"{sys.executable}"', "depthai_demo.py"] + new_args) + self.child = subprocess.Popen(cmd, shell=True, env=new_env, cwd=repo_root) + self.child.communicate() + if self.child.returncode != 0: + raise subprocess.CalledProcessError(self.child.returncode, cmd) except subprocess.CalledProcessError as ex: print("Error while running demo script... {}".format(ex)) print("Waiting 5s for the device to be discoverable again...") @@ -43,7 +56,20 @@ def runDemo(self, args): new_env = env.copy() new_env["DEPTHAI_INSTALL_SIGNAL_HANDLER"] = "0" new_args = createNewArgs(args) - subprocess.check_call(' '.join([f'"{sys.executable}"', "depthai_demo.py"] + new_args), env=new_env, shell=True, cwd=repo_root) + cmd = ' '.join([f'"{sys.executable}"', "depthai_demo.py"] + new_args) + self.child = subprocess.Popen(cmd, shell=True, env=new_env, cwd=repo_root) + self.child.communicate() def checkQtAvailability(self): return importlib.util.find_spec("PyQt5") is not None + + def cleanup(self, *args, **kwargs): + if self.child is not None and self.child.poll() is None: + self.child.terminate() + try: + self.child.wait(1) + except subprocess.TimeoutExpired: + pass + + + From 9a0c3a2aa8cc5c865e62ad72437c182d0edeec79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Thu, 24 Feb 2022 21:13:02 +0100 Subject: [PATCH 21/28] enable LRC by default --- depthai_helpers/arg_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index d295f0980..9c27d939d 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -79,8 +79,8 @@ def parseArgs(): help="Sigma value for Bilateral Filter applied on depth. Default: %(default)s") parser.add_argument("-med", "--stereoMedianSize", default=7, type=int, choices=[0, 3, 5, 7], help="Disparity / depth median filter kernel size (N x N) . 0 = filtering disabled. Default: %(default)s") - parser.add_argument('-lrc', '--stereoLrCheck', action="store_true", - help="Enable stereo 'Left-Right check' feature.") + parser.add_argument('-dlrc', '--disableStereoLrCheck', action="store_false", dest="stereoLrCheck", + help="Disable stereo 'Left-Right check' feature.") parser.add_argument('-ext', '--extendedDisparity', action="store_true", help="Enable stereo 'Extended Disparity' feature.") parser.add_argument('-sub', '--subpixel', action="store_true", From a062f524bdf765c7220416c82a93bb34ecf4f783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pi=C5=82atowski?= Date: Fri, 25 Feb 2022 17:21:40 +0100 Subject: [PATCH 22/28] update IR dot projector args --- depthai_demo.py | 12 +++++++++-- depthai_helpers/arg_manager.py | 2 ++ .../depthai_sdk/managers/pipeline_manager.py | 21 ++++++++++++------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index f3e50cd46..f91bddb6f 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -255,6 +255,9 @@ def setup(self, conf: ConfigManager): useRectifiedRight=Previews.rectifiedRight.name in self._conf.args.show, ) + if self._conf.irEnabled(self._device): + self._pm.updateIrConfig(self._device, self._conf.args.irDotBrightness, self._conf.args.irFloodBrightness) + self._encManager = None if len(self._conf.args.encode) > 0: self._encManager = EncodingManager(self._conf.args.encode, self._conf.args.encodeOutput) @@ -335,7 +338,6 @@ def run(self): self.stop() def stop(self, *args, **kwargs): - if hasattr(self, "_device"): print("Stopping demo...") self._device.close() @@ -786,7 +788,7 @@ def stopGui(self, *args, **kwargs): self.app.quit() def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold=None, irLaser=None, irFlood=None): - self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold, irLaser=irLaser, irFlood=irFlood) + self._demoInstance._pm.updateDepthConfig(self._demoInstance._device, median=median, dct=dct, sigma=sigma, lrcThreshold=lrcThreshold) if median is not None: if median == dai.MedianFilter.MEDIAN_OFF: self.updateArg("stereoMedianSize", 0, False) @@ -802,6 +804,12 @@ def guiOnDepthConfigUpdate(self, median=None, dct=None, sigma=None, lrcThreshold self.updateArg("sigma", sigma, False) if lrcThreshold is not None: self.updateArg("lrcThreshold", lrcThreshold, False) + if any([irLaser, irFlood]): + self._demoInstance._pm.updateIrConfig(self._demoInstance._device, irLaser, irFlood) + if irLaser is not None: + self.updateArg("irDotBrightness", irLaser, False) + if irFlood is not None: + self.updateArg("irFloodBrightness", irFlood, False) def guiOnCameraConfigUpdate(self, name, exposure=None, sensitivity=None, saturation=None, contrast=None, brightness=None, sharpness=None): if exposure is not None: diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index 9c27d939d..793ec3ce0 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -141,6 +141,8 @@ def parseArgs(): parser.add_argument("--cameraContrast", type=_comaSeparated("all", int), nargs="+", help="Specify image contrast") parser.add_argument("--cameraBrightness", type=_comaSeparated("all", int), nargs="+", help="Specify image brightness") parser.add_argument("--cameraSharpness", type=_comaSeparated("all", int), nargs="+", help="Specify image sharpness") + parser.add_argument("--irDotBrightness", type=int, help="Specify IR dot projector brightness") + parser.add_argument("--irFloodBrightness", type=int, help="Specify IR flood illumination brightness") parser.add_argument('--skipVersionCheck', action="store_true", help="Disable libraries version check") parser.add_argument('--noSupervisor', action="store_true", help="Disable supervisor check") parser.add_argument('--sync', action="store_true", help="Enable frame and NN synchronization. If enabled, all frames and NN results will be synced before preview (same sequence number)") diff --git a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py index 8f3629dd4..60f89b31b 100644 --- a/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py +++ b/depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py @@ -240,6 +240,19 @@ def createRightCam(self, res=None, fps=30, orientation: dai.CameraImageOrientati self.nodes.xinRightControl.setStreamName(Previews.right.name + "_control") self.nodes.xinRightControl.out.link(self.nodes.monoRight.inputControl) + def updateIrConfig(self, device, irLaser=None, irFlood=None): + """ + Updates IR configuration + + Args: + irLaser (int, Optional): Sets the IR laser dot projector brightness (0..1200) + irFlood (int, Optional): Sets the IR flood illuminator light brightness (0..1500) + """ + if irLaser is not None: + device.setIrLaserDotProjectorBrightness(irLaser) + if irFlood is not None: + device.setIrFloodLightBrightness(irFlood) + def createDepth(self, dct=245, median=dai.MedianFilter.KERNEL_7x7, sigma=0, lr=False, lrcThreshold=4, extended=False, subpixel=False, useDisparity=False, useDepth=False, useRectifiedLeft=False, useRectifiedRight=False): """ Creates :obj:`depthai.node.StereoDepth` node based on specified attributes @@ -386,7 +399,7 @@ def updateRightCamConfig(self, device, exposure=None, sensitivity=None, saturati self._updateCamConfig(self._rightConfig, Previews.right.name, device, exposure, sensitivity, saturation, contrast, brightness, sharpness) self._rightConfigInputQueue.send(self._rightConfig) - def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThreshold=None, irLaser=None, irFlood=None): + def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThreshold=None): """ Updates :obj:`depthai.node.StereoDepth` node config @@ -398,8 +411,6 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThresh sigma (int, Optional): Sigma value for bilateral filter (0..65535). If set to :code:`0`, the filter will be disabled. lrc (bool, Optional): Enables or disables Left-Right Check mode lrcThreshold (int, Optional): Sets the Left-Right Check threshold value (0..10) - irLaser (int, Optional): Sets the IR laser dot projector brightness (0..1200) - irFlood (int, Optional): Sets the IR flood illuminator light brightness (0..1500) """ if any([dct, sigma, median, lrcThreshold]): if dct is not None: @@ -411,10 +422,6 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThresh if lrcThreshold is not None: self._depthConfig.algorithmControl.leftRightCheckThreshold = lrcThreshold self._depthConfigInputQueue.send(self._depthConfig) - if irLaser is not None: - device.setIrLaserDotProjectorBrightness(irLaser) - if irFlood is not None: - device.setIrFloodLightBrightness(irFlood) def addNn(self, nn, xoutNnInput=False, xoutSbb=False): """ From 3413a6dd9d7a62ca6b755a05910b5731aa966f6a Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Fri, 25 Feb 2022 20:50:18 +0200 Subject: [PATCH 23/28] Add range (and check it) for `--irDotBrightness`, `--irFloodBrightness` --- depthai_helpers/arg_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depthai_helpers/arg_manager.py b/depthai_helpers/arg_manager.py index 793ec3ce0..6f82ed17b 100644 --- a/depthai_helpers/arg_manager.py +++ b/depthai_helpers/arg_manager.py @@ -141,8 +141,8 @@ def parseArgs(): parser.add_argument("--cameraContrast", type=_comaSeparated("all", int), nargs="+", help="Specify image contrast") parser.add_argument("--cameraBrightness", type=_comaSeparated("all", int), nargs="+", help="Specify image brightness") parser.add_argument("--cameraSharpness", type=_comaSeparated("all", int), nargs="+", help="Specify image sharpness") - parser.add_argument("--irDotBrightness", type=int, help="Specify IR dot projector brightness") - parser.add_argument("--irFloodBrightness", type=int, help="Specify IR flood illumination brightness") + parser.add_argument("--irDotBrightness", type=checkRange(0, 1200), default=0, help="For OAK-D Pro: specify IR dot projector brightness, range: 0..1200 [mA], default 0 (turned off)") + parser.add_argument("--irFloodBrightness", type=checkRange(0, 1500), default=0, help="For OAK-D Pro: specify IR flood illumination brightness, range: 0..1500 [mA], default 0 (turned off)") parser.add_argument('--skipVersionCheck', action="store_true", help="Disable libraries version check") parser.add_argument('--noSupervisor', action="store_true", help="Disable supervisor check") parser.add_argument('--sync', action="store_true", help="Enable frame and NN synchronization. If enabled, all frames and NN results will be synced before preview (same sequence number)") From 24688174dd9f1ae12d26aa9c65007022ac727121 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Fri, 25 Feb 2022 20:52:15 +0200 Subject: [PATCH 24/28] Set the IR sliders to the values of `--irDotBrightness`/`--irFloodBrightness` (were 0) --- depthai_demo.py | 2 ++ gui/views/DepthProperties.qml | 4 ++-- gui/views/root.qml | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index f91bddb6f..477c46a9c 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -704,6 +704,8 @@ def onSetup(self, instance): self.signals.setDataSignal.emit(["countLabels", []]) self.signals.setDataSignal.emit(["depthEnabled", self.conf.useDepth]) self.signals.setDataSignal.emit(["irEnabled", self.conf.irEnabled(instance._device)]) + self.signals.setDataSignal.emit(["irDotBrightness", self.conf.args.irDotBrightness]) + self.signals.setDataSignal.emit(["irFloodBrightness", self.conf.args.irFloodBrightness]) self.signals.setDataSignal.emit(["lrc", self.conf.args.stereoLrCheck]) self.signals.setDataSignal.emit(["statisticsAccepted", self.instance.metrics is not None]) self.signals.setDataSignal.emit(["modelChoices", sorted(self.conf.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) diff --git a/gui/views/DepthProperties.qml b/gui/views/DepthProperties.qml index 87aced55f..86b5ea51b 100644 --- a/gui/views/DepthProperties.qml +++ b/gui/views/DepthProperties.qml @@ -358,7 +358,7 @@ ListView { height: 27 stepSize: 1 to: 1200 - value: 0 + value: irDotBrightness from: 0 onValueChanged: { depthBridge.setIrLaserDotProjector(value) @@ -401,7 +401,7 @@ ListView { height: 27 stepSize: 1 to: 1500 - value: 0 + value: irFloodBrightness from: 0 onValueChanged: { depthBridge.setIrFloodIlluminator(value) diff --git a/gui/views/root.qml b/gui/views/root.qml index 690d238d1..e49001e89 100644 --- a/gui/views/root.qml +++ b/gui/views/root.qml @@ -74,6 +74,8 @@ ApplicationWindow { property var restartRequired property var deviceChoices property var irEnabled: false + property var irDotBrightness: 0 + property var irFloodBrightness: 0 property var depthEnabled: true property var statisticsAccepted: true property var runningApp From 1c413d8bf198b1c6975031af9d1d92a0c223981a Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Fri, 25 Feb 2022 21:18:22 +0200 Subject: [PATCH 25/28] CV GUI: set IR defaults based on command line options (they seem to be auto-applied: callback called on start) --- depthai_demo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 477c46a9c..45d9605b6 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -481,9 +481,9 @@ def _createQueueCallback(self, queueName): irDrivers = self._device.getIrDrivers() if irDrivers: print('IR drivers detected on OAK-D Pro:', [f'{d[0]} on bus {d[1]}' for d in irDrivers]) - Trackbars.createTrackbar('IR Laser Dot Projector [mA]', queueName, 0, 1200, 0, + Trackbars.createTrackbar('IR Laser Dot Projector [mA]', queueName, 0, 1200, self._conf.args.irDotBrightness, lambda value: self._device.setIrLaserDotProjectorBrightness(value)) - Trackbars.createTrackbar('IR Flood Illuminator [mA]', queueName, 0, 1500, 0, + Trackbars.createTrackbar('IR Flood Illuminator [mA]', queueName, 0, 1500, self._conf.args.irFloodBrightness, lambda value: self._device.setIrFloodLightBrightness(value)) def _updateCameraConfigs(self): From 53b1b0dd6e61e6b2deaa5a26df0ca0e88d8aae9b Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Fri, 25 Feb 2022 21:40:47 +0200 Subject: [PATCH 26/28] Info about IR drivers detected moved to a common place, show an error if cmd line args were set for non-Pro devices. TODO could be cleaned up a little... --- depthai_demo.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 45d9605b6..7ccf7d7a1 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -219,6 +219,11 @@ def setup(self, conf: ConfigManager): self._pm.enableLowBandwidth(poeQuality=self._conf.args.poeQuality) self._cap = cv2.VideoCapture(self._conf.args.video) if not self._conf.useCamera else None self._fps = FPSHandler() if self._conf.useCamera else FPSHandler(self._cap) + irDrivers = self._device.getIrDrivers() + if irDrivers: + print('IR drivers found on OAK-D Pro:', [f'{d[0]} on bus {d[1]}' for d in irDrivers]) + elif any([self._conf.args.irDotBrightness, self._conf.args.irFloodBrightness]): + print('[ERROR] IR drivers not detected on device!') if self._conf.useCamera: pvClass = SyncedPreviewManager if self._conf.args.sync else PreviewManager @@ -478,9 +483,7 @@ def _createQueueCallback(self, queueName): if self._conf.args.stereoLrCheck: Trackbars.createTrackbar('LR-check threshold', queueName, self.LRCT_MIN, self.LRCT_MAX, self._conf.args.lrcThreshold, lambda value: self._pm.updateDepthConfig(self._device, lrcThreshold=value)) - irDrivers = self._device.getIrDrivers() - if irDrivers: - print('IR drivers detected on OAK-D Pro:', [f'{d[0]} on bus {d[1]}' for d in irDrivers]) + if self._device.getIrDrivers(): Trackbars.createTrackbar('IR Laser Dot Projector [mA]', queueName, 0, 1200, self._conf.args.irDotBrightness, lambda value: self._device.setIrLaserDotProjectorBrightness(value)) Trackbars.createTrackbar('IR Flood Illuminator [mA]', queueName, 0, 1500, self._conf.args.irFloodBrightness, From a736a742fa70b58d09867928879ba279a168a7e9 Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Fri, 25 Feb 2022 21:41:22 +0200 Subject: [PATCH 27/28] Make sure the IR sliders stay at zero on non-Pro devices --- depthai_demo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depthai_demo.py b/depthai_demo.py index 7ccf7d7a1..a54f667db 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -707,8 +707,8 @@ def onSetup(self, instance): self.signals.setDataSignal.emit(["countLabels", []]) self.signals.setDataSignal.emit(["depthEnabled", self.conf.useDepth]) self.signals.setDataSignal.emit(["irEnabled", self.conf.irEnabled(instance._device)]) - self.signals.setDataSignal.emit(["irDotBrightness", self.conf.args.irDotBrightness]) - self.signals.setDataSignal.emit(["irFloodBrightness", self.conf.args.irFloodBrightness]) + self.signals.setDataSignal.emit(["irDotBrightness", self.conf.args.irDotBrightness if self.conf.irEnabled(instance._device) else 0]) + self.signals.setDataSignal.emit(["irFloodBrightness", self.conf.args.irFloodBrightness if self.conf.irEnabled(instance._device) else 0]) self.signals.setDataSignal.emit(["lrc", self.conf.args.stereoLrCheck]) self.signals.setDataSignal.emit(["statisticsAccepted", self.instance.metrics is not None]) self.signals.setDataSignal.emit(["modelChoices", sorted(self.conf.getAvailableZooModels(), key=cmp_to_key(lambda a, b: -1 if a == "mobilenet-ssd" else 1 if b == "mobilenet-ssd" else -1 if a < b else 1))]) From 0fd40df7cb6dec20606b7e29f30661404a01bc6b Mon Sep 17 00:00:00 2001 From: alex-luxonis Date: Fri, 25 Feb 2022 21:51:45 +0200 Subject: [PATCH 28/28] Print a note on OAK-D Pro devices to enable the IR --- depthai_demo.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/depthai_demo.py b/depthai_demo.py index a54f667db..7bc91cd10 100755 --- a/depthai_demo.py +++ b/depthai_demo.py @@ -220,9 +220,11 @@ def setup(self, conf: ConfigManager): self._cap = cv2.VideoCapture(self._conf.args.video) if not self._conf.useCamera else None self._fps = FPSHandler() if self._conf.useCamera else FPSHandler(self._cap) irDrivers = self._device.getIrDrivers() + irSetFromCmdLine = any([self._conf.args.irDotBrightness, self._conf.args.irFloodBrightness]) if irDrivers: print('IR drivers found on OAK-D Pro:', [f'{d[0]} on bus {d[1]}' for d in irDrivers]) - elif any([self._conf.args.irDotBrightness, self._conf.args.irFloodBrightness]): + if not irSetFromCmdLine: print(' --> Go to the `Depth` tab to enable!') + elif irSetFromCmdLine: print('[ERROR] IR drivers not detected on device!') if self._conf.useCamera: