Now using dots to show emos

This commit is contained in:
Ruben 2016-08-17 19:21:16 +02:00
parent f26802be79
commit ffe51902a3
8 changed files with 200 additions and 38 deletions

View file

@ -13,7 +13,8 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
android:hardwareAccelerated="true">
<activity <activity
android:name=".GamingActivity" android:name=".GamingActivity"

View file

@ -1,5 +1,7 @@
package com.rubenvandeven.emotionhero; package com.rubenvandeven.emotionhero;
import android.graphics.Color;
import com.affectiva.android.affdex.sdk.detector.Face; import com.affectiva.android.affdex.sdk.detector.Face;
/** /**
@ -35,4 +37,26 @@ public enum Emotion {
} }
return 0; return 0;
} }
public int getColor()
{
switch (this) {
case ANGER:
return Color.RED;
case CONTEMPT:
return Color.BLUE;
case DISGUST:
return Color.GREEN;
case FEAR:
return Color.MAGENTA;
case JOY:
return Color.YELLOW;
case SADNESS:
return Color.CYAN;
case SURPRISE:
return Color.LTGRAY;
}
return Color.BLACK;
}
} }

View file

@ -15,6 +15,7 @@ import android.view.MotionEvent;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -114,9 +115,14 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
int previewHeight = 0; int previewHeight = 0;
Scenario currentScenario; Scenario currentScenario;
ScenarioView scenarioView;
boolean has_camera_permission = false; boolean has_camera_permission = false;
Button restartButton;
TextView paramText;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -128,6 +134,16 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
mContentView = (TextView) findViewById(R.id.fullscreen_content); mContentView = (TextView) findViewById(R.id.fullscreen_content);
RelativeLayout videoLayout = (RelativeLayout) findViewById(R.id.video_layout); RelativeLayout videoLayout = (RelativeLayout) findViewById(R.id.video_layout);
// paramText = (TextView) findViewById(R.id.paramText);
restartButton = (Button) findViewById(R.id.restartButton);
restartButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
startActivity(getIntent());
}
});
// Set up the user interaction to manually show or hide the system UI. // Set up the user interaction to manually show or hide the system UI.
mContentView.setOnClickListener(new View.OnClickListener() { mContentView.setOnClickListener(new View.OnClickListener() {
@ -169,6 +185,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
} }
}; };
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(1,1);
params.addRule(RelativeLayout.CENTER_IN_PARENT,RelativeLayout.TRUE); params.addRule(RelativeLayout.CENTER_IN_PARENT,RelativeLayout.TRUE);
cameraPreview.setLayoutParams(params); cameraPreview.setLayoutParams(params);
videoLayout.addView(cameraPreview,0); videoLayout.addView(cameraPreview,0);
@ -176,7 +193,6 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
currentScenario = new ScenarioAnger(); currentScenario = new ScenarioAnger();
ScenarioView scenarioView;
scenarioView = new ScenarioView(this, currentScenario); scenarioView = new ScenarioView(this, currentScenario);
RelativeLayout.LayoutParams scenarioViewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); RelativeLayout.LayoutParams scenarioViewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
videoLayout.addView(scenarioView, 1, scenarioViewParams); videoLayout.addView(scenarioView, 1, scenarioViewParams);
@ -242,8 +258,14 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
detector.setLicensePath("emotionhero_dev.license"); detector.setLicensePath("emotionhero_dev.license");
detector.setMaxProcessRate(10); detector.setMaxProcessRate(10);
detector.setDetectAllEmotions(true); detector.setDetectAllEmotions(true);
detector.setDetectAllAppearances(false);
detector.setDetectAllEmojis(false);
detector.setDetectAllExpressions(false);
detector.setMaxProcessRate(12);
detector.setImageListener(this); detector.setImageListener(this);
detector.setOnCameraEventListener(this); detector.setOnCameraEventListener(this);
detector.setFaceListener(this);
} }
detector.start(); detector.start();
@ -304,6 +326,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
{ {
mContentView.setText(String.format("LEVEL ENDED\nScore: %.2f", currentScenario.getTotalScore())); mContentView.setText(String.format("LEVEL ENDED\nScore: %.2f", currentScenario.getTotalScore()));
stopDetector(); stopDetector();
restartButton.setVisibility(View.VISIBLE);
return; return;
} }
if (list == null) if (list == null)
@ -313,7 +336,19 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
} else { } else {
Face face = list.get(0); Face face = list.get(0);
currentScenario.validateFaceOnTime(face, timestamp); currentScenario.validateFaceOnTime(face, timestamp);
scenarioView.setCurrentAttributeScoresForFace(face);
mContentView.setText(String.format("SCORE \n%.2f",currentScenario.getTotalScore())); mContentView.setText(String.format("SCORE \n%.2f",currentScenario.getTotalScore()));
// String paramString = "";
// paramString += "Anger " + String.format("%02.2f", face.emotions.getAnger()) + "%\n";
// paramString += "Contempt " + String.format("%02.2f", face.emotions.getContempt()) + "%\n";
// paramString += "Disgust " + String.format("%02.2f", face.emotions.getDisgust()) + "%\n";
// paramString += "Fear " + String.format("%02.2f", face.emotions.getFear()) + "%\n";
// paramString += "Joy " + String.format("%02.2f", face.emotions.getJoy()) + "%\n";
// paramString += "Sadness " + String.format("%02.2f", face.emotions.getSadness()) + "%\n";
// paramString += "Surprise " + String.format("%02.2f", face.emotions.getSurprise()) + "%\n";
//
// paramText.setText(paramString);
} }
} }
@ -360,11 +395,13 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
public void onFaceDetectionStarted() public void onFaceDetectionStarted()
{ {
mContentView.setText("START!"); mContentView.setText("START!");
currentScenario.start();
} }
@Override @Override
public void onFaceDetectionStopped() public void onFaceDetectionStopped()
{ {
mContentView.setText("No face found..."); mContentView.setText("No face found...");
// paramText.setText("No face found");
} }
} }

View file

@ -126,42 +126,25 @@ abstract public class Scenario {
return timestamp <= duration; return timestamp <= duration;
} }
public void drawOnCanvas(Canvas canvas) { public ArrayList<Target> getTargets() {
// canvas; return targets;
Paint paint = new Paint(); }
paint.setColor(Color.RED);
float height = (float) canvas.getHeight();
float pix_per_sec = height / duration;
float sec_height = canvas.getHeight() * (float) 0.2; // each second is 20% of canvas height
float diff_y; /**
* Get the time within the scenario (so since start() has been called)
*/
public float getTime() {
// if not started, don't move the labels, if started, move them by diff_y // if not started, don't move the labels, if started, move them by diff_y
if(startTime == 0) { if(startTime == 0) {
diff_y = 0; return 0;
start();
} else { } else {
float diff_t = ((System.currentTimeMillis() - startTime)) / (float) 1000; float diff_t = ((System.currentTimeMillis() - startTime)) / (float) 1000;
Log.d("TIME", Float.toString(diff_t));
if(diff_t > duration) { // never larger than scenario duration if(diff_t > duration) { // never larger than scenario duration
diff_t = duration; return duration;
} }
diff_y = sec_height * diff_t; return diff_t;
} }
// bottom at 80%;
float bottomline_height = height * (float) 0.8;
canvas.drawLine(0, bottomline_height, canvas.getWidth(), bottomline_height, paint);
canvas.drawLine(0, bottomline_height+1, canvas.getWidth(), bottomline_height+1, paint);
for(Target target: targets) {
float y_pos = bottomline_height - (target.timestamp * sec_height);
String target_text = target.emotion.toString() + " " + target.value + "%";
canvas.drawText(target_text, canvas.getWidth()/2, y_pos + diff_y , paint);
}
} }
public void start() public void start()
@ -169,6 +152,8 @@ abstract public class Scenario {
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
} }
// TODO: create a 'tick' that checks all current values with requirements and increases the timer etc
// TODO: ... if scenario is running. This internal times makes it easier to pause etc.
} }
class ScenarioAnger extends Scenario{ class ScenarioAnger extends Scenario{
@ -180,5 +165,9 @@ class ScenarioAnger extends Scenario{
setTarget(Emotion.ANGER, 40, 3); setTarget(Emotion.ANGER, 40, 3);
setTarget(Emotion.ANGER, 70, 4); setTarget(Emotion.ANGER, 70, 4);
setTarget(Emotion.ANGER, 100, 5); setTarget(Emotion.ANGER, 100, 5);
setTarget(Emotion.JOY, 100, 8);
setTarget(Emotion.ANGER, 100, 10);
setTarget(Emotion.JOY, 100, 15);
setTarget(Emotion.ANGER, 100, 20);
} }
} }

