diff --git a/.gitignore b/.gitignore index 85b7772..ce28416 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ app/bin/* build/* *.pbxuser *.mode1v3 +*.perspectivev3 # old skool .svn diff --git a/README.md b/README.md index d8b09ef..143fc0f 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,35 @@ We want to recognize: - Individual fingers - Finger-based hand gestures (e.g. peace sign, etc) +Getting Started +--------------- + +Right now, you'll want to be on Chrome, on OSX, then: + +- Plug in your Kinect to your computer via USB +- Download this code from http://github.com/doug/depthjs +- Install the chrome extension + - Bring up the extensions management page by clicking the wrench icon and choosing *Tools* > *Extensions*. + - If *Developer mode* has a + by it, click the + to add developer information to the page. The + changes to a -, and more buttons and information appear. + - Click the *Load unpacked extension* button. A file dialog appears. + - In the file dialog, navigate to your *depthjs/chrome-extension-mac* and click *OK*. +- Open a new web page (it only affects new pages) +- Have fun! + +What the camera sees... + +- When the extension starts up, it opens 3 windows, blob, first, and second +- first & second show the limits of the depth of field the camera is paying attention to, you should try to make it so that your hand is in both first & second and not much else +- blob shows you everything the camera can see as well as a blue circle around where it thinks your hand is. + +After opening a new page in Chrome, + +- Pull your hand back so that both first & second windows are blank and there is no circle in the blob window +- Then bring your hand forward until it gets an outline in the blob window, and pause for a second until the blue circle appears +- You should then see a blue circle on the web site that will track your movements +- To click, just close your hand into a fist! + + Components ---------- DepthJS is very modular. The Kinect driver and computer vision are written on top of Open Frameworks and OpenCV in C++. This component can output the raw RGB image, the raw depth map (filtered for the hand), as well as the high-level events that the computer vision recognizes. The three outputs are pumped out on three separate 0MQ TCP sockets. Next, a Torando web server (written in Python) takes the 0MQ data and wraps it into a WebSocket, which is what enables the web browser extension to receive the data. Finally a pure javascript-based extension connects to the WebSocket server to receive the events. Event handlers may be placed globally, in content scripts injected into each web page, or pushed via the content script to local DOM elements written by 3rd parties. diff --git a/chrome-extension-mac/content_script/event_handlers.js b/chrome-extension-mac/content_script/event_handlers.js index 1c4875d..b63133c 100644 --- a/chrome-extension-mac/content_script/event_handlers.js +++ b/chrome-extension-mac/content_script/event_handlers.js @@ -30,16 +30,27 @@ console.log("DepthJS: Loading event handlers"); DepthJS.state = null; DepthJS.lastRegisterTime = null; +DepthJS.trigger = function(element, name) { + var event = document.createEvent("Events") + event.initEvent(name, true, true); //true for can bubble, true for cancelable + element.dispatchEvent(event); +} + +DepthJS.trigger(window, "depthjs-loading"); + DepthJS.eventHandlers.onSwipeLeft = function() { + DepthJS.trigger(window, "swipeLeft"); // history.back(); }; DepthJS.eventHandlers.onSwipeRight = function() { + DepthJS.trigger(window, "swipeRight"); // We interpret as "forward". // history.forward(); }; DepthJS.eventHandlers.onSwipeDown = function() { + DepthJS.trigger(window, "swipeDown"); // We interpret as "scroll down 75% of window". // var scrollAmount = Math.floor($(window).height() * 0.75); // $("html, body").animate({ @@ -48,6 +59,7 @@ DepthJS.eventHandlers.onSwipeDown = function() { }; DepthJS.eventHandlers.onSwipeUp = function() { + DepthJS.trigger(window, "swipeUp"); // We interpret as "scroll up 75% of window". // var scrollAmount = Math.floor($(window).height() * 0.75); // $("html, body").animate({ @@ -56,12 +68,14 @@ DepthJS.eventHandlers.onSwipeUp = function() { }; DepthJS.eventHandlers.onHandPointer = function(){ + DepthJS.trigger(window, "handPointer"); if (DepthJS.verbose) console.log("DepthJS. Hand Pointer"); DepthJS.eventHandlers.onUnregister(); DepthJS.state = "selectorBox"; }; DepthJS.eventHandlers.onHandOpen = function(){ + DepthJS.trigger(window, "handOpen"); if (DepthJS.verbose) console.log("DepthJS. Hand Open"); DepthJS.eventHandlers.onUnregister(); DepthJS.state = "panner"; @@ -83,11 +97,12 @@ DepthJS.eventHandlers.onSelectorBoxMode = function() { // POINTER ----------------------------------------------------------------------------------------- DepthJS.eventHandlers.onRegister = function(data) { if (DepthJS.verbose) console.log("DepthJS: User registered their hand"); - $(window).trigger("touchstart"); + DepthJS.trigger(window, "touchStart"); if (data.mode == "twohands") { console.log("Ignoring in two hands for now"); return; } + data.mode = "theforce"; if (data.mode == "theforce") { DepthJS.registerMode = "selectorBox"; } else if (data.mode == "twohands") { @@ -109,6 +124,7 @@ DepthJS.eventHandlers.onUnregister = function() { DepthJS.selectorBox.hide(); DepthJS.selectorBoxPopup.hide(); DepthJS.depthose.hide(); + DepthJS.trigger(window, "touchStop"); }; DepthJS.eventHandlers.onHandClick = function() { @@ -167,6 +183,8 @@ DepthJS.eventHandlers.onMove = function(data) { } else if (DepthJS.state == "selectorBoxPopup") { DepthJS.selectorBoxPopup.move(accumulatedX, accumulatedY, accumulatedZ); } else { + //console.debug("setting the force") + DepthJS.eventHandlers.onRegister({mode:"theforce"}); if (DepthJS.verbose) console.log("Ignoring move in state " + DepthJS.state); } }; diff --git a/chrome-extension-mac/content_script/init.js b/chrome-extension-mac/content_script/init.js index b7c3482..8772047 100644 --- a/chrome-extension-mac/content_script/init.js +++ b/chrome-extension-mac/content_script/init.js @@ -9,15 +9,15 @@ $(function() { // Let us know its running console.log("Finished initing, sticking in logo"); - $("").css({ - position: "fixed", - width: "32px", - height: "32px", - bottom: "20px", - left: "20px" - }).appendTo("body"); - console.log($("img")); - + $("").attr("src", chrome.extension.getURL("logo_128x128.png")) + .css({ + position: "fixed", + width: "32px", + height: "32px", + bottom: "20px", + left: "20px" + }) + .appendTo("body"); var lastTime = null; function reloadChecker() { diff --git a/chrome-extension-mac/content_script/root.js b/chrome-extension-mac/content_script/root.js index c456577..e69512a 100644 --- a/chrome-extension-mac/content_script/root.js +++ b/chrome-extension-mac/content_script/root.js @@ -54,7 +54,7 @@ function print() { }); var alphabeticalKeys = _.keys(counts).sort(); - console.log("------" + (new Date() + "")); + // console.log("------" + (new Date() + "")); _.each(alphabeticalKeys, function(type) { console.log([" " + counts[type] + " " + type + "; last = ", lastByType[type]]); }); diff --git a/chrome-extension-mac/content_script/selector_box.js b/chrome-extension-mac/content_script/selector_box.js index 9f999b2..7cd7e37 100644 --- a/chrome-extension-mac/content_script/selector_box.js +++ b/chrome-extension-mac/content_script/selector_box.js @@ -46,36 +46,48 @@ DepthJS.selectorBox.move = function(x, y) { if (x != $box.css("left") || y != $box.css("top")) { $box.css({left: x, top: y}); } + DepthJS.selectorBox.handleHover() }; -DepthJS.selectorBox.activate = function() { - if (DepthJS.verbose) console.log("DepthJS: Activating underneath selectorBox"); - // Lame code for now... - - var $intersectingLinks = $("a").filter(function() { - var $a = $(this); - var ax = $a.offset().left + $(window).scrollLeft(); - var aw = $a.width(); - var ay = $a.offset().top + $(window).scrollTop(); - var ah = $a.height(); - - var $box = DepthJS.selectorBox.$box; - var bx = $box.position().left; - var by = $box.position().top; - var bw = $box.width(); - var bh = $box.height(); - - if (by > ay + ah || // box-top is lower than link-bottom - by + bh < ay || // box-bottom is higher than link-top - bx > ax + aw || // box-left is right of link right - bx + bw < aw) { // box-right is left of link left - return false; +DepthJS.selectorBox.elementAtCursor = function() { + var $box = DepthJS.selectorBox.$box; + var x = $box.position().left + $box.width() / 2; + var y = $box.position().top + $box.height() / 2; + + $box.hide(); + var element = document.elementFromPoint(x, y); + $box.show(); + return $(element).closestMatching('a,.hoverable'); +} + +$.fn.closestMatching = function(selector) { + if ($(this).is(selector)) return $(this)[0]; + + var parents = $(this).parents(); + for (var i = 0; i < parents.length; i++) { + if ($(parents[i]).is(selector)) return $(parents[i])[0]; + } + return undefined; +} + +DepthJS.selectorBox.handleHover = function() { + var lastElement = $('.depthjs-hover')[0]; + var element = DepthJS.selectorBox.elementAtCursor(); + + if (element == lastElement) { // same element + // do nothing + } else { + if (lastElement) { + DepthJS.trigger($(lastElement).removeClass('depthjs-hover')[0], 'hoverOut'); } - return true; - }); + if (element) { + DepthJS.trigger($(element).addClass("depthjs-hover")[0], "hoverOver"); + } + } +}; - if (DepthJS.verbose) console.log("Got " + $intersectingLinks.length + " links"); - if (DepthJS.verbose) console.log($intersectingLinks); +DepthJS.selectorBox.activate = function() { + var $intersectingLinks = DepthJS.selectorBox.elementAtCursor(); if ($intersectingLinks.length > 0) { DepthJS.selectorBoxPopup.$links = $intersectingLinks; DepthJS.selectorBoxPopup.activate(); diff --git a/new_cv/NewCV/FreenectDevice.h b/new_cv/NewCV/FreenectDevice.h new file mode 100644 index 0000000..8c889f8 --- /dev/null +++ b/new_cv/NewCV/FreenectDevice.h @@ -0,0 +1,104 @@ +/* + * FreenectDevice.h + * NewCV + * + * Created by Roy Shilkrot on 3/3/11. + * Copyright 2011 MIT. All rights reserved. + * + */ +#include "libfreenect.hpp" +#include +#include +#include +#include + +using namespace cv; + +#include +using namespace std; + +class Mutex { +public: + Mutex() { + pthread_mutex_init( &m_mutex, NULL ); + } + void lock() { + pthread_mutex_lock( &m_mutex ); + } + void unlock() { + pthread_mutex_unlock( &m_mutex ); + } +private: + pthread_mutex_t m_mutex; +}; + +class MyFreenectDevice : public Freenect::FreenectDevice { +public: + MyFreenectDevice(freenect_context *_ctx, int _index) + : Freenect::FreenectDevice(_ctx, _index), m_buffer_depth(FREENECT_DEPTH_11BIT_SIZE),m_buffer_rgb(FREENECT_VIDEO_RGB_SIZE), m_gamma(2048), m_new_rgb_frame(false), m_new_depth_frame(false), + depthMat(Size(640,480),CV_16UC1), rgbMat(Size(640,480),CV_8UC3,Scalar(0)), ownMat(Size(640,480),CV_8UC3,Scalar(0)) + { + for( unsigned int i = 0 ; i < 2048 ; i++) { + float v = i/2048.0; + v = std::pow(v, 3)* 6; + m_gamma[i] = v*6*256; + } + } + // Do not call directly even in child + void VideoCallback(void* _rgb, uint32_t timestamp) { +// std::cout << "RGB callback" << std::endl; + m_rgb_mutex.lock(); + uint8_t* rgb = static_cast(_rgb); + rgbMat.data = rgb; + m_new_rgb_frame = true; + m_rgb_mutex.unlock(); + }; + // Do not call directly even in child + void DepthCallback(void* _depth, uint32_t timestamp) { +// std::cout << "Depth callback" << std::endl; + m_depth_mutex.lock(); + uint16_t* depth = static_cast(_depth); + depthMat.data = (uchar*) depth; + m_new_depth_frame = true; + m_depth_mutex.unlock(); + } + + bool getVideo(Mat& output) { + m_rgb_mutex.lock(); + if(m_new_rgb_frame) { + cv::cvtColor(rgbMat, output, CV_RGB2BGR); + m_new_rgb_frame = false; + m_rgb_mutex.unlock(); + return true; + } else { + m_rgb_mutex.unlock(); + return false; + } + } + + bool getDepth(Mat& output) { + m_depth_mutex.lock(); + if(m_new_depth_frame) { + depthMat.copyTo(output); + m_new_depth_frame = false; + m_depth_mutex.unlock(); + return true; + } else { + m_depth_mutex.unlock(); + return false; + } + } + +private: + std::vector m_buffer_depth; + std::vector m_buffer_rgb; + std::vector m_gamma; + Mat depthMat; + Mat rgbMat; + Mat ownMat; + Mutex m_rgb_mutex; + Mutex m_depth_mutex; + bool m_new_rgb_frame; + bool m_new_depth_frame; +}; + diff --git a/new_cv/NewCV/main.cpp b/new_cv/NewCV/main.cpp new file mode 100644 index 0000000..46c876f --- /dev/null +++ b/new_cv/NewCV/main.cpp @@ -0,0 +1,457 @@ +#include "FreenectDevice.h" + +Scalar refineSegments(const Mat& img, + Mat& mask, + Mat& dst, + vector& contour, + vector& second_contour, + Point2i& previous) +{ + // int niters = 3; + + vector > contours; + vector hierarchy; + + Mat temp; + + blur(mask, temp, Size(11,11)); + temp = temp > 85.0; + + findContours( temp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); + + if(dst.data==NULL) + dst = Mat::zeros(img.size(), CV_8UC1); + else + dst.setTo(Scalar(0)); + + if( contours.size() == 0 ) + return Scalar(-1,-1); + + // iterate through all the top-level contours, + // draw each connected component with its own random color + int idx = 0, largestComp = -1, secondlargest = -1; + double maxWArea = 0, maxJArea = 0; + vector justarea(contours.size()); + vector weightedarea(contours.size()); + + // for( ; idx >= 0; idx = hierarchy[idx][0] ) + for (; idx& c = contours[idx]; + Scalar _mean = mean(Mat(contours[idx])); + justarea[idx] = fabs(contourArea(Mat(c))); + weightedarea[idx] = fabs(contourArea(Mat(c))) / + ((previous.x >- 1) ? (1.0 + norm(Point(_mean[0],_mean[1])-previous)) : 1.0); //consider distance from last blob + } + for (idx = 0; idx maxWArea ) + { + maxWArea = weightedarea[idx]; + largestComp = idx; + } + } + for (idx = 0; idx < contours.size(); idx++) { + if ( justarea[idx] > maxJArea && idx != largestComp ) { + maxJArea = justarea[idx]; + secondlargest = idx; + } + } + + Scalar color( 255 ); + // cout << "largest cc " << largestComp << endl; + // drawContours( dst, contours, largestComp, color, CV_FILLED); //, 8, hierarchy ); + // for (idx=0; idx= 0) { + //find top-left values + int maxx = -INT_MAX,miny = INT_MAX; + int num = contours[largestComp].size(); + for (int i=0; i maxx) maxx = contours[largestComp][i].x; + if(contours[largestComp][i].y < miny) miny = contours[largestComp][i].y; + } + + //crop contour to 150x150 "window" + vector newblob; + int maxxp150 = MAX(maxx-200,0),minyp150 = MIN(miny+170,480); + + for (int i=0; i maxxp150 && _p.y < minyp150) newblob.push_back(_p); + } + + Point* pts = &(newblob[0]); + num = newblob.size(); + fillPoly(dst, (const Point**)(&pts), &num, 1, color); + + Scalar b = mean(Mat(newblob)); + b[2] = justarea[largestComp]; + + contour.clear(); + contour = newblob; + + second_contour.clear(); + if(secondlargest >= 0) { + second_contour = contours[secondlargest]; + b[3] = maxJArea; + } + + previous.x = b[0]; previous.y = b[1]; + return b; + } else + return Scalar(-1,-1); + +} + +#define LABEL_GARBAGE 0 +#define LABEL_OPEN 1 +#define LABEL_FIST 2 +#define LABEL_THUMB 3 + + +int main(int argc, char **argv) { + bool die(false); + string filename("snapshot"); + string suffix(".png"); + int i_snap(0),iter(0); + + Mat depthMat(Size(640,480),CV_16UC1); + Mat depthf (Size(640,480),CV_8UC1); + Mat rgbMat(Size(640,480),CV_8UC3,Scalar(0)); + Mat ownMat(Size(640,480),CV_8UC3,Scalar(0)); + + Freenect::Freenect freenect; + MyFreenectDevice& device = freenect.createDevice(0); + + bool registered = false; + Mat blobMaskOutput = Mat::zeros(Size(640,480),CV_8UC1),outC; + Point midBlob; + + int startX = 200, sizeX = 180, num_x_reps = 20, num_y_reps = 50; + double height_over_num_y_reps = 480/num_y_reps, + width_over_num_x_reps = sizeX/num_x_reps; + + + vector _d(num_x_reps * num_y_reps); //the descriptor + Mat descriptorMat(_d); + +// CvNormalBayesClassifier classifier; //doesnt work + CvKNearest classifier; +// CvSVM classifier; //doesnt work +// CvBoost classifier; //only good for 2 classes +// CvDTree classifier; + + + vector > training_data; + vector label_data; + PCA pca; + Mat labelMat, dataMat; + vector label_counts(4); + + bool trained = false, loaded = false; + + device.startVideo(); + device.startDepth(); + while (!die) { + device.getVideo(rgbMat); + device.getDepth(depthMat); +// cv::imshow("rgb", rgbMat); + depthMat.convertTo(depthf, CV_8UC1, 255.0/2048.0); + cv::imshow("depth",depthf); + + //interpolation & inpainting + { + Mat _tmp,_tmp1; // = (depthMat - 400.0); //minimum observed value is ~440. so shift a bit + Mat(depthMat - 400.0).convertTo(_tmp1,CV_64FC1); + _tmp.setTo(Scalar(2048), depthMat > 750.0); //cut off at 600 to create a "box" where the user interacts +// _tmp.convertTo(depthf, CV_8UC1, 255.0/1648.0); //values are 0-2048 (11bit), account for -400 = 1648 + + //quadratic interpolation +// cv::pow(_tmp,2.0,_tmp1); +// _tmp1 = _tmp1 * 4.0; + +// try { +// cv:log(_tmp,_tmp1); +// } +// catch (cv::Exception e) { +// cerr << e.what() << endl; +// exit(0); +// } + + Point minLoc; double minval,maxval; + minMaxLoc(_tmp1, &minval, &maxval, NULL, NULL); + _tmp1.convertTo(depthf, CV_8UC1, 255.0/maxval); + + Mat small_depthf; resize(depthf,small_depthf,Size(),0.2,0.2); + cv::inpaint(small_depthf,(small_depthf == 255),_tmp1,5.0,INPAINT_TELEA); + + resize(_tmp1, _tmp, depthf.size()); + _tmp.copyTo(depthf, (depthf == 255)); + } + + cvtColor(depthf, outC, CV_GRAY2BGR); + + Mat blobMaskInput = depthf < 120; //anything not white is "real" depth, TODO: inpainting invalid data + vector ctr,ctr2; + + //closest point to the camera + Point minLoc; double minval,maxval; + minMaxLoc(depthf, &minval, &maxval, &minLoc, NULL, blobMaskInput); + circle(outC, minLoc, 5, Scalar(0,255,0), 3); + + blobMaskInput = depthf < (minval + 18); + + Scalar blb = refineSegments(Mat(),blobMaskInput,blobMaskOutput,ctr,ctr2,midBlob); //find contours in the foreground, choose biggest +// if (blobMaskOutput.data != NULL) { +// imshow("first", blobMaskOutput); +// } + /////// blb : + //blb[0] = x, blb[1] = y, blb[2] = 1st blob size, blb[3] = 2nd blob size. + + + + if(blb[0]>=0 && blb[2] > 500) { //1st blob detected, and is big enough + //cvtColor(depthf, outC, CV_GRAY2BGR); + + Scalar mn,stdv; + meanStdDev(depthf,mn,stdv,blobMaskInput); + + //cout << "min: " << minval << ", max: " << maxval << ", mean: " << mn[0] << endl; + + //now refining blob by looking at the mean depth value it has... + blobMaskInput = depthf < (mn[0] + stdv[0]); + + blb = refineSegments(Mat(),blobMaskInput,blobMaskOutput,ctr,ctr2,midBlob); + + imshow("blob", blobMaskOutput); + + if(blb[0] >= 0 && blb[2] > 300) { + //draw contour + Scalar color(0,0,255); + for (int idx=0; idx 0) { //second blob detected + Scalar color2(255,0,255); + for (int idx=0; idx, <#const int *channels#>, <#const Mat mask#>, <#MatND hist#>, <#int dims#>, <#const int *histSize#>, <#const float **ranges#>, <#bool uniform#>, <#bool accumulate#>) + */ + +// Mat _tmp(logPolar.size(),CV_8UC1); +// cvLogPolar(&((IplImage)logPolar), &((IplImage)_tmp),Point2f(blb[0],blb[1]), 80.0, CV_WARP_INVERSE_MAP); +// imshow("descriptor", _tmp); +// imshow("logpolar", logPolar); + } + } + + if(trained) { + Mat results(1,1,CV_32FC1); + Mat samples; Mat(Mat(_d).t()).convertTo(samples,CV_32FC1); + + Mat samplesAfterPCA = samples; //pca.project(samples); + + classifier.find_nearest(&((CvMat)samplesAfterPCA), 1, &((CvMat)results)); +// ((float*)results.data)[0] = classifier.predict(&((CvMat)samples))->value; + + Mat lc(label_counts); lc *= 0.9; + +// label_counts[(int)((float*)results.data)[0]] *= 0.9; + label_counts[(int)((float*)results.data)[0]] += 0.1; + Point maxLoc; + minMaxLoc(lc, NULL, NULL, NULL, &maxLoc); + int res = maxLoc.y; + + stringstream ss; ss << "prediction: "; + if (res == LABEL_OPEN) { + ss << "Open hand"; + } + if (res == LABEL_FIST) { + ss << "Fist"; + } + if (res == LABEL_THUMB) { + ss << "Thumb"; + } + if (res == LABEL_GARBAGE) { + ss << "Garbage"; + } + putText(outC, ss.str(), Point(20,50), CV_FONT_HERSHEY_PLAIN, 3.0, Scalar(0,0,255), 2); + } + + stringstream ss; ss << "samples: " << training_data.size(); + putText(outC, ss.str(), Point(30,outC.rows - 30), CV_FONT_HERSHEY_PLAIN, 2.0, Scalar(0,0,255), 1); + + imshow("blobs", outC); + + char k = cvWaitKey(5); + if( k == 27 ){ + break; + } + if( k == 8 ) { + std::ostringstream file; + file << filename << i_snap << suffix; + cv::imwrite(file.str(),rgbMat); + i_snap++; + } + if (k == 'g') { + //put into training as 'garbage' + training_data.push_back(_d); + label_data.push_back(LABEL_GARBAGE); + cout << "learn grabage" << endl; + } + if(k == 'o') { + //put into training as 'open' + training_data.push_back(_d); + label_data.push_back(LABEL_OPEN); + cout << "learn open" << endl; + } + if(k == 'f') { + //put into training as 'fist' + training_data.push_back(_d); + label_data.push_back(LABEL_FIST); + cout << "learn fist" << endl; + } + if(k == 'h') { + //put into training as 'thumb' + training_data.push_back(_d); + label_data.push_back(LABEL_THUMB); + cout << "learn thumb" << endl; + } + if (k=='t') { + //train model + cout << "train model" << endl; + if(loaded != true) { + dataMat = Mat(training_data.size(),_d.size(),CV_32FC1); //descriptors as matrix rows + for (uint i=0; i> dataMat; + fs["labels"] >> labelMat; + fs["startX"] >> startX; + fs["sizeX"] >> sizeX; + fs["num_x_reps"] >> num_x_reps; + fs["num_y_reps"] >> num_y_reps; + height_over_num_y_reps = 480/num_y_reps; + width_over_num_x_reps = sizeX/num_x_reps; + + loaded = true; + fs.release(); + } else { + cerr << "can't open saved data" << endl; + } + } + } + + device.stopVideo(); + device.stopDepth(); + return 0; +} diff --git a/safari-extension-mac/DepthJS.safariextension/content_script/root.js b/safari-extension-mac/DepthJS.safariextension/content_script/root.js index 2caa7d7..cdc8aae 100644 --- a/safari-extension-mac/DepthJS.safariextension/content_script/root.js +++ b/safari-extension-mac/DepthJS.safariextension/content_script/root.js @@ -32,6 +32,7 @@ var DepthJS = { panner: {}, depthose: {}, browser: {}, + tabs: {}, MAX_HANDPLANE_WIDTH: 100, MAX_HANDPLANE_HEIGHT: 100 }; @@ -52,16 +53,16 @@ function print() { counts[msg.type] = counts[msg.type] + 1; lastByType[msg.type] = msg.data; }); - + var alphabeticalKeys = _.keys(counts).sort(); console.log("------" + (new Date() + "")); _.each(alphabeticalKeys, function(type) { console.log([" " + counts[type] + " " + type + "; last = ", lastByType[type]]); }); - + lastMessages = []; } setTimeout(print, 1000); })(); -} \ No newline at end of file +} diff --git a/webkit-plugin-mac/DLog.h b/webkit-plugin-mac/DLog.h new file mode 100644 index 0000000..f128a00 --- /dev/null +++ b/webkit-plugin-mac/DLog.h @@ -0,0 +1,20 @@ +/* + * DebugLog.h + * DebugLog + * + * Created by Karl Kraft on 3/22/09. + * Copyright 2009 Karl Kraft. All rights reserved. + * + */ + +#ifndef __OPTIMIZE__ + +#define DLog(args...) _DLog(__FILE__,__PRETTY_FUNCTION__,__LINE__,args); + +#else + +#define DLog(x...) + +#endif + +void _DLog(const char *file, const char *function, int lineNumber, NSString *format,...); diff --git a/webkit-plugin-mac/DLog.mm b/webkit-plugin-mac/DLog.mm new file mode 100644 index 0000000..f4ac7bc --- /dev/null +++ b/webkit-plugin-mac/DLog.mm @@ -0,0 +1,39 @@ +/* + * DebugLog.m + * DebugLog + * + * Created by Karl Kraft on 3/22/09. + * Copyright 2009 Karl Kraft. All rights reserved. + * + */ + +#include "DLog.h" + +//void _DebugLog(const char *function, int lineNumber, NSString *format,...) { +// va_list ap; +// +// va_start (ap, format); +// if (![format hasSuffix: @"\n"]) { +// format = [format stringByAppendingString: @"\n"]; +// } +// NSString *body = [[NSString alloc] initWithFormat: format arguments: ap]; +// va_end (ap); +// NSString *fileName=[[NSString stringWithUTF8String:file] lastPathComponent]; +// fprintf(stderr,"%s:%d %s",[fileName UTF8String],lineNumber,[body UTF8String]); +// [body release]; +//} + + +void _DLog(const char *file, const char *function, int lineNumber, NSString *format,...){ + va_list args; + va_start(args, format); + + NSString *body = [[NSString alloc] initWithFormat:format arguments:args]; + //NSString *filename = [[NSString stringWithFormat:@"%s",file] lastPathComponent]; + NSString *logLine = [[NSString alloc] initWithFormat:@"%s %@\n", function, body]; + va_end(args); + + [[NSFileHandle fileHandleWithStandardOutput] writeData: [logLine dataUsingEncoding: NSNEXTSTEPStringEncoding]]; + [logLine release]; + [body release]; +} diff --git a/webkit-plugin-mac/FreenectDevice.h b/webkit-plugin-mac/FreenectDevice.h new file mode 100644 index 0000000..d70f10d --- /dev/null +++ b/webkit-plugin-mac/FreenectDevice.h @@ -0,0 +1,119 @@ +/* + DepthJS + Copyright (C) 2010 Aaron Zinman, Doug Fritz, Roy Shilkrot, Greg Elliott + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + * + * FreenectDevice.h + * NewCV + * + * Created by Roy Shilkrot on 3/3/11. + * + */ +#include "libfreenect.hpp" +#include +#include +#include +#include + +using namespace cv; + +#include +using namespace std; + +class Mutex { +public: + Mutex() { + pthread_mutex_init( &m_mutex, NULL ); + } + void lock() { + pthread_mutex_lock( &m_mutex ); + } + void unlock() { + pthread_mutex_unlock( &m_mutex ); + } +private: + pthread_mutex_t m_mutex; +}; + +class MyFreenectDevice : public Freenect::FreenectDevice { +public: + MyFreenectDevice(freenect_context *_ctx, int _index) + : Freenect::FreenectDevice(_ctx, _index), m_buffer_depth(FREENECT_DEPTH_11BIT_SIZE),m_buffer_rgb(FREENECT_VIDEO_RGB_SIZE), m_gamma(2048), m_new_rgb_frame(false), m_new_depth_frame(false), + depthMat(Size(640,480),CV_16UC1), rgbMat(Size(640,480),CV_8UC3,Scalar(0)), ownMat(Size(640,480),CV_8UC3,Scalar(0)) + { + for( unsigned int i = 0 ; i < 2048 ; i++) { + float v = i/2048.0; + v = std::pow(v, 3)* 6; + m_gamma[i] = v*6*256; + } + } + // Do not call directly even in child + void VideoCallback(void* _rgb, uint32_t timestamp) { +// std::cout << "RGB callback" << std::endl; + m_rgb_mutex.lock(); + uint8_t* rgb = static_cast(_rgb); + rgbMat.data = rgb; + m_new_rgb_frame = true; + m_rgb_mutex.unlock(); + }; + // Do not call directly even in child + void DepthCallback(void* _depth, uint32_t timestamp) { +// std::cout << "Depth callback" << std::endl; + m_depth_mutex.lock(); + uint16_t* depth = static_cast(_depth); + depthMat.data = (uchar*) depth; + m_new_depth_frame = true; + m_depth_mutex.unlock(); + } + + bool getVideo(Mat& output) { + m_rgb_mutex.lock(); + if(m_new_rgb_frame) { + cv::cvtColor(rgbMat, output, CV_RGB2BGR); + m_new_rgb_frame = false; + m_rgb_mutex.unlock(); + return true; + } else { + m_rgb_mutex.unlock(); + return false; + } + } + + bool getDepth(Mat& output) { + m_depth_mutex.lock(); + if(m_new_depth_frame) { + depthMat.copyTo(output); + m_new_depth_frame = false; + m_depth_mutex.unlock(); + return true; + } else { + m_depth_mutex.unlock(); + return false; + } + } + +private: + std::vector m_buffer_depth; + std::vector m_buffer_rgb; + std::vector m_gamma; + Mat depthMat; + Mat rgbMat; + Mat ownMat; + Mutex m_rgb_mutex; + Mutex m_depth_mutex; + bool m_new_rgb_frame; + bool m_new_depth_frame; +}; + diff --git a/webkit-plugin-mac/gesture_engine.cpp b/webkit-plugin-mac/gesture_engine.cpp new file mode 100644 index 0000000..66cb24c --- /dev/null +++ b/webkit-plugin-mac/gesture_engine.cpp @@ -0,0 +1,693 @@ +/* + DepthJS + Copyright (C) 2010 Aaron Zinman, Doug Fritz, Roy Shilkrot, Greg Elliott + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +#include "FreenectDevice.h" + +#define LABEL_GARBAGE 0 +#define LABEL_OPEN 1 +#define LABEL_FIST 2 +#define LABEL_THUMB 3 + +extern void send_event(const string& etype, const string& edata); + +class GestureEngine { +private: + bool running; + + Mat depthMat; + Mat depthf; + Mat rgbMat; + Mat ownMat; + + Freenect::Freenect freenect; + MyFreenectDevice* device; + + bool registered; + Mat blobMaskOutput; + Mat outC; + Point midBlob; + + //descriptor parameters + int startX, sizeX, num_x_reps, num_y_reps; + double height_over_num_y_reps,width_over_num_x_reps; + + + vector _d; //the descriptor + Mat descriptorMat; //as a matrix + + CvKNearest classifier; + + vector > training_data; + vector label_data; + PCA pca; + Mat labelMat, dataMat; + vector label_counts; + + bool trained; + bool loaded; + + int mode; + + int register_ctr,register_secondbloc_ctr; + + Point2i appear; double appearTS; + + Point2i lastMove; + + int hcr_ctr; + vector hc_stack; + int hc_stack_ptr; + + int pca_number_of_features; + + Scalar _refineSegments(const Mat& img, + Mat& mask, + Mat& dst, + vector& contour, + vector& second_contour, + Point2i& previous); + int TrainModel(); + void SaveModelData(); + int LoadModelData(const char* filename); + void InterpolateAndInpaint(); + void ComputeDescriptor(Scalar); + string GetStringForGestureCode(int); + void CheckRegistered(Scalar,int,Scalar); + int GetMostLikelyGesture(); + +public: + bool die; + + GestureEngine(): running(false), + registered(false), + startX(250), + sizeX(150), + num_x_reps(10), + num_y_reps(10), + height_over_num_y_reps(480/num_y_reps), + width_over_num_x_reps(sizeX/num_x_reps), + label_counts(vector(4)), + trained(false), + loaded(false), + mode(LABEL_GARBAGE), + pca_number_of_features(50), + die(false) + { + depthMat = Mat(Size(640,480),CV_16UC1); + depthf = Mat(Size(640,480),CV_8UC1); + rgbMat = Mat(Size(640,480),CV_8UC3,Scalar(0)); + ownMat = Mat(Size(640,480),CV_8UC3,Scalar(0)); + blobMaskOutput = Mat(Size(640,480),CV_8UC1,Scalar(0)); + + _d = vector(num_x_reps*num_y_reps); + descriptorMat = Mat(_d); + + register_ctr = register_secondbloc_ctr = 0; + registered = false; + + appear = Point2i(-1,-1); + appearTS = -1; + + midBlob = Point2i(-1,-1); + lastMove = Point2i(-1,-1); + + hcr_ctr = -1; + hc_stack = vector(20); + hc_stack_ptr = 0; + }; + + void RunEngine(); + bool getRunning() { return running; } + int InitializeFreenect(const char* ); +}; + +Scalar GestureEngine::_refineSegments(const Mat& img, + Mat& mask, + Mat& dst, + vector& contour, + vector& second_contour, + Point2i& previous) +{ + // int niters = 3; + + vector > contours; + vector hierarchy; + + Mat temp; + + blur(mask, temp, Size(11,11)); + temp = temp > 85.0; + + findContours( temp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); + + if(dst.data==NULL) + dst = Mat::zeros(img.size(), CV_8UC1); + else + dst.setTo(Scalar(0)); + + if( contours.size() == 0 ) + return Scalar(-1,-1); + + // iterate through all the top-level contours, + // draw each connected component with its own random color + int idx = 0, largestComp = -1, secondlargest = -1; + double maxWArea = 0, maxJArea = 0; + vector justarea(contours.size()); + vector weightedarea(contours.size()); + + // for( ; idx >= 0; idx = hierarchy[idx][0] ) + for (; idx& c = contours[idx]; + Scalar _mean = mean(Mat(contours[idx])); + justarea[idx] = fabs(contourArea(Mat(c))); + weightedarea[idx] = fabs(contourArea(Mat(c))) / + ((previous.x >- 1) ? (1.0 + norm(Point(_mean[0],_mean[1])-previous)) : 1.0); //consider distance from last blob + } + for (idx = 0; idx maxWArea ) + { + maxWArea = weightedarea[idx]; + largestComp = idx; + } + } + for (idx = 0; idx < contours.size(); idx++) { + if ( justarea[idx] > maxJArea && idx != largestComp ) { + maxJArea = justarea[idx]; + secondlargest = idx; + } + } + + Scalar color( 255 ); + // cout << "largest cc " << largestComp << endl; + // drawContours( dst, contours, largestComp, color, CV_FILLED); //, 8, hierarchy ); + // for (idx=0; idx= 0) { + + //find top-left values + int maxx = -INT_MAX,miny = INT_MAX; + int num = contours[largestComp].size(); + for (int i=0; i maxx) maxx = contours[largestComp][i].x; + if(contours[largestComp][i].y < miny) miny = contours[largestComp][i].y; + } + + //crop contour to 150x150 "window" + vector newblob; + int maxxp150 = MAX(maxx-200,0),minyp150 = MIN(miny+170,480); + + circle(outC, Point(maxx,miny), 2, Scalar(0,255,0), 1); + circle(outC, Point(maxxp150,minyp150), 2, Scalar(0,255,0), 1); + + for (int i=0; i maxxp150 && _p.y < minyp150) newblob.push_back(_p); + } + + Point* pts = &(newblob[0]); + num = newblob.size(); + fillPoly(dst, (const Point**)(&pts), &num, 1, color); + + Scalar b = mean(Mat(newblob)); + b[2] = justarea[largestComp]; + + contour.clear(); + contour = newblob; + + second_contour.clear(); + if(secondlargest >= 0) { + second_contour = contours[secondlargest]; + b[3] = maxJArea; + } + + previous.x = b[0]; previous.y = b[1]; + return b; + } else + return Scalar(-1,-1); + +} + +int GestureEngine::TrainModel() { + cout << "train model" << endl; + if(loaded != true) { + dataMat = Mat(training_data.size(),_d.size(),CV_32FC1); //descriptors as matrix rows + for (uint i=0; i> dataMat; + fs["labels"] >> labelMat; + fs["startX"] >> startX; + fs["sizeX"] >> sizeX; + fs["num_x_reps"] >> num_x_reps; + fs["num_y_reps"] >> num_y_reps; + height_over_num_y_reps = 480/num_y_reps; + width_over_num_x_reps = sizeX/num_x_reps; + _d = vector(num_x_reps*num_y_reps); + descriptorMat = Mat(_d); + loaded = true; + fs.release(); + } else { + cerr << "can't open saved data" << endl; + return 0; + } + return 1; +} + +void GestureEngine::InterpolateAndInpaint() { + //interpolation & inpainting + Mat _tmp,_tmp1; // = (depthMat - 400.0); //minimum observed value is ~440. so shift a bit + Mat(depthMat - 400.0).convertTo(_tmp1,CV_64FC1); +// _tmp1.setTo(Scalar(2048-400.0), depthMat > 750.0); //cut off at 600 to create a "box" where the user interacts + + Point minLoc; double minval,maxval; + minMaxLoc(_tmp1, &minval, &maxval, NULL, NULL); + _tmp1.convertTo(depthf, CV_8UC1, 255.0/maxval); + + Mat small_depthf; resize(depthf,small_depthf,Size(),0.2,0.2); + cv::inpaint(small_depthf,(small_depthf == 255),_tmp1,5.0,INPAINT_TELEA); + + resize(_tmp1, _tmp, depthf.size()); + _tmp.copyTo(depthf, (depthf == 255)); +} + +void GestureEngine::ComputeDescriptor(Scalar blb) { + Mat blobDepth,blobEdge; + depthf.copyTo(blobDepth,blobMaskOutput); + Laplacian(blobDepth, blobEdge, 8); + // equalizeHist(blobEdge, blobEdge);//just for visualization + + Mat logPolar(depthf.size(),CV_8UC1); + cvLogPolar(&((IplImage)blobEdge), &((IplImage)logPolar), Point2f(blb[0],blb[1]), 80.0); + + // for (int i=0; i, <#const int *channels#>, <#const Mat mask#>, <#MatND hist#>, <#int dims#>, <#const int *histSize#>, <#const float **ranges#>, <#bool uniform#>, <#bool accumulate#>) + */ + + // Mat _tmp(logPolar.size(),CV_8UC1); + // cvLogPolar(&((IplImage)logPolar), &((IplImage)_tmp),Point2f(blb[0],blb[1]), 80.0, CV_WARP_INVERSE_MAP); + // imshow("descriptor", _tmp); + // imshow("logpolar", logPolar); + +} + +string GestureEngine::GetStringForGestureCode(int res) { + if (res == LABEL_OPEN) { + return "openhand"; + } + if (res == LABEL_FIST) { + return "theforce"; + } + if (res == LABEL_THUMB) { + return "Thumb"; + } + if (res == LABEL_GARBAGE) { + return "Garbage"; + } + return "none"; +} + +void GestureEngine::CheckRegistered(Scalar blb, int recognized_gesture, Scalar mn) { + if(recognized_gesture != LABEL_GARBAGE) { + register_ctr = MIN((register_ctr + 1),60); + + if(blb[3] > 5000) + register_secondbloc_ctr = MIN((register_secondbloc_ctr + 1),60); + + if (register_ctr > 30 && !registered) { + registered = true; + appear.x = -1; + lastMove.x = blb[0]; lastMove.y = blb[1]; + + cout << "blob size " << blb[2] << endl; + + if(register_secondbloc_ctr < 30) { + cout << "register pointer" << endl; + stringstream ss; ss << "\"mode\":\""<< GetStringForGestureCode(recognized_gesture) <<"\""; + send_event("Register", ss.str()); + + mode = recognized_gesture; + } else { + cout << "register tab swithcer" << endl; + send_event("Register", "\"mode\":\"twohands\""); + } + } + + if(registered) { + stringstream ss; + ss << "\"x\":" << (int)floor(blb[0]*100.0/640.0) + << ",\"y\":" << (int)floor(blb[1]*100.0/480.0) + << ",\"z\":" << (int)(mn[0] * 2.0); + //cout << "move: " << ss.str() << endl; + send_event("Move", ss.str()); + + hc_stack.at(hc_stack_ptr) = hcr_ctr; + hc_stack_ptr = (hc_stack_ptr + 1) % hc_stack.size(); + + //if thumb recognized - send "hand click" + if (mode == LABEL_FIST && recognized_gesture == LABEL_THUMB) { + bool fireClick = false; + if (appearTS > 0) { + double timediff = ((double)getTickCount()-appearTS)/getTickFrequency(); + fireClick = (timediff > 1.0); + } else { + fireClick = true; + } + if(fireClick) { + cout << "Hand click!" << endl; + send_event("HandClick", ""); + + appearTS = getTickCount(); + } + } else { + appearTS = -1; + } + } + } else { + if(!registered) { + //not registered, look for gestures + if(appear.x<0) { + //first appearence of blob + appear = midBlob; + // update_bg_model = false; + appearTS = getTickCount(); + cout << "appear ("< .2 && timediff < 1.0) { + //enough time passed from appearence + line(outC, appear, cv::Point(blb[0],blb[1]), Scalar(0,0,255), 3); + if (appear.x - blb[0] > 100) { + cout << "right"< 100) { + cout << "up" << endl; appear.x = -1; + send_event("SwipeUp", ""); + register_ctr = 0; + } else if (appear.y - blb[1] < -100) { + cout << "down" << endl; appear.x = -1; + send_event("SwipeDown", ""); + register_ctr = 0; + } + } + if(timediff >= 1.0) { + cout << "a ghost..."<startVideo(); + device->startDepth(); + } + catch (std::runtime_error e) { + return 0; + } + if(!LoadModelData(data)) return 0; + if(!TrainModel()) return 0; + + return 1; +} + +int GestureEngine::GetMostLikelyGesture() { + Mat results(1,1,CV_32FC1); + Mat samples; Mat(Mat(_d).t()).convertTo(samples,CV_32FC1); + Mat samplesAfterPCA = pca.project(samples); + + classifier.find_nearest(&((CvMat)samplesAfterPCA), 1, &((CvMat)results)); + + Mat lc(label_counts); lc *= 0.9; + label_counts[(int)((float*)results.data)[0]] += 0.1; + Point maxLoc; + minMaxLoc(lc, NULL, NULL, NULL, &maxLoc); + return maxLoc.y; +} + +void GestureEngine::RunEngine() { + + running = true; + + while (!die) { + device->getVideo(rgbMat); + device->getDepth(depthMat); + + InterpolateAndInpaint(); + + cvtColor(depthf, outC, CV_GRAY2BGR); + + Mat blobMaskInput = depthf < 120; //take closer values + vector ctr,ctr2; + + //closest point to the camera + Point minLoc; double minval,maxval; + minMaxLoc(depthf, &minval, &maxval, &minLoc, NULL, blobMaskInput); + circle(outC, minLoc, 5, Scalar(0,255,0), 3); + + blobMaskInput = depthf < (minval + 20); + + Scalar blb = _refineSegments(Mat(),blobMaskInput,blobMaskOutput,ctr,ctr2,midBlob); //find contours in the foreground, choose biggest + /////// blb : + //blb[0] = x, blb[1] = y, blb[2] = 1st blob size, blb[3] = 2nd blob size. + if(blb[0]>=0 && blb[2] > 500) { //1st blob detected, and is big enough + //cvtColor(depthf, outC, CV_GRAY2BGR); + + Scalar mn,stdv; + meanStdDev(depthf,mn,stdv,blobMaskInput); + + //cout << "min: " << minval << ", max: " << maxval << ", mean: " << mn[0] << endl; + + //now refining blob by looking at the mean depth value it has... + blobMaskInput = depthf < (mn[0] + stdv[0]*.5); + + blb = _refineSegments(Mat(),blobMaskInput,blobMaskOutput,ctr,ctr2,midBlob); + +// imshow("blob", blobMaskOutput); + + if(blb[0] >= 0 && blb[2] > 300) { + //draw contour + Scalar color(0,0,255); + for (int idx=0; idx 0) { //second blob detected + Scalar color2(255,0,255); + for (int idx=0; idxstopVideo(); + device->stopDepth(); + + running = false; +} + +GestureEngine ge; + +void* gesture_engine(void* _arg) { + + ge.RunEngine(); + +} + +void kill_gesture_engine() { + ge.die = true; +} + +bool is_gesture_engine_dead() { return !ge.getRunning(); } + +int init_gesture_engine(const char* data) { return ge.InitializeFreenect(data); } \ No newline at end of file diff --git a/webkit-plugin-mac/gesture_engine.hpp b/webkit-plugin-mac/gesture_engine.hpp new file mode 100644 index 0000000..c3dbda7 --- /dev/null +++ b/webkit-plugin-mac/gesture_engine.hpp @@ -0,0 +1,34 @@ +/* + DepthJS + Copyright (C) 2010 Aaron Zinman, Doug Fritz, Roy Shilkrot, Greg Elliott + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + * gesture_engine.hpp + * webkit-plugin-mac + * + * Created by Roy Shilkrot on 3/6/11. + * + */ + +#ifndef _GESTURE_ENGINE_HPP +#define _GESTURE_ENGINE_HPP + + +int gesture_engine(void* _arg); +void kill_gesture_engine(); +bool is_gesture_engine_dead(); +int init_gesture_engine(const char* data); + +#endif \ No newline at end of file diff --git a/webkit-plugin-mac/include/libfreenect.hpp b/webkit-plugin-mac/include/libfreenect.hpp new file mode 100644 index 0000000..98b4e8a --- /dev/null +++ b/webkit-plugin-mac/include/libfreenect.hpp @@ -0,0 +1,158 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2010 individual OpenKinect contributors. See the CONTRIB file + * for details. + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace Freenect { + class Noncopyable { + public: + Noncopyable() {} + ~Noncopyable() {} + private: + Noncopyable( const Noncopyable& ); + const Noncopyable& operator=( const Noncopyable& ); + }; + + class FreenectTiltState { + friend class FreenectDevice; + FreenectTiltState(freenect_raw_tilt_state *_state): + m_state(_state), m_code(_state->tilt_status) + {} + public: + void getAccelerometers(double* x, double* y, double* z) { + freenect_get_mks_accel(m_state, x, y, z); + } + double getTiltDegs() { + return freenect_get_tilt_degs(m_state); + } + public: + freenect_tilt_status_code m_code; + private: + freenect_raw_tilt_state *m_state; + }; + + class FreenectDevice : Noncopyable { + public: + FreenectDevice(freenect_context *_ctx, int _index) { + if(freenect_open_device(_ctx, &m_dev, _index) < 0) throw std::runtime_error("Cannot open Kinect"); + freenect_set_user(m_dev, this); + freenect_set_video_format(m_dev, FREENECT_VIDEO_RGB); + freenect_set_depth_format(m_dev, FREENECT_DEPTH_11BIT); + freenect_set_depth_callback(m_dev, freenect_depth_callback); + freenect_set_video_callback(m_dev, freenect_video_callback); + } + ~FreenectDevice() { + if(freenect_close_device(m_dev) < 0) throw std::runtime_error("Cannot shutdown Kinect"); + } + void startVideo() { + if(freenect_start_video(m_dev) < 0) throw std::runtime_error("Cannot start RGB callback"); + } + void stopVideo() { + if(freenect_stop_video(m_dev) < 0) throw std::runtime_error("Cannot stop RGB callback"); + } + void startDepth() { + if(freenect_start_depth(m_dev) < 0) throw std::runtime_error("Cannot start depth callback"); + } + void stopDepth() { + if(freenect_stop_depth(m_dev) < 0) throw std::runtime_error("Cannot stop depth callback"); + } + void setTiltDegrees(double _angle) { + if(freenect_set_tilt_degs(m_dev, _angle) < 0) throw std::runtime_error("Cannot set angle in degrees"); + } + void setLed(freenect_led_options _option) { + if(freenect_set_led(m_dev, _option) < 0) throw std::runtime_error("Cannot set led"); + } + void updateState() { + if (freenect_update_tilt_state(m_dev) < 0) throw std::runtime_error("Cannot update device state"); + } + FreenectTiltState getState() const { + return FreenectTiltState(freenect_get_tilt_state(m_dev)); + } + // Do not call directly even in child + virtual void VideoCallback(void *video, uint32_t timestamp) = 0; + // Do not call directly even in child + virtual void DepthCallback(void *depth, uint32_t timestamp) = 0; + private: + freenect_device *m_dev; + static void freenect_depth_callback(freenect_device *dev, void *depth, uint32_t timestamp) { + FreenectDevice* device = static_cast(freenect_get_user(dev)); + device->DepthCallback(depth, timestamp); + } + static void freenect_video_callback(freenect_device *dev, void *video, uint32_t timestamp) { + FreenectDevice* device = static_cast(freenect_get_user(dev)); + device->VideoCallback(video, timestamp); + } + }; + + template class Freenect : Noncopyable { + public: + Freenect() : m_stop(false) { + if(freenect_init(&m_ctx, NULL) < 0) throw std::runtime_error("Cannot initialize freenect library"); + if(pthread_create(&m_thread, NULL, pthread_callback, (void*)this) != 0) throw std::runtime_error("Cannot initialize freenect thread"); + } + ~Freenect() { + for(typename std::map::iterator it = m_devices.begin() ; it != m_devices.end() ; ++it) { + delete it->second; + } + m_stop = true; + pthread_join(m_thread, NULL); + if(freenect_shutdown(m_ctx) < 0) throw std::runtime_error("Cannot cleanup freenect library"); + } + T& createDevice(int _index) { + m_devices.insert(std::make_pair(_index, new T(m_ctx, _index))); + return *(m_devices[_index]); + } + void deleteDevice(int _index) { + m_devices.erase(_index); + } + int deviceCount() { + return freenect_num_devices(m_ctx); + } + // Do not call directly, thread runs here + void operator()() { + while(!m_stop) { + if(freenect_process_events(m_ctx) < 0) throw std::runtime_error("Cannot process freenect events"); + } + } + static void *pthread_callback(void *user_data) { + Freenect* freenect = static_cast*>(user_data); + (*freenect)(); + return NULL; + } + private: + freenect_context *m_ctx; + volatile bool m_stop; + pthread_t m_thread; + std::map m_devices; + }; + +} + diff --git a/webkit-plugin-mac/ocv_freenect.hpp b/webkit-plugin-mac/ocv_freenect.hpp index deb2211..aa72931 100644 --- a/webkit-plugin-mac/ocv_freenect.hpp +++ b/webkit-plugin-mac/ocv_freenect.hpp @@ -30,8 +30,9 @@ using namespace cv; #include -int launchOcvFreenect(); - +int initFreenect(); +void* ocvFreenectThread(void *arg); void killOcvFreenect(); +BOOL isDead(); #endif // __DEPTHJS_OCV_FREENECT_HPP__ \ No newline at end of file diff --git a/webkit-plugin-mac/ocv_freenect.cpp b/webkit-plugin-mac/ocv_freenect.mm similarity index 89% rename from webkit-plugin-mac/ocv_freenect.cpp rename to webkit-plugin-mac/ocv_freenect.mm index 5181cd3..a7d7660 100644 --- a/webkit-plugin-mac/ocv_freenect.cpp +++ b/webkit-plugin-mac/ocv_freenect.mm @@ -11,30 +11,23 @@ #include "ocv_freenect.hpp" #include -pthread_t ocv_thread; -pthread_t freenect_thread; -volatile int die = 0; +static pthread_t freenect_thread = 0; +static int die = 0; +static BOOL dead = YES; -int g_argc; -char **g_argv; +static pthread_mutex_t buf_mutex = PTHREAD_MUTEX_INITIALIZER; -int window; +static Mat depthMat(cv::Size(640,480),CV_16UC1,Scalar(0)); +static Mat rgbMat(cv::Size(640,480),CV_8UC3,Scalar(0)); -pthread_mutex_t buf_mutex = PTHREAD_MUTEX_INITIALIZER; -Mat depthMat(Size(640,480),CV_16UC1,Scalar(0)), -rgbMat(Size(640,480),CV_8UC3,Scalar(0)); +static freenect_device *f_dev; +static int freenect_angle = 15; +static pthread_cond_t frame_cond = PTHREAD_COND_INITIALIZER; +static int got_frames = 0; -freenect_device *f_dev; -int freenect_angle = 15; -int freenect_led; - -pthread_cond_t frame_cond = PTHREAD_COND_INITIALIZER; -int got_frames = 0; - -uint16_t t_gamma[2048]; -freenect_context *f_ctx; +static freenect_context *f_ctx; void *freenect_threadfunc(void* arg); // void depth_cb(freenect_device *dev, void *depth, uint32_t timestamp); @@ -42,9 +35,9 @@ void *freenect_threadfunc(void* arg); void send_event(const string& etype, const string& edata); void* freenect_threadfunc(void* arg) { //all this thread does is to fetch events from freenect - cout << "freenect thread"<= 0 ) {} - cout << "freenect die"<& contour, - vector& second_contour, - Point2i& previous); + vector& contour, + vector& second_contour, + cv::Point2i& previous); extern void makePointsFromMask(Mat& maskm,vector& points, bool _add = false); extern void drawPoint(Mat& out,vector& points,Scalar color, Mat* maskm = NULL); @@ -224,7 +217,7 @@ void* ocvFreenectThread(void* arg) { vector prevPts,nextPts; vector statusv; vector errv; - Rect cursor(frameMat.cols/2,frameMat.rows/2,10,10); + cv::Rect cursor(frameMat.cols/2,frameMat.rows/2,10,10); bool update_bg_model = true; int fr = 1; int register_ctr = 0,register_secondbloc_ctr = 0; @@ -239,6 +232,7 @@ void* ocvFreenectThread(void* arg) { vector hc_stack(20); int hc_stack_ptr = 0; die = false; + dead = NO; while (!die) { fr++; @@ -274,7 +268,7 @@ void* ocvFreenectThread(void* arg) { Mat blobMaskInput = depthf < 255; //anything not white is "real" depth - vector ctr,ctr2; + vector ctr,ctr2; Scalar blb = refineSegments(Mat(),blobMaskInput,blobMaskOutput,ctr,ctr2,midBlob); //find contours in the foreground, choose biggest @@ -287,7 +281,7 @@ void* ocvFreenectThread(void* arg) { //cvtColor(depthf, outC, CV_GRAY2BGR); //closest point to the camera - Point minLoc; double minval,maxval; + cv::Point minLoc; double minval,maxval; minMaxLoc(depthf, &minval, &maxval, &minLoc, NULL, blobMaskInput); circle(outC, minLoc, 5, Scalar(0,255,0), 3); @@ -318,12 +312,12 @@ void* ocvFreenectThread(void* arg) { // Vec4f _line; Mat curve(ctr); // fitLine(curve, _line, CV_DIST_L2, 0, 0.01, 0.01); - // line(outC, Point(blb[0]-_line[0]*70,blb[1]-_line[1]*70), - // Point(blb[0]+_line[0]*70,blb[1]+_line[1]*70), + // line(outC, cv::Point(blb[0]-_line[0]*70,blb[1]-_line[1]*70), + // cv::Point(blb[0]+_line[0]*70,blb[1]+_line[1]*70), // Scalar(255,255,0), 1); //blob center - circle(outC, Point(blb[0],blb[1]), 50, Scalar(255,0,0), 3); + circle(outC, cv::Point(blb[0],blb[1]), 50, Scalar(255,0,0), 3); // cout << "min depth " << minval << endl; @@ -365,7 +359,7 @@ void* ocvFreenectThread(void* arg) { //---------------------- fist detection --------------------- //calc laplacian of curve - vector approxCurve; //approximate curve + vector approxCurve; //approximate curve approxPolyDP(curve, approxCurve, 10.0, true); Mat approxCurveM(approxCurve); @@ -397,7 +391,7 @@ void* ocvFreenectThread(void* arg) { { //some debug on screen.. stringstream ss; ss << "high curve pts " << hcr_ctr << ", avg " << _avg[0]; - putText(outC, ss.str(), Point(50,50), CV_FONT_HERSHEY_PLAIN, 2.0,Scalar(0,0,255), 2); + putText(outC, ss.str(), cv::Point(50,50), CV_FONT_HERSHEY_PLAIN, 2.0,Scalar(0,0,255), 2); } } else { //not registered, look for gestures @@ -412,7 +406,7 @@ void* ocvFreenectThread(void* arg) { double timediff = ((double)getTickCount()-appearTS)/getTickFrequency(); if (timediff > .2 && timediff < 1.0) { //enough time passed from appearence - line(outC, appear, Point(blb[0],blb[1]), Scalar(0,0,255), 3); + line(outC, appear, cv::Point(blb[0],blb[1]), Scalar(0,0,255), 3); if (appear.x - blb[0] > 100) { cout << "right"< - - - - ActivePerspectiveName - Debug - AllowedModules - - - BundleLoadPath - - MaxInstances - n - Module - PBXSmartGroupTreeModule - Name - Groups and Files Outline View - - - BundleLoadPath - - MaxInstances - n - Module - PBXNavigatorGroup - Name - Editor - - - BundleLoadPath - - MaxInstances - n - Module - XCTaskListModule - Name - Task List - - - BundleLoadPath - - MaxInstances - n - Module - XCDetailModule - Name - File and Smart Group Detail Viewer - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXBuildResultsModule - Name - Detailed Build Results Viewer - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXProjectFindModule - Name - Project Batch Find Tool - - - BundleLoadPath - - MaxInstances - n - Module - XCProjectFormatConflictsModule - Name - Project Format Conflicts List - - - BundleLoadPath - - MaxInstances - n - Module - PBXBookmarksModule - Name - Bookmarks Tool - - - BundleLoadPath - - MaxInstances - n - Module - PBXClassBrowserModule - Name - Class Browser - - - BundleLoadPath - - MaxInstances - n - Module - PBXCVSModule - Name - Source Code Control Tool - - - BundleLoadPath - - MaxInstances - n - Module - PBXDebugBreakpointsModule - Name - Debug Breakpoints Tool - - - BundleLoadPath - - MaxInstances - n - Module - XCDockableInspector - Name - Inspector - - - BundleLoadPath - - MaxInstances - n - Module - PBXOpenQuicklyModule - Name - Open Quickly Tool - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXDebugSessionModule - Name - Debugger - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXDebugCLIModule - Name - Debug Console - - - BundleLoadPath - - MaxInstances - n - Module - XCSnapshotModule - Name - Snapshots Tool - - - BundlePath - /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources - Description - AIODescriptionKey - DockingSystemVisible - - Extension - perspectivev3 - FavBarConfig - - PBXProjectModuleGUID - 938563D1130E6093000F4333 - XCBarModuleItemNames - - XCBarModuleItems - - - FirstTimeWindowDisplayed - - Identifier - com.apple.perspectives.project.defaultV3 - MajorVersion - 34 - MinorVersion - 0 - Name - All-In-One - Notifications - - OpenEditors - - PerspectiveWidths - - 1520 - 1520 - - Perspectives - - - ChosenToolbarItems - - XCToolbarPerspectiveControl - NSToolbarSeparatorItem - active-combo-popup - action - NSToolbarFlexibleSpaceItem - debugger-enable-breakpoints - build-and-go - com.apple.ide.PBXToolbarStopButton - get-info - NSToolbarFlexibleSpaceItem - com.apple.pbx.toolbar.searchfield - - ControllerClassBaseName - - IconName - WindowOfProject - Identifier - perspective.project - IsVertical - - Layout - - - ContentConfiguration - - PBXBottomSmartGroupGIDs - - 1C37FBAC04509CD000000102 - 1C37FAAC04509CD000000102 - 1C37FABC05509CD000000102 - 1C37FABC05539CD112110102 - E2644B35053B69B200211256 - 1C37FABC04509CD000100104 - 1CC0EA4004350EF90044410B - 1CC0EA4004350EF90041110B - 1C77FABC04509CD000000102 - - PBXProjectModuleGUID - 1CA23ED40692098700951B8B - PBXProjectModuleLabel - Files - PBXProjectStructureProvided - yes - PBXSmartGroupTreeModuleColumnData - - PBXSmartGroupTreeModuleColumnWidthsKey - - 215 - - PBXSmartGroupTreeModuleColumnsKey_v4 - - MainColumn - - - PBXSmartGroupTreeModuleOutlineStateKey_v7 - - PBXSmartGroupTreeModuleOutlineStateExpansionKey - - 0259C574FE90428111CA0C5A - 32DBCF9E0370C38000C91783 - 32DBCF9F0370C38200C91783 - 0259C582FE90428111CA0C5A - 1ED78706FE9D4A0611CA0C5A - 1C37FBAC04509CD000000102 - 937655B5131308DD00AC9D36 - 9376560913136E2F00AC9D36 - 1C37FAAC04509CD000000102 - - PBXSmartGroupTreeModuleOutlineStateSelectionKey - - - 3 - 1 - 0 - - - PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 0}, {215, 1256}} - - PBXTopSmartGroupGIDs - - XCIncludePerspectivesSwitch - - - GeometryConfiguration - - Frame - {{0, 0}, {232, 1274}} - GroupTreeTableConfiguration - - MainColumn - 215 - - - Module - PBXSmartGroupTreeModule - Proportion - 232pt - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 938563CC130E6093000F4333 - PBXProjectModuleLabel - webkit_plugin_macView.mm - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - 938563CD130E6093000F4333 - PBXProjectModuleLabel - webkit_plugin_macView.mm - _historyCapacity - 0 - bookmark - 937656211313700E00AC9D36 - history - - 938DB61E130F3490008C37B1 - 938DB6E4130F3A7D008C37B1 - 938DB708130F444D008C37B1 - 938DB81E130F4A2E008C37B1 - 938DB82E130F4AF9008C37B1 - 937655E213136B9200AC9D36 - 9376561D1313700E00AC9D36 - 9376561E1313700E00AC9D36 - 9376561F1313700E00AC9D36 - - - SplitCount - 1 - - StatusBarVisibility - - XCSharingToken - com.apple.Xcode.CommonNavigatorGroupSharingToken - - GeometryConfiguration - - Frame - {{0, 0}, {1283, 1077}} - - Module - PBXNavigatorGroup - Proportion - 1077pt - - - Proportion - 192pt - Tabs - - - ContentConfiguration - - PBXProjectModuleGUID - 1CA23EDF0692099D00951B8B - PBXProjectModuleLabel - Detail - - GeometryConfiguration - - Frame - {{10, 27}, {1283, 165}} - - Module - XCDetailModule - - - ContentConfiguration - - PBXProjectModuleGUID - 1CA23EE00692099D00951B8B - PBXProjectModuleLabel - Project Find - - GeometryConfiguration - - Frame - {{10, 27}, {1043, 591}} - - Module - PBXProjectFindModule - - - ContentConfiguration - - PBXCVSModuleFilterTypeKey - 1032 - PBXProjectModuleGUID - 1CA23EE10692099D00951B8B - PBXProjectModuleLabel - SCM Results - - GeometryConfiguration - - Frame - {{10, 27}, {1043, 591}} - - Module - PBXCVSModule - - - ContentConfiguration - - PBXProjectModuleGUID - XCMainBuildResultsModuleGUID - PBXProjectModuleLabel - Build Results - XCBuildResultsTrigger_Collapse - 1021 - XCBuildResultsTrigger_Open - 1011 - - GeometryConfiguration - - Frame - {{10, 27}, {1043, 591}} - - Module - PBXBuildResultsModule - - - - - Proportion - 1283pt - - - Name - Project - ServiceClasses - - XCModuleDock - PBXSmartGroupTreeModule - XCModuleDock - PBXNavigatorGroup - XCDockableTabModule - XCDetailModule - PBXProjectFindModule - PBXCVSModule - PBXBuildResultsModule - - TableOfContents - - 937655BC131308DE00AC9D36 - 1CA23ED40692098700951B8B - 937655BD131308DE00AC9D36 - 938563CC130E6093000F4333 - 937655BE131308DE00AC9D36 - 1CA23EDF0692099D00951B8B - 1CA23EE00692099D00951B8B - 1CA23EE10692099D00951B8B - XCMainBuildResultsModuleGUID - - ToolbarConfigUserDefaultsMinorVersion - 2 - ToolbarConfiguration - xcode.toolbar.config.defaultV3 - - - ChosenToolbarItems - - XCToolbarPerspectiveControl - NSToolbarSeparatorItem - active-combo-popup - NSToolbarFlexibleSpaceItem - debugger-enable-breakpoints - build-and-go - com.apple.ide.PBXToolbarStopButton - debugger-restart-executable - debugger-pause - debugger-step-over - debugger-step-into - debugger-step-out - NSToolbarFlexibleSpaceItem - servicesModulebreakpoints - debugger-show-console-window - - ControllerClassBaseName - PBXDebugSessionModule - IconName - DebugTabIcon - Identifier - perspective.debug - IsVertical - - Layout - - - BecomeActive - - ContentConfiguration - - PBXProjectModuleGUID - 1CCC7628064C1048000F2A68 - PBXProjectModuleLabel - Debugger Console - - GeometryConfiguration - - Frame - {{0, 0}, {1520, 391}} - RubberWindowFrame - 652 197 1520 1315 0 0 2560 1578 - - Module - PBXDebugCLIModule - Proportion - 391pt - - - ContentConfiguration - - Debugger - - HorizontalSplitView - - _collapsingFrameDimension - 0.0 - _indexOfCollapsedView - 0 - _percentageOfCollapsedView - 0.0 - isCollapsed - yes - sizes - - {{0, 0}, {729, 200}} - {{729, 0}, {791, 200}} - - - VerticalSplitView - - _collapsingFrameDimension - 0.0 - _indexOfCollapsedView - 0 - _percentageOfCollapsedView - 0.0 - isCollapsed - yes - sizes - - {{0, 0}, {1520, 200}} - {{0, 200}, {1520, 678}} - - - - LauncherConfigVersion - 8 - PBXProjectModuleGUID - 1CCC7629064C1048000F2A68 - PBXProjectModuleLabel - Debug - - GeometryConfiguration - - DebugConsoleVisible - None - DebugConsoleWindowFrame - {{200, 200}, {500, 300}} - DebugSTDIOWindowFrame - {{200, 200}, {500, 300}} - Frame - {{0, 396}, {1520, 878}} - PBXDebugSessionStackFrameViewKey - - DebugVariablesTableConfiguration - - Name - 120 - Value - 85 - Summary - 561 - - Frame - {{729, 0}, {791, 200}} - RubberWindowFrame - 652 197 1520 1315 0 0 2560 1578 - - RubberWindowFrame - 652 197 1520 1315 0 0 2560 1578 - - Module - PBXDebugSessionModule - Proportion - 878pt - - - Name - Debug - ServiceClasses - - XCModuleDock - PBXDebugCLIModule - PBXDebugSessionModule - PBXDebugProcessAndThreadModule - PBXDebugProcessViewModule - PBXDebugThreadViewModule - PBXDebugStackFrameViewModule - PBXNavigatorGroup - - TableOfContents - - 937655C3131308E800AC9D36 - 1CCC7628064C1048000F2A68 - 1CCC7629064C1048000F2A68 - 937655C4131308E800AC9D36 - 937655C5131308E800AC9D36 - 937655C6131308E800AC9D36 - 937655C7131308E800AC9D36 - 938563CC130E6093000F4333 - - ToolbarConfigUserDefaultsMinorVersion - 2 - ToolbarConfiguration - xcode.toolbar.config.debugV3 - - - PerspectivesBarVisible - - ShelfIsVisible - - SourceDescription - file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecification.xcperspec' - StatusbarIsVisible - - TimeStamp - 0.0 - ToolbarConfigUserDefaultsMinorVersion - 2 - ToolbarDisplayMode - 1 - ToolbarIsVisible - - ToolbarSizeMode - 1 - Type - Perspectives - UpdateMessage - - WindowJustification - 5 - WindowOrderList - - 937656221313700E00AC9D36 - 937655C9131308E800AC9D36 - 937655CA131308E800AC9D36 - /Volumes/New HD/Users/aaron/eclipseWorkspace/depthjs/webkit-plugin-mac/webkit-plugin-mac.xcodeproj - - WindowString - 652 197 1520 1315 0 0 2560 1578 - WindowToolsV3 - - - Identifier - windowTool.debugger - Layout - - - Dock - - - ContentConfiguration - - Debugger - - HorizontalSplitView - - _collapsingFrameDimension - 0.0 - _indexOfCollapsedView - 0 - _percentageOfCollapsedView - 0.0 - isCollapsed - yes - sizes - - {{0, 0}, {317, 164}} - {{317, 0}, {377, 164}} - - - VerticalSplitView - - _collapsingFrameDimension - 0.0 - _indexOfCollapsedView - 0 - _percentageOfCollapsedView - 0.0 - isCollapsed - yes - sizes - - {{0, 0}, {694, 164}} - {{0, 164}, {694, 216}} - - - - LauncherConfigVersion - 8 - PBXProjectModuleGUID - 1C162984064C10D400B95A72 - PBXProjectModuleLabel - Debug - GLUTExamples (Underwater) - - GeometryConfiguration - - DebugConsoleDrawerSize - {100, 120} - DebugConsoleVisible - None - DebugConsoleWindowFrame - {{200, 200}, {500, 300}} - DebugSTDIOWindowFrame - {{200, 200}, {500, 300}} - Frame - {{0, 0}, {694, 380}} - RubberWindowFrame - 321 238 694 422 0 0 1440 878 - - Module - PBXDebugSessionModule - Proportion - 100% - - - Proportion - 100% - - - Name - Debugger - ServiceClasses - - PBXDebugSessionModule - - StatusbarIsVisible - 1 - TableOfContents - - 1CD10A99069EF8BA00B06720 - 1C0AD2AB069F1E9B00FABCE6 - 1C162984064C10D400B95A72 - 1C0AD2AC069F1E9B00FABCE6 - - ToolbarConfiguration - xcode.toolbar.config.debugV3 - WindowString - 321 238 694 422 0 0 1440 878 - WindowToolGUID - 1CD10A99069EF8BA00B06720 - WindowToolIsVisible - 0 - - - Identifier - windowTool.build - Layout - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 1CD0528F0623707200166675 - PBXProjectModuleLabel - <No Editor> - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - 1CD052900623707200166675 - - SplitCount - 1 - - StatusBarVisibility - 1 - - GeometryConfiguration - - Frame - {{0, 0}, {500, 215}} - RubberWindowFrame - 192 257 500 500 0 0 1280 1002 - - Module - PBXNavigatorGroup - Proportion - 218pt - - - BecomeActive - 1 - ContentConfiguration - - PBXProjectModuleGUID - XCMainBuildResultsModuleGUID - PBXProjectModuleLabel - Build Results - - GeometryConfiguration - - Frame - {{0, 222}, {500, 236}} - RubberWindowFrame - 192 257 500 500 0 0 1280 1002 - - Module - PBXBuildResultsModule - Proportion - 236pt - - - Proportion - 458pt - - - Name - Build Results - ServiceClasses - - PBXBuildResultsModule - - StatusbarIsVisible - 1 - TableOfContents - - 1C78EAA5065D492600B07095 - 1C78EAA6065D492600B07095 - 1CD0528F0623707200166675 - XCMainBuildResultsModuleGUID - - ToolbarConfiguration - xcode.toolbar.config.buildV3 - WindowString - 192 257 500 500 0 0 1280 1002 - - - Identifier - windowTool.find - Layout - - - Dock - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 1CDD528C0622207200134675 - PBXProjectModuleLabel - <No Editor> - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - 1CD0528D0623707200166675 - - SplitCount - 1 - - StatusBarVisibility - 1 - - GeometryConfiguration - - Frame - {{0, 0}, {781, 167}} - RubberWindowFrame - 62 385 781 470 0 0 1440 878 - - Module - PBXNavigatorGroup - Proportion - 781pt - - - Proportion - 50% - - - BecomeActive - 1 - ContentConfiguration - - PBXProjectModuleGUID - 1CD0528E0623707200166675 - PBXProjectModuleLabel - Project Find - - GeometryConfiguration - - Frame - {{8, 0}, {773, 254}} - RubberWindowFrame - 62 385 781 470 0 0 1440 878 - - Module - PBXProjectFindModule - Proportion - 50% - - - Proportion - 428pt - - - Name - Project Find - ServiceClasses - - PBXProjectFindModule - - StatusbarIsVisible - 1 - TableOfContents - - 1C530D57069F1CE1000CFCEE - 1C530D58069F1CE1000CFCEE - 1C530D59069F1CE1000CFCEE - 1CDD528C0622207200134675 - 1C530D5A069F1CE1000CFCEE - 1CE0B1FE06471DED0097A5F4 - 1CD0528E0623707200166675 - - WindowString - 62 385 781 470 0 0 1440 878 - WindowToolGUID - 1C530D57069F1CE1000CFCEE - WindowToolIsVisible - 0 - - - Identifier - windowTool.snapshots - Layout - - - Dock - - - Module - XCSnapshotModule - Proportion - 100% - - - Proportion - 100% - - - Name - Snapshots - ServiceClasses - - XCSnapshotModule - - StatusbarIsVisible - Yes - ToolbarConfiguration - xcode.toolbar.config.snapshots - WindowString - 315 824 300 550 0 0 1440 878 - WindowToolIsVisible - Yes - - - Identifier - windowTool.debuggerConsole - Layout - - - Dock - - - BecomeActive - 1 - ContentConfiguration - - PBXProjectModuleGUID - 1C78EAAC065D492600B07095 - PBXProjectModuleLabel - Debugger Console - - GeometryConfiguration - - Frame - {{0, 0}, {700, 358}} - RubberWindowFrame - 149 87 700 400 0 0 1440 878 - - Module - PBXDebugCLIModule - Proportion - 358pt - - - Proportion - 358pt - - - Name - Debugger Console - ServiceClasses - - PBXDebugCLIModule - - StatusbarIsVisible - 1 - TableOfContents - - 1C530D5B069F1CE1000CFCEE - 1C530D5C069F1CE1000CFCEE - 1C78EAAC065D492600B07095 - - ToolbarConfiguration - xcode.toolbar.config.consoleV3 - WindowString - 149 87 440 400 0 0 1440 878 - WindowToolGUID - 1C530D5B069F1CE1000CFCEE - WindowToolIsVisible - 0 - - - Identifier - windowTool.scm - Layout - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 1C78EAB2065D492600B07095 - PBXProjectModuleLabel - <No Editor> - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - 1C78EAB3065D492600B07095 - - SplitCount - 1 - - StatusBarVisibility - 1 - - GeometryConfiguration - - Frame - {{0, 0}, {452, 0}} - RubberWindowFrame - 743 379 452 308 0 0 1280 1002 - - Module - PBXNavigatorGroup - Proportion - 0pt - - - BecomeActive - 1 - ContentConfiguration - - PBXProjectModuleGUID - 1CD052920623707200166675 - PBXProjectModuleLabel - SCM - - GeometryConfiguration - - ConsoleFrame - {{0, 259}, {452, 0}} - Frame - {{0, 7}, {452, 259}} - RubberWindowFrame - 743 379 452 308 0 0 1280 1002 - TableConfiguration - - Status - 30 - FileName - 199 - Path - 197.09500122070312 - - TableFrame - {{0, 0}, {452, 250}} - - Module - PBXCVSModule - Proportion - 262pt - - - Proportion - 266pt - - - Name - SCM - ServiceClasses - - PBXCVSModule - - StatusbarIsVisible - 1 - TableOfContents - - 1C78EAB4065D492600B07095 - 1C78EAB5065D492600B07095 - 1C78EAB2065D492600B07095 - 1CD052920623707200166675 - - ToolbarConfiguration - xcode.toolbar.config.scmV3 - WindowString - 743 379 452 308 0 0 1280 1002 - - - Identifier - windowTool.breakpoints - IsVertical - 0 - Layout - - - Dock - - - BecomeActive - 1 - ContentConfiguration - - PBXBottomSmartGroupGIDs - - 1C77FABC04509CD000000102 - - PBXProjectModuleGUID - 1CE0B1FE06471DED0097A5F4 - PBXProjectModuleLabel - Files - PBXProjectStructureProvided - no - PBXSmartGroupTreeModuleColumnData - - PBXSmartGroupTreeModuleColumnWidthsKey - - 168 - - PBXSmartGroupTreeModuleColumnsKey_v4 - - MainColumn - - - PBXSmartGroupTreeModuleOutlineStateKey_v7 - - PBXSmartGroupTreeModuleOutlineStateExpansionKey - - 1C77FABC04509CD000000102 - - PBXSmartGroupTreeModuleOutlineStateSelectionKey - - - 0 - - - PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 0}, {168, 350}} - - PBXTopSmartGroupGIDs - - XCIncludePerspectivesSwitch - 0 - - GeometryConfiguration - - Frame - {{0, 0}, {185, 368}} - GroupTreeTableConfiguration - - MainColumn - 168 - - RubberWindowFrame - 315 424 744 409 0 0 1440 878 - - Module - PBXSmartGroupTreeModule - Proportion - 185pt - - - ContentConfiguration - - PBXProjectModuleGUID - 1CA1AED706398EBD00589147 - PBXProjectModuleLabel - Detail - - GeometryConfiguration - - Frame - {{190, 0}, {554, 368}} - RubberWindowFrame - 315 424 744 409 0 0 1440 878 - - Module - XCDetailModule - Proportion - 554pt - - - Proportion - 368pt - - - MajorVersion - 3 - MinorVersion - 0 - Name - Breakpoints - ServiceClasses - - PBXSmartGroupTreeModule - XCDetailModule - - StatusbarIsVisible - 1 - TableOfContents - - 1CDDB66807F98D9800BB5817 - 1CDDB66907F98D9800BB5817 - 1CE0B1FE06471DED0097A5F4 - 1CA1AED706398EBD00589147 - - ToolbarConfiguration - xcode.toolbar.config.breakpointsV3 - WindowString - 315 424 744 409 0 0 1440 878 - WindowToolGUID - 1CDDB66807F98D9800BB5817 - WindowToolIsVisible - 1 - - - Identifier - windowTool.debugAnimator - Layout - - - Dock - - - Module - PBXNavigatorGroup - Proportion - 100% - - - Proportion - 100% - - - Name - Debug Visualizer - ServiceClasses - - PBXNavigatorGroup - - StatusbarIsVisible - 1 - ToolbarConfiguration - xcode.toolbar.config.debugAnimatorV3 - WindowString - 100 100 700 500 0 0 1280 1002 - - - Identifier - windowTool.bookmarks - Layout - - - Dock - - - Module - PBXBookmarksModule - Proportion - 166pt - - - Proportion - 166pt - - - Name - Bookmarks - ServiceClasses - - PBXBookmarksModule - - StatusbarIsVisible - 0 - WindowString - 538 42 401 187 0 0 1280 1002 - - - Identifier - windowTool.projectFormatConflicts - Layout - - - Dock - - - Module - XCProjectFormatConflictsModule - Proportion - 100% - - - Proportion - 100% - - - Name - Project Format Conflicts - ServiceClasses - - XCProjectFormatConflictsModule - - StatusbarIsVisible - 0 - WindowContentMinSize - 450 300 - WindowString - 50 850 472 307 0 0 1440 877 - - - Identifier - windowTool.classBrowser - Layout - - - Dock - - - BecomeActive - 1 - ContentConfiguration - - OptionsSetName - Hierarchy, all classes - PBXProjectModuleGUID - 1CA6456E063B45B4001379D8 - PBXProjectModuleLabel - Class Browser - NSObject - - GeometryConfiguration - - ClassesFrame - {{0, 0}, {369, 96}} - ClassesTreeTableConfiguration - - PBXClassNameColumnIdentifier - 208 - PBXClassBookColumnIdentifier - 22 - - Frame - {{0, 0}, {616, 353}} - MembersFrame - {{0, 105}, {369, 395}} - MembersTreeTableConfiguration - - PBXMemberTypeIconColumnIdentifier - 22 - PBXMemberNameColumnIdentifier - 216 - PBXMemberTypeColumnIdentifier - 94 - PBXMemberBookColumnIdentifier - 22 - - PBXModuleWindowStatusBarHidden2 - 1 - RubberWindowFrame - 597 125 616 374 0 0 1280 1002 - - Module - PBXClassBrowserModule - Proportion - 354pt - - - Proportion - 354pt - - - Name - Class Browser - ServiceClasses - - PBXClassBrowserModule - - StatusbarIsVisible - 0 - TableOfContents - - 1C78EABA065D492600B07095 - 1C78EABB065D492600B07095 - 1CA6456E063B45B4001379D8 - - ToolbarConfiguration - xcode.toolbar.config.classbrowser - WindowString - 597 125 616 374 0 0 1280 1002 - - - Identifier - windowTool.refactoring - IncludeInToolsMenu - 0 - Layout - - - Dock - - - BecomeActive - 1 - GeometryConfiguration - - Frame - {0, 0}, {500, 335} - RubberWindowFrame - {0, 0}, {500, 335} - - Module - XCRefactoringModule - Proportion - 100% - - - Proportion - 100% - - - Name - Refactoring - ServiceClasses - - XCRefactoringModule - - WindowString - 200 200 500 356 0 0 1920 1200 - - - - diff --git a/webkit-plugin-mac/webkit-plugin-mac.xcodeproj/project.pbxproj b/webkit-plugin-mac/webkit-plugin-mac.xcodeproj/project.pbxproj index 6239433..9face7e 100644 --- a/webkit-plugin-mac/webkit-plugin-mac.xcodeproj/project.pbxproj +++ b/webkit-plugin-mac/webkit-plugin-mac.xcodeproj/project.pbxproj @@ -13,11 +13,15 @@ 8D1AC9800486D23B00FE50C9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D1AC97F0486D23B00FE50C9 /* InfoPlist.strings */; }; 937655FA13136C7500AC9D36 /* libMallocDebug.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 937655F913136C7500AC9D36 /* libMallocDebug.A.dylib */; }; 938563E3130E61AF000F4333 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 938563DC130E61AF000F4333 /* Info.plist */; }; - 938564A3130E6EC0000F4333 /* ocv_freenect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 938564A1130E6EC0000F4333 /* ocv_freenect.cpp */; }; + 938564A3130E6EC0000F4333 /* ocv_freenect.mm in Sources */ = {isa = PBXBuildFile; fileRef = 938564A1130E6EC0000F4333 /* ocv_freenect.mm */; }; 938564A8130E6EE0000F4333 /* bg_fg_blobs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 938564A6130E6EE0000F4333 /* bg_fg_blobs.cpp */; }; 938DB6F5130F3CDC008C37B1 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 938DB6F4130F3CDC008C37B1 /* IOKit.framework */; }; 938DB6FE130F3D7D008C37B1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 938DB6FD130F3D7D008C37B1 /* libz.dylib */; }; 938DB702130F43F0008C37B1 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 938DB701130F43F0008C37B1 /* Accelerate.framework */; }; + 93F690C71321789600F53A8A /* DLog.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93F690C61321789600F53A8A /* DLog.mm */; }; + 93F691821321A45600F53A8A /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93F691811321A45600F53A8A /* JavaScriptCore.framework */; }; + D713093013235B55001594A0 /* gesture_engine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D713092E13235B55001594A0 /* gesture_engine.cpp */; }; + D7CC1ABA1325B7EC001FB6D2 /* data-samples-labels.yaml in Resources */ = {isa = PBXBuildFile; fileRef = D7CC1AB91325B7EC001FB6D2 /* data-samples-labels.yaml */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -58,13 +62,20 @@ 93856486130E6E4B000F4333 /* libopencv_objdetect.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopencv_objdetect.a; path = opencv/libopencv_objdetect.a; sourceTree = ""; }; 93856488130E6E4B000F4333 /* libopencv_video_pch_dephelp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopencv_video_pch_dephelp.a; path = opencv/libopencv_video_pch_dephelp.a; sourceTree = ""; }; 9385648A130E6E4B000F4333 /* libopencv_video.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopencv_video.a; path = opencv/libopencv_video.a; sourceTree = ""; }; - 938564A1130E6EC0000F4333 /* ocv_freenect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ocv_freenect.cpp; sourceTree = ""; }; + 938564A1130E6EC0000F4333 /* ocv_freenect.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ocv_freenect.mm; sourceTree = ""; }; 938564A2130E6EC0000F4333 /* ocv_freenect.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ocv_freenect.hpp; sourceTree = ""; }; 938564A6130E6EE0000F4333 /* bg_fg_blobs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bg_fg_blobs.cpp; sourceTree = ""; }; 938564A7130E6EE0000F4333 /* bg_fg_blobs.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = bg_fg_blobs.hpp; sourceTree = ""; }; 938DB6F4130F3CDC008C37B1 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 938DB6FD130F3D7D008C37B1 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 938DB701130F43F0008C37B1 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; + 93F690C51321789600F53A8A /* DLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DLog.h; sourceTree = ""; }; + 93F690C61321789600F53A8A /* DLog.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DLog.mm; sourceTree = ""; }; + 93F691811321A45600F53A8A /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + D713092E13235B55001594A0 /* gesture_engine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gesture_engine.cpp; sourceTree = ""; }; + D713092F13235B55001594A0 /* FreenectDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FreenectDevice.h; sourceTree = ""; }; + D713093213235BCB001594A0 /* gesture_engine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = gesture_engine.hpp; sourceTree = ""; }; + D7CC1AB91325B7EC001FB6D2 /* data-samples-labels.yaml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "data-samples-labels.yaml"; path = "../new_cv/NewCV/build/Debug/data-samples-labels.yaml"; sourceTree = SOURCE_ROOT; }; DD92D38A0106425D02CA0E72 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; /* End PBXFileReference section */ @@ -79,6 +90,7 @@ 938DB6FE130F3D7D008C37B1 /* libz.dylib in Frameworks */, 938DB702130F43F0008C37B1 /* Accelerate.framework in Frameworks */, 937655FA13136C7500AC9D36 /* libMallocDebug.A.dylib in Frameworks */, + 93F691821321A45600F53A8A /* JavaScriptCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -95,6 +107,7 @@ 2E58F364FFB232C311CA0CBA /* Frameworks */, 938DB701130F43F0008C37B1 /* Accelerate.framework */, 937655F913136C7500AC9D36 /* libMallocDebug.A.dylib */, + 93F691811321A45600F53A8A /* JavaScriptCore.framework */, ); name = webkit_plugin_mac; sourceTree = ""; @@ -102,6 +115,7 @@ 0259C582FE90428111CA0C5A /* Resources */ = { isa = PBXGroup; children = ( + D7CC1AB91325B7EC001FB6D2 /* data-samples-labels.yaml */, 8D1AC9730486D14A00FE50C9 /* Info.plist */, 8D1AC97F0486D23B00FE50C9 /* InfoPlist.strings */, ); @@ -160,6 +174,8 @@ children = ( 0259C57AFE90428111CA0C5A /* webkit_plugin_macView.h */, 0259C576FE90428111CA0C5A /* webkit_plugin_macView.mm */, + 93F690C51321789600F53A8A /* DLog.h */, + 93F690C61321789600F53A8A /* DLog.mm */, ); name = Classes; sourceTree = ""; @@ -167,7 +183,10 @@ 32DBCF9F0370C38200C91783 /* Other Sources */ = { isa = PBXGroup; children = ( - 938564A1130E6EC0000F4333 /* ocv_freenect.cpp */, + D713093213235BCB001594A0 /* gesture_engine.hpp */, + D713092E13235B55001594A0 /* gesture_engine.cpp */, + D713092F13235B55001594A0 /* FreenectDevice.h */, + 938564A1130E6EC0000F4333 /* ocv_freenect.mm */, 938564A2130E6EC0000F4333 /* ocv_freenect.hpp */, 938564A6130E6EE0000F4333 /* bg_fg_blobs.cpp */, 938564A7130E6EE0000F4333 /* bg_fg_blobs.hpp */, @@ -230,6 +249,7 @@ files = ( 8D1AC9800486D23B00FE50C9 /* InfoPlist.strings in Resources */, 938563E3130E61AF000F4333 /* Info.plist in Resources */, + D7CC1ABA1325B7EC001FB6D2 /* data-samples-labels.yaml in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -257,8 +277,10 @@ buildActionMask = 2147483647; files = ( 8D1AC96B0486D14A00FE50C9 /* webkit_plugin_macView.mm in Sources */, - 938564A3130E6EC0000F4333 /* ocv_freenect.cpp in Sources */, + 938564A3130E6EC0000F4333 /* ocv_freenect.mm in Sources */, 938564A8130E6EE0000F4333 /* bg_fg_blobs.cpp in Sources */, + 93F690C71321789600F53A8A /* DLog.mm in Sources */, + D713093013235B55001594A0 /* gesture_engine.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -384,6 +406,13 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "-I${SOURCE_ROOT}/include", + "-I${SOURCE_ROOT}/include/libusb-1.0", + "-I${SOURCE_ROOT}/include/opencv", + "-I${SOURCE_ROOT}/include/opencv2", + "-I${SOURCE_ROOT}/include/libfreenect", + ); PREBINDING = NO; SDKROOT = macosx10.5; STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = dynamic; diff --git a/webkit-plugin-mac/webkit-plugin-mac_Prefix.pch b/webkit-plugin-mac/webkit-plugin-mac_Prefix.pch index d4c4c67..2990a27 100644 --- a/webkit-plugin-mac/webkit-plugin-mac_Prefix.pch +++ b/webkit-plugin-mac/webkit-plugin-mac_Prefix.pch @@ -3,7 +3,11 @@ // #ifdef __OBJC__ +#ifdef __cplusplus #include +#endif #import #import + #import "DLog.h" #endif + diff --git a/webkit-plugin-mac/webkit_plugin_macView.h b/webkit-plugin-mac/webkit_plugin_macView.h index f2a0490..abc8a2f 100644 --- a/webkit-plugin-mac/webkit_plugin_macView.h +++ b/webkit-plugin-mac/webkit_plugin_macView.h @@ -10,13 +10,11 @@ @interface webkit_plugin_macView : NSView { - BOOL haveInitDevice; NSDictionary *pluginArguments; + BOOL haveInitDevice; + NSThread *ocvThread; } - (NSDictionary *)pluginArguments; - (void)setPluginArguments:(NSDictionary *)value; - -- (void) InitDepthJS; -- (void) ShutdownDepthJS; - + @end diff --git a/webkit-plugin-mac/webkit_plugin_macView.mm b/webkit-plugin-mac/webkit_plugin_macView.mm index 8296ef2..58ea774 100644 --- a/webkit-plugin-mac/webkit_plugin_macView.mm +++ b/webkit-plugin-mac/webkit_plugin_macView.mm @@ -7,49 +7,52 @@ // #import "webkit_plugin_macView.h" - - #import #import -#include "ocv_freenect.hpp" +#import +//#include "ocv_freenect.hpp" +#include "gesture_engine.hpp" -static volatile bool haveInitDevice = false; +// PRIVATE METHODS --------------------------------------------------------------------------------- -static volatile webkit_plugin_macView* hostPlugin = nil; +@interface webkit_plugin_macView (JsExposed) +- (void) InitDepthJS; +- (void) ShutdownDepthJS; +- (void) CallbackTest; +@end -bool SendEventToBrowser(const string& _eventJson) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Top-level pool - - NSString *eventJson = [NSString stringWithCString:_eventJson.c_str() encoding:[NSString defaultCStringEncoding]]; - NSLog(@"Going to send the following eventJson nsstring: %@", eventJson); - +@interface webkit_plugin_macView (Internal) +- (id)_initWithArguments:(NSDictionary *)arguments; +- (void) ocvMainLoop; +@end + +// BRIDGE BACK FROM C++ LAND ----------------------------------------------------------------------- +static webkit_plugin_macView* hostPlugin = nil; + +bool SendEventToBrowser(const string& _eventJson) { if (hostPlugin == nil) { - NSLog(@"DepthJS Plugin: Ignoring event for uninit host"); return false; } - + + BOOL success = false; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Top-level pool id pluginContainer = [[hostPlugin pluginArguments] objectForKey:WebPlugInContainerKey]; - if (pluginContainer) { - /* retrieve a reference to the webview */ + if (pluginContainer != nil) { WebView *myWebView = [[pluginContainer webFrame] webView]; + NSString *eventJson = [NSString stringWithCString:_eventJson.c_str() encoding:[NSString defaultCStringEncoding]]; NSString *js = [NSString stringWithFormat:@"if(DepthJS && DepthJS.npBackend)DepthJS.npBackend.receiveEvent(%@)", eventJson]; - // [[myWebView windowScriptObject] evaluateWebScript:js]; - NSLog(@"Sent to javascript"); - [pool release]; // Release the objects in the pool. - return true; + [[myWebView windowScriptObject] performSelectorOnMainThread:@selector(evaluateWebScript:) withObject:js waitUntilDone:NO]; + DLog(@"[DepthJS] Sent: %@", eventJson); + success = true; } else { - NSLog(@"Could not find pluginContainer?!;"); - [pool release]; // Release the objects in the pool. + DLog(@"[DepthJS] Could not find pluginContainer?!;"); return false; } + [pool release]; // Release the objects in the pool. + return success; } - -@interface webkit_plugin_macView (Internal) -- (id)_initWithArguments:(NSDictionary *)arguments; -@end - @implementation webkit_plugin_macView // WebPlugInViewFactory protocol @@ -70,6 +73,7 @@ - (void)setPluginArguments:(NSDictionary *)value { if (pluginArguments != value) { [pluginArguments release]; pluginArguments = [value copy]; + DLog(@"just set args: %@", pluginArguments); } } @@ -84,41 +88,21 @@ - (void)webPlugInInitialize { // This method will be only called once per instance of the plug-in object, and will be called // before any other methods in the WebPlugIn protocol. // You are not required to implement this method. It may safely be removed. - NSLog(@"webPlugInInitialize"); + DLog(@"webPlugInInitialize"); haveInitDevice = NO; -} - -- (void)webPlugInStart { - // The plug-in usually begins drawing, playing sounds and/or animation in this method. - // You are not required to implement this method. It may safely be removed. - NSLog(@"webPlugInStart"); -} - -- (void)webPlugInStop { - // The plug-in normally stop animations/sounds in this method. - // You are not required to implement this method. It may safely be removed. - NSLog(@"webPlugInStop"); + ocvThread = nil; + if (hostPlugin == nil) { + hostPlugin = self; + } } - (void)webPlugInDestroy { - // Perform cleanup and prepare to be deallocated. - // You are not required to implement this method. It may safely be removed. - NSLog(@"webPlugInDestroy"); - haveInitDevice = FALSE; - -} - -- (void)webPlugInSetIsSelected:(BOOL)isSelected { - // This is typically used to allow the plug-in to alter its appearance when selected. - // You are not required to implement this method. It may safely be removed. - NSLog(@"webPlugInSetIsSelected"); + DLog(@"webPlugInDestroy"); + [self ShutdownDepthJS]; + DLog(@"webPlugInDestroy finished"); } - (id)objectForWebScript { - // Returns the object that exposes the plug-in's interface. The class of this object can implement - // methods from the WebScripting informal protocol. - // You are not required to implement this method. It may safely be removed. - NSLog(@"objectForWebScript"); return self; } @@ -127,62 +111,135 @@ - (NSString *)webScriptNameForSelector:(SEL)selector { return @"InitDepthJS"; } else if (selector == @selector(ShutdownDepthJS)) { return @"ShutdownDepthJS"; + } else if (selector == @selector(CallbackTest)) { + return @"CallbackTest"; } return nil; } + (BOOL)isSelectorExcludedFromWebScript:(SEL)selector { - NSLog(@"isSelectorExcludedFromWebScript"); + DLog(@"isSelectorExcludedFromWebScript"); if(selector == @selector(InitDepthJS) || - selector == @selector(ShutdownDepthJS)) { - NSLog(@"NO"); + selector == @selector(ShutdownDepthJS) || + selector == @selector(CallbackTest)) { + DLog(@"NO"); return NO; } - NSLog(@"YES"); + DLog(@"YES"); return YES; } - (void)finalizeForWebScript { - NSLog(@"finalizeForWebScript"); + DLog(@"finalizeForWebScript"); +} + +@end + +@implementation webkit_plugin_macView (Internal) + +- (id)_initWithArguments:(NSDictionary *)newArguments { + if (!(self = [super initWithFrame:NSZeroRect])) + return nil; + + [self setPluginArguments: newArguments]; + return self; +} + +- (void) ocvMainLoop { + ocvThread = [NSThread currentThread]; + [ocvThread setName:@"ocvMainLoop"]; +// ocvFreenectThread(NULL); + gesture_engine(NULL); +} + +@end + +@implementation webkit_plugin_macView (JsExposed) + +NSString* jsRefToTypeString(JSContextRef& ctx, JSValueRef& t) { + switch (JSValueGetType(ctx, t)) { + case kJSTypeNull: + return @"null"; + case kJSTypeUndefined: + return @"undefined"; + case kJSTypeBoolean: + return @"boolean"; + case kJSTypeNumber: + return @"number"; + case kJSTypeString: + return @"string"; + case kJSTypeObject: + return @"object"; + default: + return [NSString stringWithFormat:@"Unknown type: %d", t]; + } +} + +- (void) CallbackTest { + id pluginContainer = [[self pluginArguments] objectForKey:WebPlugInContainerKey]; + WebView *myWebView = [[pluginContainer webFrame] webView]; + JSObjectRef globalObj = [[myWebView windowScriptObject] JSObject]; + JSValueRef exception; + DLog(@"starting stuff to call DepthJS.k()"); + + // JSObjectRef globalObj = JSContextGetGlobalObject(ctx); + JSContextRef ctx = [[myWebView mainFrame] globalContext]; + JSValueRef depthJsRef = JSObjectGetProperty(ctx, globalObj, JSStringCreateWithCFString((CFStringRef)@"DepthJS"), &exception);; + DLog(@"depthjs ref type %s", jsRefToTypeString(ctx, depthJsRef)); + JSObjectRef depthJsObj = JSValueToObject(ctx, depthJsRef, &exception); + JSValueRef funcRef = JSObjectGetProperty(ctx, depthJsObj, JSStringCreateWithCFString((CFStringRef)@"k"), &exception); + DLog(@"depthjs.k ref type %s", jsRefToTypeString(ctx, funcRef)); + JSObjectRef funcObj = JSValueToObject(ctx, funcRef, &exception); + + JSValueRef result = JSObjectCallAsFunction(ctx, funcObj, NULL, 0, NULL, &exception); + if (result == NULL) { + DLog(@"got back null"); + } else { + DLog(@"got back type %s", jsRefToTypeString(ctx, result)); + } + DLog(@"done"); } - (void) InitDepthJS { - NSLog(@"DepthJS Plugin: InitDepthJS"); + DLog(@"[DepthJS] InitDepthJS"); + // If the windowScriptObject is not first referenced from this thread, we will later get a thread + // exception. Even though this doesn't do anything. Yah. I have no idea either. + id pluginContainer = [[hostPlugin pluginArguments] objectForKey:WebPlugInContainerKey]; + WebView *myWebView = [[pluginContainer webFrame] webView]; + [myWebView windowScriptObject]; if (!haveInitDevice) { - NSLog(@"DepthJS Plugin: Device not yet init; initing"); - haveInitDevice = launchOcvFreenect() == 0; + DLog(@"[DepthJS] Device not yet init; initing"); + hostPlugin = self; + NSString* pathToData = [[NSBundle bundleWithIdentifier:@"edu.mit.media.depthjs"] pathForResource:@"data-samples-labels" ofType:@"yaml"]; + int success = init_gesture_engine([pathToData cStringUsingEncoding:NSASCIIStringEncoding]); + haveInitDevice = success; if (haveInitDevice) { - NSLog(@"DepthJS Plugin: Successfully inited Kinect"); - hostPlugin = self; + DLog(@"[DepthJS] Successfully inited Kinect; Starting ocv thread"); + [NSThread detachNewThreadSelector:@selector(ocvMainLoop) toTarget:self withObject:nil]; } else { - NSLog(@"DepthJS Plugin: Failed to init Kinect"); + DLog(@"[DepthJS] Failed to init Kinect"); + hostPlugin = nil; } } else { - NSLog(@"DepthJS Plugin: Already init, ignoring"); + DLog(@"[DepthJS] Already init, ignoring"); } } - (void) ShutdownDepthJS { - NSLog(@"DepthJS Plugin: ShutdownDepthJS"); - killOcvFreenect(); - NSLog(@"DepthJS Plugin: ShutdownDepthJS complete"); + DLog(@"[DepthJS] ShutdownDepthJS"); haveInitDevice = false; if (hostPlugin == self) { hostPlugin = NULL; +// killOcvFreenect(); + kill_gesture_engine(); + if (ocvThread != nil) [ocvThread cancel]; + ocvThread = nil; + while (!is_gesture_engine_dead()) { + [NSThread sleepForTimeInterval:0.01]; + } } + DLog(@"[DepthJS] ShutdownDepthJS complete"); } -@end - -@implementation webkit_plugin_macView (Internal) - -- (id)_initWithArguments:(NSDictionary *)newArguments { - if (!(self = [super initWithFrame:NSZeroRect])) - return nil; - - [self setPluginArguments: newArguments]; - return self; -} - -@end +@end \ No newline at end of file