├── .gitignore
├── README.md
├── addon_config.mk
├── mobileVisionExample
├── .gitignore
├── AndroidManifest.xml
├── addons.make
└── src
│ ├── main.cpp
│ ├── ofApp.cpp
│ └── ofApp.h
├── ofxAndroidMobileVisionLib
├── .gitignore
├── build.gradle
├── ofxandroidmobilevisionlib.iml
├── settings.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cc
│ │ └── ofxandroidmobilevisionlib
│ │ └── ofxAndroidMobileVisionLib.java
│ └── res
│ └── values
│ └── strings.xml
├── ofxaddons_thumbnail.png
└── src
├── ofxAndroidMobileVision.cpp
└── ofxAndroidMobileVision.h
/.gitignore:
--------------------------------------------------------------------------------
1 | mobileVisionExample/libs
2 | .idea
3 | .DS_Store
4 | mobileVisionExample/gradle
5 | mobileVisionExample/gradlew
6 | mobileVisionExample/gradlew.bat
7 | mobileVisionExample/build.gradle
8 | mobileVisionExample/mobileVisionExample.iml
9 | mobileVisionExample/res
10 | mobileVisionExample/settings.gradle
11 | ofxAndroidMobileVisionLib/ofxAndroidMobileVision.iml
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ofxAndroidMobileVision
2 | An addon that enables access to the [Google Mobile Vision API](https://developers.google.com/vision/).
3 | This addon is useful for simple and easy face detection, landmark detection, eye open probability estimation and smile estimation.
4 |
5 | The addons works only on Android, as it accesses a native Android library.
6 |
7 | ## Example app
8 | 
9 |
10 | There is one example app that demonstrates how to work with landmarks and eye and smile probabilities. Use the project generator to generate the project files for Android Studio.
11 |
12 | ## Requirements
13 | Only tested on experimental Android Studio branch of openFrameworks. [Follow these instructions](https://github.com/HalfdanJ/openFrameworks/blob/gradle-experimental/docs/android_studio.md).
14 |
15 |
--------------------------------------------------------------------------------
/addon_config.mk:
--------------------------------------------------------------------------------
1 | # All variables and this file are optional, if they are not present the PG and the
2 | # makefiles will try to parse the correct values from the file system.
3 | #
4 | # Variables that specify exclusions can use % as a wildcard to specify that anything in
5 | # that position will match. A partial path can also be specified to, for example, exclude
6 | # a whole folder from the parsed paths from the file system
7 | #
8 | # Variables can be specified using = or +=
9 | # = will clear the contents of that variable both specified from the file or the ones parsed
10 | # from the file system
11 | # += will add the values to the previous ones in the file or the ones parsed from the file
12 | # system
13 | #
14 | # The PG can be used to detect errors in this file, just create a new project with this addon
15 | # and the PG will write to the console the kind of error and in which line it is
16 |
17 | meta:
18 | ADDON_NAME = ofxAndroidMobileVision
19 | ADDON_DESCRIPTION = Addon for accessing native sensors on android
20 | ADDON_AUTHOR = Jonas Jongejan
21 | ADDON_TAGS = "utils"
22 | ADDON_URL = http://github.com/halfdanj/ofxAndroidSensors
23 |
24 | common:
25 | # dependencies with other addons, a list of them separated by spaces
26 | # or use += in several lines
27 | # ADDON_DEPENDENCIES =
28 |
29 | # include search paths, this will be usually parsed from the file system
30 | # but if the addon or addon libraries need special search paths they can be
31 | # specified here separated by spaces or one per line using +=
32 | # ADDON_INCLUDES =
33 |
34 | # any special flag that should be passed to the compiler when using this
35 | # addon
36 | # ADDON_CFLAGS =
37 |
38 | # any special flag that should be passed to the linker when using this
39 | # addon, also used for system libraries with -lname
40 | # ADDON_LDFLAGS = -landroid
41 |
42 | # linux only, any library that should be included in the project using
43 | # pkg-config
44 | # ADDON_PKG_CONFIG_LIBRARIES =
45 |
46 | # osx/iOS only, any framework that should be included in the project
47 | # ADDON_FRAMEWORKS =
48 |
49 | # source files, these will be usually parsed from the file system looking
50 | # in the src folders in libs and the root of the addon. if your addon needs
51 | # to include files in different places or a different set of files per platform
52 | # they can be specified here
53 | # ADDON_SOURCES =
54 |
55 | # some addons need resources to be copied to the bin/data folder of the project
56 | # specify here any files that need to be copied, you can use wildcards like * and ?
57 | # ADDON_DATA =
58 |
59 | # when parsing the file system looking for libraries exclude this for all or
60 | # a specific platform
61 | # ADDON_LIBS_EXCLUDE =
62 |
63 | android:
64 | ADDON_ANDROID_LIBS = ofxAndroidMobileVisionLib
65 | # ADDON_INCLUDES = "src"
66 |
--------------------------------------------------------------------------------
/mobileVisionExample/.gitignore:
--------------------------------------------------------------------------------
1 | ### Android ###
2 | # Built application files
3 | *.apk
4 | *.ap_
5 |
6 | # Files for the Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | ### Android Patch ###
33 | gen-external-apklibs
34 | reports
35 | obj
36 | assets
37 |
--------------------------------------------------------------------------------
/mobileVisionExample/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/mobileVisionExample/addons.make:
--------------------------------------------------------------------------------
1 | ofxAndroidMobileVision
2 |
--------------------------------------------------------------------------------
/mobileVisionExample/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "ofMain.h"
2 | #include "ofApp.h"
3 |
4 | int main(){
5 | ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context
6 |
7 | // this kicks off the running of my app
8 | // can be OF_WINDOW or OF_FULLSCREEN
9 | // pass in width and height too:
10 | ofRunApp( new ofApp() );
11 | return 0;
12 | }
13 |
14 |
15 | #ifdef TARGET_ANDROID
16 | void ofAndroidApplicationInit()
17 | {
18 | //application scope init
19 | }
20 |
21 | void ofAndroidActivityInit()
22 | {
23 | //activity scope init
24 | main();
25 | }
26 | #endif
27 |
--------------------------------------------------------------------------------
/mobileVisionExample/src/ofApp.cpp:
--------------------------------------------------------------------------------
1 | #include "ofApp.h"
2 |
3 | //--------------------------------------------------------------
4 | void ofApp::setup(){
5 | // Use frontal facing camera
6 | grabber.setDeviceID(1);
7 |
8 | // Use native (NV21) pixel format for best performance
9 | grabber.setPixelFormat(OF_PIXELS_NV21);
10 |
11 | grabber.setup(640,360);
12 |
13 | vision.setup();
14 |
15 | // Get orientation of camera, and force orientation of app
16 | int cameraOrientation = ((ofxAndroidVideoGrabber*)grabber.getGrabber().get())->getCameraOrientation();
17 | if(cameraOrientation == 270){
18 | ofSetOrientation(OF_ORIENTATION_90_LEFT);
19 | } else if(cameraOrientation == 90){
20 | ofSetOrientation(OF_ORIENTATION_90_RIGHT);
21 | }
22 |
23 |
24 | font.load("Roboto-Regular.ttf",30);
25 | }
26 |
27 | //--------------------------------------------------------------
28 | void ofApp::update(){
29 | grabber.update();
30 | if(grabber.isFrameNew()) {
31 | vision.update(grabber.getPixels());
32 | }
33 | }
34 |
35 | //--------------------------------------------------------------
36 | void ofApp::draw(){
37 | ofBackground(0);
38 | ofSetColor(170);
39 |
40 | // Calculate scaling factor in order for image to fill screen
41 | float scale = ofGetWidth() / grabber.getWidth();
42 | ofPushMatrix();
43 | ofScale(scale,scale);
44 |
45 | grabber.draw(0,0);
46 |
47 | ofNoFill();
48 | // Iterate over all faces and draw circles on landmarks
49 | for(auto face : vision.getFaces()){
50 | for(int i=0;i<12;i++){
51 | ofSetColor(0,150);
52 | ofSetLineWidth(25);
53 | ofDrawCircle(face.landmarks[i].x,face.landmarks[i].y, 10);
54 | ofSetColor(255);
55 | ofSetLineWidth(2);
56 | ofDrawCircle(face.landmarks[i].x,face.landmarks[i].y, 10);
57 | }
58 | }
59 | ofSetLineWidth(1);
60 | ofFill();
61 | ofPopMatrix();
62 |
63 | ofPushMatrix();
64 |
65 | ofTranslate(0, ofGetHeight() - 200);
66 | ofSetColor(0);
67 | ofDrawRectangle(0,0, ofGetWidth(), 200);
68 |
69 | ofSetColor(255);
70 | // Iterate faces and draw bars with probabilities
71 | if(vision.getFaces().size() > 0){
72 | auto face = vision.getFaces()[0];
73 |
74 | // Draw bar graph titles
75 | if(face.leftEyeOpenProbability == -1) ofSetColor(70);
76 | else ofSetColor(255);
77 | font.drawString("Left Eye Open", 30, 70);
78 |
79 | if(face.rightEyeOpenProbability == -1) ofSetColor(70);
80 | else ofSetColor(255);
81 | font.drawString("Right Eye Open", 400, 70);
82 |
83 | if(face.smileProbability == -1) ofSetColor(70);
84 | else ofSetColor(255);
85 | font.drawString("Smile", 800, 70);
86 |
87 | // Draw bar graphs backgrounds
88 | ofSetColor(56, 90, 138, 100);
89 | ofDrawRectangle(30, 110, 280, 20);
90 | ofDrawRectangle(400, 110, 280, 20);
91 | ofDrawRectangle(800, 110, 280, 20);
92 |
93 | // Draw bar graphs
94 | ofSetColor(56, 90, 138);
95 | ofDrawRectangle(30, 110, 280 * MAX(0,face.leftEyeOpenProbability), 20);
96 | ofDrawRectangle(400, 110, 280 * MAX(0,face.rightEyeOpenProbability), 20);
97 | ofDrawRectangle(800, 110, 280 * MAX(0,face.smileProbability), 20);
98 |
99 | ofTranslate(0,200);
100 | } else {
101 | font.drawString("No faces detected", 30, 70);
102 | }
103 | ofPopMatrix();
104 | }
105 |
--------------------------------------------------------------------------------
/mobileVisionExample/src/ofApp.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "ofMain.h"
4 | #include "ofxAndroid.h"
5 | #include "ofxAndroidMobileVision.h"
6 |
7 | class ofApp : public ofxAndroidApp{
8 |
9 | public:
10 | void setup();
11 | void update();
12 | void draw();
13 |
14 | ofxAndroidMobileVision vision;
15 | ofVideoGrabber grabber;
16 |
17 | ofTrueTypeFont font;
18 | };
19 |
--------------------------------------------------------------------------------
/ofxAndroidMobileVisionLib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/ofxAndroidMobileVisionLib/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle-experimental:0.7.0-alpha4'
8 | }
9 | }
10 |
11 | allprojects {
12 | repositories {
13 | jcenter()
14 | }
15 | }
16 | apply plugin: 'com.android.model.library'
17 |
18 | model {
19 | android {
20 | compileSdkVersion = 22
21 | buildToolsVersion = "23.0.2"
22 |
23 | defaultConfig.with {
24 | minSdkVersion.apiLevel 9
25 | targetSdkVersion.apiLevel 22
26 | versionCode 1
27 | versionName "1.0"
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | }
33 | }
34 | }
35 |
36 | }
37 |
38 |
39 | dependencies {
40 | compile 'com.android.support:appcompat-v7:22.+'
41 | compile 'com.google.android.gms:play-services-vision:8.4.0'
42 | compile fileTree(dir: 'libs', include: ['*.jar'])
43 | compile project(path: ':ofAndroidLib')
44 | }
45 |
--------------------------------------------------------------------------------
/ofxAndroidMobileVisionLib/ofxandroidmobilevisionlib.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/ofxAndroidMobileVisionLib/settings.gradle:
--------------------------------------------------------------------------------
1 | // openFrameworks-relative root directories (don't touch)
2 | def ofRoot = '../../../'
3 |
4 |
5 |
6 | include ':ofAndroidLib'
7 | project(':ofAndroidLib').projectDir = new File(ofRoot + 'addons/ofxAndroid/ofAndroidLib')
8 |
--------------------------------------------------------------------------------
/ofxAndroidMobileVisionLib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ofxAndroidMobileVisionLib/src/main/java/cc/ofxandroidmobilevisionlib/ofxAndroidMobileVisionLib.java:
--------------------------------------------------------------------------------
1 | package cc.ofxandroidmobilevisionlib;
2 |
3 | import android.content.Context;
4 |
5 | import com.google.android.gms.vision.Detector;
6 | import com.google.android.gms.vision.Frame;
7 | import com.google.android.gms.vision.face.Face;
8 | import com.google.android.gms.vision.face.FaceDetector;
9 | import com.google.android.gms.vision.face.Landmark;
10 |
11 | import android.graphics.ImageFormat;
12 | import android.util.Log;
13 | import android.util.SparseArray;
14 |
15 | import java.nio.ByteBuffer;
16 | import java.util.List;
17 |
18 | import cc.openframeworks.OFAndroid;
19 |
20 | public class ofxAndroidMobileVisionLib {
21 | private static final String TAG = "ofxAndroidMobileVision";
22 |
23 | private FaceDetector detector;
24 | private SparseArray faces;
25 | private boolean isInitialized = false;
26 |
27 | private float minFaceSize = 0.15f;
28 | private boolean prominentFaceOnly = true;
29 |
30 | public void setup(){
31 | Context context = OFAndroid.getContext();
32 |
33 | detector = new FaceDetector.Builder(context)
34 | .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
35 | .setLandmarkType(FaceDetector.ALL_LANDMARKS)
36 | .setMode(FaceDetector.FAST_MODE)
37 | .setProminentFaceOnly(prominentFaceOnly)
38 | .setMinFaceSize(minFaceSize)
39 | .build();
40 |
41 | if (!detector.isOperational()) {
42 | // Note: The first time that an app using face API is installed on a device, GMS will
43 | // download a native library to the device in order to do detection. Usually this
44 | // completes before the app is run for the first time. But if that download has not yet
45 | // completed, then the above call will not detect any faces.
46 | //
47 | // isOperational() can be used to check if the required native library is currently
48 | // available. The detector will automatically become operational once the library
49 | // download completes on device.
50 | Log.w(TAG, "Face detector dependencies are not yet available.");
51 | }
52 |
53 | Detector.Processor processor;
54 |
55 | isInitialized = true;
56 | }
57 |
58 |
59 | public void setMinFaceSize(float _minFaceSize){
60 | if(isInitialized) Log.w(TAG,"setMinFaceSize() cannot be called after setup()");
61 | minFaceSize = _minFaceSize;
62 | }
63 |
64 | public void setProminentFaceOnly(boolean _prominentFaceOnly){
65 | if(isInitialized) Log.w(TAG,"setProminentFaceOnly() cannot be called after setup()");
66 | prominentFaceOnly = _prominentFaceOnly;
67 | }
68 |
69 | public float[] getData(int face){
70 | float ret[] = new float[3+24];
71 | if(faces.size() > face) {
72 | ret[0] = faces.get(faces.keyAt(face)).getIsSmilingProbability();
73 | ret[1] = faces.get(faces.keyAt(face)).getIsLeftEyeOpenProbability();
74 | ret[2] = faces.get(faces.keyAt(face)).getIsRightEyeOpenProbability();
75 |
76 | List landmarks = faces.get(faces.keyAt(face)).getLandmarks();
77 | for (int i = 0; i < 12; i++) {
78 | if (landmarks.size() > i) {
79 | ret[i * 2 + 3] = landmarks.get(i).getPosition().x;
80 | ret[i * 2 + 3 + 1] = landmarks.get(i).getPosition().y;
81 | } else {
82 | ret[i * 2 + 3] = -1;
83 | ret[i * 2 + 3 + 1] = -1;
84 | }
85 | }
86 | }
87 |
88 | return ret;
89 | }
90 |
91 | public int update(byte[] bytes, int width, int height){
92 | if(!detector.isOperational()) return -1;
93 |
94 | // Wrap image bytes
95 | ByteBuffer buffer = ByteBuffer.wrap(bytes);
96 | Frame frame = new Frame.Builder()
97 | .setImageData(buffer, width, height, ImageFormat.NV21)
98 | .build();
99 |
100 | // Run face detector
101 | faces = detector.detect(frame);
102 | return faces.size();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/ofxAndroidMobileVisionLib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ofxAndroidMobileVisionLib
3 |
4 |
--------------------------------------------------------------------------------
/ofxaddons_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HalfdanJ/ofxAndroidMobileVision/4f6434e4e619ada1490bdc85705dbce901bed4b6/ofxaddons_thumbnail.png
--------------------------------------------------------------------------------
/src/ofxAndroidMobileVision.cpp:
--------------------------------------------------------------------------------
1 | #include "ofxAndroidMobileVision.h"
2 | #ifdef TARGET_ANDROID
3 | #include "ofxAndroidUtils.h"
4 |
5 |
6 | ofxAndroidMobileVision::ofxAndroidMobileVision()
7 | :threaded(true){
8 |
9 | if(!ofGetJavaVMPtr()){
10 | ofLogNotice("ofxAndroidMobileVision") << "couldn't find java virtual machine";
11 | return;
12 | }
13 |
14 | JNIEnv *env;
15 | if (ofGetJavaVMPtr()->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
16 | ofLogNotice("ofxAndroidMobileVision") << "failed to get environment using GetEnv()";
17 | return;
18 | }
19 | jclass localClass = env->FindClass("cc/ofxandroidmobilevisionlib/ofxAndroidMobileVisionLib");
20 | javaClass = (jclass) env->NewGlobalRef(localClass);
21 |
22 | if(!javaClass){
23 | ofLogError("ofxAndroidMobileVision") << "constructor: couldn't get java class for MobileVision";
24 | return;
25 | }
26 |
27 | jmethodID constructor = env->GetMethodID(javaClass,"","()V");
28 | if(!constructor){
29 | ofLogError("ofxAndroidMobileVision") << "constructor: couldn't get java constructor for MobileVision";
30 | return;
31 | }
32 |
33 | javaMobileVision = env->NewObject(javaClass,constructor);
34 | if(!javaMobileVision){
35 | ofLogError("ofxAndroidMobileVision") << "constructor: couldn't create java MobileVision";
36 | return;
37 | }
38 |
39 | javaMobileVision = (jobject)env->NewGlobalRef(javaMobileVision);
40 | }
41 |
42 | ofxAndroidMobileVision::~ofxAndroidMobileVision(){
43 | toAnalyze.close();
44 | }
45 |
46 | bool ofxAndroidMobileVision::setThreaded(bool _threaded){
47 | threaded = _threaded;
48 | }
49 |
50 | void ofxAndroidMobileVision::setup(){
51 | if(!javaMobileVision){
52 | ofLogError("ofxAndroidMobileVision") << "setup(): java MobileVision not loaded";
53 | return;
54 | }
55 |
56 | JNIEnv *env = ofGetJNIEnv();
57 | jmethodID javaSetupMethod = env->GetMethodID(javaClass,"setup","()V");
58 | if(!javaSetupMethod){
59 | ofLogError("ofxAndroidMobileVision") << "setup(): couldn't get java setup for MobileVision";
60 | return;
61 | }
62 |
63 | env->CallVoidMethod(javaMobileVision,javaSetupMethod);
64 |
65 | if(threaded){
66 | startThread();
67 | }
68 | return;
69 | }
70 |
71 | void ofxAndroidMobileVision::setTrackProminentFaceOnly(bool prominentOnly){
72 | if(!javaMobileVision) return;
73 | JNIEnv *env = ofGetJNIEnv();
74 | env->CallVoidMethod(javaMobileVision,env->GetMethodID(javaClass,"setProminentFaceOnly","(Z)V"), prominentOnly);
75 | }
76 |
77 | void ofxAndroidMobileVision::setMinFaceSize(float minFaceSize){
78 | if(!javaMobileVision) return;
79 | JNIEnv *env = ofGetJNIEnv();
80 | env->CallVoidMethod(javaMobileVision,env->GetMethodID(javaClass,"setMinFaceSize","(F)V"), minFaceSize);
81 | }
82 |
83 | void ofxAndroidMobileVision::update(ofPixels &pixels){
84 | if(threaded) {
85 | if (toAnalyze.empty()) {
86 | ToAnalyzeData d = ToAnalyzeData();
87 | d.pixels = pixels;
88 | toAnalyze.send(d);
89 | }
90 | } else {
91 | process(pixels);
92 | }
93 |
94 | fromAnalyze.tryReceive(faces);
95 |
96 | }
97 |
98 | vector & ofxAndroidMobileVision::getFaces(){
99 | return faces;
100 | }
101 |
102 | void ofxAndroidMobileVision::process(ofPixels &pixels){
103 | if(!javaMobileVision){
104 | ofLogError("ofxAndroidMobileVision") << "update(): java not loaded";
105 | return;
106 | }
107 |
108 | JNIEnv *env = ofGetJNIEnv();
109 | jmethodID javaMethod = env->GetMethodID(javaClass,"update","([BII)I");
110 | if(!javaMethod ){
111 | ofLogError("ofxAndroidMobileVision") << "update(): couldn't get java update for MobileVision";
112 | return;
113 | }
114 |
115 | jbyteArray arr = env->NewByteArray(pixels.size());
116 | env->SetByteArrayRegion( arr, 0, pixels.size(), (const signed char*) pixels.getData());
117 | int numFaces = env->CallIntMethod(javaMobileVision, javaMethod, arr, pixels.getWidth(), pixels.getHeight());
118 | env->DeleteLocalRef(arr);
119 |
120 | vector analyzedfaces;
121 | for(int i=0;iGetMethodID(javaClass, "getData", "(I)[F");
124 | jfloatArray data = (jfloatArray) env->CallObjectMethod(javaMobileVision, method, 0);
125 |
126 | jboolean isCopy;
127 | jfloat *body = env->GetFloatArrayElements(data, &isCopy);
128 |
129 | ofxAndroidMobileVisionFace face;
130 | face.smileProbability = body[0];
131 | face.leftEyeOpenProbability = body[1];
132 | face.rightEyeOpenProbability = body[2];
133 | for(int j=0;j<12;j++){
134 | ofVec2f p;
135 | p.x = body[j*2+3];
136 | p.y = body[j*2+4];
137 | face.landmarks.push_back(p);
138 | }
139 | analyzedfaces.push_back(face);
140 |
141 | env->DeleteLocalRef(data);
142 | }
143 |
144 | fromAnalyze.send(analyzedfaces);
145 | }
146 |
147 | void ofxAndroidMobileVision::threadedFunction(){
148 | ToAnalyzeData d;
149 | while(toAnalyze.receive(d)){
150 | process(d.pixels);
151 | }
152 | }
153 | #endif
--------------------------------------------------------------------------------
/src/ofxAndroidMobileVision.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "ofConstants.h"
3 | #include "ofThread.h"
4 | #include "ofThreadChannel.h"
5 |
6 | #ifdef TARGET_ANDROID
7 |
8 | #include
9 |
10 | #include "ofBaseTypes.h"
11 |
12 |
13 | struct ofxAndroidMobileVisionFace {
14 | float smileProbability;
15 | float leftEyeOpenProbability;
16 | float rightEyeOpenProbability;
17 |
18 | vector landmarks;
19 | };
20 |
21 | struct ToAnalyzeData{
22 | ofPixels pixels;
23 | };
24 |
25 | class ofxAndroidMobileVision : ofThread{
26 | public:
27 |
28 | ofxAndroidMobileVision();
29 | ~ofxAndroidMobileVision();
30 |
31 | void setup();
32 | void update(ofPixels & pixels);
33 |
34 | bool setThreaded(bool threaded);
35 |
36 | void setTrackProminentFaceOnly(bool prominentOnly);
37 | void setMinFaceSize(float minFaceSize);
38 |
39 | vector &getFaces();
40 |
41 | private:
42 | jclass javaClass;
43 | jobject javaMobileVision;
44 |
45 | bool threaded;
46 |
47 | ofThreadChannel toAnalyze;
48 | ofThreadChannel > fromAnalyze;
49 |
50 | vector faces;
51 |
52 | void threadedFunction();
53 | void process(ofPixels &pixels);
54 | };
55 |
56 | #endif
--------------------------------------------------------------------------------