diff --git a/zonebb/addons.make b/zonebb/addons.make new file mode 100644 index 0000000..4b55504 --- /dev/null +++ b/zonebb/addons.make @@ -0,0 +1,6 @@ +ofxAzureKinect +ofxFluid +ofxFX +ofxGui +ofxShader +ofxV4L2 diff --git a/zonebb/bin/data/.gitkeep b/zonebb/bin/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/zonebb/bin/data/settings.xml b/zonebb/bin/data/settings.xml new file mode 100644 index 0000000..0f0ee4b --- /dev/null +++ b/zonebb/bin/data/settings.xml @@ -0,0 +1,9 @@ + + + 61.2245, -28.5714 + 1.7965 + video3 + 4 + 1 + 3 + diff --git a/zonebb/config.make b/zonebb/config.make new file mode 100644 index 0000000..836fce7 --- /dev/null +++ b/zonebb/config.make @@ -0,0 +1,141 @@ +################################################################################ +# CONFIGURE PROJECT MAKEFILE (optional) +# This file is where we make project specific configurations. +################################################################################ + +################################################################################ +# OF ROOT +# The location of your root openFrameworks installation +# (default) OF_ROOT = ../../.. +################################################################################ +# OF_ROOT = ../../.. + +################################################################################ +# PROJECT ROOT +# The location of the project - a starting place for searching for files +# (default) PROJECT_ROOT = . (this directory) +# +################################################################################ +# PROJECT_ROOT = . + +################################################################################ +# PROJECT SPECIFIC CHECKS +# This is a project defined section to create internal makefile flags to +# conditionally enable or disable the addition of various features within +# this makefile. For instance, if you want to make changes based on whether +# GTK is installed, one might test that here and create a variable to check. +################################################################################ +# None + +################################################################################ +# PROJECT EXTERNAL SOURCE PATHS +# These are fully qualified paths that are not within the PROJECT_ROOT folder. +# Like source folders in the PROJECT_ROOT, these paths are subject to +# exlclusion via the PROJECT_EXLCUSIONS list. +# +# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXTERNAL_SOURCE_PATHS = + +################################################################################ +# PROJECT EXCLUSIONS +# These makefiles assume that all folders in your current project directory +# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations +# to look for source code. The any folders or files that match any of the +# items in the PROJECT_EXCLUSIONS list below will be ignored. +# +# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete +# string unless teh user adds a wildcard (%) operator to match subdirectories. +# GNU make only allows one wildcard for matching. The second wildcard (%) is +# treated literally. +# +# (default) PROJECT_EXCLUSIONS = (blank) +# +# Will automatically exclude the following: +# +# $(PROJECT_ROOT)/bin% +# $(PROJECT_ROOT)/obj% +# $(PROJECT_ROOT)/%.xcodeproj +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_EXCLUSIONS = + +################################################################################ +# PROJECT LINKER FLAGS +# These flags will be sent to the linker when compiling the executable. +# +# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs +# +# Note: Leave a leading space when adding list items with the += operator +# +# Currently, shared libraries that are needed are copied to the +# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to +# add a runtime path to search for those shared libraries, since they aren't +# incorporated directly into the final executable application binary. +################################################################################ +# PROJECT_LDFLAGS=-Wl,-rpath=./libs + +################################################################################ +# PROJECT DEFINES +# Create a space-delimited list of DEFINES. The list will be converted into +# CFLAGS with the "-D" flag later in the makefile. +# +# (default) PROJECT_DEFINES = (blank) +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_DEFINES = + +################################################################################ +# PROJECT CFLAGS +# This is a list of fully qualified CFLAGS required when compiling for this +# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS +# defined in your platform specific core configuration files. These flags are +# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. +# +# (default) PROJECT_CFLAGS = (blank) +# +# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in +# your platform specific configuration file will be applied by default and +# further flags here may not be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CFLAGS = + +################################################################################ +# PROJECT OPTIMIZATION CFLAGS +# These are lists of CFLAGS that are target-specific. While any flags could +# be conditionally added, they are usually limited to optimization flags. +# These flags are added BEFORE the PROJECT_CFLAGS. +# +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank) +# +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets. +# +# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank) +# +# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the +# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration +# file will be applied by default and further optimization flags here may not +# be needed. +# +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = +# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = + +################################################################################ +# PROJECT COMPILERS +# Custom compilers can be set for CC and CXX +# (default) PROJECT_CXX = (blank) +# (default) PROJECT_CC = (blank) +# Note: Leave a leading space when adding list items with the += operator +################################################################################ +# PROJECT_CXX = +# PROJECT_CC = diff --git a/zonebb/src/main.cpp b/zonebb/src/main.cpp new file mode 100644 index 0000000..e57370b --- /dev/null +++ b/zonebb/src/main.cpp @@ -0,0 +1,13 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main( ){ + ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/zonebb/src/ofApp.cpp b/zonebb/src/ofApp.cpp new file mode 100644 index 0000000..35ace6c --- /dev/null +++ b/zonebb/src/ofApp.cpp @@ -0,0 +1,345 @@ +#include "ofApp.h" + +void ofApp::setupGui() +{ + gui.setup("ZONE B", "settings.xml"); // most of the time you don't need a name + gui.add(registrationXY.setup("XY", {-208, -257}, {-400, -400}, {400, 400})); + gui.add(registrationScale.setup("scale", 2.0, 0.1, 3)); + gui.add(v4l2Delay.setup("thermo delay", 0, 0, 59)); + gui.add(captureDeviceName.setup("device", "video3")); + gui.loadFromFile("settings.xml"); + gui.setPosition(10, 10); + + debugGui.setup("DEBUG"); + debugGui.add(calibMode.setup("calib", false)); + debugGui.add(dummyMode.setup("dummy", true)); // should be false + debugGui.add(dummyXY.setup("XY", {0, 0}, {-500, -500}, {500, 500})); // should be false + debugGui.add(debugFps.setup("FPS", "0")); + debugGui.setPosition(230, 10); +} + +void ofApp::setupKinect() +{ + ofLogNotice(__FUNCTION__) << "Found " << ofxAzureKinect::Device::getInstalledCount() << " installed devices."; + + auto kinectSettings = ofxAzureKinect::DeviceSettings(); + kinectSettings.updateIr = false; + kinectSettings.updateColor = true; + kinectSettings.colorResolution = K4A_COLOR_RESOLUTION_1080P; + kinectSettings.updateVbo = false; + + auto deviceSettings = ofxAzureKinect::DeviceSettings(); + deviceSettings.syncImages = false; + deviceSettings.depthMode = K4A_DEPTH_MODE_NFOV_UNBINNED; + deviceSettings.updateIr = false; + deviceSettings.updateColor = false; + //deviceSettings.colorResolution = K4A_COLOR_RESOLUTION_1080P; + deviceSettings.updateWorld = true; + deviceSettings.updateVbo = false; + auto bodyTrackingSettings = ofxAzureKinect::BodyTrackingSettings(); + //bodyTrackingSettings.processingMode = K4ABT_TRACKER_PROCESSING_MODE_CPU; + bodyTrackingSettings.updateBodies = true; + if (kinectDevice.open()) + { + kinectDevice.startCameras(kinectSettings, bodyTrackingSettings); + } +} + +void ofApp::setupThermal() +{ + // this must be called before init (otherwise fprintf will tell you so) + // note that high framerates will only function properly if the usb has enough bandwidth + // for example, a ps3 eye cam at 60 fps will only function when it has full USB 2.0 bandwidth available + v4l2Cam.setDesiredFramerate(60); + + // use this to set appropriate device and capture method + std::string dev = captureDeviceName; + v4l2Cam.initGrabber((std::string("/dev/") + dev).c_str(), IO_METHOD_MMAP, camWidth, camHeight); + + // some initial settings + int set_gain = 2.0; + bool set_autogain = true; + + // rudimentary settings implementation: each settings needs a seperate call to the settings method + v4l2Cam.settings(ofxV4L2_AUTOGAIN, set_autogain); + v4l2Cam.settings(ofxV4L2_GAIN, set_gain); + + v4l2Buffer.resize(60); + for (int i = 0; i < v4l2Buffer.size(); i++) + { + v4l2Buffer.at(i).allocate(512, 512, GL_RGB); + } + + v4l2Pixels.allocate(512, 512, OF_PIXELS_RGB); + for (int i = 0; i < 512; i++) + { + for (int j = 0; j < 512; j++) + { + v4l2Pixels.setColor(j, i, 0); + } + } + + areThereTwoPeople = false; + areThereTwoPeopleTween = 0; +} + +void ofApp::setupFluid() +{ + width = 1920; + height = 1200; + + // Initial Allocation + // + fluid.allocate(width, height, 0.5); + + // Seting the gravity set up & injecting the background image + // + fluid.dissipation = 0.9; + fluid.velocityDissipation = 0.995; + + fluid.setGravity(ofVec2f(0.0, 0.0)); + // fluid.setGravity(ofVec2f(0.0,0.0098)); + + // Set obstacle + // + // fluid.begin(); + // ofSetColor(0, 0); + // ofSetColor(255); + // ofCircle(width * 0.5, height * 0.35, 40); + // fluid.end(); + fluid.setUseObstacles(false); + + // Adding constant forces + // + // fluid.addConstantForce(ofPoint(width * 0.5, height * 0.85), ofPoint(0, -2), ofFloatColor(0.5, 0.1, 0.0), 10.f); +} + +void ofApp::setup() +{ + ofEnableAlphaBlending(); + ofSetCircleResolution(100); + + ofSetWindowShape(1920, 1080); + + setupGui(); + setupKinect(); + setupThermal(); + setupFluid(); + + fbos.insert({"main", ofFbo()}); + fbos.at("main").allocate(ofGetWidth(), ofGetHeight(), GL_RGBA32F_ARB); +} + +ofVec3f ofApp::getDepthAt(int x, int y) +{ + auto ray = kinectDevice.getDepthToWorldPix().getColor(x, y); + auto depthShort = kinectDevice.getDepthPix().getColor(x, y).r; + float depth = -depthShort; + if (depthShort == 0) + depth = -2000; + ofVec3f pos(ray.r * depth, ray.g * depth, depth); + return pos; +} + +void ofApp::updateThermal() +{ + v4l2Cam.grabFrame(); + if (v4l2Cam.isNewFrame()) + { + auto &body = kinectDevice.getBodyIndexPix(); + hotspots.clear(); + for (int i = 0; i < kinectDevice.getNumBodies(); i++) + { + hotspots.push_back(std::vector()); + } + for (int i = 0; i < 512; i++) + { + for (int j = 0; j < 512; j++) + { + int x = (j - 256) * registrationScale + 256 + registrationXY->x; + int y = (i - 256) * registrationScale + 256 + registrationXY->y; + if (ofInRange(x, 0, camWidth - 1) == false || ofInRange(y, 0, camHeight - 1) == false) + { + continue; + } + int count = x + y * camWidth; + int a = v4l2Cam.getPixels()[count]; + v4l2Pixels.setColor(j, i, a); + if (i % 4 == 0 && j % 4 == 0) + { + auto c = body.getColor(j, i); + if (c.r < hotspots.size()) + { + hotspots.at(c.r).push_back(ofVec3f(j, i, a)); + } + } + } + } + v4l2BufferCount = (v4l2BufferCount + 1) % (v4l2Delay + 1); + v4l2Buffer.at(v4l2BufferCount).allocate(v4l2Pixels); + + struct + { + bool operator()(ofVec3f a, ofVec3f b) const + { + return a.z > b.z; + } + } compareZThermal; + for (int i = 0; i < hotspots.size(); i++) + { + std::sort(hotspots.at(i).begin(), hotspots.at(i).end(), compareZThermal); + } + + if (dummyMode == false) + { + if (hotspots.size() > 0 && hotspots.at(0).size() > 0) + { + hotspot0 = hotspots.at(0).at(0); + } + if (hotspots.size() > 1 && hotspots.at(1).size() > 0) + { + hotspot1 = hotspots.at(1).at(0); + areThereTwoPeople = true; + areThereTwoPeopleTween = ofClamp(areThereTwoPeopleTween + 0.02, 0, 1); + } + else + { + areThereTwoPeople = false; + areThereTwoPeopleTween = ofClamp(areThereTwoPeopleTween - 0.02, 0, 1); + } + } + else + { + if (hotspots.size() > 0 && hotspots.at(0).size() > 0) + { + hotspot0 = hotspots.at(0).at(0); + } + { + hotspot1 = ofVec3f(dummyXY->x + 500, dummyXY->y + 500, 0); + areThereTwoPeople = true; + areThereTwoPeopleTween = ofClamp(areThereTwoPeopleTween + 0.02, 0, 1); + } + } + } +} + +void ofApp::updateFluid() +{ + fluid.addColor(v4l2Buffer.at(v4l2BufferCount), 0.1f); + + ofPoint m = ofPoint(mouseX,mouseY); + ofPoint d = (m - oldM)*10.0; + oldM = m; + ofPoint c = ofPoint(640*0.5, 480*0.5) - m; + c.normalize(); + fluid.addTemporalForce(m, d, ofFloatColor(0)*sin(ofGetElapsedTimef()),15.0f,20); + + // Update + // + fluid.update(); +} + +void ofApp::update() +{ + if (dummyMode == false) + { + auto &bodySkeletons = kinectDevice.getBodySkeletons(); + std::vector bodies; + if (bodySkeletons.size() >= 2) + { + for (auto &skeleton : bodySkeletons) + { + auto joint = skeleton.joints[26]; + bodies.push_back(toGlm(joint.position)); + } + uBetween = uBetween.getInterpolated(bodies.at(0).getInterpolated(bodies.at(1), 0.5f), 0.1f); + } + else + { + // uBetween = ofVec3f(10000000, 0, 0); + } + } + else + { + uBetween = ofVec3f(dummyXY->x, 0, dummyXY->y); + } + + updateThermal(); + updateFluid(); + + debugFps = ofToString(ofGetFrameRate(), 2); +} + +void ofApp::drawMain() +{ + ofBackgroundGradient(ofColor::gray, ofColor::black, OF_GRADIENT_LINEAR); + + fluid.draw(); +} + +void ofApp::drawDebug() +{ + gui.draw(); + debugGui.draw(); +} + +void ofApp::draw() +{ + drawMain(); + drawDebug(); +} + + +void ofApp::keyPressed(int key) +{ +} + + +void ofApp::keyReleased(int key) +{ +} + + +void ofApp::mouseMoved(int x, int y) +{ +} + + +void ofApp::mouseDragged(int x, int y, int button) +{ +} + + +void ofApp::mousePressed(int x, int y, int button) +{ +} + + +void ofApp::mouseReleased(int x, int y, int button) +{ +} + + +void ofApp::mouseEntered(int x, int y) +{ +} + + +void ofApp::mouseExited(int x, int y) +{ +} + + +void ofApp::windowResized(int w, int h) +{ +} + + +void ofApp::gotMessage(ofMessage msg) +{ +} + + +void ofApp::dragEvent(ofDragInfo dragInfo) +{ +} diff --git a/zonebb/src/ofApp.h b/zonebb/src/ofApp.h new file mode 100644 index 0000000..af1282c --- /dev/null +++ b/zonebb/src/ofApp.h @@ -0,0 +1,76 @@ +#pragma once + +#include "ofMain.h" +#include "ofxGui.h" +#include "ofxAzureKinect.h" +#include "ofxFluid.h" +#include "ofxV4L2.h" + +class ofApp : public ofBaseApp +{ + +public: + void setupKinect(); + void setupThermal(); + void setupFluid(); + void setupGui(); + void setup(); + + ofVec3f getDepthAt(int x, int y); + void updateThermal(); + void updateFluid(); + void update(); + void drawMain(); + void drawDebug(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(int x, int y); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseEntered(int x, int y); + void mouseExited(int x, int y); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + std::map fbos; + std::map gradients; + std::vector gradientNames{"warm1", "warm2", "cold1", "cold2"}; + + ofxAzureKinect::Device kinectDevice; + + ofxFluid fluid; + + ofVec2f oldM; + int width, height; + bool bPaint, bObstacle, bBounding, bClear; + + const int camWidth = 640; + const int camHeight = 480; + + ofxV4L2 v4l2Cam; + std::vector v4l2Buffer; + int v4l2BufferCount; + ofPixels v4l2Pixels; + + std::vector> hotspots; + ofVec3f hotspot0, hotspot1; + ofVec3f uBetween; + bool areThereTwoPeople; + float areThereTwoPeopleTween; + + ofxVec2Slider registrationXY; + ofxFloatSlider registrationScale; + ofxIntSlider v4l2Delay; + ofxInputField captureDeviceName; + ofxPanel gui; + + ofxToggle calibMode; + ofxToggle dummyMode; + ofxVec2Slider dummyXY; + ofxLabel debugFps; + ofxPanel debugGui; +};