Skip to content

Commit e34719d

Browse files
Merge pull request #297 from luxonis/edge_detector
Add EdgeDetector node
2 parents 2bf6934 + 1ba72b8 commit e34719d

File tree

9 files changed

+195
-7
lines changed

9 files changed

+195
-7
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Edge detector
2+
=============
3+
4+
This example performs edge detection on 3 different inputs: left, right and RGB camera.
5+
HW accelerated sobel filter 3x3 is used.
6+
Sobel filter parameters can be changed by keys 1 and 2.
7+
8+
Demo
9+
####
10+
11+
12+
Setup
13+
#####
14+
15+
.. include:: /includes/install_from_pypi.rst
16+
17+
Source code
18+
###########
19+
20+
.. tabs::
21+
22+
.. tab:: Python
23+
24+
Also `available on GitHub <https://github.com/luxonis/depthai-python/blob/main/examples/edge_detector.py>`__
25+
26+
.. literalinclude:: ../../../examples/edge_detector.py
27+
:language: python
28+
:linenos:
29+
30+
.. tab:: C++
31+
32+
Also `available on GitHub <https://github.com/luxonis/depthai-core/blob/main/examples/src/edge_detector.cpp>`__
33+
34+
.. literalinclude:: ../../../depthai-core/examples/src/edge_detector.cpp
35+
:language: cpp
36+
:linenos:
37+
38+
.. include:: /includes/footer-short.rst

docs/source/tutorials/code_samples.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Code samples are used for automated testing. They are also a great starting poin
2929
- :ref:`Video & MobilenetSSD` - Runs MobileNetSSD on the video from the host
3030
- :ref:`IMU Accelerometer & Gyroscope` - Accelerometer and gyroscope at 500hz rate
3131
- :ref:`IMU Rotation Vector` - Rotation vector at 400 hz rate
32+
- :ref:`Edge detector` - Edge detection on input frame
3233

3334
.. rubric:: Complex
3435

docs/source/tutorials/simple_samples.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Simple
2121
../samples/video_mobilenet.rst
2222
../samples/imu_accelerometer_gyroscope.rst
2323
../samples/imu_rotation_vector.rst
24-
24+
../samples/edge_detector.rst
2525

2626
These samples are great starting point for the gen2 API.
2727

@@ -38,3 +38,4 @@ These samples are great starting point for the gen2 API.
3838
- :ref:`RGB & MobileNetSSD @ 4K` - Runs MobileNetSSD on RGB frames and displays detections on both preview and 4k frames
3939
- :ref:`Mono & MobilenetSSD` - Runs MobileNetSSD on mono frames and displays detections on the frame
4040
- :ref:`Video & MobilenetSSD` - Runs MobileNetSSD on the video from the host
41+
- :ref:`Edge detector` - Edge detection on input frame

examples/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,5 @@ add_python_example(object_tracker_video object_tracker_video.py)
123123
add_python_example(stereo_depth_from_host stereo_depth_from_host.py)
124124
add_python_example(stereo_depth_video stereo_depth_video.py)
125125
add_python_example(imu_gyroscope_accelerometer imu_gyroscope_accelerometer.py)
126-
add_python_example(imu_rotation_vector imu_rotation_vector.py)
126+
add_python_example(imu_rotation_vector imu_rotation_vector.py)
127+
add_python_example(edge_detector edge_detector.py)

