diff --git a/depthai-core b/depthai-core index 7cd031a48..63ac4f1ae 160000 --- a/depthai-core +++ b/depthai-core @@ -1 +1 @@ -Subproject commit 7cd031a487f8c96264e2746638ca4d3d69f4747f +Subproject commit 63ac4f1ae98eae3e77ce7ded0c6a3d6bc7f9fea2 diff --git a/docs/source/components/nodes/stereo_depth.rst b/docs/source/components/nodes/stereo_depth.rst index c6d6d4fdf..98f142659 100644 --- a/docs/source/components/nodes/stereo_depth.rst +++ b/docs/source/components/nodes/stereo_depth.rst @@ -62,7 +62,7 @@ as: (this confidence score is kind-of inverted, if say comparing with NN) For the final disparity map, a filtering is applied based on the confidence threshold value: the pixels that have their confidence score larger than -the threshold get invalidated, i.e. their disparity value is set to zero. You can set the confidence threshold with :code:`stereo.setConfidenceThreshold()`. +the threshold get invalidated, i.e. their disparity value is set to zero. You can set the confidence threshold with :code:`stereo.initialConfig.setConfidenceThreshold()`. Current limitations ################### diff --git a/docs/source/samples/edge_detector.rst b/docs/source/samples/edge_detector.rst new file mode 100644 index 000000000..8ba8f24d5 --- /dev/null +++ b/docs/source/samples/edge_detector.rst @@ -0,0 +1,38 @@ +Edge detector +============= + +This example performs edge detection on 3 different inputs: left, right and RGB camera. +HW accelerated sobel filter 3x3 is used. +Sobel filter parameters can be changed by keys 1 and 2. + +Demo +#### + + +Setup +##### + +.. include:: /includes/install_from_pypi.rst + +Source code +########### + +.. tabs:: + + .. tab:: Python + + Also `available on GitHub `__ + + .. literalinclude:: ../../../examples/edge_detector.py + :language: python + :linenos: + + .. tab:: C++ + + Also `available on GitHub `__ + + .. literalinclude:: ../../../depthai-core/examples/src/edge_detector.cpp + :language: cpp + :linenos: + +.. include:: /includes/footer-short.rst diff --git a/docs/source/tutorials/code_samples.rst b/docs/source/tutorials/code_samples.rst index 68cae2c2f..8cb2bcd17 100644 --- a/docs/source/tutorials/code_samples.rst +++ b/docs/source/tutorials/code_samples.rst @@ -29,6 +29,7 @@ Code samples are used for automated testing. They are also a great starting poin - :ref:`Video & MobilenetSSD` - Runs MobileNetSSD on the video from the host - :ref:`IMU Accelerometer & Gyroscope` - Accelerometer and gyroscope at 500hz rate - :ref:`IMU Rotation Vector` - Rotation vector at 400 hz rate +- :ref:`Edge detector` - Edge detection on input frame .. rubric:: Complex diff --git a/docs/source/tutorials/hello_world.rst b/docs/source/tutorials/hello_world.rst index 119d702a6..ca3a92b72 100644 --- a/docs/source/tutorials/hello_world.rst +++ b/docs/source/tutorials/hello_world.rst @@ -70,9 +70,10 @@ Let's verify we're able to load all of our dependencies. Open the :code:`hello_w .. code-block:: python - import numpy as np # numpy - manipulate the packet data returned by depthai - import cv2 # opencv - display the video stream - import depthai # access the camera and its data packets + import numpy as np # numpy - manipulate the packet data returned by depthai + import cv2 # opencv - display the video stream + import depthai # depthai - access the camera and its data packets + import blobconverter # blobconverter - compile and download MyriadX neural network blobs Try running the script and ensure it executes without error: @@ -111,13 +112,16 @@ Now, first node we will add is a :class:`ColorCamera`. We will use the :code:`pr cam_rgb.setPreviewSize(300, 300) cam_rgb.setInterleaved(False) -Up next, let's define a :class:`NeuralNetwork` node with `mobilenet-ssd network `__. -The blob file for this example can be found `here `__ +Up next, let's define a :class:`MobileNetDetectionNetwork` node with `mobilenet-ssd network `__. +The blob file for this example will be compiled automatically using `blobconverter tool `__, we'll be provided with a ready-to-use blob path. +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 +to filter out the incorrect results .. code-block:: python - detection_nn = pipeline.createNeuralNetwork() - detection_nn.setBlobPath("/path/to/mobilenet-ssd.blob") + detection_nn = pipeline.createMobileNetDetectionNetwork() + detection_nn.setBlobPath(str(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6))) + detection_nn.setConfidenceThreshold(0.5) And now, let's connect a color camera :code:`preview` output to neural network input @@ -143,12 +147,11 @@ and in our case, since we want to receive data from device to host, we will use Initialize the DepthAI Device ############################# -Having the pipeline defined, we can now initialize a device and start it +Having the pipeline defined, we can now initialize a device with pipeline and start it .. code-block:: python - device = depthai.Device(pipeline) - device.startPipeline() + with depthai.Device(pipeline) as device: .. note:: @@ -158,7 +161,7 @@ Having the pipeline defined, we can now initialize a device and start it .. code-block:: python - device = depthai.Device(pipeline, True) + device = depthai.Device(pipeline, usb2mode=True) @@ -181,19 +184,22 @@ for rgb frame and one for nn results .. code-block:: python frame = None - bboxes = [] + detections = [] Also, due to neural network implementation details, bounding box coordinates in inference results are represented as floats from <0..1> range - so relative to frame width/height (e.g. if image has 200px width and nn returned x_min coordinate equal to 0.2, this means the actual (normalised) x_min coordinate is 40px). -That's why we need to define a helper function, :code:`frame_form`, that will convert these <0..1> values into actual +That's why we need to define a helper function, :code:`frameNorm`, that will convert these <0..1> values into actual pixel positions .. code-block:: python - def frame_norm(frame, bbox): - return (np.array(bbox) * np.array([*frame.shape[:2], *frame.shape[:2]])[::-1]).astype(int) + def frameNorm(frame, bbox): + normVals = np.full(len(bbox), frame.shape[0]) + normVals[::2] = frame.shape[1] + return (np.clip(np.array(bbox), 0, 1) * normVals).astype(int) + Consuming the results ##################### @@ -215,65 +221,22 @@ Now, inside this loop, first thing to do is fetching latest results from both nn The :code:`tryGet` method returns either the latest result or :code:`None` if the queue is empty. Results, both from rgb camera or neural network, will be delivered as 1D arrays, so both of them will require transformations -to be useful for display (we have already defined one of the transformations needed - the :code:`frame_norm` function) +to be useful for display (we have already defined one of the transformations needed - the :code:`frameNorm` function) -First up, if we receive a frame from rgb camera, we need to convert it from 1D array into HWC form (HWC stands for -Height Width Channels, so 3D array, with first dimension being width, second height, and third the color channel) +First up, if we receive a frame from rgb camera using the :code:`getCvFrame` command .. code-block:: python if in_rgb is not None: - shape = (3, in_rgb.getHeight(), in_rgb.getWidth()) - frame = in_rgb.getData().reshape(shape).transpose(1, 2, 0).astype(np.uint8) - frame = np.ascontiguousarray(frame) + frame = in_rgb.getCvFrame() -Second, the neural network results will also need transformations. These are also returned as a 1D array, but this time -the array has a fixed size (constant, no matter how many results the neural network has actually produced). -Actual results in array are followed with :code:`-1` and then filled to meet the fixed size with :code:`0`. -One results has 7 fields, each being respectively :code:`image_id, label, confidence, x_min, y_min, x_max, y_max`. -We will want only the last four values (being the bounding box), but we'll also filter out the ones which :code:`confidence` -is below a certain threshold - it can be anywhere between <0..1>, and for this example we will use :code:`0.8` threshold +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`, +and by accessing the :code:`detections` array, we receive the detection objects that allow us to access these fields .. code-block:: python if in_nn is not None: - bboxes = np.array(in_nn.getFirstLayerFp16()) - bboxes = bboxes[:np.where(bboxes == -1)[0][0]] - bboxes = bboxes.reshape((bboxes.size // 7, 7)) - bboxes = bboxes[bboxes[:, 2] > 0.8][:, 3:7] - -To better understand this flow, let's take an example. Let's assume the :code:`np.array(in_nn.getFirstLayerFp16())` returns the following array - -.. code-block:: python - - [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, ...] - -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 - -.. code-block:: python - - [0, 15, 0.99023438, 0.45556641, 0.34399414 0.88037109, 0.9921875, 0, 15, 0.98828125, 0.03076172, 0.23388672, 0.60205078, 1.0078125] - -Second one - :code:`bboxes.reshape((bboxes.size // 7, 7))`, reshapes the 1D array into 2D array - where each row is a separate result - -.. code-block:: python - - [ - [0, 15, 0.99023438, 0.45556641, 0.34399414 0.88037109, 0.9921875], - [0, 15, 0.98828125, 0.03076172, 0.23388672, 0.60205078, 1.0078125] - ] - -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`) -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. -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 -array will look like this - -.. code-block:: python - - [ - [0.45556641, 0.34399414 0.88037109, 0.9921875], - [0.03076172, 0.23388672, 0.60205078, 1.0078125] - ] + detections = in_nn.detections Display the results ################### @@ -283,12 +246,12 @@ Up to this point, we have all our results consumed from the DepthaI device, and .. code-block:: python if frame is not None: - for raw_bbox in bboxes: - bbox = frame_norm(frame, raw_bbox) + for detection in detections: + bbox = frameNorm(frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax)) cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (255, 0, 0), 2) cv2.imshow("preview", frame) -You can see here the usage of :code:`frame_norm` we defined earlier for bounding box coordinates normalization. +You can see here the usage of :code:`frameNorm` we defined earlier for bounding box coordinates normalization. By using :code:`cv2.rectangle` we draw a rectangle on the rgb frame as an indicator where the face position is, and then we display the frame using :code:`cv2.imshow` diff --git a/docs/source/tutorials/local_convert_openvino.rst b/docs/source/tutorials/local_convert_openvino.rst index 5a5e45c30..1372af8cb 100644 --- a/docs/source/tutorials/local_convert_openvino.rst +++ b/docs/source/tutorials/local_convert_openvino.rst @@ -275,8 +275,8 @@ In particular, let's change the :code:`setBlobPath` invocation to load our model .. code-block:: diff - - detection_nn.setBlobPath("/path/to/mobilenet-ssd.blob") - - detection_nn.setBlobPath("/path/to/face-detection-retail-0004.blob") + - detection_nn.setBlobPath(str(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6))) + + detection_nn.setBlobPath("/path/to/face-detection-retail-0004.blob") And that's all! diff --git a/docs/source/tutorials/simple_samples.rst b/docs/source/tutorials/simple_samples.rst index b573cb9b6..80c87b185 100644 --- a/docs/source/tutorials/simple_samples.rst +++ b/docs/source/tutorials/simple_samples.rst @@ -21,7 +21,7 @@ Simple ../samples/video_mobilenet.rst ../samples/imu_accelerometer_gyroscope.rst ../samples/imu_rotation_vector.rst - + ../samples/edge_detector.rst These samples are great starting point for the gen2 API. @@ -38,3 +38,4 @@ These samples are great starting point for the gen2 API. - :ref:`RGB & MobileNetSSD @ 4K` - Runs MobileNetSSD on RGB frames and displays detections on both preview and 4k frames - :ref:`Mono & MobilenetSSD` - Runs MobileNetSSD on mono frames and displays detections on the frame - :ref:`Video & MobilenetSSD` - Runs MobileNetSSD on the video from the host +- :ref:`Edge detector` - Edge detection on input frame diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 114f7aa4e..86f9e7659 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -124,7 +124,5 @@ add_python_example(stereo_depth_from_host stereo_depth_from_host.py) add_python_example(stereo_depth_video stereo_depth_video.py) add_python_example(imu_gyroscope_accelerometer imu_gyroscope_accelerometer.py) add_python_example(imu_rotation_vector imu_rotation_vector.py) -add_python_example(calibration_flash_v5 calibration_flash_v5.py) -add_python_example(calibration_flash calibration_flash.py) -add_python_example(calibration_load calibration_load.py) -add_python_example(calibration_reader calibration_reader.py) \ No newline at end of file +add_python_example(rgb_depth_aligned rgb_depth_aligned.py) +add_python_example(edge_detector edge_detector.py) diff --git a/examples/depth_crop_control.py b/examples/depth_crop_control.py index 694caa1db..a48805ab9 100755 --- a/examples/depth_crop_control.py +++ b/examples/depth_crop_control.py @@ -39,7 +39,7 @@ manip.initialConfig.setCropRect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y) manip.setMaxOutputFrameSize(monoRight.getResolutionHeight()*monoRight.getResolutionWidth()*3) -stereo.setConfidenceThreshold(200) +stereo.initialConfig.setConfidenceThreshold(200) # Linking configIn.out.link(manip.inputConfig) diff --git a/examples/depth_preview.py b/examples/depth_preview.py index 351937c15..1461e963f 100755 --- a/examples/depth_preview.py +++ b/examples/depth_preview.py @@ -29,9 +29,9 @@ monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT) # Create a node that will produce the depth map (using disparity output as it's easier to visualize depth this way) -depth.setConfidenceThreshold(200) +depth.initialConfig.setConfidenceThreshold(200) # Options: MEDIAN_OFF, KERNEL_3x3, KERNEL_5x5, KERNEL_7x7 (default) -depth.setMedianFilter(dai.StereoDepthProperties.MedianFilter.KERNEL_7x7) +depth.initialConfig.setMedianFilter(dai.MedianFilter.KERNEL_7x7) depth.setLeftRightCheck(lr_check) depth.setExtendedDisparity(extended_disparity) depth.setSubpixel(subpixel) diff --git a/examples/edge_detector.py b/examples/edge_detector.py new file mode 100755 index 000000000..d5103da02 --- /dev/null +++ b/examples/edge_detector.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +import cv2 +import depthai as dai +import numpy as np + +# Create pipeline +pipeline = dai.Pipeline() + +# Define sources and outputs +camRgb = pipeline.createColorCamera() +monoLeft = pipeline.createMonoCamera() +monoRight = pipeline.createMonoCamera() + +edgeDetectorLeft = pipeline.createEdgeDetector() +edgeDetectorRight = pipeline.createEdgeDetector() +edgeDetectorRgb = pipeline.createEdgeDetector() + +xoutEdgeLeft = pipeline.createXLinkOut() +xoutEdgeRight = pipeline.createXLinkOut() +xoutEdgeRgb = pipeline.createXLinkOut() +xinEdgeCfg = pipeline.createXLinkIn() + +edgeLeftStr = "edge left" +edgeRightStr = "edge right" +edgeRgbStr = "edge rgb" +edgeCfgStr = "edge cfg" + +xoutEdgeLeft.setStreamName(edgeLeftStr) +xoutEdgeRight.setStreamName(edgeRightStr) +xoutEdgeRgb.setStreamName(edgeRgbStr) +xinEdgeCfg.setStreamName(edgeCfgStr) + +# Properties +camRgb.setBoardSocket(dai.CameraBoardSocket.RGB) +camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P) + +monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P) +monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT) +monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P) +monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT) + +edgeDetectorRgb.setMaxOutputFrameSize(camRgb.getVideoWidth() * camRgb.getVideoHeight()) + +# Linking +monoLeft.out.link(edgeDetectorLeft.inputImage) +monoRight.out.link(edgeDetectorRight.inputImage) +camRgb.video.link(edgeDetectorRgb.inputImage) + +edgeDetectorLeft.outputImage.link(xoutEdgeLeft.input) +edgeDetectorRight.outputImage.link(xoutEdgeRight.input) +edgeDetectorRgb.outputImage.link(xoutEdgeRgb.input) + +xinEdgeCfg.out.link(edgeDetectorLeft.inputConfig) +xinEdgeCfg.out.link(edgeDetectorRight.inputConfig) +xinEdgeCfg.out.link(edgeDetectorRgb.inputConfig) + +# Connect to device and start pipeline +with dai.Device(pipeline) as device: + + # Output/input queues + edgeLeftQueue = device.getOutputQueue(edgeLeftStr, 8, False) + edgeRightQueue = device.getOutputQueue(edgeRightStr, 8, False) + edgeRgbQueue = device.getOutputQueue(edgeRgbStr, 8, False) + edgeCfgQueue = device.getInputQueue(edgeCfgStr) + + print("Switch between sobel filter kernels using keys '1' and '2'") + + while(True): + edgeLeft = edgeLeftQueue.get() + edgeRight = edgeRightQueue.get() + edgeRgb = edgeRgbQueue.get() + + edgeLeftFrame = edgeLeft.getFrame() + edgeRightFrame = edgeRight.getFrame() + edgeRgbFrame = edgeRgb.getFrame() + + # Show the frame + cv2.imshow(edgeLeftStr, edgeLeftFrame) + cv2.imshow(edgeRightStr, edgeRightFrame) + cv2.imshow(edgeRgbStr, edgeRgbFrame) + + key = cv2.waitKey(1) + if key == ord('q'): + break + + if key == ord('1'): + print("Switching sobel filter kernel.") + cfg = dai.EdgeDetectorConfig() + sobelHorizontalKernel = [[1, 0, -1], [2, 0, -2], [1, 0, -1]] + sobelVerticalKernel = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]] + cfg.setSobelFilterKernels(sobelHorizontalKernel, sobelVerticalKernel) + edgeCfgQueue.send(cfg) + + if key == ord('2'): + print("Switching sobel filter kernel.") + cfg = dai.EdgeDetectorConfig() + sobelHorizontalKernel = [[3, 0, -3], [10, 0, -10], [3, 0, -3]] + sobelVerticalKernel = [[3, 10, 3], [0, 0, 0], [-3, -10, -3]] + cfg.setSobelFilterKernels(sobelHorizontalKernel, sobelVerticalKernel) + edgeCfgQueue.send(cfg) + diff --git a/examples/mono_depth_mobilenetssd.py b/examples/mono_depth_mobilenetssd.py index 6268f20ea..39cc27342 100755 --- a/examples/mono_depth_mobilenetssd.py +++ b/examples/mono_depth_mobilenetssd.py @@ -47,7 +47,7 @@ monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P) # Produce the depth map (using disparity output as it's easier to visualize depth this way) -stereo.setConfidenceThreshold(255) +stereo.initialConfig.setConfidenceThreshold(255) stereo.setRectifyEdgeFillColor(0) # Black, to better see the cutout from rectification (black stripe on the edges) # Convert the grayscale frame into the nn-acceptable form manip.initialConfig.setResize(300, 300) diff --git a/examples/rgb_depth_aligned.py b/examples/rgb_depth_aligned.py index 28b405c27..2e2c7f3e7 100755 --- a/examples/rgb_depth_aligned.py +++ b/examples/rgb_depth_aligned.py @@ -7,6 +7,9 @@ # Optional. If set (True), the ColorCamera is downscaled from 1080p to 720p. # Otherwise (False), the aligned depth is automatically upscaled to 1080p downscaleColor = True +fps = 30 +# The disparity is computed at this resolution, then upscaled to RGB resolution +monoResolution = dai.MonoCameraProperties.SensorResolution.THE_400_P # Create pipeline pipeline = dai.Pipeline() @@ -29,17 +32,20 @@ #Properties camRgb.setBoardSocket(dai.CameraBoardSocket.RGB) camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P) +camRgb.setFps(fps) if downscaleColor: camRgb.setIspScale(2, 3) # For now, RGB needs fixed focus to properly align with depth. # This value was used during calibration camRgb.initialControl.setManualFocus(130) -left.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P) +left.setResolution(monoResolution) left.setBoardSocket(dai.CameraBoardSocket.LEFT) -right.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P) +left.setFps(fps) +right.setResolution(monoResolution) right.setBoardSocket(dai.CameraBoardSocket.RIGHT) +right.setFps(fps) -stereo.setConfidenceThreshold(200) +stereo.initialConfig.setConfidenceThreshold(230) # LR-check is required for depth alignment stereo.setLeftRightCheck(True) stereo.setDepthAlign(dai.CameraBoardSocket.RGB) diff --git a/examples/rgb_encoding_mono_mobilenet_depth.py b/examples/rgb_encoding_mono_mobilenet_depth.py index cfc925d88..89d10d000 100755 --- a/examples/rgb_encoding_mono_mobilenet_depth.py +++ b/examples/rgb_encoding_mono_mobilenet_depth.py @@ -56,7 +56,7 @@ videoEncoder.setDefaultProfilePreset(1920, 1080, 30, dai.VideoEncoderProperties.Profile.H265_MAIN) # Note: the rectified streams are horizontally mirrored by default -depth.setConfidenceThreshold(255) +depth.initialConfig.setConfidenceThreshold(255) depth.setRectifyMirrorFrame(False) depth.setRectifyEdgeFillColor(0) # Black, to better see the cutout diff --git a/examples/spatial_location_calculator.py b/examples/spatial_location_calculator.py index cde16bd06..26825d95b 100755 --- a/examples/spatial_location_calculator.py +++ b/examples/spatial_location_calculator.py @@ -33,7 +33,7 @@ lrcheck = False subpixel = False -stereo.setConfidenceThreshold(255) +stereo.initialConfig.setConfidenceThreshold(255) stereo.setLeftRightCheck(lrcheck) stereo.setSubpixel(subpixel) @@ -128,4 +128,4 @@ cfg = dai.SpatialLocationCalculatorConfig() cfg.addROI(config) spatialCalcConfigInQueue.send(cfg) - newConfig = False + newConfig = False \ No newline at end of file diff --git a/examples/spatial_mobilenet.py b/examples/spatial_mobilenet.py index a22c0163e..d6d4c1e25 100755 --- a/examples/spatial_mobilenet.py +++ b/examples/spatial_mobilenet.py @@ -60,7 +60,7 @@ monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT) # Setting node configs -stereo.setConfidenceThreshold(255) +stereo.initialConfig.setConfidenceThreshold(255) spatialDetectionNetwork.setBlobPath(nnBlobPath) spatialDetectionNetwork.setConfidenceThreshold(0.5) diff --git a/examples/spatial_mobilenet_mono.py b/examples/spatial_mobilenet_mono.py index 07c6bb8f7..4310657ea 100755 --- a/examples/spatial_mobilenet_mono.py +++ b/examples/spatial_mobilenet_mono.py @@ -62,7 +62,7 @@ monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT) # StereoDepth -stereo.setConfidenceThreshold(255) +stereo.initialConfig.setConfidenceThreshold(255) # Define a neural network that will make predictions based on the source frames spatialDetectionNetwork.setConfidenceThreshold(0.5) diff --git a/examples/spatial_object_tracker.py b/examples/spatial_object_tracker.py index d1fdbb62b..64d7bdb2e 100755 --- a/examples/spatial_object_tracker.py +++ b/examples/spatial_object_tracker.py @@ -49,7 +49,7 @@ monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT) # setting node configs -stereo.setConfidenceThreshold(255) +stereo.initialConfig.setConfidenceThreshold(255) spatialDetectionNetwork.setBlobPath(args.nnPath) spatialDetectionNetwork.setConfidenceThreshold(0.5) diff --git a/examples/spatial_tiny_yolo.py b/examples/spatial_tiny_yolo.py index 92b2ad0fc..a2de2fb68 100755 --- a/examples/spatial_tiny_yolo.py +++ b/examples/spatial_tiny_yolo.py @@ -73,7 +73,7 @@ monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT) # setting node configs -stereo.setConfidenceThreshold(255) +stereo.initialConfig.setConfidenceThreshold(255) spatialDetectionNetwork.setBlobPath(nnBlobPath) spatialDetectionNetwork.setConfidenceThreshold(0.5) diff --git a/examples/stereo_depth_from_host.py b/examples/stereo_depth_from_host.py index a93652709..70f4a88ee 100755 --- a/examples/stereo_depth_from_host.py +++ b/examples/stereo_depth_from_host.py @@ -17,18 +17,77 @@ import sys raise FileNotFoundError(f'Required file/s not found, please run "{sys.executable} install_requirements.py"') +class trackbar: + def __init__(self, trackbarName, windowName, minValue, maxValue, defaultValue, handler): + cv2.createTrackbar(trackbarName, windowName, minValue, maxValue, handler) + cv2.setTrackbarPos(trackbarName, windowName, defaultValue) + +class depthHandler: + depthStream = "depth" + _send_new_config = False + currentConfig = dai.StereoDepthConfig() + + def on_trackbar_change_sigma(self, value): + self._sigma = value + self._send_new_config = True + + def on_trackbar_change_confidence(self, value): + self._confidence = value + self._send_new_config = True + + def on_trackbar_change_lr_threshold(self, value): + self._lrCheckThreshold = value + self._send_new_config = True + + def handleKeypress(self, key, stereoDepthConfigInQueue): + if key == ord('m'): + self._send_new_config = True + medianSettings = [dai.MedianFilter.MEDIAN_OFF, dai.MedianFilter.KERNEL_3x3, dai.MedianFilter.KERNEL_5x5, dai.MedianFilter.KERNEL_7x7] + currentMedian = self.currentConfig.getMedianFilter() + # circle through median settins + nextMedian = medianSettings[(medianSettings.index(currentMedian)+1) % len(medianSettings)] + self.currentConfig.setMedianFilter(nextMedian) + print(f"Changing median to {nextMedian.name} from {currentMedian.name}") + self.sendConfig(stereoDepthConfigInQueue) + + def __init__(self, _confidence, _sigma, _lrCheckThreshold): + print("Control median filter using the 'm' key.") + print("Use slider to adjust disparity confidence.") + print("Use slider to adjust bilateral filter intensity.") + print("Use slider to adjust left-right check threshold.") + + self._confidence = _confidence + self._sigma = _sigma + self._lrCheckThreshold = _lrCheckThreshold + cv2.namedWindow(self.depthStream) + self.lambdaTrackbar = trackbar('Disparity confidence', self.depthStream, 0, 255, _confidence, self.on_trackbar_change_confidence) + self.sigmaTrackbar = trackbar('Bilateral sigma', self.depthStream, 0, 250, _sigma, self.on_trackbar_change_sigma) + self.lrcheckTrackbar = trackbar('LR-check threshold', self.depthStream, 0, 10, _lrCheckThreshold, self.on_trackbar_change_lr_threshold) + + def imshow(self, frame): + cv2.imshow(self.depthStream, frame) + + def sendConfig(self, stereoDepthConfigInQueue): + if self._send_new_config: + self._send_new_config = False + self.currentConfig.setConfidenceThreshold(self._confidence) + self.currentConfig.setBilateralFilterSigma(self._sigma) + self.currentConfig.setLeftRightCheckThreshold(self._lrCheckThreshold) + stereoDepthConfigInQueue.send(self.currentConfig) # StereoDepth config options. -out_depth = False # Disparity by default +out_depth = True # Disparity by default out_rectified = True # Output and display rectified streams lrcheck = True # Better handling for occlusions extended = False # Closer-in minimum depth, disparity range is doubled -subpixel = True # Better accuracy for longer distance, fractional disparity 32-levels -median = dai.StereoDepthProperties.MedianFilter.KERNEL_7x7 +subpixel = False # Better accuracy for longer distance, fractional disparity 32-levels +median = dai.MedianFilter.KERNEL_7x7 # Sanitize some incompatible options -if lrcheck or extended or subpixel: - median = dai.StereoDepthProperties.MedianFilter.MEDIAN_OFF +if extended or subpixel: + median = dai.MedianFilter.MEDIAN_OFF + +depth_handler = None print("StereoDepth config options: ") print("Left-Right check: ", lrcheck) @@ -46,6 +105,8 @@ def create_stereo_depth_pipeline(): monoLeft = pipeline.createXLinkIn() monoRight = pipeline.createXLinkIn() + xinStereoDepthConfig = pipeline.createXLinkIn() + stereo = pipeline.createStereoDepth() xoutLeft = pipeline.createXLinkOut() xoutRight = pipeline.createXLinkOut() @@ -54,18 +115,26 @@ def create_stereo_depth_pipeline(): xoutRectifLeft = pipeline.createXLinkOut() xoutRectifRight = pipeline.createXLinkOut() + xinStereoDepthConfig.setStreamName("stereoDepthConfig") monoLeft.setStreamName('in_left') monoRight.setStreamName('in_right') - stereo.setConfidenceThreshold(200) + stereo.initialConfig.setConfidenceThreshold(200) stereo.setRectifyEdgeFillColor(0) # Black, to better see the cutout - stereo.setMedianFilter(median) # KERNEL_7x7 default + stereo.initialConfig.setMedianFilter(median) # KERNEL_7x7 default stereo.setLeftRightCheck(lrcheck) stereo.setExtendedDisparity(extended) stereo.setSubpixel(subpixel) + xinStereoDepthConfig.out.link(stereo.inputConfig) + global depth_handler + _confidence=stereo.initialConfig.getConfidenceThreshold() + _sigma=stereo.initialConfig.getBilateralFilterSigma() + _lrCheckThreshold=stereo.initialConfig.getLeftRightCheckThreshold() + depth_handler = depthHandler(_confidence, _sigma, _lrCheckThreshold) + - stereo.setEmptyCalibration() # Set if the input frames are already rectified stereo.setInputResolution(1280, 720) + stereo.setRectification(False) xoutLeft.setStreamName('left') xoutRight.setStreamName('right') @@ -107,8 +176,11 @@ def convert_to_cv2_frame(name, image): data, w, h = image.getData(), image.getWidth(), image.getHeight() if name == 'depth': - # this contains FP16 with (lrcheck or extended or subpixel) - frame = np.array(data).astype(np.uint8).view(np.uint16).reshape((h, w)) + depthFrame = image.getFrame() + depthFrameColor = cv2.normalize(depthFrame, None, 255, 0, cv2.NORM_INF, cv2.CV_8UC1) + depthFrameColor = cv2.equalizeHist(depthFrameColor) + depthFrameColor = cv2.applyColorMap(depthFrameColor, cv2.COLORMAP_HOT) + frame = depthFrameColor elif name == 'disparity': disp = np.array(data).astype(np.uint8).view(disp_type).reshape((h, w)) @@ -136,6 +208,7 @@ def convert_to_cv2_frame(name, image): # Connect to device and start pipeline with dai.Device(pipeline) as device: + stereoDepthConfigInQueue = device.getInputQueue("stereoDepthConfig") inStreams = ['in_right', 'in_left'] inStreamsCameraID = [dai.CameraBoardSocket.RIGHT, dai.CameraBoardSocket.LEFT] in_q_list = [] @@ -155,7 +228,7 @@ def convert_to_cv2_frame(name, image): while True: # Handle input streams, if any if in_q_list: - dataset_size = 2 # Number of image pairs + dataset_size = 1 # Number of image pairs frame_interval_ms = 500 for i, q in enumerate(in_q_list): path = args.dataset + '/' + str(index) + '/' + q.getName() + '.png' @@ -178,8 +251,14 @@ def convert_to_cv2_frame(name, image): sleep(frame_interval_ms / 1000) # Handle output streams for q in q_list: - if q.getName() in ['left', 'right', 'depth']: continue + if q.getName() in ['left', 'right']: continue frame = convert_to_cv2_frame(q.getName(), q.get()) - cv2.imshow(q.getName(), frame) - if cv2.waitKey(1) == ord('q'): + if q.getName() == 'depth': + depth_handler.imshow(frame) + else: + cv2.imshow(q.getName(), frame) + + key = cv2.waitKey(1) + if key == ord('q'): break + depth_handler.handleKeypress(key, stereoDepthConfigInQueue) diff --git a/examples/stereo_depth_video.py b/examples/stereo_depth_video.py index 76149db53..11d81fc77 100755 --- a/examples/stereo_depth_video.py +++ b/examples/stereo_depth_video.py @@ -45,10 +45,10 @@ if withDepth: # StereoDepth - stereo.setConfidenceThreshold(200) + stereo.initialConfig.setConfidenceThreshold(230) stereo.setRectifyEdgeFillColor(0) # black, to better see the cutout # stereo.setInputResolution(1280, 720) - stereo.setMedianFilter(dai.StereoDepthProperties.MedianFilter.MEDIAN_OFF) + stereo.initialConfig.setMedianFilter(dai.MedianFilter.KERNEL_5x5) stereo.setLeftRightCheck(lrcheck) stereo.setExtendedDisparity(extended) stereo.setSubpixel(subpixel) diff --git a/src/DatatypeBindings.cpp b/src/DatatypeBindings.cpp index b821377dc..c939b8f3b 100644 --- a/src/DatatypeBindings.cpp +++ b/src/DatatypeBindings.cpp @@ -18,6 +18,8 @@ #include "depthai/pipeline/datatype/SpatialLocationCalculatorConfig.hpp" #include "depthai/pipeline/datatype/Tracklets.hpp" #include "depthai/pipeline/datatype/IMUData.hpp" +#include "depthai/pipeline/datatype/StereoDepthConfig.hpp" +#include "depthai/pipeline/datatype/EdgeDetectorConfig.hpp" // depthai-shared #include "depthai-shared/datatype/RawBuffer.hpp" @@ -32,6 +34,8 @@ #include "depthai-shared/datatype/RawSpatialLocations.hpp" #include "depthai-shared/datatype/RawTracklets.hpp" #include "depthai-shared/datatype/RawIMUData.hpp" +#include "depthai-shared/datatype/RawStereoDepthConfig.hpp" +#include "depthai-shared/datatype/RawEdgeDetectorConfig.hpp" //pybind @@ -913,4 +917,45 @@ void DatatypeBindings::bind(pybind11::module& m){ .def_property("packets", [](IMUData& imuDta) { return &imuDta.packets; }, [](IMUData& imuDta, std::vector val) { imuDta.packets = val; }, DOC(dai, IMUData, packets)) ; -} \ No newline at end of file + // Bind RawStereoDepthConfig + py::class_> rawStereoDepthConfig(m, "RawStereoDepthConfig", DOC(dai, RawStereoDepthConfig)); + rawStereoDepthConfig + .def(py::init<>()) + .def_readwrite("config", &RawStereoDepthConfig::config) + ; + + // StereoDepthConfig (after ConfigData) + py::class_>(m, "StereoDepthConfig", DOC(dai, StereoDepthConfig)) + .def(py::init<>()) + .def("setConfidenceThreshold", &StereoDepthConfig::setConfidenceThreshold, py::arg("confThr"), DOC(dai, StereoDepthConfig, setConfidenceThreshold)) + .def("setMedianFilter", &StereoDepthConfig::setMedianFilter, py::arg("median"), DOC(dai, StereoDepthConfig, setMedianFilter)) + .def("setBilateralFilterSigma", &StereoDepthConfig::setBilateralFilterSigma, py::arg("sigma"), DOC(dai, StereoDepthConfig, setBilateralFilterSigma)) + .def("setLeftRightCheckThreshold", &StereoDepthConfig::setLeftRightCheckThreshold, py::arg("sigma"), DOC(dai, StereoDepthConfig, setLeftRightCheckThreshold)) + .def("getConfidenceThreshold", &StereoDepthConfig::getConfidenceThreshold, DOC(dai, StereoDepthConfig, getConfidenceThreshold)) + .def("getMedianFilter", &StereoDepthConfig::getMedianFilter, DOC(dai, StereoDepthConfig, getMedianFilter)) + .def("getBilateralFilterSigma", &StereoDepthConfig::getBilateralFilterSigma, DOC(dai, StereoDepthConfig, getBilateralFilterSigma)) + .def("getLeftRightCheckThreshold", &StereoDepthConfig::getLeftRightCheckThreshold, DOC(dai, StereoDepthConfig, getLeftRightCheckThreshold)) + ; + + + py::class_ (m, "EdgeDetectorConfigData", DOC(dai, EdgeDetectorConfigData)) + .def(py::init<>()) + .def_readwrite("sobelFilterHorizontalKernel", &EdgeDetectorConfigData::sobelFilterHorizontalKernel, DOC(dai, EdgeDetectorConfigData, sobelFilterHorizontalKernel)) + .def_readwrite("sobelFilterVerticalKernel", &EdgeDetectorConfigData::sobelFilterVerticalKernel, DOC(dai, EdgeDetectorConfigData, sobelFilterVerticalKernel)) + ; + + // Bind RawEdgeDetectorConfig + py::class_> rawEdgeDetectorConfig(m, "RawEdgeDetectorConfig", DOC(dai, RawEdgeDetectorConfig)); + rawEdgeDetectorConfig + .def(py::init<>()) + .def_readwrite("config", &RawEdgeDetectorConfig::config) + ; + + // EdgeDetectorConfig (after ConfigData) + py::class_>(m, "EdgeDetectorConfig", DOC(dai, EdgeDetectorConfig)) + .def(py::init<>()) + .def("setSobelFilterKernels", &EdgeDetectorConfig::setSobelFilterKernels, py::arg("horizontalKernel"), py::arg("verticalKernel"), DOC(dai, EdgeDetectorConfig, setSobelFilterKernels)) + .def("getConfigData", &EdgeDetectorConfig::getConfigData, DOC(dai, EdgeDetectorConfig, getConfigData)) + ; + +} diff --git a/src/pipeline/NodeBindings.cpp b/src/pipeline/NodeBindings.cpp index c59455459..226006c67 100644 --- a/src/pipeline/NodeBindings.cpp +++ b/src/pipeline/NodeBindings.cpp @@ -16,6 +16,7 @@ #include "depthai/pipeline/node/SpatialDetectionNetwork.hpp" #include "depthai/pipeline/node/ObjectTracker.hpp" #include "depthai/pipeline/node/IMU.hpp" +#include "depthai/pipeline/node/EdgeDetector.hpp" // Libraries #include "hedley/hedley.h" @@ -292,6 +293,8 @@ void NodeBindings::bind(pybind11::module& m){ // StereoDepth node py::class_>(m, "StereoDepth", DOC(dai, node, StereoDepth)) + .def_readonly("initialConfig", &StereoDepth::initialConfig, DOC(dai, node, StereoDepth, initialConfig)) + .def_readonly("inputConfig", &StereoDepth::inputConfig, DOC(dai, node, StereoDepth, inputConfig)) .def_readonly("left", &StereoDepth::left, DOC(dai, node, StereoDepth, left)) .def_readonly("right", &StereoDepth::right, DOC(dai, node, StereoDepth, right)) .def_readonly("depth", &StereoDepth::depth, DOC(dai, node, StereoDepth, depth)) @@ -300,17 +303,36 @@ void NodeBindings::bind(pybind11::module& m){ .def_readonly("syncedRight", &StereoDepth::syncedRight, DOC(dai, node, StereoDepth, syncedRight)) .def_readonly("rectifiedLeft", &StereoDepth::rectifiedLeft, DOC(dai, node, StereoDepth, rectifiedLeft)) .def_readonly("rectifiedRight", &StereoDepth::rectifiedRight, DOC(dai, node, StereoDepth, rectifiedRight)) - .def("setEmptyCalibration", &StereoDepth::setEmptyCalibration, DOC(dai, node, StereoDepth, setEmptyCalibration)) + .def("loadMeshFiles", &StereoDepth::loadMeshFiles, py::arg("pathLeft"), py::arg("pathRight"), DOC(dai, node, StereoDepth, loadMeshFiles)) + .def("loadMeshData", &StereoDepth::loadMeshData, py::arg("dataLeft"), py::arg("dataRight"), DOC(dai, node, StereoDepth, loadMeshData)) + .def("setMeshStep", &StereoDepth::setMeshStep, py::arg("width"), py::arg("height"), DOC(dai, node, StereoDepth, setMeshStep)) .def("setInputResolution", &StereoDepth::setInputResolution, py::arg("width"), py::arg("height"), DOC(dai, node, StereoDepth, setInputResolution)) - .def("setMedianFilter", &StereoDepth::setMedianFilter, py::arg("median"), DOC(dai, node, StereoDepth, setMedianFilter)) + .def("setOutputSize", &StereoDepth::setOutputSize, py::arg("width"), py::arg("height"), DOC(dai, node, StereoDepth, setOutputSize)) + .def("setOutputKeepAspectRatio",&StereoDepth::setOutputKeepAspectRatio, py::arg("keep"), DOC(dai, node, StereoDepth, setOutputKeepAspectRatio)) .def("setDepthAlign", static_cast(&StereoDepth::setDepthAlign), py::arg("align"), DOC(dai, node, StereoDepth, setDepthAlign)) .def("setDepthAlign", static_cast(&StereoDepth::setDepthAlign), py::arg("camera"), DOC(dai, node, StereoDepth, setDepthAlign, 2)) - .def("setConfidenceThreshold", &StereoDepth::setConfidenceThreshold, py::arg("confThr"), DOC(dai, node, StereoDepth, setConfidenceThreshold)) + .def("setRectification", &StereoDepth::setRectification, py::arg("enable"), DOC(dai, node, StereoDepth, setRectification)) .def("setLeftRightCheck", &StereoDepth::setLeftRightCheck, py::arg("enable"), DOC(dai, node, StereoDepth, setLeftRightCheck)) .def("setSubpixel", &StereoDepth::setSubpixel, py::arg("enable"), DOC(dai, node, StereoDepth, setSubpixel)) .def("setExtendedDisparity", &StereoDepth::setExtendedDisparity, py::arg("enable"), DOC(dai, node, StereoDepth, setExtendedDisparity)) .def("setRectifyEdgeFillColor", &StereoDepth::setRectifyEdgeFillColor, py::arg("color"), DOC(dai, node, StereoDepth, setRectifyEdgeFillColor)) .def("setRectifyMirrorFrame", &StereoDepth::setRectifyMirrorFrame, py::arg("enable"), DOC(dai, node, StereoDepth, setRectifyMirrorFrame)) + .def("setConfidenceThreshold", [](StereoDepth& s, int confThr) { + // Issue an deprecation warning + PyErr_WarnEx(PyExc_DeprecationWarning, "setConfidenceThreshold() is deprecated, Use 'initialConfig.setConfidenceThreshold()' instead", 1); + HEDLEY_DIAGNOSTIC_PUSH + HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED + s.setConfidenceThreshold(confThr); + HEDLEY_DIAGNOSTIC_POP + }, DOC(dai, node, StereoDepth, setConfidenceThreshold)) + .def("setMedianFilter", [](StereoDepth& s, dai::MedianFilter median) { + // Issue an deprecation warning + PyErr_WarnEx(PyExc_DeprecationWarning, "setMedianFilter() is deprecated, Use 'initialConfig.setMedianFilter()' instead", 1); + HEDLEY_DIAGNOSTIC_PUSH + HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED + s.setMedianFilter(median); + HEDLEY_DIAGNOSTIC_POP + }, DOC(dai, node, StereoDepth, setMedianFilter)) .def("setOutputRectified", [](StereoDepth& s, bool enable) { // Issue an deprecation warning PyErr_WarnEx(PyExc_DeprecationWarning, "setOutputRectified() is deprecated, the output is auto-enabled if used.", 1); @@ -341,6 +363,13 @@ void NodeBindings::bind(pybind11::module& m){ s.loadCalibrationData(data); HEDLEY_DIAGNOSTIC_POP }) + .def("setEmptyCalibration", [](StereoDepth& s){ + PyErr_WarnEx(PyExc_DeprecationWarning, "setEmptyCalibration() is deprecated, Use 'setRectification(False)' instead", 1); + HEDLEY_DIAGNOSTIC_PUSH + HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED + s.setEmptyCalibration(); + HEDLEY_DIAGNOSTIC_POP + }, DOC(dai, node, StereoDepth, setEmptyCalibration)) .def("getMaxDisparity", &StereoDepth::getMaxDisparity, DOC(dai, node, StereoDepth, getMaxDisparity)) ; @@ -476,6 +505,17 @@ void NodeBindings::bind(pybind11::module& m){ .def("getMaxBatchReports", &IMU::getMaxBatchReports, DOC(dai, node, IMU, getMaxBatchReports)) ; + // EdgeDetector node + py::class_>(m, "EdgeDetector", DOC(dai, node, EdgeDetector)) + .def_readonly("initialConfig", &EdgeDetector::initialConfig, DOC(dai, node, EdgeDetector, initialConfig)) + .def_readonly("inputConfig", &EdgeDetector::inputConfig, DOC(dai, node, EdgeDetector, inputConfig)) + .def_readonly("inputImage", &EdgeDetector::inputImage, DOC(dai, node, EdgeDetector, inputImage)) + .def_readonly("outputImage", &EdgeDetector::outputImage, DOC(dai, node, EdgeDetector, outputImage)) + .def("setWaitForConfigInput", &EdgeDetector::setWaitForConfigInput, DOC(dai, node, EdgeDetector, setWaitForConfigInput)) + .def("setNumFramesPool", &EdgeDetector::setNumFramesPool, DOC(dai, node, EdgeDetector, setNumFramesPool)) + .def("setMaxOutputFrameSize", &EdgeDetector::setMaxOutputFrameSize, DOC(dai, node, EdgeDetector, setMaxOutputFrameSize)) + ; + //////////////////////////////////// // Node properties bindings //////////////////////////////////// @@ -534,10 +574,10 @@ void NodeBindings::bind(pybind11::module& m){ py::class_ stereoDepthProperties(m, "StereoDepthProperties", DOC(dai, StereoDepthProperties)); stereoDepthProperties .def_readwrite("calibration", &StereoDepthProperties::calibration) - .def_readwrite("median", &StereoDepthProperties::median) + .def_readwrite("initialConfig", &StereoDepthProperties::initialConfig) + .def_readwrite("inputConfigSync", &StereoDepthProperties::inputConfigSync) .def_readwrite("depthAlign", &StereoDepthProperties::depthAlign) .def_readwrite("depthAlignCamera", &StereoDepthProperties::depthAlignCamera) - .def_readwrite("confidenceThreshold", &StereoDepthProperties::confidenceThreshold) .def_readwrite("enableLeftRightCheck", &StereoDepthProperties::enableLeftRightCheck) .def_readwrite("enableSubpixel", &StereoDepthProperties::enableSubpixel) .def_readwrite("enableExtendedDisparity", &StereoDepthProperties::enableExtendedDisparity) @@ -545,13 +585,18 @@ void NodeBindings::bind(pybind11::module& m){ .def_readwrite("rectifyEdgeFillColor", &StereoDepthProperties::rectifyEdgeFillColor) .def_readwrite("width", &StereoDepthProperties::width) .def_readwrite("height", &StereoDepthProperties::height) + .def_readwrite("outWidth", &StereoDepthProperties::outWidth, DOC(dai, StereoDepthProperties, outWidth)) + .def_readwrite("outHeight", &StereoDepthProperties::outHeight, DOC(dai, StereoDepthProperties, outHeight)) + .def_readwrite("outKeepAspectRatio", &StereoDepthProperties::outKeepAspectRatio, DOC(dai, StereoDepthProperties, outKeepAspectRatio)) + .def_readwrite("mesh", &StereoDepthProperties::mesh, DOC(dai, StereoDepthProperties, mesh)) ; - py::enum_(stereoDepthProperties, "MedianFilter", DOC(dai, StereoDepthProperties, MedianFilter)) - .value("MEDIAN_OFF", StereoDepthProperties::MedianFilter::MEDIAN_OFF) - .value("KERNEL_3x3", StereoDepthProperties::MedianFilter::KERNEL_3x3) - .value("KERNEL_5x5", StereoDepthProperties::MedianFilter::KERNEL_5x5) - .value("KERNEL_7x7", StereoDepthProperties::MedianFilter::KERNEL_7x7) + py::enum_ medianFilter(m, "MedianFilter", DOC(dai, MedianFilter)); + medianFilter + .value("MEDIAN_OFF", MedianFilter::MEDIAN_OFF) + .value("KERNEL_3x3", MedianFilter::KERNEL_3x3) + .value("KERNEL_5x5", MedianFilter::KERNEL_5x5) + .value("KERNEL_7x7", MedianFilter::KERNEL_7x7) ; py::enum_(stereoDepthProperties, "DepthAlign") @@ -560,6 +605,18 @@ void NodeBindings::bind(pybind11::module& m){ .value("CENTER", StereoDepthProperties::DepthAlign::CENTER) ; + py::class_ stereoDepthConfigData(m, "StereoDepthConfigData", DOC(dai, StereoDepthConfigData)); + stereoDepthConfigData + .def(py::init<>()) + .def_readwrite("median", &StereoDepthConfigData::median, DOC(dai, StereoDepthConfigData, median)) + .def_readwrite("confidenceThreshold", &StereoDepthConfigData::confidenceThreshold, DOC(dai, StereoDepthConfigData, confidenceThreshold)) + .def_readwrite("bilateralSigmaValue", &StereoDepthConfigData::bilateralSigmaValue, DOC(dai, StereoDepthConfigData, bilateralSigmaValue)) + .def_readwrite("leftRightCheckThreshold", &StereoDepthConfigData::leftRightCheckThreshold, DOC(dai, StereoDepthConfigData, leftRightCheckThreshold)) + ; + + m.attr("StereoDepthProperties").attr("MedianFilter") = medianFilter; + m.attr("StereoDepthConfigData").attr("MedianFilter") = medianFilter; + // ALIAS m.attr("StereoDepth").attr("Properties") = stereoDepthProperties; @@ -702,5 +759,16 @@ void NodeBindings::bind(pybind11::module& m){ m.attr("IMU").attr("Properties") = imuProperties; + py::class_ edgeDetectorProperties(m, "EdgeDetectorProperties", DOC(dai, EdgeDetectorProperties)); + edgeDetectorProperties + .def_readwrite("initialConfig", &EdgeDetectorProperties::initialConfig, DOC(dai, EdgeDetectorProperties, initialConfig)) + .def_readwrite("inputConfigSync", &EdgeDetectorProperties::inputConfigSync, DOC(dai, EdgeDetectorProperties, inputConfigSync)) + .def_readwrite("outputFrameSize", &EdgeDetectorProperties::outputFrameSize, DOC(dai, EdgeDetectorProperties, outputFrameSize)) + .def_readwrite("numFramesPool", &EdgeDetectorProperties::numFramesPool, DOC(dai, EdgeDetectorProperties, numFramesPool)) + + ; + m.attr("EdgeDetector").attr("Properties") = edgeDetectorProperties; + + } diff --git a/src/pipeline/PipelineBindings.cpp b/src/pipeline/PipelineBindings.cpp index ea26f5e36..193f762b4 100644 --- a/src/pipeline/PipelineBindings.cpp +++ b/src/pipeline/PipelineBindings.cpp @@ -19,6 +19,7 @@ #include "depthai/pipeline/node/SpatialDetectionNetwork.hpp" #include "depthai/pipeline/node/ObjectTracker.hpp" #include "depthai/pipeline/node/IMU.hpp" +#include "depthai/pipeline/node/EdgeDetector.hpp" // depthai-shared #include "depthai-shared/properties/GlobalProperties.hpp" @@ -80,6 +81,7 @@ void PipelineBindings::bind(pybind11::module& m){ .def("createYoloSpatialDetectionNetwork", &Pipeline::create) .def("createObjectTracker", &Pipeline::create) .def("createIMU", &Pipeline::create) + .def("createEdgeDetector", &Pipeline::create) ;