hybridgroup/cylon-opencv

View on GitHub
lib/adaptor.js

Summary

Maintainability
A
0 mins
Test Coverage
/*
 * Cylonjs Opencv adaptor
 * http://cylonjs.com
 *
 * Copyright (c) 2014 The Hybrid Group
 * Licensed under the Apache 2.0 license.
*/

"use strict";

var OpenCV = require("opencv"),
    Cylon = require("cylon"),
    path = require("path");

var Adaptor = module.exports = function Adaptor() {
  Adaptor.__super__.constructor.apply(this, arguments);

  this.videoFeeds = {};
  this.windows = {};

  this.events = [
    /**
     * Emitted when the video feed from the Camera is initialized and ready for
     * capture
     *
     * @event videoFeedReady
     */
    "videoFeedReady",

    /**
     * Emitted whenever a new frame is available from the video feed.
     *
     * @event frameReady
     * @value err
     * @value frame
     */
    "frameReady",

    /**
     * Emitted when faces are detected in an image
     *
     * @event frameReady
     * @value err
     * @value im
     * @value faces
     */
    "facesDetected"
  ];
};

Cylon.Utils.subclass(Adaptor, Cylon.Adaptor);

Adaptor.prototype.commands = [
  "readFrame", "initVideoCapture",
  "detectFaces", "createWindow",
  "showFrame", "readImage"
];

Adaptor.prototype.connect = function(callback) {
  callback();
};

Adaptor.prototype.disconnect = function(callback) {
  callback();
};

/**
 * Initializes video capture from the supplied feed
 *
 * @param {Object} feed feed to capture video from
 * @return {void}
 * @publish
 */
Adaptor.prototype.initVideoCapture = function(feed) {
  var videoFeed,
      feedSource;

  feedSource = this._feedSource(feed);

  if (this.videoFeeds[feedSource.id] == null) {
    this.videoFeeds[feedSource.id] = new OpenCV.VideoCapture(feedSource.source);
  }

  videoFeed = this.videoFeeds[feedSource.id];

  var interval = setInterval(function() {
    var triggered = false;

    videoFeed.read(function(err, im) {
      if (err) { return; }

      var width = im.width(),
          height = im.height();

      if (width > 0 && height > 0 && triggered === false) {
        triggered = true;

        this.emit("videoFeedReady");

        if (interval) {
          clearInterval(interval);
        }
      }
    }.bind(this));
  }.bind(this), 100);
};

/**
 * Reads frames from a video feed
 *
 * @param {Object} feed feed to read video frames from
 * @return {void}
 * @publish
 */
Adaptor.prototype.readFrame = function(feed) {
  var feedSource = this._feedSource(feed);

  this.videoFeeds[feedSource.id].read(function(err, frame) {
    this.emit("frameReady", err, frame);
  }.bind(this));
};

/**
 * Reads an image through OpenCV
 *
 * @param {Object} image feed to read video frames from
 * @param {Function} cb callback to be triggered when the image is read
 * @return {void}
 * @publish
 */
Adaptor.prototype.readImage = function(image, cb) {
  OpenCV.readImage(image, cb);
};

/**
 * Detects faces in an image, using the provided haarcascade file
 *
 * @param {Object} im image to scan for faces
 * @param {Object} haarcascade file to use for image detection
 * @return {void}
 * @publish
 */
Adaptor.prototype.detectFaces = function(im, haarcascade) {
  im.detectObject(haarcascade, {}, function(err, faces) {
    this.emit("facesDetected", err, im, faces);
  }.bind(this));
};

/**
 * Creates a new, named OpenCV window
 *
 * @param {String} name name for OpenCV window
 * @return {Object} OpenCV NamedWindow instance
 * @publish
 */
Adaptor.prototype.createWindow = function(name) {
  if (!this.windows[name]) {
    this.windows[name] = new OpenCV.NamedWindow(name, 0);
  }

  return this.windows[name];
};

/**
 * Shows a video frame in an OpenCV window
 *
 * @param {String} name OpenCV NamedWindow to display in
 * @param {Object} frame frame to display
 * @param {Number} delay how long the delay should be
 * @return {Object} blocking delay
 * @publish
 */
Adaptor.prototype.showFrame = function(name, frame, delay) {
  var win = this.windows[name];
  win.show(frame);
  return win.blockingWaitKey(0, delay || 42);
};

Adaptor.prototype._feedSource = function(feed) {
  var feedSource;

  if (!isNaN(feed)) {
    feedSource = { id: feed, source: feed };
  } else if (typeof feed === "string") {
    feedSource = { id: path.basename(feed), source: path.resolve(feed) };
  }

  return feedSource;
};