examples/edge_detector.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/env python3
2+
3+
import cv2
4+
import depthai as dai
5+
import numpy as np
6+
7+
# Create pipeline
8+
pipeline = dai.Pipeline()
9+
10+
# Define sources and outputs
11+
camRgb = pipeline.createColorCamera()
12+
monoLeft = pipeline.createMonoCamera()
13+
monoRight = pipeline.createMonoCamera()
14+
15+
edgeDetectorLeft = pipeline.createEdgeDetector()
16+
edgeDetectorRight = pipeline.createEdgeDetector()
17+
edgeDetectorRgb = pipeline.createEdgeDetector()
18+
19+
xoutEdgeLeft = pipeline.createXLinkOut()
20+
xoutEdgeRight = pipeline.createXLinkOut()
21+
xoutEdgeRgb = pipeline.createXLinkOut()
22+
xinEdgeCfg = pipeline.createXLinkIn()
23+
24+
edgeLeftStr = "edge left"
25+
edgeRightStr = "edge right"
26+
edgeRgbStr = "edge rgb"
27+
edgeCfgStr = "edge cfg"
28+
29+
xoutEdgeLeft.setStreamName(edgeLeftStr)
30+
xoutEdgeRight.setStreamName(edgeRightStr)
31+
xoutEdgeRgb.setStreamName(edgeRgbStr)
32+
xinEdgeCfg.setStreamName(edgeCfgStr)
33+
34+
# Properties
35+
camRgb.setBoardSocket(dai.CameraBoardSocket.RGB)
36+
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
37+
38+
monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
39+
monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
40+
monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
41+
monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
42+
43+
edgeDetectorRgb.setMaxOutputFrameSize(camRgb.getVideoWidth() * camRgb.getVideoHeight())
44+
45+
# Linking
46+
monoLeft.out.link(edgeDetectorLeft.inputImage)
47+
monoRight.out.link(edgeDetectorRight.inputImage)
48+
camRgb.video.link(edgeDetectorRgb.inputImage)
49+
50+
edgeDetectorLeft.outputImage.link(xoutEdgeLeft.input)
51+
edgeDetectorRight.outputImage.link(xoutEdgeRight.input)
52+
edgeDetectorRgb.outputImage.link(xoutEdgeRgb.input)
53+
54+
xinEdgeCfg.out.link(edgeDetectorLeft.inputConfig)
55+
xinEdgeCfg.out.link(edgeDetectorRight.inputConfig)
56+
xinEdgeCfg.out.link(edgeDetectorRgb.inputConfig)
57+
58+
# Connect to device and start pipeline
59+
with dai.Device(pipeline) as device:
60+
61+
# Output/input queues
62+
edgeLeftQueue = device.getOutputQueue(edgeLeftStr, 8, False)
63+
edgeRightQueue = device.getOutputQueue(edgeRightStr, 8, False)
64+
edgeRgbQueue = device.getOutputQueue(edgeRgbStr, 8, False)
65+
edgeCfgQueue = device.getInputQueue(edgeCfgStr)
66+
67+
print("Switch between sobel filter kernels using keys '1' and '2'")
68+
69+
while(True):
70+
edgeLeft = edgeLeftQueue.get()
71+
edgeRight = edgeRightQueue.get()
72+
edgeRgb = edgeRgbQueue.get()
73+
74+
edgeLeftFrame = edgeLeft.getFrame()
75+
edgeRightFrame = edgeRight.getFrame()
76+
edgeRgbFrame = edgeRgb.getFrame()
77+
78+
# Show the frame
79+
cv2.imshow(edgeLeftStr, edgeLeftFrame)
80+
cv2.imshow(edgeRightStr, edgeRightFrame)
81+
cv2.imshow(edgeRgbStr, edgeRgbFrame)
82+
83+
key = cv2.waitKey(1)
84+
if key == ord('q'):
85+
break
86+
87+
if key == ord('1'):
88+
print("Switching sobel filter kernel.")
89+
cfg = dai.EdgeDetectorConfig()
90+
sobelHorizontalKernel = [[1, 0, -1], [2, 0, -2], [1, 0, -1]]
91+
sobelVerticalKernel = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]
92+
cfg.setSobelFilterKernels(sobelHorizontalKernel, sobelVerticalKernel)
93+
edgeCfgQueue.send(cfg)
94+
95+
if key == ord('2'):
96+
print("Switching sobel filter kernel.")
97+
cfg = dai.EdgeDetectorConfig()
98+
sobelHorizontalKernel = [[3, 0, -3], [10, 0, -10], [3, 0, -3]]
99+
sobelVerticalKernel = [[3, 10, 3], [0, 0, 0], [-3, -10, -3]]
100+
cfg.setSobelFilterKernels(sobelHorizontalKernel, sobelVerticalKernel)
101+
edgeCfgQueue.send(cfg)
102+

