diff --git a/wrappers/matlab/MatlabParamParser.h b/wrappers/matlab/MatlabParamParser.h index d7dc60b7b3..8cb5c241c7 100644 --- a/wrappers/matlab/MatlabParamParser.h +++ b/wrappers/matlab/MatlabParamParser.h @@ -70,6 +70,40 @@ class MatlabParamParser using value = value_t; using type = typename std::conditional::value, int64_t, uint64_t>::type; }; + // uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, and int64_t + // are exposed as the relevant native Matlab type + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = uint8_t; + }; + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = uint16_t; + }; + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = uint32_t; + }; + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = uint64_t; + }; + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = int8_t; + }; + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = int16_t; + }; + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = int32_t; + }; + template <> struct mx_wrapper { + using value = std::integral_constant; + using type = int64_t; + }; // by default non-basic types are wrapped as pointers template struct mx_wrapper::value>::type> : mx_wrapper {}; public: @@ -83,7 +117,7 @@ class MatlabParamParser struct traits_trampoline { private: template struct detector { - struct fallback { int to_internal, from_internal; }; + struct fallback { int to_internal, from_internal, use_cells; }; struct derived : type_traits, fallback {}; template struct checker; typedef char ao1[1]; @@ -92,9 +126,16 @@ class MatlabParamParser template static ao2& check_to(...); template static ao1& check_from(checker *); template static ao2& check_from(...); + template static ao1& check_cells(checker *); + template static ao2& check_cells(...); +// template struct use_cells_t : false_type {}; +// template struct use_cells_t(0)) == 2>::type> +// : T::use_cells {}; enum { has_to = sizeof(check_to(0)) == 2 }; enum { has_from = sizeof(check_from(0)) == 2 }; +// enum { use_cells = use_cells_t::value }; + enum { use_cells = sizeof(check_cells(0)) == 2 }; }; template using internal_t = typename type_traits::rs2_internal_t; public: @@ -111,7 +152,7 @@ class MatlabParamParser // selected if it doesnt template static typename std::enable_if::has_from, T>::type from_internal(typename internal_t* ptr) { return T(*ptr); } - + template using use_cells = std::integral_constant::use_cells>; }; public: MatlabParamParser() {}; @@ -125,7 +166,8 @@ class MatlabParamParser template static typename std::enable_if::value, std::vector>::type parse_array(const mxArray* cells); template static typename std::enable_if::value, std::vector>::type parse_array(const mxArray* cells); - template static typename std::enable_if::value, mxArray*>::type wrap_array(const T* var, size_t length); + template static typename std::enable_if::value && !traits_trampoline::use_cells::value, mxArray*>::type wrap_array(const T* var, size_t length); + template static typename std::enable_if::value && traits_trampoline::use_cells::value, mxArray*>::type wrap_array(const T* var, size_t length); template static typename std::enable_if::value, mxArray*>::type wrap_array(const T* var, size_t length); }; @@ -264,8 +306,8 @@ template static typename std::enable_if::value, st } return ret; } - -template static typename std::enable_if::value, mxArray*>::type MatlabParamParser::wrap_array(const T* var, size_t length) +template static typename std::enable_if::value && !MatlabParamParser::traits_trampoline::use_cells::value, mxArray*>::type +MatlabParamParser::wrap_array(const T* var, size_t length) { auto cells = mxCreateNumericMatrix(1, length, MatlabParamParser::mx_wrapper::value::value, mxREAL); auto ptr = static_cast::type*>(mxGetData(cells)); @@ -275,6 +317,16 @@ template static typename std::enable_if::value, m return cells; } +template static typename std::enable_if::value && MatlabParamParser::traits_trampoline::use_cells::value, mxArray*>::type +MatlabParamParser::wrap_array(const T* var, size_t length) +{ + auto cells = mxCreateCellMatrix(1, length); + for (int x = 0; x < length; ++x) + mxSetCell(cells, x, wrap(T(var[x]))); + + return cells; +} + template static typename std::enable_if::value, mxArray*>::type MatlabParamParser::wrap_array(const T* var, size_t length) { auto cells = mxCreateNumericMatrix(1, length, MatlabParamParser::mx_wrapper::value::value, mxREAL); diff --git a/wrappers/matlab/align.m b/wrappers/matlab/align.m new file mode 100644 index 0000000000..ffd3b40222 --- /dev/null +++ b/wrappers/matlab/align.m @@ -0,0 +1,32 @@ +% Wraps librealsense2 align class +classdef align < handle + properties (SetAccess = private, Hidden = true) + objectHandle; + end + methods + % Constructor + function this = align(align_to) + narginchk(1, 1); + validateattributes(align_to, {'realsense.stream', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.stream.count}); + this.objectHandle = realsense.librealsense_mex('rs2::align', 'new', int64(align_to)); + end + + % Destructor + function delete(this) + if (this.objectHandle ~= 0) + realsense.librealsense_mex('rs2::align', 'delete', this.objectHandle); + end + end + + % Functions + function frames = process(this, frame) + narginchk(2, 2); + validateattributes(frame, {'realsense.frame'}, {'scalar'}, '', 'frame', 2); + if ~frame.is('frameset') + error('Expected input number 2, frame, to be a frameset'); + end + out = realsense.librealsense_mex('rs2::align', 'process', this.objectHandle, frame.objectHandle); + frames = realsense.frame(out); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/colorizer.m b/wrappers/matlab/colorizer.m new file mode 100644 index 0000000000..bc4ed97fba --- /dev/null +++ b/wrappers/matlab/colorizer.m @@ -0,0 +1,23 @@ +% Wraps librealsense2 colorizer class +classdef colorizer < realsense.options + methods + % Constructor + function this = colorizer() + out = realsense.librealsense_mex('rs2::colorizer', 'new'); + this = this@realsense.options(out); + end + + % Destructor (uses base class destructor) + + % Functions + function video_frame = colorize(this, depth) + narginchk(2, 2) + validateattributes(depth, {'realsense.frame'}, {'scalar'}, '', 'depth', 2); + if ~depth.is('depth_frame') + error('Expected input number 2, depth, to be a depth_frame'); + end + out = realsense.librealsense_mex('rs2::colorizer', 'colorize', this.objectHandle, depth.objectHandle); + video_frame = realsense.video_frame(out); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/config.m b/wrappers/matlab/config.m new file mode 100644 index 0000000000..f0c965e0ac --- /dev/null +++ b/wrappers/matlab/config.m @@ -0,0 +1,127 @@ +% Wraps librealsense2 config class +classdef config < handle + properties (SetAccess = private, Hidden = true) + objectHandle; + end + methods + % Constructor + function this = pipeline_profile() + this.objectHandle = realsense.librealsense_mex('rs2::config', 'new'); + end + % Destructor + function delete(this) + if (this.objectHandle ~= 0) + realsense.librealsense_mex('rs2::config', 'delete', this.objectHandle); + end + end + + % Functions + function enable_stream(this, varargin) + narginchk(2, 7); + validateattributes(varargin{1}, {'realsense.stream', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.stream.count}, '', 'stream_type', 2); + which = 'none' + switch nargin + case 2 + which = 'enable_stream#stream'; + case 3 + if isa(varargin{2}, 'realsense.format') + validateattributes(varargin{2}, {'realsense.format'}, {'scalar'}, '', 'format', 3); + which = 'enable_stream#format'; + else + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'real', 'integer'}, '', 'stream_index', 3); + which = 'enable_stream#stream'; + end + case 4 + if isa(varargin{2}, 'realsense.format') + validateattributes(varargin{2}, {'realsense.format'}, {'scalar'}, '', 'format', 3); + validateattributes(varargin{3}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'framerate', 4); + which = 'enable_stream#format'; + elseif isa(varargin{3}, 'realsense.format') + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'real', 'integer'}, '', 'stream_index', 3); + validateattributes(varargin{3}, {'realsense.format'}, {'scalar'}, '', 'format', 4); + which = 'enable_stream#extended'; + else + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'width', 3); + validateattributes(varargin{3}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'height', 4); + which = 'enable_stream#size'; + end + case 5 + if isa(varargin{3}, 'realsense.format') + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'real', 'integer'}, '', 'stream_index', 3); + validateattributes(varargin{3}, {'realsense.format'}, {'scalar'}, '', 'format', 4); + validateattributes(varargin{4}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'framerate', 5); + which = 'enable_stream#extended'; + elseif isa(varargin{4}, 'realsense.format') + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'width', 3); + validateattributes(varargin{3}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'height', 4); + validateattributes(varargin{4}, {'realsense.format'}, {'scalar'}, '', 'format', 5); + which = 'enable_stream#size'; + else + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'real', 'integer'}, '', 'stream_index', 3); + validateattributes(varargin{3}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'width', 4); + validateattributes(varargin{4}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'height', 5); + which = 'enable_stream#full'; + end + case 6 + if isa(varargin{4}, 'realsense.format') + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'width', 3); + validateattributes(varargin{3}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'height', 4); + validateattributes(varargin{4}, {'realsense.format'}, {'scalar'}, '', 'format', 5); + validateattributes(varargin{5}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'framerate', 6); + which = 'enable_stream#size'; + else + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'real', 'integer'}, '', 'stream_index', 3); + validateattributes(varargin{3}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'width', 4); + validateattributes(varargin{4}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'height', 5); + validateattributes(varargin{5}, {'realsense.format', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.format.count}, '', 'format', 6); + which = 'enable_stream#full'; + end + case 7 + validateattributes(varargin{2}, {'numeric'}, {'scalar', 'real', 'integer'}, '', 'stream_index', 3); + validateattributes(varargin{3}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'width', 4); + validateattributes(varargin{4}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'height', 5); + validateattributes(varargin{5}, {'realsense.format', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.format.count}, '', 'format', 6); + validateattributes(varargin{6}, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'framerate', 7); + end + args = num2cell(int64([varargin{:}])); + realsense.librealsense_mex('rs2::config', which, this.objectHandle, args{:}); + end + function enable_all_streams(this) + realsense.librealsense_mex('rs2::config', 'enable_all_streams', this.objectHandle); + end + function enable_device(this, serial) + narginchk(2, 2); + validateattributes(serial, {'char', 'string'}, {'scalartext'}, '', 'serial', 2); + realsense.librealsense_mex('rs2::config', 'enable_device', this.objectHandle, serial); + end + function enable_device_from_file(this, file_name, repeat_playback) + narginchk(2, 3); + validateattributes(file_name, {'char', 'string'}, {'scalartext'}, '', 'file_name', 2); + if nargin==2: + realsense.librealsense_mex('rs2::config', 'enable_device_from_file', this.objectHandle, file_name); + else + validateattributes(repeat_playback, {'logical', 'numeric'}, {'scalar', 'real'}, '', 'repeat_playback', 3); + realsense.librealsense_mex('rs2::config', 'enable_device_from_file', this.objectHandle, file_name, logical(repeat_playback)); + end + end + function enable_record_to_file(this, serialv) + narginchk(2, 2); + validateattributes(file_name, {'char', 'string'}, {'scalartext'}, '', 'file_name', 2); + realsense.librealsense_mex('rs2::config', 'enable_record_to_file', this.objectHandle, file_name); + end + function disable_stream(this, stream, index) + narginchk(2, 3); + validateattributes(stream, {'realsense.stream', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.stream.count}, '', 'stream', 2); + if nargin == 2 + out = realsense.librealsense_mex('rs2::config', 'disable_stream', this.objectHandle, int64(stream)); + else + validateattributes(index, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'index', 3); + out = realsense.librealsense_mex('rs2::config', 'disable_stream', this.objectHandle, int64(stream), int64(index)); + end + stream = realsense.stream_profile(out{:}); + end + function disable_all_streams(this) + realsense.librealsense_mex('rs2::config', 'disable_all_streams', this.objectHandle); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/context.m b/wrappers/matlab/context.m index 52da06d360..f35f85e326 100644 --- a/wrappers/matlab/context.m +++ b/wrappers/matlab/context.m @@ -19,24 +19,28 @@ function delete(this) % Functions function device_array = query_devices(this) arr = realsense.librealsense_mex('rs2::context', 'query_devices', this.objectHandle); - device_array = arrayfun(@realsense.device, arr(:,1), arr(:,2), 'UniformOutput', false); + % TODO: Might be cell array + device_array = arrayfun(@(x) realsense.device(x{:}{:}), arr, 'UniformOutput', false); end function sensor_array = query_all_sensors(this) arr = realsense.librealsense_mex('rs2::context', 'query_all_sensors', this.objectHandle); sensor_array = arrayfun(@realsense.sensor, arr, 'UniformOutput', false); end function device = get_sensor_parent(this, sensor) - if (isa(sensor, 'sensor')) - device = realsense.device(realsense.librealsense_mex('rs2::context', 'get_sensor_parent', this.objectHandle, sensor.objectHandle)); - else - error('sensor must be a sensor'); - end + narginchk(2, 2); + validateattributes(sensor, {'realsense.sensor'}, {'scalar'}, '', 'sensor', 2); + out = realsense.librealsense_mex('rs2::context', 'get_sensor_parent', this.objectHandle, sensor.objectHandle); + device = realsense.device(out); end function playback = load_device(this, file) - % TODO: finalize once playback is wrapped - playback = realsense.playback(realsense.librealsense_mex('rs2::context', 'load_device', this.objectHandle, file)); + narginchk(2, 2); + validateattributes(file, {'string', 'char'}, {'scalartext', 'nonempty'}, '', 'file', 2); + out = realsense.librealsense_mex('rs2::context', 'load_device', this.objectHandle, file); + playback = realsense.playback(out(1), out(2)); end function unload_device(this, file) + narginchk(2, 2); + validateattributes(file, {'string', 'char'}, {'scalartext', 'nonempty'}, '', 'file', 2); realsense.librealsense_mex('rs2::context', 'unload_device', this.objectHandle, file); end end diff --git a/wrappers/matlab/decimation_filter.m b/wrappers/matlab/decimation_filter.m new file mode 100644 index 0000000000..f48264c985 --- /dev/null +++ b/wrappers/matlab/decimation_filter.m @@ -0,0 +1,14 @@ +% Wraps librealsense2 decimation_filter class +classdef decimation_filter < realsense.process_interface + methods + % Constructor + function this = decimation_filter() + out = realsense.librealsense_mex('rs2::decimation_filter', 'new'); + this = this@realsense.process_interface(out); + end + + % Destructor (uses base class destructor) + + % Functions + end +end \ No newline at end of file diff --git a/wrappers/matlab/depth_sensor.m b/wrappers/matlab/depth_sensor.m index cee4c9eb2e..67cc5968f2 100644 --- a/wrappers/matlab/depth_sensor.m +++ b/wrappers/matlab/depth_sensor.m @@ -3,7 +3,7 @@ methods % Constructor function this = depth_sensor(handle) - this = this@realsense.sensor(handle); + this = this@realsense.sensor(handle); end % Destructor (uses base class destructor) diff --git a/wrappers/matlab/depth_stereo_sensor.m b/wrappers/matlab/depth_stereo_sensor.m index c5a0eede42..2533798d73 100644 --- a/wrappers/matlab/depth_stereo_sensor.m +++ b/wrappers/matlab/depth_stereo_sensor.m @@ -3,7 +3,7 @@ methods % Constructor function this = depth_stereo_sensor(handle) - this = this@realsense.depth_sensor(handle); + this = this@realsense.depth_sensor(handle); end % Destructor (uses base class destructor) diff --git a/wrappers/matlab/device.m b/wrappers/matlab/device.m index 8f074cebb0..8af20bd6d8 100644 --- a/wrappers/matlab/device.m +++ b/wrappers/matlab/device.m @@ -4,7 +4,7 @@ objectHandle; id; end - methods (Access = private) + methods (Access = protected) function do_init(this) if (this.id >= 0) this.objectHandle = realsense.librealsense_mex('rs2::device', 'init', this.objectHandle, this.id); @@ -56,7 +56,7 @@ function delete(this) this.do_init(); value = realsense.librealsense_mex('rs2::device', 'supports', this.objectHandle, int64(info)); end - function value = get_info(this, info) + function info = get_info(this, info) narginchk(2, 2); validateattributes(info, {'realsense.camera_info', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.camera_info.count}, '', 'info', 2); this.do_init(); @@ -72,19 +72,26 @@ function hardware_reset(this) validateattributes(type, {'char', 'string'}, {'scalartext'}, '', 'type', 2); this.do_init(); out = realsense.librealsense_mex('rs2::device', 'is', this.objectHandle, type); + value = logical(out); + end + function dev = as(this, type) + narginchk(2, 2); + % C++ function validates contents of type + validateattributes(type, {'char', 'string'}, {'scalartext'}, '', 'type', 2); + this.do_init(); + out = realsense.librealsense_mex('rs2::device', 'as', this.objectHandle, type); + switch type + case 'device' + dev = realsense.device(out{:}); + case 'debug_protocol' + error('debug_protocol is not supported in Matlab'); + case 'advanced_mode' + error('advanced_mode is not supported in Matlab'); + case 'recorder' + dev = realsense.recorder(out{:}); + case 'playback' + dev = realsense.playback(out{:}); + end end -% function dev = as(this, type) -% % validation and initialization done in is -% if ~this.is(type) -% error('cannot downcast dev to requested type'); -% end -% switch type -% case 'debug_protocol' -% case 'advanced_mode' -% case 'recorder' -% realsense.recorder(this) -% case 'playback' -% end -% end end end diff --git a/wrappers/matlab/device_hub.m b/wrappers/matlab/device_hub.m index b971a61e2d..15b84532a7 100644 --- a/wrappers/matlab/device_hub.m +++ b/wrappers/matlab/device_hub.m @@ -6,6 +6,8 @@ methods % Constructor function this = device_hub(context) + narginchk(1, 1); + validateattributes(context, {'realsense.context'}, {'scalar'}); this.objectHandle = realsense.librealsense_mex('rs2::device_hub', 'new', context.objectHandle); end % Destructor @@ -17,9 +19,12 @@ function delete(this) % Functions function device = wait_for_device(this) - device = realsense.device(realsense.librealsense_mex('rs2::device_hub', 'wait_for_device', this.objectHandle)); + out = realsense.librealsense_mex('rs2::device_hub', 'wait_for_device', this.objectHandle) + device = realsense.device(out(1), out(2)); end function value = is_connected(this, dev) + narginchk(2, 2); + validateattributes(dev, {'realsense.device'}, {'scalar'}, '', 'dev', 2); value = realsense.librealsense_mex('rs2::device_hub', 'is_connected', this.objectHandle, dev.objectHandle); end end diff --git a/wrappers/matlab/disparity_transform.m b/wrappers/matlab/disparity_transform.m new file mode 100644 index 0000000000..0d1b1844d5 --- /dev/null +++ b/wrappers/matlab/disparity_transform.m @@ -0,0 +1,18 @@ +% Wraps librealsense2 disparity_transform class +classdef disparity_transform < realsense.process_interface + methods + % Constructor + function this = disparity_transform(transform_to_disparity) + if nargin == 0 + out = realsense.librealsense_mex('rs2::disparity_transform', 'new'); + else + validateattributes(transform_to_disparity, {'logical', 'numeric'}, {'scalar', 'real'}); + out = realsense.librealsense_mex('rs2::disparity_transform', 'new', logical(transform_to_disparity)); + this = this@realsense.process_interface(out); + end + + % Destructor (uses base class destructor) + + % Functions + end +end \ No newline at end of file diff --git a/wrappers/matlab/example1.m b/wrappers/matlab/example1.m index 421859e2f9..1798f82b70 100644 --- a/wrappers/matlab/example1.m +++ b/wrappers/matlab/example1.m @@ -1,21 +1,31 @@ function example1() % Make Pipeline object pipe = realsense.pipeline(); - % Start recording on arbitrary camera with default settings - pipe.start(); + + % Start streaming on an arbitrary camera with default settings + profile = pipe.start(); + + % Get streaming device's name + dev = profile.get_device(); + name = dev.get_info(realsense.camera_info.name); % Get a frameset fs = pipe.wait_for_frames(); + + % Stop streaming + pipe.stop(); + % Select depth frame depth = fs.get_depth_frame(); % get actual data data = depth.get_data(); - % data is given as byte vector. convert into a matrix of uint16s - rawimg = vec2mat(typecast(data, 'uint16'), depth.get_width()); + % data is returned by the wrapper as an unsigned byte vector. + % Here we convert it into a matrix of uint16s + rawimg = vec2mat(data, depth.get_width()); - % convert to greyscale image + % convert to greyscale image and display img = mat2gray(rawimg, [0 double(max(rawimg(:)))]); imshow(img); - pipe.stop(); + title(sprintf("Depth frame from %s", name)); end \ No newline at end of file diff --git a/wrappers/matlab/format.m b/wrappers/matlab/format.m index c18925abaa..55ac4324ec 100644 --- a/wrappers/matlab/format.m +++ b/wrappers/matlab/format.m @@ -1,6 +1,6 @@ classdef format < int64 enumeration - any ( 0) + any_format ( 0) z16 ( 1) disparity16 ( 2) xyz32f ( 3) diff --git a/wrappers/matlab/frame.m b/wrappers/matlab/frame.m index 21a0286e5d..b6afe3cb6d 100644 --- a/wrappers/matlab/frame.m +++ b/wrappers/matlab/frame.m @@ -43,8 +43,7 @@ function delete(this) end function profile = get_profile(this) ret = realsense.librealsense_mex('rs2::frame', 'get_profile', this.objectHandle); - % TODO: stream_profile takes two args - profile = realsense.stream_profile(ret); + profile = realsense.stream_profile(ret{:}); end % TODO: is [frame, video_frame, points, depth_frame, disparity_frame, motion_frame, pose_frame, frameset] % TODO: as [frame, video_frame, points, depth_frame, disparity_frame, motion_frame, pose_frame, frameset] diff --git a/wrappers/matlab/frame_queue.m b/wrappers/matlab/frame_queue.m new file mode 100644 index 0000000000..b85dc58813 --- /dev/null +++ b/wrappers/matlab/frame_queue.m @@ -0,0 +1,43 @@ +% Wraps librealsense2 frame_queue class +classdef frame_queue < handle + properties (SetAccess = private, Hidden = true) + objectHandle; + end + methods + % Constructor + function this = frame_queue(capacity) + if nargin == 0 + this.objectHandle = realsense.librealsense_mex('rs2::frame_queue', 'new'); + else + validateattributes(capacity, {'numeric'}, {'scalar', 'positive', 'real', 'integer'}); + this.objectHandle = realsense.librealsense_mex('rs2::frame_queue', 'new', uint64(capacity)); + end + end + + % Destructor + function delete(this) + if (this.objectHandle ~= 0) + realsense.librealsense_mex('rs2::frame_queue', 'delete', this.objectHandle); + end + end + + % Functions + function frame = wait_for_frame(this, timeout_ms) + narginchk(1, 2); + if nargin == 1 + out = realsense.librealsense_mex('rs2::frame_queue', 'wait_for_frame', this.objectHandle); + else + if isduration(timeout_ms) + timeout_ms = milliseconds(timeout_ms); + end + validateattributes(timeout_ms, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'timeout_ms', 2); + out = realsense.librealsense_mex('rs2::frame_queue', 'wait_for_frame', this.objectHandle, double(timeout_ms)); + end + frame = realsense.frame(out); + end + % TODO: poll_for_frame [frame, video_frame, points, depth_frame, disparity_frame, motion_frame, pose_frame, frameset] + function cap = capacity(this) + cap = realsense.librealsense_mex('rs2::frame_queue', 'capacity', this.objectHandle); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/frameset.m b/wrappers/matlab/frameset.m index 008509074b..d3d8037056 100644 --- a/wrappers/matlab/frameset.m +++ b/wrappers/matlab/frameset.m @@ -32,7 +32,7 @@ function infrared_frame = get_infrared_frame(this) ret = realsense.librealsense_mex('rs2::frameset', 'get_infrared_frame', this.objectHandle); infrared_frame = realsense.video_frame(ret); - enda + end function size = get_size(this) size = realsense.librealsense_mex('rs2::frameset', 'get_size', this.objectHandle); end diff --git a/wrappers/matlab/hole_filling_filter.m b/wrappers/matlab/hole_filling_filter.m new file mode 100644 index 0000000000..a888994a74 --- /dev/null +++ b/wrappers/matlab/hole_filling_filter.m @@ -0,0 +1,14 @@ +% Wraps librealsense2 hole_filling_filter class +classdef hole_filling_filter < realsense.process_interface + methods + % Constructor + function this = hole_filling_filter() + out = realsense.librealsense_mex('rs2::hole_filling_filter', 'new'); + this = this@realsense.process_interface(out); + end + + % Destructor (uses base class destructor) + + % Functions + end +end \ No newline at end of file diff --git a/wrappers/matlab/librealsense_mex.cpp b/wrappers/matlab/librealsense_mex.cpp index d0ac4f55c2..d678c0ef54 100644 --- a/wrappers/matlab/librealsense_mex.cpp +++ b/wrappers/matlab/librealsense_mex.cpp @@ -164,22 +164,60 @@ void make_factory(){ { // TODO - What's going on here? / support more formats auto thiz = MatlabParamParser::parse(inv[0]); + size_t n_bytes = 0; if (auto vf = thiz.as()) { - /*switch (vf.get_profile().format()) { - case RS2_FORMAT_RGB8: case RS2_FORMAT_BRG2: - outv[0] = MatlabParamParser::wrap_array(vf.get_data(), ) - }*/ - outv[0] = MatlabParamParser::wrap_array(reinterpret_cast(vf.get_data()), vf.get_height() * vf.get_stride_in_bytes()); - } else { - uint8_t byte = *reinterpret_cast(thiz.get_data()); - outv[0] = MatlabParamParser::wrap(std::move(byte)); - mexWarnMsgTxt("Can't detect frame dims, sending only first byte"); + n_bytes = vf.get_height() * vf.get_stride_in_bytes(); + } + + switch (thiz.get_profile().format()) { + case RS2_FORMAT_RAW10: + // TODO: Do the bit hackery ourselves? + mexWarnMsgTxt("Raw10 data provided as unsigned byte array."); + case RS2_FORMAT_RGB8: case RS2_FORMAT_RGBA8: + case RS2_FORMAT_BGR8: case RS2_FORMAT_BGRA8: + case RS2_FORMAT_Y8: case RS2_FORMAT_RAW8: + if (n_bytes == 0) { + n_bytes = 1; + mexWarnMsgTxt("Can't detect frame dims, sending only first pixel"); + } + outv[0] = MatlabParamParser::wrap_array(reinterpret_cast(thiz.get_data()), n_bytes); + break; + case RS2_FORMAT_Z16: case RS2_FORMAT_DISPARITY16: + case RS2_FORMAT_Y16: case RS2_FORMAT_RAW16: + if (n_bytes == 0) { + n_bytes = 2; + mexWarnMsgTxt("Can't detect frame dims, sending only first pixel"); + } + outv[0] = MatlabParamParser::wrap_array(reinterpret_cast(thiz.get_data()), n_bytes / 2); + break; + case RS2_FORMAT_XYZ32F: case RS2_FORMAT_DISPARITY32: + case RS2_FORMAT_MOTION_XYZ32F: + if (n_bytes == 0) { + n_bytes = 4; + mexWarnMsgTxt("Can't detect frame dims, sending only first pixel"); + } + outv[0] = MatlabParamParser::wrap_array(reinterpret_cast(thiz.get_data()), n_bytes / 4); + break; + case RS2_FORMAT_UYVY: case RS2_FORMAT_YUYV: + if (n_bytes == 0) { + n_bytes = 4; + mexWarnMsgTxt("Can't detect frame dims, sending only first pixel"); + } + outv[0] = MatlabParamParser::wrap_array(reinterpret_cast(thiz.get_data()), n_bytes / 4); + break; + default: + mexWarnMsgTxt("This format isn't supported yet. Sending unsigned byte stream"); + if (n_bytes == 0) { + n_bytes = 1; + mexWarnMsgTxt("Can't detect frame dims, sending only first pixel"); + } + outv[0] = MatlabParamParser::wrap_array(reinterpret_cast(thiz.get_data()), n_bytes); } }); frame_factory.record("get_profile", 1, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { auto thiz = MatlabParamParser::parse(inv[0]); - outv[0] = MatlabParamParser::wrap(thiz.get_frame_number()); + outv[0] = MatlabParamParser::wrap(thiz.get_profile()); }); // rs2::frame::is [TODO] [T = {frame, video_frame, points, depth_frame, disparity_frame, motion_frame, pose_frame, frameset}] // rs2::frame::as [TODO] [T = {frame, video_frame, points, depth_frame, disparity_frame, motion_frame, pose_frame, frameset}] @@ -586,11 +624,35 @@ void make_factory(){ outv[0] = MatlabParamParser::wrap(thiz.is()); else { // TODO: need warn/error message? which? if so, fill in - mexWarnMsgTxt("rs2::device::is: ..."); + mexWarnMsgTxt("rs2::device::is: invalid type parameter"); + outv[0] = MatlabParamParser::wrap(false); + } + }); + device_factory.record("as", 1, 2, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + // TODO: something more maintainable? + auto thiz = MatlabParamParser::parse(inv[0]); + auto type = MatlabParamParser::parse(inv[1]); + if (type == "device") + outv[0] = MatlabParamParser::wrap(thiz.as()); + else if (type == "debug_protocol") { + mexErrMsgTxt("rs2::device::as: Debug Protocol not supported in MATLAB"); +// outv[0] = MatlabParamParser::wrap(thiz.as()); + } + else if (type == "advanced_mode") { + mexErrMsgTxt("rs2::device::as: Advanced Mode not supported in MATLAB"); +// outv[0] = MatlabParamParser::wrap(false); + } + else if (type == "recorder") + outv[0] = MatlabParamParser::wrap(thiz.as()); + else if (type == "playback") + outv[0] = MatlabParamParser::wrap(thiz.as()); + else { + // TODO: need warn/error message? which? if so, fill in + mexWarnMsgTxt("rs2::device::as: invalid type parameter"); outv[0] = MatlabParamParser::wrap(false); } }); - // rs2::device::as [Can't actually be done as pure matlab because matlab is dumb and handle objects don't work the way I want] factory->record(device_factory); } // rs2::debug_protocol [?] @@ -715,7 +777,7 @@ void make_factory(){ } }); // rs2::frame_queue::poll_for_frame(T*) [TODO] [T = {frame, video_frame, points, depth_frame, disparity_frame, motion_frame, pose_frame, frameset}] - frame_queue_factory.record("new", 1, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + frame_queue_factory.record("capacity", 1, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { auto thiz = MatlabParamParser::parse(inv[0]); outv[0] = MatlabParamParser::wrap(thiz.capacity()); @@ -754,6 +816,10 @@ void make_factory(){ outv[0] = MatlabParamParser::wrap(rs2::syncer(queue_size)); } }); + syncer_factory.record("delete", 0, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + MatlabParamParser::destroy(inv[0]); + }); syncer_factory.record("wait_for_frames", 1, 1, 2, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { auto thiz = MatlabParamParser::parse(inv[0]); @@ -775,6 +841,10 @@ void make_factory(){ auto align_to = MatlabParamParser::parse(inv[0]); outv[0] = MatlabParamParser::wrap(rs2::align(align_to)); }); + align_factory.record("delete", 0, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + MatlabParamParser::destroy(inv[0]); + }); align_factory.record("process", 1, 2, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { auto thiz = MatlabParamParser::parse(inv[0]); @@ -927,10 +997,14 @@ void make_factory(){ { ClassFactory pipeline_profile_factory("rs2::pipeline_profile"); // rs2::pipeline_profile::constructor() [?] + pipeline_profile_factory.record("delete", 0, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + MatlabParamParser::destroy(inv[0]); + }); pipeline_profile_factory.record("get_streams", 1, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { auto thiz = MatlabParamParser::parse(inv[0]); - outv[0] = MatlabParamParser::wrap(thiz.get_streams()); // TODO: switch to make_array + outv[0] = MatlabParamParser::wrap(thiz.get_streams()); }); pipeline_profile_factory.record("get_stream", 1, 2, 3, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { @@ -957,11 +1031,81 @@ void make_factory(){ { outv[0] = MatlabParamParser::wrap(rs2::config()); }); - // rs2::config::enable_stream(rs2_stream, int, int, int, rs2_format=DEF, int=DEF) [TODO] - // rs2::config::enable_stream(rs2_stream, int=DEF) [TODO] - // rs2::config::enable_stream(rs2_stream, int, int, rs2_format=DEF, int=DEF) [TODO] - // rs2::config::enable_stream(rs2_stream, rs2_format, int=DEF) [TODO] - // rs2::config::enable_stream(rs2_stream, int, rs2_format, int=DEF) [TODO] + config_factory.record("delete", 0, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + MatlabParamParser::destroy(inv[0]); + }); + config_factory.record("enable_stream#full", 0, 5, 7, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + auto thiz = MatlabParamParser::parse(inv[0]); + auto stream_type = MatlabParamParser::parse(inv[1]); + auto stream_index = MatlabParamParser::parse(inv[2]); + auto width = MatlabParamParser::parse(inv[3]); + auto height = MatlabParamParser::parse(inv[4]); + if (inc == 5) { + thiz.enable_stream(stream_type, stream_index, width, height); + } else if (inc == 6) { + auto format = MatlabParamParser::parse(inv[5]); + thiz.enable_stream(stream_type, stream_index, width, height, format); + } else if (inc == 7) { + auto format = MatlabParamParser::parse(inv[5]); + auto framerate = MatlabParamParser::parse(inv[6]); + thiz.enable_stream(stream_type, stream_index, width, height, format, framerate); + } + }); + config_factory.record("enable_stream#stream", 0, 2, 3, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + auto thiz = MatlabParamParser::parse(inv[0]); + auto stream_type = MatlabParamParser::parse(inv[1]); + if (inc == 2) { + thiz.enable_stream(stream_type); + } else if (inc == 3){ + auto stream_index = MatlabParamParser::parse(inv[2]); + thiz.enable_stream(stream_type, stream_index); + } + }); + config_factory.record("enable_stream#size", 0, 4, 6, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + auto thiz = MatlabParamParser::parse(inv[0]); + auto stream_type = MatlabParamParser::parse(inv[1]); + auto width = MatlabParamParser::parse(inv[2]); + auto height = MatlabParamParser::parse(inv[3]); + if (inc == 4) { + thiz.enable_stream(stream_type, width, height); + } else if (inc == 5) { + auto format = MatlabParamParser::parse(inv[4]); + thiz.enable_stream(stream_type, width, height, format); + } else if (inc == 6) { + auto format = MatlabParamParser::parse(inv[4]); + auto framerate = MatlabParamParser::parse(inv[5]); + thiz.enable_stream(stream_type, width, height, format, framerate); + } + }); + config_factory.record("enable_stream#format", 0, 3, 4, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + auto thiz = MatlabParamParser::parse(inv[0]); + auto stream_type = MatlabParamParser::parse(inv[1]); + auto format = MatlabParamParser::parse(inv[2]); + if (inc == 3) { + thiz.enable_stream(stream_type, format); + } else if (inc == 4) { + auto framerate = MatlabParamParser::parse(inv[3]); + thiz.enable_stream(stream_type, format, framerate); + } + }); + config_factory.record("enable_stream#extended", 0, 4, 5, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + auto thiz = MatlabParamParser::parse(inv[0]); + auto stream_type = MatlabParamParser::parse(inv[1]); + auto stream_index = MatlabParamParser::parse(inv[2]); + auto format = MatlabParamParser::parse(inv[3]); + if (inc == 4) { + thiz.enable_stream(stream_type, stream_index, format); + } else if (inc == 5) { + auto framerate = MatlabParamParser::parse(inv[4]); + thiz.enable_stream(stream_type, stream_index, format, framerate); + } + }); config_factory.record("enable_all_streams", 0, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { auto thiz = MatlabParamParser::parse(inv[0]); @@ -1111,6 +1255,7 @@ void mexFunction(int nOutParams, mxArray *outParams[], int nInParams, const mxAr std::string errmsg = cname + "::" + fname.substr(0, fname.find("#", 0)) + ": Wrong number of inputs"; mexErrMsgTxt(errmsg.c_str()); } + try { f_data.f(nOutParams, outParams, nInParams - 2, inParams + 2); // "eat" the two function specifiers } catch (std::exception &e) { diff --git a/wrappers/matlab/librealsense_mex.vcxproj b/wrappers/matlab/librealsense_mex.vcxproj index 5c0a6ab7ec..2221ffaf7f 100644 --- a/wrappers/matlab/librealsense_mex.vcxproj +++ b/wrappers/matlab/librealsense_mex.vcxproj @@ -162,30 +162,46 @@ + + + + + + + + + + + + + + + + diff --git a/wrappers/matlab/librealsense_mex.vcxproj.filters b/wrappers/matlab/librealsense_mex.vcxproj.filters index 80927081a4..20cd7db935 100644 --- a/wrappers/matlab/librealsense_mex.vcxproj.filters +++ b/wrappers/matlab/librealsense_mex.vcxproj.filters @@ -130,5 +130,53 @@ Matlab Files\Classes + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Enums + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + + + Matlab Files\Classes + \ No newline at end of file diff --git a/wrappers/matlab/options.m b/wrappers/matlab/options.m index b74100e5f4..f53867aad0 100644 --- a/wrappers/matlab/options.m +++ b/wrappers/matlab/options.m @@ -6,6 +6,7 @@ methods % Constructor function this = options(handle) + narginchk(1, 1); validateattributes(handle, {'uint64'}, {'scalar'}); this.objectHandle = handle; end diff --git a/wrappers/matlab/pipeline.m b/wrappers/matlab/pipeline.m index e6cba2c205..f13f9c6928 100644 --- a/wrappers/matlab/pipeline.m +++ b/wrappers/matlab/pipeline.m @@ -6,13 +6,12 @@ methods % Constructor function this = pipeline(ctx) - if (nargin == 0) - ctx = realsense.context(); + if nargin == 0 + this.objectHandle = realsense.librealsense_mex('rs2::pipeline', 'new'); + else + validateattributes(ctx, {'realsense.context'}, {'scalar'}); + this.objectHandle = realsense.librealsense_mex('rs2::pipeline', 'new', ctx.objectHandle); end - if (~isa(ctx, 'realsense.context')) - error('ctx must be of type realsense.context') - end - this.objectHandle = realsense.librealsense_mex('rs2::pipeline', 'new', ctx.objectHandle); end % Destructor function delete(this) @@ -22,32 +21,36 @@ function delete(this) end % Functions - function start(this, config) - % TODO: add output parameter after binding pipeline_profile - switch nargin - case 1 - realsense.librealsense_mex('rs2::pipeline', 'start', this.objectHandle); - case 2 - if (isa(config, 'config')) -% realsense.librealsense_mex('rs2::pipeline', 'start', this.objectHandle, config.objectHandle); - else - % TODO: Error out meaningfully? - return - end + function pipeline_profile = start(this, config) + narginchk(1, 2); + if nargin == 1 + out = realsense.librealsense_mex('rs2::pipeline', 'start', this.objectHandle); + else + validateattributes(config, {'realsense.config'}, {'scalar'}, '', 'config', 2); + out = realsense.librealsense_mex('rs2::pipeline', 'start', this.objectHandle, config.objectHandle); end + pipeline_profile = realsense.pipeline_profile(out); end function stop(this) realsense.librealsense_mex('rs2::pipeline', 'stop', this.objectHandle); end - function frameset = wait_for_frames(this, timeout_ms) - switch nargin - case 1 - frameset = realsense.frameset(realsense.librealsense_mex('rs2::pipeline', 'wait_for_frames', this.objectHandle)); - case 2 - % TODO: is there a good way to do type safety in matlab? - frameset = realsense.frameset(realsense.librealsense_mex('rs2::pipeline', 'wait_for_frames', this.objectHandle, uint64(timeout_ms))); + function frames = wait_for_frames(this, timeout_ms) + narginchk(1, 2); + if nargin == 1 + out = realsense.librealsense_mex('rs2::pipeline', 'wait_for_frames', this.objectHandle); + else + if isduration(timeout_ms) + timeout_ms = milliseconds(timeout_ms); + end + validateattributes(timeout_ms, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'timeout_ms', 2); + out = realsense.librealsense_mex('rs2::pipeline', 'wait_for_frames', this.objectHandle, double(timeout_ms)); end + frames = realsense.frameset(out); + end + % TODO: poll_for_frames + function profile = get_active_profile(this) + out = realsense.librealsense_mex('rs2::pipeline', 'get_active_profile', this.objectHandle); + realsense.pipeline_profile(out); end - % TODO: poll_for_frames, get_active_profile end end \ No newline at end of file diff --git a/wrappers/matlab/pipeline_profile.m b/wrappers/matlab/pipeline_profile.m new file mode 100644 index 0000000000..2acf449ec3 --- /dev/null +++ b/wrappers/matlab/pipeline_profile.m @@ -0,0 +1,42 @@ +% Wraps librealsense2 pipeline_profile class +classdef pipeline_profile < handle + properties (SetAccess = private, Hidden = true) + objectHandle; + end + methods + % Constructor + function this = pipeline_profile(handle) + narginchk(1, 1); + validateattributes(handle, {'uint64'}, {'scalar'}); + this.objectHandle = handle; + end + % Destructor + function delete(this) + if (this.objectHandle ~= 0) + realsense.librealsense_mex('rs2::pipeline_profile', 'delete', this.objectHandle); + end + end + + % Functions + function streams = get_streams(this) + arr = realsense.librealsense_mex('rs2::pipeline_profile', 'get_streams', this.objectHandle); + % TOOD: Might be cell array + streams = arrayfun(@(x) realsense.stream_profile(x{:}{:}), arr, 'UniformOutput', false); + end + function stream = get_stream(this, stream_type, stream_index) + narginchk(2, 3); + validateattributes(stream_type, {'realsense.stream', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.stream.count}, '', 'stream_type', 2); + if nargin == 2 + out = realsense.librealsense_mex('rs2::pipeline_profile', 'get_streams', this.objectHandle, int64(stream_type)); + else + validateattributes(stream_index, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'stream_index', 3); + out = realsense.librealsense_mex('rs2::pipeline_profile', 'get_stream', this.objectHandle, int64(stream_type), int64(stream_index)); + end + stream = realsense.stream_profile(out{:}); + end + function dev = get_device(this) + out = realsense.librealsense_mex('rs2::pipeline_profile', 'get_device', this.objectHandle); + dev = realsense.device(out); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/playback.m b/wrappers/matlab/playback.m new file mode 100644 index 0000000000..e9b4614f15 --- /dev/null +++ b/wrappers/matlab/playback.m @@ -0,0 +1,65 @@ +% Wraps librealsense2 playback class +classdef playback < realsense.device + methods + % Constructor + function this = playback(handle, index) + this = this@realsense.device(handle, index); + end + + % Destructor (uses base class destructor) + + % Functions + function pause(this) + this.do_init(); + realsense.librealsense_mex('rs2::playback', 'pause', this.objectHandle); + end + function resume(this) + this.do_init(); + realsense.librealsense_mex('rs2::playback', 'resume', this.objectHandle); + end + function fname = file_name(this) + this.do_init(); + fname = realsense.librealsense_mex('rs2::playback', 'file_name', this.objectHandle); + end + function pos = get_position(this) + this.do_init(); + pos = realsense.librealsense_mex('rs2::playback', 'get_position', this.objectHandle); + end + function dur = get_duration(this) + this.do_init(); + out = realsense.librealsense_mex('rs2::playback', 'get_duration', this.objectHandle); + dur = milliseconds(out); + end + function seek(this, time) + narginchk(2, 2); + validateattributes(time, {'duration'}, {'scalar', 'nonnegative'}, '', 'time', 2); + this.do_init(); + realsense.librealsense_mex('rs2::playback', 'seek', this.objectHandle, milliseconds(time)); + end + function value = is_real_time(this) + this.do_init(); + value = realsense.librealsense_mex('rs2::playback', 'is_real_time', this.objectHandle); + end + function set_real_time(this, real_time) + narginchk(2, 2); + validateattributes(real_time, {'logical', 'numeric'}, {'scalar', 'real'}, '', 'real_time', 2); + this.do_init(); + realsense.librealsense_mex('rs2::playback', 'set_real_time', this.objectHandle, logical(real_time)); + end + function set_playback_speed(this, speed) + narginchk(2, 2); + validateattributes(speed, {'numeric'}, {'scalar', 'real'}, '', 'speed', 2); + this.do_init(); + realsense.librealsense_mex('rs2::playback', 'set_playback_speed', this.objectHandle, double(speed)); + end + function status = current_status(this) + this.do_init(); + out = realsense.librealsense_mex('rs2::playback', 'current_status', this.objectHandle); + status = realsense.playback_status(out); + end + function current_status(this) + this.do_init(); + realsense.librealsense_mex('rs2::playback', 'stop', this.objectHandle); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/playback_status.m b/wrappers/matlab/playback_status.m new file mode 100644 index 0000000000..627af3f58a --- /dev/null +++ b/wrappers/matlab/playback_status.m @@ -0,0 +1,9 @@ +classdef playback_status < int64 + enumeration + unknown (0) + playing (1) + paused (2) + stopped (3) + count (4) + end +end \ No newline at end of file diff --git a/wrappers/matlab/pointcloud.m b/wrappers/matlab/pointcloud.m new file mode 100644 index 0000000000..508d26649e --- /dev/null +++ b/wrappers/matlab/pointcloud.m @@ -0,0 +1,28 @@ +% Wraps librealsense2 pointcloud class +classdef pointcloud < realsense.options + methods + % Constructor + function this = pointcloud() + out = realsense.librealsense_mex('rs2::pointcloud', 'new'); + this = this@realsense.options(out); + end + + % Destructor (uses base class destructor) + + % Functions + function points = calculate(this, depth) + narginchk(2, 2) + validateattributes(depth, {'realsense.frame'}, {'scalar'}, '', 'depth', 2); + if ~depth.is('depth_frame') + error('Expected input number 2, depth, to be a depth_frame'); + end + out = realsense.librealsense_mex('rs2::pointcloud', 'calculate', this.objectHandle, depth.objectHandle); + points = realsense.points(out); + end + function map_to(this, mapped) + narginchk(2, 2) + validateattributes(mapped, {'realsense.frame'}, {'scalar'}, '', 'mapped', 2); + realsense.librealsense_mex('rs2::pointcloud', 'map_to', this.objectHandle, mapped.objectHandle); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/process_interface.m b/wrappers/matlab/process_interface.m new file mode 100644 index 0000000000..0ba9e589b2 --- /dev/null +++ b/wrappers/matlab/process_interface.m @@ -0,0 +1,19 @@ +% Wraps librealsense2 process_interface class +classdef process_interface < realsense.options + methods + % Constructor + function this = process_interface(handle) + this = this@realsense.options(handle); + end + + % Destructor (uses base class destructor) + + % Functions + function value = process(this, frame) + narginchk(2, 2) + validateattributes(frame, {'realsense.frame'}, {'scalar'}, '', 'frame', 2); + out = realsense.librealsense_mex('rs2::process_interface', 'process', this.objectHandle, frame.objectHandle); + value = realsense.frame(out); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/recorder.m b/wrappers/matlab/recorder.m new file mode 100644 index 0000000000..34405687ab --- /dev/null +++ b/wrappers/matlab/recorder.m @@ -0,0 +1,33 @@ +% Wraps librealsense2 recorder class +classdef recorder < realsense.device + methods + % Constructor + function this = recorder(device, other) + narginchk(2, 2); + validateattributes(device, {'uint64', 'realsense.device'}, 'scalar'); + if isa(device, 'realsense.device') + validateattributes(other, {'string', 'char'}, {'scalartext', 'nonempty'}); + out = realsense.librealsense_mex('rs2::recorder', 'new#string_device', other, device.objectHandle); + this = this@realsense.device(out{:}); + else + this = this@realsense.device(handle, other); + end + end + + % Destructor (uses base class destructor) + + % Functions + function pause(this) + this.do_init(); + realsense.librealsense_mex('rs2::recorder', 'pause', this.objectHandle); + end + function resume(this) + this.do_init(); + realsense.librealsense_mex('rs2::recorder', 'resume', this.objectHandle); + end + function fname = filename(this) + this.do_init(); + fname = realsense.librealsense_mex('rs2::recorder', 'filename', this.objectHandle); + end + end +end \ No newline at end of file diff --git a/wrappers/matlab/roi_sensor.m b/wrappers/matlab/roi_sensor.m index 45465de372..864b03fd9c 100644 --- a/wrappers/matlab/roi_sensor.m +++ b/wrappers/matlab/roi_sensor.m @@ -3,7 +3,7 @@ methods % Constructor function this = roi_sensor(handle) - this = this@realsense.sensor(handle); + this = this@realsense.sensor(handle); end % Destructor (uses base class destructor) diff --git a/wrappers/matlab/rs2_type_traits.h b/wrappers/matlab/rs2_type_traits.h index 7665a79578..60a81f5db3 100644 --- a/wrappers/matlab/rs2_type_traits.h +++ b/wrappers/matlab/rs2_type_traits.h @@ -14,6 +14,7 @@ template using extra_checks = std::bool_constant struct MatlabParamParser::type_traits::value>::type> { using rs2_internal_t = const rs2_stream_profile*; + using use_cells = std::true_type; static T from_internal(rs2_internal_t * ptr) { return T(rs2::stream_profile(*ptr)); } }; template struct MatlabParamParser::type_traits::value>::type> { using rs2_internal_t = rs2_frame * ; }; @@ -42,7 +43,10 @@ template struct MatlabParamParser::type_traits struct MatlabParamParser::type_traits { using rs2_internal_t = std::shared_ptr; }; -template<> struct MatlabParamParser::type_traits { using rs2_internal_t = std::shared_ptr; }; +template<> struct MatlabParamParser::type_traits { + using rs2_internal_t = std::shared_ptr; + using use_cells = std::true_type; +}; // rs_record_playback.hpp template<> struct MatlabParamParser::type_traits : MatlabParamParser::type_traits { diff --git a/wrappers/matlab/sensor.m b/wrappers/matlab/sensor.m index 7413904eca..14b0e8b099 100644 --- a/wrappers/matlab/sensor.m +++ b/wrappers/matlab/sensor.m @@ -3,7 +3,7 @@ methods % Constructor function this = sensor(handle) - this = this@realsense.options(handle); + this = this@realsense.options(handle); end % Destructor (uses base class destructor) @@ -36,7 +36,9 @@ function stop(this) realsense.librealsense_mex('rs2::sensor', 'stop', this.objectHandle); end function profiles = get_stream_profiles(this) - profiles = realsense.librealsense_mex('rs2::sensor', 'get_stream_profiles', this.objectHandle); + arr = realsense.librealsense_mex('rs2::sensor', 'get_stream_profiles', this.objectHandle); + % TODO: Might be cell array + profiles = arrayfun(@(x) realsense.stream_profile(x{:}{:}), arr, 'UniformOutput', false); end % TODO: is [sensor, roi_sensor, depth_sensor, depth_stereo_sensor] % TODO: as [sensor, roi_sensor, depth_sensor, depth_stereo_sensor] diff --git a/wrappers/matlab/spatial_filter.m b/wrappers/matlab/spatial_filter.m new file mode 100644 index 0000000000..3149089312 --- /dev/null +++ b/wrappers/matlab/spatial_filter.m @@ -0,0 +1,14 @@ +% Wraps librealsense2 spatial_filter class +classdef spatial_filter < realsense.process_interface + methods + % Constructor + function this = spatial_filter() + out = realsense.librealsense_mex('rs2::spatial_filter', 'new'); + this = this@realsense.process_interface(out); + end + + % Destructor (uses base class destructor) + + % Functions + end +end \ No newline at end of file diff --git a/wrappers/matlab/stream.m b/wrappers/matlab/stream.m index 401489654a..08aa5f0f06 100644 --- a/wrappers/matlab/stream.m +++ b/wrappers/matlab/stream.m @@ -1,6 +1,6 @@ classdef stream < int64 enumeration - any ( 0) + any_stream ( 0) depth ( 1) color ( 2) infrared ( 3) diff --git a/wrappers/matlab/stream_profile.m b/wrappers/matlab/stream_profile.m index dbc59a8003..dcbbe4077c 100644 --- a/wrappers/matlab/stream_profile.m +++ b/wrappers/matlab/stream_profile.m @@ -6,12 +6,12 @@ end methods % Constructor - function this = stream_profile(ownHandle, handle) + function this = stream_profile(handle, ownHandle) narginchk(2, 2); - validateattributes(ownHandle, {'uint64'}, {'scalar'}); validateattributes(handle, {'uint64'}, {'scalar'}); - this.objectOwnHandle = ownHandle; + validateattributes(ownHandle, {'uint64'}, {'scalar'}); this.objectHandle = handle; + this.objectOwnHandle = ownHandle; end % Destructor function delete(this) @@ -42,8 +42,7 @@ function delete(this) validateattributes(index, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'index', 3); validateattributes(fmt, {'realsense.format', 'numeric'}, {'scalar', 'nonnegative', 'real', 'integer', '<=', realsense.format.count}, '', 'fmt', 4); out = realsense.librealsense_mex('rs2::stream_profile', 'clone', this.objectHandle, int64(type), int64(index), int64(fmt)); - % TODO: stream_profile gets two args - realsense.stream_profile(out); + realsense.stream_profile(out{:}); end % TODO: is [stream_profile, video_stream_profile, motion_stream_profile] % TODO: as [stream_profile, video_stream_profile, motion_stream_profile] diff --git a/wrappers/matlab/syncer.m b/wrappers/matlab/syncer.m new file mode 100644 index 0000000000..af0fa3f827 --- /dev/null +++ b/wrappers/matlab/syncer.m @@ -0,0 +1,37 @@ +% Wraps librealsense2 syncer class +classdef syncer < handle + properties (SetAccess = private, Hidden = true) + objectHandle; + end + methods + % Constructor + function this = syncer(queue_size) + if nargin == 0 + this.objectHandle = realsense.librealsense_mex('rs2::syncer', 'new'); + else + validateattributes(queue_size, {'numeric'}, {'scalar', 'positive', 'real', 'integer'}); + this.objectHandle = realsense.librealsense_mex('rs2::syncer', 'new', uint64(queue_size)); + end + end + + % Destructor + function delete(this) + if (this.objectHandle ~= 0) + realsense.librealsense_mex('rs2::syncer', 'delete', this.objectHandle); + end + end + + % Functions + function frames = wait_for_frames(this, timeout_ms) + narginchk(1, 2); + if nargin == 1 + out = realsense.librealsense_mex('rs2::syncer', 'wait_for_frames', this.objectHandle); + else + if isduration(timeout_ms) + timeout_ms = milliseconds(timeout_ms); + end + validateattributes(timeout_ms, {'numeric'}, {'scalar', 'nonnegative', 'real', 'integer'}, '', 'timeout_ms', 2); + out = realsense.librealsense_mex('rs2::syncer', 'wait_for_frames', this.objectHandle, double(timeout_ms)); + end + frames = realsense.frameset(out); + end \ No newline at end of file diff --git a/wrappers/matlab/temporal_filter.m b/wrappers/matlab/temporal_filter.m new file mode 100644 index 0000000000..cd53c35364 --- /dev/null +++ b/wrappers/matlab/temporal_filter.m @@ -0,0 +1,14 @@ +% Wraps librealsense2 temporal_filter class +classdef temporal_filter < realsense.process_interface + methods + % Constructor + function this = temporal_filter() + out = realsense.librealsense_mex('rs2::temporal_filter', 'new'); + this = this@realsense.process_interface(out); + end + + % Destructor (uses base class destructor) + + % Functions + end +end \ No newline at end of file diff --git a/wrappers/matlab/types.h b/wrappers/matlab/types.h index 13f895efd0..7122734205 100644 --- a/wrappers/matlab/types.h +++ b/wrappers/matlab/types.h @@ -121,14 +121,20 @@ template<> static mxArray* MatlabParamParser::mx_wrapper_fns:: // Device list is sent as a native array of (ptr, id) pairs to preserve lazy instantiation of devices size_t len = var.size(); - mxArray* vec = mxCreateNumericMatrix(len, 2, mxUINT64_CLASS, mxREAL); - uint64_t* outp = static_cast(mxGetData(vec)); - - for (int i = 0; i < len; ++i) + mxArray* vec = mxCreateCellMatrix(1, len); + for (unsigned int i = 0; i < len; ++i) { + using dl_wrap_t = mx_wrapper; + using idx_wrap_t = mx_wrapper; + auto cells = mxCreateCellMatrix(1, 2); + auto dl_cell = mxCreateNumericMatrix(1, 1, dl_wrap_t::value::value, mxREAL); mexLock(); // lock once for each created pointer - outp[0 * len + i] = reinterpret_cast(new type_traits::rs2_internal_t(var)); - outp[1 * len + i] = i; + *static_cast(mxGetData(dl_cell)) = reinterpret_cast(new type_traits::rs2_internal_t(var)); + auto idx_cell = mxCreateNumericMatrix(1, 1, idx_wrap_t::value::value, mxREAL); + *static_cast(mxGetData(idx_cell)) = static_cast(i); + mxSetCell(cells, 0, dl_cell); + mxSetCell(cells, 1, dl_cell); + mxSetCell(vec, i, cells); } return vec; @@ -147,21 +153,29 @@ template struct MatlabParamParser::mx_wrapper_fns(mxGetData(cells)); + auto cells = mxCreateCellMatrix(1, 2); + auto handle_cell = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); + auto handle_ptr = static_cast(mxGetData(cells)); + *handle_ptr = reinterpret_cast(type_traits::rs2_internal_t(val)); + + auto own_cell = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); + auto own_ptr = static_cast(mxGetData(cells)); // if its cloned, give the wrapper ownership of the stream_profile if (val.is_cloned()) { mexLock(); - outp[0] = reinterpret_cast(new std::shared_ptr(val)); + *own_ptr = reinterpret_cast(new std::shared_ptr(val)); } - else outp[0] = reinterpret_cast(nullptr); + else *own_ptr = reinterpret_cast(nullptr); - outp[1] = reinterpret_cast(type_traits::rs2_internal_t(val)); + mxSetCell(cells, 0, handle_cell); + mxSetCell(cells, 1, own_cell); return cells; } static void destroy(const mxArray* cell) { + // we parse a std::shard_ptr* because that is how the ownership + // pointer is stored, which is the one we need to destroy (assuming it exists) auto ptr = mx_wrapper_fns*>::parse(cell); if (!ptr) return; // only destroy if wrapper owns the profile delete ptr;