View file

@ -2,13 +2,20 @@ package com.rubenvandeven.emotionhero;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import com.affectiva.android.affdex.sdk.detector.Face;
import java.util.HashMap;
import java.util.Map;
/** /**
* Created by ruben on 16/08/16. * Created by ruben on 16/08/16.
*/ */
@ -19,6 +26,12 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
private Scenario _scenario; private Scenario _scenario;
/**
* The scorres in this moment, as to draw them on the screen.
* Indexes are Emotion ordinals
*/
private Map<Emotion, Float> currentAttributeScores = new HashMap<>();
// see: http://blog.danielnadeau.io/2012/01/android-canvas-beginners-tutorial.html // see: http://blog.danielnadeau.io/2012/01/android-canvas-beginners-tutorial.html
class PanelThread extends Thread { class PanelThread extends Thread {
@ -69,15 +82,92 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
@Override @Override
public void onDraw(Canvas canvas) { public void onDraw(Canvas canvas) {
//do drawing stuff here. //do drawing stuff here.
// Log.e("TEST2", "Jaa!");
_scenario.drawOnCanvas(canvas); float height = canvas.getHeight();
float width = canvas.getWidth();
// bottom at 80%;
float bottomline_height = height * (float) 0.8;
// draw current scores:
float used_width = (float) 0.8; // 0.7: only use center
float padding_left = canvas.getWidth() * (1-used_width) / 2;
float step_y = (canvas.getWidth() * used_width) / Emotion.values().length;
float max_ball_radius = step_y * (float) 0.8 / 2;
// bottom at 80%;
Paint mainPaint = new Paint();
mainPaint.setColor(Color.GRAY);
Paint linePaint = new Paint();
linePaint.setColor(Color.GRAY);
linePaint.setStrokeWidth(5);
// canvas.drawLine(0, bottomline_height, width, bottomline_height, linePaint);
for(Emotion emotion: Emotion.values())
{
float value = 0;
if(currentAttributeScores.containsKey(emotion)) {
value = currentAttributeScores.get(emotion);
}
if(value < 5) {
value = 5;
}
Paint emoPaint = new Paint();
Paint emoPaintOutline = new Paint();
emoPaint.setColor(emotion.getColor());
emoPaintOutline.setColor(emotion.getColor());
emoPaintOutline.setStyle(Paint.Style.STROKE);
emoPaintOutline.setStrokeWidth(2);
float cx = padding_left + (step_y * emotion.ordinal() + step_y / 2);
float cy = bottomline_height;
canvas.drawCircle(cx, cy, max_ball_radius, mainPaint);
canvas.drawCircle(cx, cy, max_ball_radius, emoPaintOutline);
canvas.drawCircle(cx, cy, max_ball_radius * value/100, emoPaint);
canvas.drawText(emotion.toString(), cx, cy + max_ball_radius * (float) 1.3, emoPaint);
}
// Draw targets:
float sec_height = height * (float) 0.2; // each second is 20% of canvas height
// current moved position
float diff_y = sec_height * _scenario.getTime();
for(Scenario.Target target: _scenario.getTargets()) {
Paint emoPaint = new Paint();
emoPaint.setColor(target.emotion.getColor());
float cy = bottomline_height - (target.timestamp * sec_height) + diff_y;
float cx = padding_left + (step_y * target.emotion.ordinal() + step_y / 2);
canvas.drawCircle(cx, cy, max_ball_radius * target.value/100, emoPaint);
// String target_text = target.emotion.toString() + " " + target.value + "%";
// canvas.drawText(target_text, cx, y_pos + diff_y , emoPaint);
}
}
public void setCurrentAttributeScoresForFace(Face face)
{
for(Emotion emotion: Emotion.values()) {
currentAttributeScores.put(emotion, emotion.getValueFromFace(face));
}
} }
@Override @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
} }
@Override @Override
@ -105,6 +195,4 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
} }
} }