src/DatatypeBindings.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "depthai/pipeline/datatype/Tracklets.hpp"
2020
#include "depthai/pipeline/datatype/IMUData.hpp"
2121
#include "depthai/pipeline/datatype/StereoDepthConfig.hpp"
22+
#include "depthai/pipeline/datatype/EdgeDetectorConfig.hpp"
2223

2324
// depthai-shared
2425
#include "depthai-shared/datatype/RawBuffer.hpp"
@@ -34,6 +35,7 @@
3435
#include "depthai-shared/datatype/RawTracklets.hpp"
3536
#include "depthai-shared/datatype/RawIMUData.hpp"
3637
#include "depthai-shared/datatype/RawStereoDepthConfig.hpp"
38+
#include "depthai-shared/datatype/RawEdgeDetectorConfig.hpp"
3739

3840

3941
//pybind
@@ -915,9 +917,6 @@ void DatatypeBindings::bind(pybind11::module& m){
915917
.def_property("packets", [](IMUData& imuDta) { return &imuDta.packets; }, [](IMUData& imuDta, std::vector<IMUPacket> val) { imuDta.packets = val; }, DOC(dai, IMUData, packets))
916918
;
917919

918-
919-
920-
921920
// Bind RawStereoDepthConfig
922921
py::class_<RawStereoDepthConfig, RawBuffer, std::shared_ptr<RawStereoDepthConfig>> rawStereoDepthConfig(m, "RawStereoDepthConfig", DOC(dai, RawStereoDepthConfig));
923922
rawStereoDepthConfig
@@ -938,4 +937,25 @@ void DatatypeBindings::bind(pybind11::module& m){
938937
.def("getLeftRightCheckThreshold", &StereoDepthConfig::getLeftRightCheckThreshold, DOC(dai, StereoDepthConfig, getLeftRightCheckThreshold))
939938
;
940939

941-
}
940+
941+
py::class_<EdgeDetectorConfigData> (m, "EdgeDetectorConfigData", DOC(dai, EdgeDetectorConfigData))
942+
.def(py::init<>())
943+
.def_readwrite("sobelFilterHorizontalKernel", &EdgeDetectorConfigData::sobelFilterHorizontalKernel, DOC(dai, EdgeDetectorConfigData, sobelFilterHorizontalKernel))
944+
.def_readwrite("sobelFilterVerticalKernel", &EdgeDetectorConfigData::sobelFilterVerticalKernel, DOC(dai, EdgeDetectorConfigData, sobelFilterVerticalKernel))
945+
;
946+
947+
// Bind RawEdgeDetectorConfig
948+
py::class_<RawEdgeDetectorConfig, RawBuffer, std::shared_ptr<RawEdgeDetectorConfig>> rawEdgeDetectorConfig(m, "RawEdgeDetectorConfig", DOC(dai, RawEdgeDetectorConfig));
949+
rawEdgeDetectorConfig
950+
.def(py::init<>())
951+
.def_readwrite("config", &RawEdgeDetectorConfig::config)
952+
;
953+
954+
// EdgeDetectorConfig (after ConfigData)
955+
py::class_<EdgeDetectorConfig, Buffer, std::shared_ptr<EdgeDetectorConfig>>(m, "EdgeDetectorConfig", DOC(dai, EdgeDetectorConfig))
956+
.def(py::init<>())
957+
.def("setSobelFilterKernels", &EdgeDetectorConfig::setSobelFilterKernels, py::arg("horizontalKernel"), py::arg("verticalKernel"), DOC(dai, EdgeDetectorConfig, setSobelFilterKernels))
958+
.def("getConfigData", &EdgeDetectorConfig::getConfigData, DOC(dai, EdgeDetectorConfig, getConfigData))
959+
;
960+
961+
}

