Skip to content

Commit 841cfaf

Browse files
Merge pull request #302 from luxonis/develop
Release 2.6.0.0
2 parents 7950bdc + 0c927d5 commit 841cfaf

24 files changed

+420
-117
lines changed

depthai-core

Submodule depthai-core updated 45 files

docs/source/components/nodes/stereo_depth.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ as:
6262
(this confidence score is kind-of inverted, if say comparing with NN)
6363

6464
For the final disparity map, a filtering is applied based on the confidence threshold value: the pixels that have their confidence score larger than
65-
the threshold get invalidated, i.e. their disparity value is set to zero. You can set the confidence threshold with :code:`stereo.setConfidenceThreshold()`.
65+
the threshold get invalidated, i.e. their disparity value is set to zero. You can set the confidence threshold with :code:`stereo.initialConfig.setConfidenceThreshold()`.
6666

6767
Current limitations
6868
###################
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/hello_world.rst

Lines changed: 30 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,10 @@ Let's verify we're able to load all of our dependencies. Open the :code:`hello_w
7070

7171
.. code-block:: python
7272
73-
import numpy as np # numpy - manipulate the packet data returned by depthai
74-
import cv2 # opencv - display the video stream
75-
import depthai # access the camera and its data packets
73+
import numpy as np # numpy - manipulate the packet data returned by depthai
74+
import cv2 # opencv - display the video stream
75+
import depthai # depthai - access the camera and its data packets
76+
import blobconverter # blobconverter - compile and download MyriadX neural network blobs
7677
7778
Try running the script and ensure it executes without error:
7879

@@ -111,13 +112,16 @@ Now, first node we will add is a :class:`ColorCamera`. We will use the :code:`pr
111112
cam_rgb.setPreviewSize(300, 300)
112113
cam_rgb.setInterleaved(False)
113114
114-
Up next, let's define a :class:`NeuralNetwork` node with `mobilenet-ssd network <https://docs.openvinotoolkit.org/latest/omz_models_public_mobilenet_ssd_moblenet_ssd.html>`__.
115-
The blob file for this example can be found `here <https://github.com/luxonis/depthai-tutorials/raw/e37989e07a36a57ffef624b7aa8cf20ab493fa07/1-hello-world/mobilenet-ssd/mobilenet-ssd.blob>`__
115+
Up next, let's define a :class:`MobileNetDetectionNetwork` node with `mobilenet-ssd network <https://docs.openvinotoolkit.org/latest/omz_models_public_mobilenet_ssd_moblenet_ssd.html>`__.
116+
The blob file for this example will be compiled automatically using `blobconverter tool <https://pypi.org/project/blobconverter/>`__, we'll be provided with a ready-to-use blob path.
117+
With this node, the output from nn will be parsed on device side and we'll receive a ready to use detection objects. For this to work properly, we need also to set the confidence threshold
118+
to filter out the incorrect results
116119

117120
.. code-block:: python
118121
119-
detection_nn = pipeline.createNeuralNetwork()
120-
detection_nn.setBlobPath("/path/to/mobilenet-ssd.blob")
122+
detection_nn = pipeline.createMobileNetDetectionNetwork()
123+
detection_nn.setBlobPath(str(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6)))
124+
detection_nn.setConfidenceThreshold(0.5)
121125
122126
And now, let's connect a color camera :code:`preview` output to neural network input
123127

@@ -143,12 +147,11 @@ and in our case, since we want to receive data from device to host, we will use
143147
Initialize the DepthAI Device
144148
#############################
145149

146-
Having the pipeline defined, we can now initialize a device and start it
150+
Having the pipeline defined, we can now initialize a device with pipeline and start it
147151

148152
.. code-block:: python
149153
150-
device = depthai.Device(pipeline)
151-
device.startPipeline()
154+
with depthai.Device(pipeline) as device:
152155
153156
.. note::
154157

@@ -158,7 +161,7 @@ Having the pipeline defined, we can now initialize a device and start it
158161

159162
.. code-block:: python
160163
161-
device = depthai.Device(pipeline, True)
164+
device = depthai.Device(pipeline, usb2mode=True)
162165
163166
164167
@@ -181,19 +184,22 @@ for rgb frame and one for nn results
181184
.. code-block:: python
182185
183186
frame = None
184-
bboxes = []
187+
detections = []
185188
186189
Also, due to neural network implementation details, bounding box coordinates in inference results are represented
187190
as floats from <0..1> range - so relative to frame width/height (e.g. if image has 200px width and nn returned x_min
188191
coordinate equal to 0.2, this means the actual (normalised) x_min coordinate is 40px).
189192