View file

@ -37,6 +37,16 @@
<!--android:layout_height="match_parent" />--> <!--android:layout_height="match_parent" />-->
<!--<TextView-->
<!--android:text="No face found"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:id="@+id/paramText"-->
<!--android:textColor="@android:color/white"-->
<!--android:layout_marginLeft="10dp"-->
<!--android:layout_marginTop="10dp"-->
<!--android:fontFamily="monospace" />-->
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -62,10 +72,13 @@
</LinearLayout> </LinearLayout>
<SurfaceView <Button
android:layout_width="1dp" android:text="@string/restart"
android:layout_height="1dp" android:layout_width="wrap_content"
android:id="@+id/surfaceView" /> android:layout_height="wrap_content"
android:id="@+id/restartButton"
android:layout_gravity="center_vertical|center_horizontal"
android:visibility="gone" />
</FrameLayout> </FrameLayout>

View file

@ -6,4 +6,13 @@
<color name="colorScenarioLine">#FF0000</color> <color name="colorScenarioLine">#FF0000</color>
<color name="black_overlay">#66000000</color> <color name="black_overlay">#66000000</color>
<!--TODO: implement in Emotion.java-->
<color name="emotion_anger">#ff0000</color>
<color name="emotion_contempt">#0000ff</color>
<color name="emotion_disgust">#009000</color>
<color name="emotion_fear">#ffff00</color>
<color name="emotion_joy">#ff00ff</color>
<color name="emotion_sadness">#ff8c00</color>
<color name="emotion_surprise">#00aaff</color>
</resources> </resources>

View file

@ -4,4 +4,5 @@
<string name="dummy_button">Dummy Button</string> <string name="dummy_button">Dummy Button</string>
<string name="dummy_content">initialising&#8230;</string> <string name="dummy_content">initialising&#8230;</string>
<string name="camera_required">The camera permission is required. Please start again</string> <string name="camera_required">The camera permission is required. Please start again</string>
<string name="restart">Restart</string>
</resources> </resources>