Skip to content

Commit

Permalink
Merge pull request luxonis#561 from luxonis/ir_frame_control
Browse files Browse the repository at this point in the history
Color/MonoCamera frameEvent output, per-frame IR control
  • Loading branch information
alex-luxonis authored Oct 7, 2022
2 parents 6d893a8 + 4517dc8 commit 2509395
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 2 deletions.
116 changes: 116 additions & 0 deletions examples/MonoCamera/mono_preview_alternate_pro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env python3

import cv2
import depthai as dai

if 1: # PoE config
fps = 30
res = dai.MonoCameraProperties.SensorResolution.THE_400_P
poolSize = 24 # default 3, increased to prevent desync
else: # USB
fps = 30
res = dai.MonoCameraProperties.SensorResolution.THE_720_P
poolSize = 8 # default 3, increased to prevent desync

# Create pipeline
pipeline = dai.Pipeline()

# Define sources and outputs
monoL = pipeline.create(dai.node.MonoCamera)
monoR = pipeline.create(dai.node.MonoCamera)

monoL.setBoardSocket(dai.CameraBoardSocket.LEFT)
monoL.setResolution(res)
monoL.setFps(fps)
monoL.setNumFramesPool(poolSize)
monoR.setBoardSocket(dai.CameraBoardSocket.RIGHT)
monoR.setResolution(res)
monoR.setFps(fps)
monoR.setNumFramesPool(poolSize)

xoutDotL = pipeline.create(dai.node.XLinkOut)
xoutDotR = pipeline.create(dai.node.XLinkOut)
xoutFloodL = pipeline.create(dai.node.XLinkOut)
xoutFloodR = pipeline.create(dai.node.XLinkOut)

xoutDotL.setStreamName('dot-left')
xoutDotR.setStreamName('dot-right')
xoutFloodL.setStreamName('flood-left')
xoutFloodR.setStreamName('flood-right')
streams = ['dot-left', 'dot-right', 'flood-left', 'flood-right']

# Script node for frame routing and IR dot/flood alternate
script = pipeline.create(dai.node.Script)
script.setProcessor(dai.ProcessorType.LEON_CSS)
script.setScript("""
dotBright = 500 # Note: recommended to not exceed 765, for max duty cycle
floodBright = 200
LOGGING = False # Set `True` for latency/timings debugging
node.warn(f'IR drivers detected: {str(Device.getIrDrivers())}')
flagDot = False
while True:
# Wait first for a frame event, received at MIPI start-of-frame
event = node.io['event'].get()
if LOGGING: tEvent = Clock.now()
# Immediately reconfigure the IR driver.
# Note the logic is inverted, as it applies for next frame
Device.setIrLaserDotProjectorBrightness(0 if flagDot else dotBright)
Device.setIrFloodLightBrightness(floodBright if flagDot else 0)
if LOGGING: tIrSet = Clock.now()
# Wait for the actual frames (after MIPI capture and ISP proc is done)
frameL = node.io['frameL'].get()
if LOGGING: tLeft = Clock.now()
frameR = node.io['frameR'].get()
if LOGGING: tRight = Clock.now()
if LOGGING:
latIR = (tIrSet - tEvent ).total_seconds() * 1000
latEv = (tEvent - event.getTimestamp() ).total_seconds() * 1000
latProcL = (tLeft - event.getTimestamp() ).total_seconds() * 1000
diffRecvRL = (tRight - tLeft ).total_seconds() * 1000
node.warn(f'T[ms] latEv:{latEv:5.3f} latIR:{latIR:5.3f} latProcL:{latProcL:6.3f} '
+ f' diffRecvRL:{diffRecvRL:5.3f}')
# Sync checks
diffSeq = frameL.getSequenceNum() - event.getSequenceNum()
diffTsEv = (frameL.getTimestamp() - event.getTimestamp()).total_seconds() * 1000
diffTsRL = (frameR.getTimestamp() - frameL.getTimestamp()).total_seconds() * 1000
if diffSeq or diffTsEv or (abs(diffTsRL) > 0.8):
node.error(f'frame/event desync! Fr-Ev: {diffSeq} frames,'
+ f' {diffTsEv:.3f} ms; R-L: {diffTsRL:.3f} ms')
# Route the frames to their respective outputs
node.io['dotL' if flagDot else 'floodL'].send(frameL)
node.io['dotR' if flagDot else 'floodR'].send(frameR)
flagDot = not flagDot
""")

# Linking
monoL.frameEvent.link(script.inputs['event'])
monoL.out.link(script.inputs['frameL'])
monoR.out.link(script.inputs['frameR'])

script.outputs['dotL'].link(xoutDotL.input)
script.outputs['dotR'].link(xoutDotR.input)
script.outputs['floodL'].link(xoutFloodL.input)
script.outputs['floodR'].link(xoutFloodR.input)