src/pipeline/NodeBindings.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "depthai/pipeline/node/SpatialDetectionNetwork.hpp"
1717
#include "depthai/pipeline/node/ObjectTracker.hpp"
1818
#include "depthai/pipeline/node/IMU.hpp"
19+
#include "depthai/pipeline/node/EdgeDetector.hpp"
1920

2021
// Libraries
2122
#include "hedley/hedley.h"
@@ -504,6 +505,17 @@ void NodeBindings::bind(pybind11::module& m){
504505
.def("getMaxBatchReports", &IMU::getMaxBatchReports, DOC(dai, node, IMU, getMaxBatchReports))
505506
;
506507

508+
// EdgeDetector node
509+
py::class_<EdgeDetector, Node, std::shared_ptr<EdgeDetector>>(m, "EdgeDetector", DOC(dai, node, EdgeDetector))
510+
.def_readonly("initialConfig", &EdgeDetector::initialConfig, DOC(dai, node, EdgeDetector, initialConfig))
511+
.def_readonly("inputConfig", &EdgeDetector::inputConfig, DOC(dai, node, EdgeDetector, inputConfig))
512+
.def_readonly("inputImage", &EdgeDetector::inputImage, DOC(dai, node, EdgeDetector, inputImage))
513+
.def_readonly("outputImage", &EdgeDetector::outputImage, DOC(dai, node, EdgeDetector, outputImage))
514+
.def("setWaitForConfigInput", &EdgeDetector::setWaitForConfigInput, DOC(dai, node, EdgeDetector, setWaitForConfigInput))
515+
.def("setNumFramesPool", &EdgeDetector::setNumFramesPool, DOC(dai, node, EdgeDetector, setNumFramesPool))
516+
.def("setMaxOutputFrameSize", &EdgeDetector::setMaxOutputFrameSize, DOC(dai, node, EdgeDetector, setMaxOutputFrameSize))
517+
;
518+
507519
////////////////////////////////////
508520
// Node properties bindings
509521
////////////////////////////////////
@@ -747,5 +759,16 @@ void NodeBindings::bind(pybind11::module& m){
747759
m.attr("IMU").attr("Properties") = imuProperties;
748760

749761

762+
py::class_<EdgeDetectorProperties> edgeDetectorProperties(m, "EdgeDetectorProperties", DOC(dai, EdgeDetectorProperties));
763+
edgeDetectorProperties
764+
.def_readwrite("initialConfig", &EdgeDetectorProperties::initialConfig, DOC(dai, EdgeDetectorProperties, initialConfig))
765+
.def_readwrite("inputConfigSync", &EdgeDetectorProperties::inputConfigSync, DOC(dai, EdgeDetectorProperties, inputConfigSync))
766+
.def_readwrite("outputFrameSize", &EdgeDetectorProperties::outputFrameSize, DOC(dai, EdgeDetectorProperties, outputFrameSize))
767+
.def_readwrite("numFramesPool", &EdgeDetectorProperties::numFramesPool, DOC(dai, EdgeDetectorProperties, numFramesPool))
768+
769+
;
770+
m.attr("EdgeDetector").attr("Properties") = edgeDetectorProperties;
771+
772+
750773

751774
}

src/pipeline/PipelineBindings.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "depthai/pipeline/node/SpatialDetectionNetwork.hpp"
2020
#include "depthai/pipeline/node/ObjectTracker.hpp"
2121
#include "depthai/pipeline/node/IMU.hpp"
22+
#include "depthai/pipeline/node/EdgeDetector.hpp"
2223

2324
// depthai-shared
2425
#include "depthai-shared/properties/GlobalProperties.hpp"
@@ -80,6 +81,7 @@ void PipelineBindings::bind(pybind11::module& m){
8081
.def("createYoloSpatialDetectionNetwork", &Pipeline::create<node::YoloSpatialDetectionNetwork>)
8182
.def("createObjectTracker", &Pipeline::create<node::ObjectTracker>)
8283
.def("createIMU", &Pipeline::create<node::IMU>)
84+
.def("createEdgeDetector", &Pipeline::create<node::EdgeDetector>)
8385
;
8486

8587

0 commit comments

Comments
 (0)