Skip to content

Commit

Permalink
Merge pull request IntelRealSense#1062 from tingshao/add_disparity
Browse files Browse the repository at this point in the history
[Node.js] Add disparity frame support
  • Loading branch information
Halton Huo authored Jan 25, 2018
2 parents 87f93c7 + 0c77285 commit 239a518
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 11 deletions.
5 changes: 4 additions & 1 deletion wrappers/nodejs/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
"header"
],
"rules": {
"header/header": [2, "tools/header.js"],
"header/header": [2, "line",
[{"pattern": "^ Copyright \\(c\\) 201\\d Intel Corporation\\. All rights reserved\\.$"},
{"pattern": "^ Use of this source code is governed by an Apache 2\\.0 license$"},
{"pattern": "^ that can be found in the LICENSE file\\.$"}]],
"max-len": ["error", 100, 2, { "ignoreUrls": true }],
"quotes": ["error", "single"],
"require-jsdoc": ["error", {
Expand Down
76 changes: 72 additions & 4 deletions wrappers/nodejs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -702,12 +702,16 @@ class Sensor extends Options {
this.frame = new Frame();
this.depthFrame = new DepthFrame();
this.videoFrame = new VideoFrame();
this.disparityFrame = new DisparityFrame();

let inst = this;
this.cxxSensor.frameCallback = function() {
// When the callback is triggered, the underlying frame bas been saved in the objects
// created above, we need to update it and callback.
if (inst.depthFrame.isValid) {
if (inst.disparityFrame.isValid) {
inst.disparityFrame.updateProfile();
callback(inst.disparityFrame);
} else if (inst.depthFrame.isValid) {
inst.depthFrame.updateProfile();
callback(inst.depthFrame);
} else if (inst.videoFrame.isValid) {
Expand All @@ -719,7 +723,7 @@ class Sensor extends Options {
}
};
this.cxxSensor.startWithCallback('frameCallback', this.frame.cxxFrame,
this.depthFrame.cxxFrame, this.videoFrame.cxxFrame);
this.depthFrame.cxxFrame, this.videoFrame.cxxFrame, this.disparityFrame.cxxFrame);
}
}

Expand Down Expand Up @@ -1942,6 +1946,23 @@ class DepthFrame extends VideoFrame {
}
}

/**
* Disparity Frame
*/
class DisparityFrame extends DepthFrame {
constructor(cxxFrame) {
super(cxxFrame);
}

/**
* Retrieve the stereoscopic baseline value. Applicable to stereo-based depth modules
* @return {Float} Stereoscopic baseline in millimeters
*/
get baseLine() {
return this.cxxFrame.getBaseLine();
}
}

/**
* Class containing a set of frames
*
Expand Down Expand Up @@ -2013,6 +2034,7 @@ class FrameSet {

__internalAssembleFrame(cxxFrame) {
if (!cxxFrame) return undefined;
if (cxxFrame.isDisparityFrame()) return new DisparityFrame(cxxFrame);
if (cxxFrame.isDepthFrame()) return new DepthFrame(cxxFrame);
if (cxxFrame.isVideoFrame()) return new VideoFrame(cxxFrame);
return new Frame(cxxFrame);
Expand Down Expand Up @@ -2637,10 +2659,18 @@ class DeviceHub {
class Filter extends Options {
constructor(type) {
super(new RS2.RSFilter(type));
this.frame = new DepthFrame();
internal.addObject(this);
}

_internalGetInputType() {
return DepthFrame;
}

_internalPrepareOutputFrame() {
if (!this.frame) {
this.frame = new DepthFrame();
}
}
/**
* Apply the filter processing on the frame and return the processed frame
* @param {Frame} frame the depth frame to be processed
Expand All @@ -2649,7 +2679,8 @@ class Filter extends Options {
process(frame) {
const funcName = 'Filter.process()';
checkArgumentLength(1, 1, arguments.length, funcName);
checkArgumentType(arguments, Frame, 0, funcName);
checkArgumentType(arguments, this._internalGetInputType(), 0, funcName);
this._internalPrepareOutputFrame();
if (this.cxxObj && this.cxxObj.process(frame.cxxFrame, this.frame.cxxFrame)) {
this.frame.updateProfile();
return this.frame;
Expand All @@ -2665,6 +2696,10 @@ class Filter extends Options {
this.cxxObj.destroy();
this.cxxObj = null;
}
if (this.frame) {
this.frame.destroy();
this.frame = undefined;
}
}
}

Expand Down Expand Up @@ -2695,6 +2730,36 @@ class SpatialFilter extends Filter {
}
}

/**
* Post processing block that could transform disparity frame to depth frame
*/
class DisparityToDepthTransform extends Filter {
constructor() {
super('disparity-to-depth');
}

// override base implementation
_internalGetInputType() {
return DisparityFrame;
}
}

/**
* Post processing block that could transform depth frame to disparity frame
*/
class DepthToDisparityTransform extends Filter {
constructor() {
super('depth-to-disparity');
}

// override base implementation
_internalPrepareOutputFrame() {
if (!this.frame) {
this.frame = new DisparityFrame();
}
}
}

/**
* <code>util.preset_preference</code>: The enum for preset preference values.
* @readonly
Expand Down Expand Up @@ -5028,6 +5093,7 @@ module.exports = {
FrameSet: FrameSet,
VideoFrame: VideoFrame,
DepthFrame: DepthFrame,
DisparityFrame: DisparityFrame,
Align: Align,
PointCloud: PointCloud,
Points: Points,
Expand All @@ -5037,6 +5103,8 @@ module.exports = {
DecimationFilter: DecimationFilter,
TemporalFilter: TemporalFilter,
SpatialFilter: SpatialFilter,
DisparityToDepthTransform: DisparityToDepthTransform,
DepthToDisparityTransform: DepthToDisparityTransform,


stream: stream,
Expand Down
44 changes: 41 additions & 3 deletions wrappers/nodejs/src/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ class RSFrame : public Nan::ObjectWrap {
SupportsFrameMetadata);
Nan::SetPrototypeMethod(tpl, "isVideoFrame", IsVideoFrame);
Nan::SetPrototypeMethod(tpl, "isDepthFrame", IsDepthFrame);
Nan::SetPrototypeMethod(tpl, "isDisparityFrame", IsDisparityFrame);

// Points related APIs
Nan::SetPrototypeMethod(tpl, "canGetPoints", CanGetPoints);
Expand All @@ -520,6 +521,7 @@ class RSFrame : public Nan::ObjectWrap {
Nan::SetPrototypeMethod(tpl, "getPointsCount", GetPointsCount);
Nan::SetPrototypeMethod(tpl, "isValid", IsValid);
Nan::SetPrototypeMethod(tpl, "getDistance", GetDistance);
Nan::SetPrototypeMethod(tpl, "getBaseLine", GetBaseLine);

constructor_.Reset(tpl->GetFunction());
exports->Set(Nan::New("RSFrame").ToLocalChecked(), tpl->GetFunction());
Expand Down Expand Up @@ -725,6 +727,16 @@ class RSFrame : public Nan::ObjectWrap {
info.GetReturnValue().Set(Nan::Undefined());
}

static NAN_METHOD(IsDisparityFrame) {
auto me = Nan::ObjectWrap::Unwrap<RSFrame>(info.Holder());
info.GetReturnValue().Set(Nan::Undefined());
if (!me) return;

auto is_disparity = rs2_is_frame_extendable_to(
me->frame_, RS2_EXTENSION_DISPARITY_FRAME, &me->error_);
info.GetReturnValue().Set(Nan::New(is_disparity ? true : false));
}

static NAN_METHOD(GetFrameMetadata) {
auto me = Nan::ObjectWrap::Unwrap<RSFrame>(info.Holder());
rs2_frame_metadata_value metadata =
Expand Down Expand Up @@ -946,6 +958,15 @@ class RSFrame : public Nan::ObjectWrap {
info.GetReturnValue().Set(Nan::Undefined());
}

static NAN_METHOD(GetBaseLine) {
auto me = Nan::ObjectWrap::Unwrap<RSFrame>(info.Holder());
info.GetReturnValue().Set(Nan::Undefined());
if (!me) return;

auto val = rs2_depth_stereo_frame_get_baseline(me->frame_, &me->error_);
info.GetReturnValue().Set(Nan::New(val));
}

private:
static Nan::Persistent<v8::Function> constructor_;
rs2_frame* frame_;
Expand Down Expand Up @@ -1679,8 +1700,12 @@ class RSSensor : public Nan::ObjectWrap, Options {
frame_->Replace(nullptr);
video_frame_->Replace(nullptr);
depth_frame_->Replace(nullptr);
disparity_frame_->Replace(nullptr);

if (rs2_is_frame_extendable_to(raw_frame, RS2_EXTENSION_DEPTH_FRAME,
if (rs2_is_frame_extendable_to(raw_frame, RS2_EXTENSION_DISPARITY_FRAME,
&error_)) {
disparity_frame_->Replace(raw_frame);
} else if (rs2_is_frame_extendable_to(raw_frame, RS2_EXTENSION_DEPTH_FRAME,
&error_)) {
depth_frame_->Replace(raw_frame);
} else if (rs2_is_frame_extendable_to(raw_frame, RS2_EXTENSION_VIDEO_FRAME,
Expand All @@ -1693,7 +1718,8 @@ class RSSensor : public Nan::ObjectWrap, Options {

private:
RSSensor() : sensor_(nullptr), error_(nullptr), profile_list_(nullptr),
frame_(nullptr), video_frame_(nullptr), depth_frame_(nullptr) {}
frame_(nullptr), video_frame_(nullptr), depth_frame_(nullptr),
disparity_frame_(nullptr) {}

~RSSensor() {
DestroyMe();
Expand Down Expand Up @@ -1793,11 +1819,14 @@ class RSSensor : public Nan::ObjectWrap, Options {
auto frame = Nan::ObjectWrap::Unwrap<RSFrame>(info[1]->ToObject());
auto depth_frame = Nan::ObjectWrap::Unwrap<RSFrame>(info[2]->ToObject());
auto video_frame = Nan::ObjectWrap::Unwrap<RSFrame>(info[3]->ToObject());
auto disparity_frame = Nan::ObjectWrap::Unwrap<RSFrame>(
info[4]->ToObject());
auto me = Nan::ObjectWrap::Unwrap<RSSensor>(info.Holder());
if (me && frame && depth_frame && video_frame) {
if (me && frame && depth_frame && video_frame && disparity_frame) {
me->frame_ = frame;
me->depth_frame_ = depth_frame;
me->video_frame_ = video_frame;
me->disparity_frame_ = disparity_frame;
v8::String::Utf8Value str(info[0]);
me->frame_callback_name_ = std::string(*str);
rs2_start_cpp(me->sensor_, new FrameCallbackForProc(me), &me->error_);
Expand Down Expand Up @@ -1970,6 +1999,7 @@ class RSSensor : public Nan::ObjectWrap, Options {
RSFrame* frame_;
RSFrame* video_frame_;
RSFrame* depth_frame_;
RSFrame* disparity_frame_;
friend class RSContext;
friend class DevicesChangedCallbackInfo;
friend class FrameCallbackInfo;
Expand Down Expand Up @@ -3644,6 +3674,8 @@ class RSFilter : public Nan::ObjectWrap, Options {
kFilterDecimation = 0,
kFilterTemporal,
kFilterSpatial,
kFilterDisparity2Depth,
kFilterDepth2Disparity
};
static void Init(v8::Local<v8::Object> exports) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
Expand Down Expand Up @@ -3708,6 +3740,12 @@ class RSFilter : public Nan::ObjectWrap, Options {
} else if (!(type.compare("spatial"))) {
obj->type_ = kFilterSpatial;
obj->block_ = rs2_create_spatial_filter_block(&obj->error_);
} else if (!(type.compare("disparity-to-depth"))) {
obj->type_ = kFilterDisparity2Depth;
obj->block_ = rs2_create_disparity_transform_block(0, &obj->error_);
} else if (!(type.compare("depth-to-disparity"))) {
obj->type_ = kFilterDepth2Disparity;
obj->block_ = rs2_create_disparity_transform_block(1, &obj->error_);
}
obj->frame_queue_ = rs2_create_frame_queue(1, &obj->error_);
auto callback = new FrameCallbackForFrameQueue(obj->frame_queue_);
Expand Down
48 changes: 48 additions & 0 deletions wrappers/nodejs/test/test-functional-online.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2018 Intel Corporation. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license
// that can be found in the LICENSE file.

'use strict';

/* global describe, it, before, after */
const assert = require('assert');
let rs2;
try {
rs2 = require('node-librealsense');
} catch (e) {
rs2 = require('../index.js');
}

describe('Disparity transform tests', function() {
let ctx;
let pipe;
let depth2Disparity;
let disparith2Depth;
before(function() {
ctx = new rs2.Context();
pipe = new rs2.Pipeline(ctx);
depth2Disparity = new rs2.DepthToDisparityTransform();
disparith2Depth = new rs2.DisparityToDepthTransform();
});

after(function() {
rs2.cleanup();
});

it('depth frame <=> disparity frame using transform', () => {
pipe.start();
const frames = pipe.waitForFrames();
assert.equal(frames.size > 0, true);
frames.forEach((frame) => {
if (frame instanceof rs2.DepthFrame) {
let output = depth2Disparity.process(frame);
assert.equal(output instanceof rs2.DisparityFrame, true);
assert.equal(typeof output.baseLine, 'number');

let dout = disparith2Depth.process(output);
assert.equal(dout instanceof rs2.DepthFrame, true);
}
});
pipe.stop();
});
});
3 changes: 0 additions & 3 deletions wrappers/nodejs/tools/header.js

This file was deleted.

0 comments on commit 239a518

Please sign in to comment.