Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAK-D Pro support, update to depthai 2.15.0.0 #556

Merged
merged 29 commits into from
Feb 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
165abff
Add simple IR register control for OAK-D-Pro. Need to install:
alex-luxonis Oct 1, 2021
da8765f
IR projector handler: more GUI controls
alex-luxonis Oct 2, 2021
3d539e6
Add basic manual exposure/gain control for Mono cameras. Usage:
alex-luxonis Oct 4, 2021
5b4a9e3
Add log wrapper for IR ops
alex-luxonis Nov 18, 2021
ca6f7a3
Added OpenCV to requirements
saching13 Nov 23, 2021
d5709bc
Update depthai version to depthai-python `oak-d-pro_develop`
alex-luxonis Nov 30, 2021
2820b01
Update depthai version to depthai-python `oak-d-pro_develop`
alex-luxonis Dec 30, 2021
7de1b30
Update depthai to work with OAK-D-Pro-W. Notes:
alex-luxonis Jan 17, 2022
bb6c0af
Fix a typo in requirements.txt
alex-luxonis Jan 17, 2022
2c21d9b
Updated with board config files
saching13 Jan 26, 2022
b72c6f0
Update resources/boards/OAK-D-PRO-W.json
saching13 Jan 27, 2022
33f00c5
Update resources/boards/OAK-D-PRO.json
saching13 Jan 27, 2022
1abec08
Merge 'main' into oak-d-pro. Revert all changes to depthai_demo.py
alex-luxonis Feb 24, 2022
944bda5
Update to latest release: 2.15.0.0, with support for OAK-D-Pro
alex-luxonis Feb 24, 2022
e5b0f7a
Temporarily change `-gt` : "auto" -> "cv", as the sliders will be add…
alex-luxonis Feb 24, 2022
853d85c
Remove low-level IR control `ir_handler.py`,
alex-luxonis Feb 24, 2022
9f29741
Add sliders for IR dot-projector and flood-illuminator control with C…
alex-luxonis Feb 24, 2022
7990e5c
add QT slider and fix LRC setting
VanDavv Feb 24, 2022
23182a1
add value indicators
VanDavv Feb 24, 2022
b8af7a4
fix dct and value setting of LRC value
VanDavv Feb 24, 2022
041d2c6
add better exit codes handling
VanDavv Feb 24, 2022
9a0c3a2
enable LRC by default
VanDavv Feb 24, 2022
a062f52
update IR dot projector args
VanDavv Feb 25, 2022
3413a6d
Add range (and check it) for `--irDotBrightness`, `--irFloodBrightness`
alex-luxonis Feb 25, 2022
2468817
Set the IR sliders to the values of `--irDotBrightness`/`--irFloodBri…
alex-luxonis Feb 25, 2022
1c413d8
CV GUI: set IR defaults based on command line options
alex-luxonis Feb 25, 2022
53b1b0d
Info about IR drivers detected moved to a common place,
alex-luxonis Feb 25, 2022
a736a74
Make sure the IR sliders stay at zero on non-Pro devices
alex-luxonis Feb 25, 2022
0fd40df
Print a note on OAK-D Pro devices to enable the IR
alex-luxonis Feb 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 52 additions & 12 deletions depthai_demo.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#!/usr/bin/env python3
import atexit
import signal
import sys

if sys.version_info[0] < 3:
Expand Down Expand Up @@ -217,6 +219,13 @@ 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()
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])
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:
pvClass = SyncedPreviewManager if self._conf.args.sync else PreviewManager
Expand Down Expand Up @@ -253,6 +262,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)
Expand Down Expand Up @@ -318,7 +330,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()
Expand All @@ -332,10 +344,12 @@ 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()
Expand All @@ -347,7 +361,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()
Expand Down Expand Up @@ -472,6 +485,11 @@ 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))
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,
lambda value: self._device.setIrFloodLightBrightness(value))

def _updateCameraConfigs(self):
parsedConfig = {}
Expand Down Expand Up @@ -690,6 +708,10 @@ 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(["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))])

Expand Down Expand Up @@ -750,6 +772,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)

Expand All @@ -767,8 +790,12 @@ 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 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)
if median is not None:
if median == dai.MedianFilter.MEDIAN_OFF:
self.updateArg("stereoMedianSize", 0, False)
Expand All @@ -782,10 +809,14 @@ 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)
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:
Expand Down Expand Up @@ -815,7 +846,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:
Expand All @@ -824,6 +855,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:
Expand Down Expand Up @@ -978,12 +1011,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)


Expand Down
6 changes: 4 additions & 2 deletions depthai_helpers/arg_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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=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)")
Expand Down
4 changes: 4 additions & 0 deletions depthai_helpers/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 28 additions & 2 deletions depthai_helpers/supervisor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import atexit
import importlib.util
import os
import signal
import subprocess
import sys
import time
Expand All @@ -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
Expand All @@ -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...")
Expand All @@ -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



40 changes: 26 additions & 14 deletions depthai_sdk/src/depthai_sdk/managers/pipeline_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -268,13 +281,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!")
Expand Down Expand Up @@ -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, lrc=None, lrcThreshold=None):
def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrcThreshold=None):
"""
Updates :obj:`depthai.node.StereoDepth` node config

Expand All @@ -399,17 +412,16 @@ def updateDepthConfig(self, device, dct=None, sigma=None, median=None, lrc=None,
lrc (bool, Optional): Enables or disables Left-Right Check mode
lrcThreshold (int, Optional): Sets the Left-Right Check threshold value (0..10)
"""
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)

def addNn(self, nn, xoutNnInput=False, xoutSbb=False):
"""
Expand Down
10 changes: 9 additions & 1 deletion gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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):
Expand Down
Loading