# Connect to device and start pipeline
with dai.Device(pipeline) as device:
queues = [device.getOutputQueue(name=s, maxSize=4, blocking=False) for s in streams]

while True:
for q in queues:
pkt = q.tryGet()
if pkt is not None:
name = q.getName()
frame = pkt.getCvFrame()
cv2.imshow(name, frame)

if cv2.waitKey(5) == ord('q'):
break
1 change: 1 addition & 0 deletions src/pipeline/node/ColorCameraBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ void bind_colorcamera(pybind11::module& m, void* pCallstack){
.def_readonly("still", &ColorCamera::still, DOC(dai, node, ColorCamera, still))
.def_readonly("isp", &ColorCamera::isp, DOC(dai, node, ColorCamera, isp))
.def_readonly("raw", &ColorCamera::raw, DOC(dai, node, ColorCamera, raw))
.def_readonly("frameEvent", &ColorCamera::frameEvent, DOC(dai, node, ColorCamera, frameEvent))
.def("setCamId", [](ColorCamera& c, int64_t id) {
// Issue an deprecation warning
PyErr_WarnEx(PyExc_DeprecationWarning, "setCamId() is deprecated, use setBoardSocket() instead.", 1);
Expand Down
8 changes: 8 additions & 0 deletions src/pipeline/node/MonoCameraBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,16 @@ void bind_monocamera(pybind11::module& m, void* pCallstack){
.def_readwrite("boardSocket", &MonoCameraProperties::boardSocket)
.def_readwrite("resolution", &MonoCameraProperties::resolution)
.def_readwrite("fps", &MonoCameraProperties::fps)
.def_readwrite("numFramesPool", &MonoCameraProperties::numFramesPool)
.def_readwrite("numFramesPoolRaw", &MonoCameraProperties::numFramesPoolRaw)
;

// Node
monoCamera
.def_readonly("inputControl", &MonoCamera::inputControl, DOC(dai, node, MonoCamera, inputControl))
.def_readonly("out", &MonoCamera::out, DOC(dai, node, MonoCamera, out))
.def_readonly("raw", &MonoCamera::raw, DOC(dai, node, MonoCamera, raw))
.def_readonly("frameEvent", &MonoCamera::frameEvent, DOC(dai, node, MonoCamera, frameEvent))
.def_readonly("initialControl", &MonoCamera::initialControl, DOC(dai, node, MonoCamera, initialControl))
.def("setCamId", [](MonoCamera& c, int64_t id) {
// Issue an deprecation warning
Expand Down Expand Up @@ -77,6 +80,11 @@ void bind_monocamera(pybind11::module& m, void* pCallstack){
.def("getResolutionSize", &MonoCamera::getResolutionSize, DOC(dai, node, MonoCamera, getResolutionSize))
.def("getResolutionWidth", &MonoCamera::getResolutionWidth, DOC(dai, node, MonoCamera, getResolutionWidth))
.def("getResolutionHeight", &MonoCamera::getResolutionHeight, DOC(dai, node, MonoCamera, getResolutionHeight))
.def("setNumFramesPool", &MonoCamera::setNumFramesPool, DOC(dai, node, MonoCamera, setNumFramesPool))
.def("getNumFramesPool", &MonoCamera::getNumFramesPool, DOC(dai, node, MonoCamera, getNumFramesPool))
.def("setRawNumFramesPool", &MonoCamera::setRawNumFramesPool, DOC(dai, node, MonoCamera, setRawNumFramesPool))
.def("getRawNumFramesPool", &MonoCamera::getRawNumFramesPool, DOC(dai, node, MonoCamera, getRawNumFramesPool))

;
// ALIAS
daiNodeModule.attr("MonoCamera").attr("Properties") = monoCameraProperties;
Expand Down
2 changes: 1 addition & 1 deletion src/pipeline/node/ScriptBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void bind_script(pybind11::module& m, void* pCallstack){
.def("setScriptPath", &Script::setScriptPath, DOC(dai, node, Script, setScriptPath))
.def("setScript", py::overload_cast<const std::string&, const std::string&>(&Script::setScript), py::arg("script"), py::arg("name") = "", DOC(dai, node, Script, setScript))
.def("setScript", py::overload_cast<const std::vector<std::uint8_t>&, const std::string&>(&Script::setScript), py::arg("data"), py::arg("name") = "", DOC(dai, node, Script, setScript, 2))
.def("getScriptPath", &Script::getScriptPath, DOC(dai, node, Script, getScriptPath))
.def("setScriptPath", &Script::setScriptPath, py::arg("path"), py::arg("name") = "", DOC(dai, node, Script, setScriptPath))
.def("getScriptName", &Script::getScriptName, DOC(dai, node, Script, getScriptName))
.def("setProcessor", &Script::setProcessor, DOC(dai, node, Script, setProcessor))
.def("getProcessor", &Script::getProcessor, DOC(dai, node, Script, getProcessor))
Expand Down

0 comments on commit 2509395

Please sign in to comment.