190-
That's why we need to define a helper function, :code:`frame_form`, that will convert these <0..1> values into actual
193+
That's why we need to define a helper function, :code:`frameNorm`, that will convert these <0..1> values into actual
191194
pixel positions
192195

193196
.. code-block:: python
194197
195-
def frame_norm(frame, bbox):
196-
return (np.array(bbox) * np.array([*frame.shape[:2], *frame.shape[:2]])[::-1]).astype(int)
198+
def frameNorm(frame, bbox):
199+
normVals = np.full(len(bbox), frame.shape[0])
200+
normVals[::2] = frame.shape[1]
201+
return (np.clip(np.array(bbox), 0, 1) * normVals).astype(int)
202+
197203
198204
Consuming the results
199205
#####################
@@ -215,65 +221,22 @@ Now, inside this loop, first thing to do is fetching latest results from both nn
215221
The :code:`tryGet` method returns either the latest result or :code:`None` if the queue is empty.
216222

217223
Results, both from rgb camera or neural network, will be delivered as 1D arrays, so both of them will require transformations
218-
to be useful for display (we have already defined one of the transformations needed - the :code:`frame_norm` function)
224+
to be useful for display (we have already defined one of the transformations needed - the :code:`frameNorm` function)
219225

220-
First up, if we receive a frame from rgb camera, we need to convert it from 1D array into HWC form (HWC stands for
221-
Height Width Channels, so 3D array, with first dimension being width, second height, and third the color channel)
226+
First up, if we receive a frame from rgb camera using the :code:`getCvFrame` command
222227

223228
.. code-block:: python
224229
225230
if in_rgb is not None:
226-
shape = (3, in_rgb.getHeight(), in_rgb.getWidth())
227-
frame = in_rgb.getData().reshape(shape).transpose(1, 2, 0).astype(np.uint8)
228-
frame = np.ascontiguousarray(frame)
231+
frame = in_rgb.getCvFrame()
229232
230-
Second, the neural network results will also need transformations. These are also returned as a 1D array, but this time
231-
the array has a fixed size (constant, no matter how many results the neural network has actually produced).
232-
Actual results in array are followed with :code:`-1` and then filled to meet the fixed size with :code:`0`.
233-
One results has 7 fields, each being respectively :code:`image_id, label, confidence, x_min, y_min, x_max, y_max`.
234-
We will want only the last four values (being the bounding box), but we'll also filter out the ones which :code:`confidence`
235-
is below a certain threshold - it can be anywhere between <0..1>, and for this example we will use :code:`0.8` threshold
233+
Second, we will receive the neural network results. Default MobileNetSSD result has 7 fields, each being respectively :code:`image_id, label, confidence, x_min, y_min, x_max, y_max`,
234+
and by accessing the :code:`detections` array, we receive the detection objects that allow us to access these fields
236235

