/* License: Apache 2.0. See LICENSE file in root directory. Copyright(c) 2017 Intel Corporation. All Rights Reserved. */ #include "pyrealsense2.h" #include void init_processing(py::module &m) { /** rs_processing.hpp **/ py::class_ frame_source(m, "frame_source", "The source used to generate frames, which is usually done by the low level driver for each sensor. " "frame_source is one of the parameters of processing_block's callback function, which can be used to re-generate the " "frame and via frame_ready invoke another callback function to notify application frame is ready."); frame_source.def("allocate_video_frame", &rs2::frame_source::allocate_video_frame, "Allocate a new video frame with given params", "profile"_a, "original"_a, "new_bpp"_a = 0, "new_width"_a = 0, "new_height"_a = 0, "new_stride"_a = 0, "frame_type"_a = RS2_EXTENSION_VIDEO_FRAME) .def("allocate_motion_frame", &rs2::frame_source::allocate_motion_frame, "Allocate a new motion frame with given params", "profile"_a, "original"_a, "frame_type"_a = RS2_EXTENSION_MOTION_FRAME) .def("allocate_points", &rs2::frame_source::allocate_points, "profile"_a, "original"_a) // No docstring in C++ .def("allocate_composite_frame", &rs2::frame_source::allocate_composite_frame, "Allocate composite frame with given params", "frames"_a) .def("frame_ready", &rs2::frame_source::frame_ready, "Invoke the " "callback funtion informing the frame is ready.", "result"_a); // Not binding frame_processor_callback, templated py::class_ frame_queue(m, "frame_queue", "Frame queues are the simplest cross-platform " "synchronization primitive provided by librealsense to help " "developers who are not using async APIs."); frame_queue.def(py::init<>()) .def(py::init(), "capacity"_a, "keep_frames"_a = false) .def("enqueue", &rs2::frame_queue::enqueue, "Enqueue a new frame into the queue.", "f"_a) .def("wait_for_frame", &rs2::frame_queue::wait_for_frame, "Wait until a new frame " "becomes available in the queue and dequeue it.", "timeout_ms"_a = 5000, py::call_guard()) .def("poll_for_frame", [](const rs2::frame_queue &self) { rs2::frame frame; self.poll_for_frame(&frame); return frame; }, "Poll if a new frame is available and dequeue it if it is") .def("try_wait_for_frame", [](const rs2::frame_queue &self, unsigned int timeout_ms) { rs2::frame frame; auto success = self.try_wait_for_frame(&frame, timeout_ms); return std::make_tuple(success, frame); }, "timeout_ms"_a = 5000, py::call_guard()) // No docstring in C++ .def("__call__", &rs2::frame_queue::operator(), "Identical to calling enqueue.", "f"_a) .def("capacity", &rs2::frame_queue::capacity, "Return the capacity of the queue.") .def("size", &rs2::frame_queue::size, "Number of enqueued frames.") .def("keep_frames", &rs2::frame_queue::keep_frames, "Return whether or not the queue calls keep on enqueued frames."); py::class_ processing_block(m, "processing_block", "Define the processing block workflow, inherit this class to " "generate your own processing_block."); processing_block.def(py::init([](std::function processing_function) { return new rs2::processing_block([=](rs2::frame f, rs2::frame_source& fs) {processing_function(f, &fs); }); }), "processing_function"_a) .def("start", [](rs2::processing_block& self, std::function f) { self.start(f); }, "Start the processing block with callback function to inform the application the frame is processed.", "callback"_a) .def("invoke", &rs2::processing_block::invoke, "Ask processing block to process the frame", "f"_a) .def("supports", (bool (rs2::processing_block::*)(rs2_camera_info) const) &rs2::processing_block::supports, "Check if a specific camera info field is supported.") .def("get_info", &rs2::processing_block::get_info, "Retrieve camera specific information, like versions of various internal components."); /*.def("__call__", &rs2::processing_block::operator(), "f"_a)*/ // supports(camera_info) / get_info(camera_info)? py::class_ filter(m, "filter", "Define the filter workflow, inherit this class to generate your own filter."); filter.def(py::init([](std::function filter_function, int queue_size) { return new rs2::filter(filter_function, queue_size); }), "filter_function"_a, "queue_size"_a = 1) .def(BIND_DOWNCAST(filter, decimation_filter)) .def(BIND_DOWNCAST(filter, disparity_transform)) .def(BIND_DOWNCAST(filter, hole_filling_filter)) .def(BIND_DOWNCAST(filter, spatial_filter)) .def(BIND_DOWNCAST(filter, temporal_filter)) .def(BIND_DOWNCAST(filter, threshold_filter)) .def(BIND_DOWNCAST(filter, hdr_merge)) .def(BIND_DOWNCAST(filter, sequence_id_filter)) .def("__nonzero__", &rs2::filter::operator bool) // Called to implement truth value testing in Python 2 .def("__bool__", &rs2::filter::operator bool); // Called to implement truth value testing in Python 3 // get_queue? // is/as? py::class_ pointcloud(m, "pointcloud", "Generates 3D point clouds based on a depth frame. Can also map textures from a color frame."); pointcloud.def(py::init<>()) .def(py::init(), "stream"_a, "index"_a = 0) .def("calculate", &rs2::pointcloud::calculate, "Generate the pointcloud and texture mappings of depth map.", "depth"_a) .def("map_to", &rs2::pointcloud::map_to, "Map the point cloud to the given color frame.", "mapped"_a); py::class_ yuy_decoder(m, "yuy_decoder", "Converts frames in raw YUY format to RGB. This conversion is somewhat costly, " "but the SDK will automatically try to use SSE2, AVX, or CUDA instructions where available to " "get better performance. Othere implementations (GLSL, OpenCL, Neon, NCS) should follow."); yuy_decoder.def(py::init<>()); py::class_ threshold(m, "threshold_filter", "Depth thresholding filter. By controlling min and " "max options on the block, one could filter out depth values that are either too large " "or too small, as a software post-processing step"); threshold.def(py::init(), "min_dist"_a = 0.15f, "max_dist"_a = 4.f); py::class_ units_transform(m, "units_transform"); units_transform.def(py::init<>()); // rs2::asynchronous_syncer py::class_ syncer(m, "syncer", "Sync instance to align frames from different streams"); auto poll_for_frame = []( const rs2::syncer & self ) { rs2::frameset frames; self.poll_for_frames( &frames ); return frames; }; auto wait_for_frame = []( const rs2::syncer& self, unsigned int timeout_ms ) { rs2::frameset fs; auto success = self.try_wait_for_frames( &fs, timeout_ms ); return std::make_tuple( success, fs ); }; syncer.def( py::init< int >(), "queue_size"_a = 1 ) .def( "wait_for_frames", &rs2::syncer::wait_for_frames, "Wait until a coherent set of frames becomes available", "timeout_ms"_a = 5000, py::call_guard< py::gil_scoped_release >() ) .def( "wait_for_frame", // same, but with a name that matches frame_queue! &rs2::syncer::wait_for_frames, "Wait until a coherent set of frames becomes available", "timeout_ms"_a = 5000, py::call_guard< py::gil_scoped_release >() ) .def( "poll_for_frames", poll_for_frame, "Check if a coherent set of frames is available" ) .def( "poll_for_frame", poll_for_frame, "Check if a coherent set of frames is available" ) // same, but with a name that matches frame_queue! .def( "try_wait_for_frames", wait_for_frame, "timeout_ms"_a = 5000, py::call_guard< py::gil_scoped_release >() ) .def( "try_wait_for_frame", // same, but with a name that matches frame_queue! wait_for_frame, "timeout_ms"_a = 5000, py::call_guard< py::gil_scoped_release >() ); /*.def("__call__", &rs2::syncer::operator(), "frame"_a)*/ py::class_ align(m, "align", "Performs alignment between depth image and another image."); align.def(py::init(), "To perform alignment of a depth image to the other, set the align_to parameter with the other stream type.\n" "To perform alignment of a non depth image to a depth image, set the align_to parameter to RS2_STREAM_DEPTH.\n" "Camera calibration and frame's stream type are determined on the fly, according to the first valid frameset passed to process().", "align_to"_a) .def("process", (rs2::frameset(rs2::align::*)(rs2::frameset)) &rs2::align::process, "Run thealignment process on the given frames to get an aligned set of frames", "frames"_a); py::class_ colorizer(m, "colorizer", "Colorizer filter generates color images based on input depth frame"); colorizer.def(py::init<>()) .def(py::init(), "Possible values for color_scheme:\n" "0 - Jet\n" "1 - Classic\n" "2 - WhiteToBlack\n" "3 - BlackToWhite\n" "4 - Bio\n" "5 - Cold\n" "6 - Warm\n" "7 - Quantized\n" "8 - Pattern", "color_scheme"_a) .def("colorize", &rs2::colorizer::colorize, "Start to generate color image base on depth frame", "depth"_a) /*.def("__call__", &rs2::colorizer::operator())*/; py::class_ decimation_filter(m, "decimation_filter", "Performs downsampling by using the median with specific kernel size."); decimation_filter.def(py::init<>()) .def(py::init(), "magnitude"_a); py::class_ temporal_filter(m, "temporal_filter", "Temporal filter smooths the image by calculating multiple frames " "with alpha and delta settings. Alpha defines the weight of current frame, and delta defines the" "threshold for edge classification and preserving."); temporal_filter.def(py::init<>()) .def(py::init(), "Possible values for persistence_control:\n" "1 - Valid in 8/8 - Persistency activated if the pixel was valid in 8 out of the last 8 frames\n" "2 - Valid in 2 / last 3 - Activated if the pixel was valid in two out of the last 3 frames\n" "3 - Valid in 2 / last 4 - Activated if the pixel was valid in two out of the last 4 frames\n" "4 - Valid in 2 / 8 - Activated if the pixel was valid in two out of the last 8 frames\n" "5 - Valid in 1 / last 2 - Activated if the pixel was valid in one of the last two frames\n" "6 - Valid in 1 / last 5 - Activated if the pixel was valid in one out of the last 5 frames\n" "7 - Valid in 1 / last 8 - Activated if the pixel was valid in one out of the last 8 frames\n" "8 - Persist Indefinitely - Persistency will be imposed regardless of the stored history(most aggressive filtering)", "smooth_alpha"_a, "smooth_delta"_a, "persistence_control"_a); py::class_ spatial_filter(m, "spatial_filter", "Spatial filter smooths the image by calculating frame with alpha and delta settings. " "Alpha defines the weight of the current pixel for smoothing, and is bounded within [25..100]%. Delta " "defines the depth gradient below which the smoothing will occur as number of depth levels."); spatial_filter.def(py::init<>()) .def(py::init(), "smooth_alpha"_a, "smooth_delta"_a, "magnitude"_a, "hole_fill"_a);; py::class_ disparity_transform(m, "disparity_transform", "Converts from depth representation " "to disparity representation and vice - versa in depth frames"); disparity_transform.def(py::init(), "transform_to_disparity"_a = true); py::class_ hole_filling_filter(m, "hole_filling_filter", "The processing performed depends on the selected hole filling mode."); hole_filling_filter.def(py::init<>()) .def(py::init(), "Possible values for mode:\n" "0 - fill_from_left - Use the value from the left neighbor pixel to fill the hole\n" "1 - farest_from_around - Use the value from the neighboring pixel which is furthest away from the sensor\n" "2 - nearest_from_around - -Use the value from the neighboring pixel closest to the sensor", "mode"_a); py::class_ hdr_merge(m, "hdr_merge", "Merges depth frames with different sequence ID"); hdr_merge.def(py::init<>()); py::class_ sequence_id_filter(m, "sequence_id_filter", "Splits depth frames with different sequence ID"); sequence_id_filter.def(py::init<>()) .def(py::init(), "sequence_id"_a); // rs2::rates_printer /** end rs_processing.hpp **/ }