This commit is contained in:
Ivan
2022-04-05 11:42:28 +03:00
commit 6dc0eb0fcf
5565 changed files with 1200500 additions and 0 deletions

View File

@@ -0,0 +1,656 @@
/* This file is part of the Pangolin Project.
* http://github.com/stevenlovegrove/Pangolin
*
* Copyright (c) 2014 Steven Lovegrove
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <pangolin/video/drivers/depthsense.h>
#include <pangolin/factory/factory_registry.h>
#include <pangolin/video/iostream_operators.h>
#include <iomanip>
namespace pangolin
{
const size_t ROGUE_ADDR = 0x01;
const double MAX_DELTA_TIME = 20000.0; //u_s
DepthSenseContext& DepthSenseContext::I()
{
static DepthSenseContext s;
return s;
}
DepthSense::Context& DepthSenseContext::Context()
{
return g_context;
}
void DepthSenseContext::NewDeviceRunning()
{
running_devices++;
if(running_devices == 1) {
StartNodes();
}
}
void DepthSenseContext::DeviceClosing()
{
running_devices--;
if(running_devices == 0) {
StopNodes();
// Force destruction of current context
g_context = DepthSense::Context();
}
}
DepthSenseVideo* DepthSenseContext::GetDepthSenseVideo(size_t device_num, DepthSenseSensorType s1, DepthSenseSensorType s2, ImageDim dim1, ImageDim dim2, unsigned int fps1, unsigned int fps2, const Uri& uri)
{
if(running_devices == 0) {
// Initialise SDK
g_context = DepthSense::Context::create("localhost");
}
// Get the list of currently connected devices
std::vector<DepthSense::Device> da = g_context.getDevices();
if( da.size() > device_num )
{
return new DepthSenseVideo(da[device_num], s1, s2, dim1, dim2, fps1, fps2, uri);
}
throw VideoException("DepthSense device not connected.");
}
DepthSenseContext::DepthSenseContext()
: is_running(false), running_devices(0)
{
}
DepthSenseContext::~DepthSenseContext()
{
StopNodes();
}
void DepthSenseContext::StartNodes()
{
if(!is_running) {
// Launch EventLoop thread
event_thread = std::thread(&DepthSenseContext::EventLoop, this );
}
}
void DepthSenseContext::StopNodes()
{
if(is_running && event_thread.joinable()) {
g_context.quit();
event_thread.join();
}
}
void DepthSenseContext::EventLoop()
{
is_running = true;
g_context.startNodes();
g_context.run();
g_context.stopNodes();
is_running = false;
}
DepthSenseVideo::DepthSenseVideo(DepthSense::Device device, DepthSenseSensorType s1, DepthSenseSensorType s2, ImageDim dim1, ImageDim dim2, unsigned int fps1, unsigned int fps2, const Uri& uri)
: device(device), fill_image(0), depthmap_stream(-1), rgb_stream(-1), gotDepth(0), gotColor(0),
enableDepth(false), enableColor(false), depthTs(0.0), colorTs(0.0), size_bytes(0)
{
streams_properties = &frame_properties["streams"];
*streams_properties = picojson::value(picojson::array_type, false);
streams_properties->get<picojson::array>().resize(2);
sensorConfig[0] = {s1, dim1, fps1};
sensorConfig[1] = {s2, dim2, fps2};
ConfigureNodes(uri);
DepthSenseContext::I().NewDeviceRunning();
}
DepthSenseVideo::~DepthSenseVideo()
{
if (g_cnode.isSet()) DepthSenseContext::I().Context().unregisterNode(g_cnode);
if (g_dnode.isSet()) DepthSenseContext::I().Context().unregisterNode(g_dnode);
fill_image = (unsigned char*)ROGUE_ADDR;
cond_image_requested.notify_all();
DepthSenseContext::I().DeviceClosing();
}
picojson::value Json(DepthSense::IntrinsicParameters& p)
{
picojson::value js;
js["model"] = "polynomial";
js["width"] = p.width;
js["height"] = p.height;
js["RDF"] = "[1,0,0; 0,1,0; 0,0,1]";
js["fx"] = p.fx;
js["fy"] = p.fy;
js["u0"] = p.cx;
js["v0"] = p.cy;
js["k1"] = p.k1;
js["k2"] = p.k2;
js["k3"] = p.k3;
js["p1"] = p.p1;
js["p2"] = p.p2;
return js;
}
picojson::value Json(DepthSense::ExtrinsicParameters& p)
{
picojson::value js;
js["rows"] = "3";
js["cols"] = "4";
std::ostringstream oss;
oss << std::setprecision(17);
oss << "[" << p.r11 << "," << p.r12 << "," << p.r13 << "," << p.t1 << ";";
oss << p.r21 << "," << p.r22 << "," << p.r23 << "," << p.t2 << ";";
oss << p.r31 << "," << p.r32 << "," << p.r33 << "," << p.t3 << "]";
js["data"] = oss.str();
return js;
}
void DepthSenseVideo::ConfigureNodes(const Uri& uri)
{
std::vector<DepthSense::Node> nodes = device.getNodes();
for (int i = 0; i<2; ++i)
{
switch (sensorConfig[i].type)
{
case DepthSenseDepth:
{
for (int n = 0; n < (int)nodes.size(); n++)
{
DepthSense::Node node = nodes[n];
if ((node.is<DepthSense::DepthNode>()) && (!g_dnode.isSet()))
{
depthmap_stream = i;
g_dnode = node.as<DepthSense::DepthNode>();
ConfigureDepthNode(sensorConfig[i], uri);
DepthSenseContext::I().Context().registerNode(node);
}
}
break;
}
case DepthSenseRgb:
{
for (int n = 0; n < (int)nodes.size(); n++)
{
DepthSense::Node node = nodes[n];
if ((node.is<DepthSense::ColorNode>()) && (!g_cnode.isSet()))
{
rgb_stream = i;
g_cnode = node.as<DepthSense::ColorNode>();
ConfigureColorNode(sensorConfig[i], uri);
DepthSenseContext::I().Context().registerNode(node);
}
}
break;
}
default:
continue;
}
}
DepthSense::StereoCameraParameters scp = device.getStereoCameraParameters();
//Set json device properties for intrinsics and extrinsics
picojson::value& jsintrinsics = device_properties["intrinsics"];
if (jsintrinsics.is<picojson::null>()) {
jsintrinsics = picojson::value(picojson::array_type, false);
jsintrinsics.get<picojson::array>().resize(streams.size());
if (depthmap_stream >= 0) jsintrinsics[depthmap_stream] = Json(scp.depthIntrinsics);
if (rgb_stream >= 0) jsintrinsics[rgb_stream] = Json(scp.colorIntrinsics);
}
picojson::value& jsextrinsics = device_properties["extrinsics"];
if(jsextrinsics.is<picojson::null>()){
jsextrinsics = Json(scp.extrinsics);
}
}
inline DepthSense::FrameFormat ImageDim2FrameFormat(const ImageDim& dim)
{
DepthSense::FrameFormat retVal = DepthSense::FRAME_FORMAT_UNKNOWN;
if(dim.x == 160 && dim.y == 120)
{
retVal = DepthSense::FRAME_FORMAT_QQVGA;
}
else if(dim.x == 176 && dim.y == 144)
{
retVal = DepthSense::FRAME_FORMAT_QCIF;
}
else if(dim.x == 240 && dim.y == 160)
{
retVal = DepthSense::FRAME_FORMAT_HQVGA;
}
else if(dim.x == 320 && dim.y == 240)
{
retVal = DepthSense::FRAME_FORMAT_QVGA;
}
else if(dim.x == 352 && dim.y == 288)
{
retVal = DepthSense::FRAME_FORMAT_CIF;
}
else if(dim.x == 480 && dim.y == 320)
{
retVal = DepthSense::FRAME_FORMAT_HVGA;
}
else if(dim.x == 640 && dim.y == 480)
{
retVal = DepthSense::FRAME_FORMAT_VGA;
}
else if(dim.x == 1280 && dim.y == 720)
{
retVal = DepthSense::FRAME_FORMAT_WXGA_H;
}
else if(dim.x == 320 && dim.y == 120)
{
retVal = DepthSense::FRAME_FORMAT_DS311;
}
else if(dim.x == 1024 && dim.y == 768)
{
retVal = DepthSense::FRAME_FORMAT_XGA;
}
else if(dim.x == 800 && dim.y == 600)
{
retVal = DepthSense::FRAME_FORMAT_SVGA;
}
else if(dim.x == 636 && dim.y == 480)
{
retVal = DepthSense::FRAME_FORMAT_OVVGA;
}
else if(dim.x == 640 && dim.y == 240)
{
retVal = DepthSense::FRAME_FORMAT_WHVGA;
}
else if(dim.x == 640 && dim.y == 360)
{
retVal = DepthSense::FRAME_FORMAT_NHD;
}
return retVal;
}
void DepthSenseVideo::UpdateParameters(const DepthSense::Node& node, const Uri& uri)
{
DepthSense::Type type = node.getType();
picojson::value& jsnode = device_properties[type.name()];
std::vector<DepthSense::PropertyBase> properties = type.getProperties();
for(std::vector<DepthSense::PropertyBase>::const_iterator it = properties.begin(); it != properties.end(); ++it) {
const DepthSense::PropertyBase& prop = *it;
if (prop.is<DepthSense::Property<int32_t> >()) {
DepthSense::Property<int32_t> tprop = prop.as<DepthSense::Property<int32_t> >();
if (uri.Contains(prop.name())) {
if (!prop.isReadOnly()) {
tprop.setValue(node, uri.Get<int32_t>(prop.name(), tprop.getValue(node)));
} else {
pango_print_warn("DepthSense property '%s' is read-only\n", prop.name().c_str() );
}
}
jsnode[prop.name()] = tprop.getValue(node);
} else if (prop.is<DepthSense::Property<float> >()) {
DepthSense::Property<float> tprop = prop.as<DepthSense::Property<float> >();
if (uri.Contains(prop.name())) {
if (!prop.isReadOnly()) {
tprop.setValue(node, uri.Get<float>(prop.name(), tprop.getValue(node)));
} else {
pango_print_warn("DepthSense property '%s' is read-only\n", prop.name().c_str() );
}
}
jsnode[prop.name()] = tprop.getValue(node);
} else if (prop.is<DepthSense::Property<bool> >()) {
DepthSense::Property<bool> tprop = prop.as<DepthSense::Property<bool> >();
if (uri.Contains(prop.name())) {
if (!prop.isReadOnly()) {
tprop.setValue(node, uri.Get<bool>(prop.name(), tprop.getValue(node)));
} else {
pango_print_warn("DepthSense property '%s' is read-only\n", prop.name().c_str() );
}
}
jsnode[prop.name()] = tprop.getValue(node);
} else if (prop.is<DepthSense::Property<std::string> >()){
DepthSense::Property<std::string> tprop = prop.as<DepthSense::Property<std::string> >();
if (uri.Contains(prop.name())) {
if (!prop.isReadOnly()) {
tprop.setValue(node, uri.Get<std::string>(prop.name(), tprop.getValue(node)).c_str() );
} else {
pango_print_warn("DepthSense property '%s' is read-only\n", prop.name().c_str() );
}
}
jsnode[prop.name()] = tprop.getValue(node);
}
}
}
void DepthSenseVideo::ConfigureDepthNode(const SensorConfig& sensorConfig, const Uri& uri)
{
g_dnode.newSampleReceivedEvent().connect(this, &DepthSenseVideo::onNewDepthSample);
DepthSense::DepthNode::Configuration config = g_dnode.getConfiguration();
config.frameFormat = ImageDim2FrameFormat(sensorConfig.dim);
config.framerate = sensorConfig.fps;
config.mode = DepthSense::DepthNode::CAMERA_MODE_CLOSE_MODE;
config.saturation = true;
try {
DepthSenseContext::I().Context().requestControl(g_dnode, 0);
g_dnode.setConfiguration(config);
g_dnode.setEnableDepthMap(true);
} catch (DepthSense::Exception& e) {
throw pangolin::VideoException("DepthSense exception whilst configuring node", e.what());
}
//Set pangolin stream for this channel
const int w = sensorConfig.dim.x;
const int h = sensorConfig.dim.y;
const PixelFormat pfmt = PixelFormatFromString("GRAY16LE");
const StreamInfo stream_info(pfmt, w, h, (w*pfmt.bpp) / 8, (unsigned char*)0);
streams.push_back(stream_info);
size_bytes += stream_info.SizeBytes();
enableDepth = true;
UpdateParameters(g_dnode, uri);
}
void DepthSenseVideo::ConfigureColorNode(const SensorConfig& sensorConfig, const Uri& uri)
{
// connect new color sample handler
g_cnode.newSampleReceivedEvent().connect(this, &DepthSenseVideo::onNewColorSample);
DepthSense::ColorNode::Configuration config = g_cnode.getConfiguration();
config.frameFormat = ImageDim2FrameFormat(sensorConfig.dim);
config.compression = DepthSense::COMPRESSION_TYPE_MJPEG;
config.powerLineFrequency = DepthSense::POWER_LINE_FREQUENCY_50HZ;
config.framerate = sensorConfig.fps;
try {
DepthSenseContext::I().Context().requestControl(g_cnode,0);
g_cnode.setConfiguration(config);
g_cnode.setEnableColorMap(true);
UpdateParameters(g_cnode, uri);
} catch (DepthSense::Exception& e) {
throw pangolin::VideoException("DepthSense exception whilst configuring node", e.what());
}
//Set pangolin stream for this channel
const int w = sensorConfig.dim.x;
const int h = sensorConfig.dim.y;
const PixelFormat pfmt = PixelFormatFromString("BGR24");
const StreamInfo stream_info(pfmt, w, h, (w*pfmt.bpp) / 8, (unsigned char*)0 + size_bytes);
streams.push_back(stream_info);
size_bytes += stream_info.SizeBytes();
enableColor = true;
}
void DepthSenseVideo::onNewColorSample(DepthSense::ColorNode node, DepthSense::ColorNode::NewSampleReceivedData data)
{
{
std::unique_lock<std::mutex> lock(update_mutex);
// Wait for fill request
while (!fill_image) {
cond_image_requested.wait(lock);
}
// Update per-frame parameters
//printf("Color delta: %.1f\n", fabs(colorTs - data.timeOfCapture));
colorTs = data.timeOfCapture;
picojson::value& jsstream = frame_properties["streams"][rgb_stream];
jsstream["time_us"] = data.timeOfCapture;
if (fill_image != (unsigned char*)ROGUE_ADDR) {
// Fill with data
unsigned char* imagePtr = fill_image;
bool copied = false;
for (int i = 0; !copied && i < 2; ++i)
{
switch (sensorConfig[i].type)
{
case DepthSenseDepth:
{
imagePtr += streams[i].SizeBytes();
break;
}
case DepthSenseRgb:
{
// Leave as BGR
std::memcpy(imagePtr, data.colorMap, streams[i].SizeBytes());
copied = true;
break;
}
default:
continue;
}
}
gotColor++;
}
//printf("Got color at: %.1f\n", colorTs);
if(gotDepth)
{
double delta = fabs(GetDeltaTime());
if(delta > MAX_DELTA_TIME)
{
//printf("**** Waiting for another depth, delta: %.1f ****\n", delta);
gotDepth = 0;
return;
}
}
}
cond_image_filled.notify_one();
}
void DepthSenseVideo::onNewDepthSample(DepthSense::DepthNode node, DepthSense::DepthNode::NewSampleReceivedData data)
{
{
std::unique_lock<std::mutex> lock(update_mutex);
// Wait for fill request
while(!fill_image) {
cond_image_requested.wait(lock);
}
// Update per-frame parameters
//printf("Depth delta: %.1f\n", fabs(depthTs - data.timeOfCapture));
depthTs = data.timeOfCapture;
picojson::value& jsstream = frame_properties["streams"][depthmap_stream];
jsstream["time_us"] = depthTs;
if(fill_image != (unsigned char*)ROGUE_ADDR) {
// Fill with data
unsigned char* imagePtr = fill_image;
bool copied = false;
for (int i = 0; i < 2; ++i)
{
switch (sensorConfig[i].type)
{
case DepthSenseDepth:
{
memcpy(imagePtr, data.depthMap, streams[i].SizeBytes());
copied = true;
break;
}
case DepthSenseRgb:
{
imagePtr += streams[i].SizeBytes();
break;
}
default:
continue;
}
if(copied)
{
break;
}
}
gotDepth++;
}
//printf("Got depth at: %.1f\n", depthTs);
if(gotColor)
{
double delta = fabs(GetDeltaTime());
if(delta > MAX_DELTA_TIME)
{
//printf("**** Waiting for another color, delta: %.1f ****\n", delta);
gotColor = 0;
return;
}
}
}
cond_image_filled.notify_one();
}
void DepthSenseVideo::Start()
{
}
void DepthSenseVideo::Stop()
{
}
size_t DepthSenseVideo::SizeBytes() const
{
return size_bytes;
}
const std::vector<StreamInfo>& DepthSenseVideo::Streams() const
{
return streams;
}
bool DepthSenseVideo::GrabNext( unsigned char* image, bool /*wait*/ )
{
if(fill_image) {
throw std::runtime_error("GrabNext Cannot be called concurrently");
}
//printf("#### Grab Next ####\n");
// Request that image is filled with data
fill_image = image;
cond_image_requested.notify_one();
// Wait until it has been filled successfully.
{
std::unique_lock<std::mutex> lock(update_mutex);
while ((enableDepth && !gotDepth) || (enableColor && !gotColor))
{
cond_image_filled.wait(lock);
}
if (gotDepth)
{
gotDepth = 0;
}
if (gotColor)
{
gotColor = 0;
}
fill_image = 0;
}
//printf("Delta time: %.1f\n", fabs(GetDeltaTime()));
return true;
}
bool DepthSenseVideo::GrabNewest( unsigned char* image, bool wait )
{
return GrabNext(image,wait);
}
double DepthSenseVideo::GetDeltaTime() const
{
return depthTs - colorTs;
}
DepthSenseSensorType depthsense_sensor(const std::string& str)
{
if (!str.compare("rgb")) {
return DepthSenseRgb;
}
else if (!str.compare("depth")) {
return DepthSenseDepth;
}
else if (str.empty()) {
return DepthSenseUnassigned;
}
else{
throw pangolin::VideoException("Unknown DepthSense sensor", str);
}
}
PANGOLIN_REGISTER_FACTORY(DepthSenseVideo)
{
struct DepthSenseVideoFactory final : public FactoryInterface<VideoInterface> {
std::unique_ptr<VideoInterface> Open(const Uri& uri) override {
DepthSenseSensorType img1 = depthsense_sensor(uri.Get<std::string>("img1", "depth"));
DepthSenseSensorType img2 = depthsense_sensor(uri.Get<std::string>("img2", ""));
const ImageDim dim1 = uri.Get<ImageDim>("size1", img1 == DepthSenseDepth ? ImageDim(320, 240) : ImageDim(640, 480) );
const ImageDim dim2 = uri.Get<ImageDim>("size2", img2 == DepthSenseDepth ? ImageDim(320, 240) : ImageDim(640, 480) );
const unsigned int fps1 = uri.Get<unsigned int>("fps1", 30);
const unsigned int fps2 = uri.Get<unsigned int>("fps2", 30);
return std::unique_ptr<VideoInterface>(
DepthSenseContext::I().GetDepthSenseVideo(0, img1, img2, dim1, dim2, fps1, fps2, uri)
);
}
};
FactoryRegistry<VideoInterface>::I().RegisterFactory(std::make_shared<DepthSenseVideoFactory>(), 10, "depthsense");
}
}