237236
.. code-block:: python
238237
239238
if in_nn is not None:
240-
bboxes = np.array(in_nn.getFirstLayerFp16())
241-
bboxes = bboxes[:np.where(bboxes == -1)[0][0]]
242-
bboxes = bboxes.reshape((bboxes.size // 7, 7))
243-
bboxes = bboxes[bboxes[:, 2] > 0.8][:, 3:7]
244-
245-
To better understand this flow, let's take an example. Let's assume the :code:`np.array(in_nn.getFirstLayerFp16())` returns the following array
246-
247-
.. code-block:: python
248-
249-
[0, 15, 0.99023438, 0.45556641, 0.34399414 0.88037109, 0.9921875, 0, 15, 0.98828125, 0.03076172, 0.23388672, 0.60205078, 1.0078125, -1, 0, 0, 0, ...]
250-
251-
First operation, :code:`bboxes[:np.where(bboxes == -1)[0][0]]`, removes the trailing zeros from the array, so now the bbox array will look like this
252-
253-
.. code-block:: python
254-
255-
[0, 15, 0.99023438, 0.45556641, 0.34399414 0.88037109, 0.9921875, 0, 15, 0.98828125, 0.03076172, 0.23388672, 0.60205078, 1.0078125]
256-
257-
Second one - :code:`bboxes.reshape((bboxes.size // 7, 7))`, reshapes the 1D array into 2D array - where each row is a separate result
258-
259-
.. code-block:: python
260-
261-
[
262-
[0, 15, 0.99023438, 0.45556641, 0.34399414 0.88037109, 0.9921875],
263-
[0, 15, 0.98828125, 0.03076172, 0.23388672, 0.60205078, 1.0078125]
264-
]
265-
266-
Last one - :code:`bboxes = bboxes[bboxes[:, 2] > 0.8][:, 3:7]` - will filter the results based on the confidence column (3rd one, with index :code:`2`)
267-
to be above a defined threshold (:code:`0.8`) - and from these results, it will only take the last 4 columns being the bounding boxes.
268-
Since both our results have a very high confidence (:code:`0.99023438` and :code:`0.98828125` respectively), they won't be filtered, and the final
269-
array will look like this
270-
271-
.. code-block:: python
272-
273-
[
274-
[0.45556641, 0.34399414 0.88037109, 0.9921875],
275-
[0.03076172, 0.23388672, 0.60205078, 1.0078125]
276-
]
239+
detections = in_nn.detections
277240
278241
Display the results
279242
###################
@@ -283,12 +246,12 @@ Up to this point, we have all our results consumed from the DepthaI device, and
283246
.. code-block:: python
284247
285248
if frame is not None:
286-
for raw_bbox in bboxes:
287-
bbox = frame_norm(frame, raw_bbox)
249+
for detection in detections:
250+
bbox = frameNorm(frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax))
288251
cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (255, 0, 0), 2)
289252
cv2.imshow("preview", frame)
290253
291-
You can see here the usage of :code:`frame_norm` we defined earlier for bounding box coordinates normalization.
254+
You can see here the usage of :code:`frameNorm` we defined earlier for bounding box coordinates normalization.
292255
By using :code:`cv2.rectangle` we draw a rectangle on the rgb frame as an indicator where the face position is, and then
293256
we display the frame using :code:`cv2.imshow`
294257

docs/source/tutorials/local_convert_openvino.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,8 @@ In particular, let's change the :code:`setBlobPath` invocation to load our model
275275

276276
.. code-block:: diff
277277
278-
- detection_nn.setBlobPath("/path/to/mobilenet-ssd.blob")
279-
- detection_nn.setBlobPath("/path/to/face-detection-retail-0004.blob")
278+
- detection_nn.setBlobPath(str(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6)))
279+
+ detection_nn.setBlobPath("/path/to/face-detection-retail-0004.blob")
280280
281281
And that's all!
282282

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 & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,5 @@ 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)
126126
add_python_example(imu_rotation_vector imu_rotation_vector.py)
127-
add_python_example(calibration_flash_v5 calibration_flash_v5.py)
128-
add_python_example(calibration_flash calibration_flash.py)
129-
add_python_example(calibration_load calibration_load.py)
130-
add_python_example(calibration_reader calibration_reader.py)
127+
add_python_example(rgb_depth_aligned rgb_depth_aligned.py)
128+
add_python_example(edge_detector edge_detector.py)

examples/depth_crop_control.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
manip.initialConfig.setCropRect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y)
4141
manip.setMaxOutputFrameSize(monoRight.getResolutionHeight()*monoRight.getResolutionWidth()*3)
42-
stereo.setConfidenceThreshold(200)
42+
stereo.initialConfig.setConfidenceThreshold(200)
4343

4444
# Linking
4545
configIn.out.link(manip.inputConfig)

examples/depth_preview.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
3030

3131
# Create a node that will produce the depth map (using disparity output as it's easier to visualize depth this way)
32-
depth.setConfidenceThreshold(200)
32+
depth.initialConfig.setConfidenceThreshold(200)
3333
# Options: MEDIAN_OFF, KERNEL_3x3, KERNEL_5x5, KERNEL_7x7 (default)
34-
depth.setMedianFilter(dai.StereoDepthProperties.MedianFilter.KERNEL_7x7)
34+
depth.initialConfig.setMedianFilter(dai.MedianFilter.KERNEL_7x7)
3535
depth.setLeftRightCheck(lr_check)
3636
depth.setExtendedDisparity(extended_disparity)
3737
depth.setSubpixel(subpixel)

0 commit comments

Comments
 (0)