emotionhero/app/src/main/java/com/rubenvandeven/emotionhero/Hit.java

227 lines
10 KiB
Java

package com.rubenvandeven.emotionhero;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.Base64;
import android.util.Log;
import com.affectiva.android.affdex.sdk.detector.Face;
import com.google.gson.annotations.Expose;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ruben on 02/09/16.
*/
public class Hit {
public long id;
public Scenario.Target target;
@Expose(serialize = false, deserialize = false)
public Game game;
public float score;
public float bonus;
public Map<Emotion, Float> emotions = new HashMap<>(7);
public boolean glasses;
public String ethnicity;
public String age;
public String gender;
public Map<Expression, Float> expressions = new HashMap<>(Expression.values().length); // also includes measurements
public PointF[] points = new PointF[34];
public String remoteId;
public Bitmap frame;
/**
* Constructor for game moment
*/
public Hit(Scenario.Target target, Game game, Face face) {
this.target = target;
this.game = game;
for(Emotion emotion: Emotion.values()) {
emotions.put(emotion,emotion.getValueFromFace(face));
}
this.gender = face.appearance.getGender() == Face.GENDER.UNKNOWN ? "U" : (face.appearance.getGender() == Face.GENDER.MALE ? "M" : "F");
this.glasses = face.appearance.getGlasses() == Face.GLASSES.YES ? true : false;
this.ethnicity = face.appearance.getEthnicity().name();
this.age = face.appearance.getAge().name();
for(Expression exp: Expression.values()) {
this.expressions.put(exp, exp.getValueFromFace(face));
}
this.points = face.getFacePoints().clone();
// this.frame = frame;
this.score = calculateScore();
this.bonus = calculateBonus();
// this in a way is strange behaviour:
// preferably do the game.addHit after creating hit, and call hit.game = game from there.
game.addHit(this);
}
/**
* Constructor from database entity
*/
public Hit(Game game, Cursor c) {
this.id = c.getLong(c.getColumnIndex("id"));
this.score = c.getFloat(c.getColumnIndex("score"));
this.bonus = c.getFloat(c.getColumnIndex("bonus"));
String rId = c.getString(c.getColumnIndex("remoteId"));
this.remoteId = (rId == null || rId.length() == 0) ? null : c.getString(c.getColumnIndex("remoteId"));
this.target = game.scenario.getTargetByIndex(c.getInt(c.getColumnIndex("target_index")));
this.glasses = c.getInt(c.getColumnIndex("glasses")) == 1;
this.ethnicity = c.getString(c.getColumnIndex("ethnicity"));
this.age = c.getString(c.getColumnIndex("age"));
this.gender = c.getString(c.getColumnIndex("gender"));
this.emotions.put(Emotion.ANGER, c.getFloat(c.getColumnIndex("anger")));
this.emotions.put(Emotion.CONTEMPT, c.getFloat(c.getColumnIndex("contempt")));
this.emotions.put(Emotion.DISGUST, c.getFloat(c.getColumnIndex("disgust")));
this.emotions.put(Emotion.FEAR, c.getFloat(c.getColumnIndex("fear")));
this.emotions.put(Emotion.JOY, c.getFloat(c.getColumnIndex("joy")));
this.emotions.put(Emotion.SADNESS, c.getFloat(c.getColumnIndex("sadness")));
this.emotions.put(Emotion.SURPRISE, c.getFloat(c.getColumnIndex("surprise")));
for(Expression exp: Expression.values()) {
this.expressions.put(exp, c.getFloat( c.getColumnIndex( exp.getDbName() )));
}
this.points[0] = new PointF(c.getFloat(c.getColumnIndex("point_0x")), c.getFloat(c.getColumnIndex("point_0y")));
this.points[1] = new PointF(c.getFloat(c.getColumnIndex("point_1x")), c.getFloat(c.getColumnIndex("point_1y")));
this.points[2] = new PointF(c.getFloat(c.getColumnIndex("point_2x")), c.getFloat(c.getColumnIndex("point_2y")));
this.points[3] = new PointF(c.getFloat(c.getColumnIndex("point_3x")), c.getFloat(c.getColumnIndex("point_3y")));
this.points[4] = new PointF(c.getFloat(c.getColumnIndex("point_4x")), c.getFloat(c.getColumnIndex("point_4y")));
this.points[5] = new PointF(c.getFloat(c.getColumnIndex("point_5x")), c.getFloat(c.getColumnIndex("point_5y")));
this.points[6] = new PointF(c.getFloat(c.getColumnIndex("point_6x")), c.getFloat(c.getColumnIndex("point_6y")));
this.points[7] = new PointF(c.getFloat(c.getColumnIndex("point_7x")), c.getFloat(c.getColumnIndex("point_7y")));
this.points[8] = new PointF(c.getFloat(c.getColumnIndex("point_8x")), c.getFloat(c.getColumnIndex("point_8y")));
this.points[9] = new PointF(c.getFloat(c.getColumnIndex("point_9x")), c.getFloat(c.getColumnIndex("point_9y")));
this.points[10] = new PointF(c.getFloat(c.getColumnIndex("point_10x")), c.getFloat(c.getColumnIndex("point_10y")));
this.points[11] = new PointF(c.getFloat(c.getColumnIndex("point_11x")), c.getFloat(c.getColumnIndex("point_11y")));
this.points[12] = new PointF(c.getFloat(c.getColumnIndex("point_12x")), c.getFloat(c.getColumnIndex("point_12y")));
this.points[13] = new PointF(c.getFloat(c.getColumnIndex("point_13x")), c.getFloat(c.getColumnIndex("point_13y")));
this.points[14] = new PointF(c.getFloat(c.getColumnIndex("point_14x")), c.getFloat(c.getColumnIndex("point_14y")));
this.points[15] = new PointF(c.getFloat(c.getColumnIndex("point_15x")), c.getFloat(c.getColumnIndex("point_15y")));
this.points[16] = new PointF(c.getFloat(c.getColumnIndex("point_16x")), c.getFloat(c.getColumnIndex("point_16y")));
this.points[17] = new PointF(c.getFloat(c.getColumnIndex("point_17x")), c.getFloat(c.getColumnIndex("point_17y")));
this.points[18] = new PointF(c.getFloat(c.getColumnIndex("point_18x")), c.getFloat(c.getColumnIndex("point_18y")));
this.points[19] = new PointF(c.getFloat(c.getColumnIndex("point_19x")), c.getFloat(c.getColumnIndex("point_19y")));
this.points[20] = new PointF(c.getFloat(c.getColumnIndex("point_20x")), c.getFloat(c.getColumnIndex("point_20y")));
this.points[21] = new PointF(c.getFloat(c.getColumnIndex("point_21x")), c.getFloat(c.getColumnIndex("point_21y")));
this.points[22] = new PointF(c.getFloat(c.getColumnIndex("point_22x")), c.getFloat(c.getColumnIndex("point_22y")));
this.points[23] = new PointF(c.getFloat(c.getColumnIndex("point_23x")), c.getFloat(c.getColumnIndex("point_23y")));
this.points[24] = new PointF(c.getFloat(c.getColumnIndex("point_24x")), c.getFloat(c.getColumnIndex("point_24y")));
this.points[25] = new PointF(c.getFloat(c.getColumnIndex("point_25x")), c.getFloat(c.getColumnIndex("point_25y")));
this.points[26] = new PointF(c.getFloat(c.getColumnIndex("point_26x")), c.getFloat(c.getColumnIndex("point_26y")));
this.points[27] = new PointF(c.getFloat(c.getColumnIndex("point_27x")), c.getFloat(c.getColumnIndex("point_27y")));
this.points[28] = new PointF(c.getFloat(c.getColumnIndex("point_28x")), c.getFloat(c.getColumnIndex("point_28y")));
this.points[29] = new PointF(c.getFloat(c.getColumnIndex("point_29x")), c.getFloat(c.getColumnIndex("point_29y")));
this.points[30] = new PointF(c.getFloat(c.getColumnIndex("point_30x")), c.getFloat(c.getColumnIndex("point_30y")));
this.points[31] = new PointF(c.getFloat(c.getColumnIndex("point_31x")), c.getFloat(c.getColumnIndex("point_31y")));
this.points[32] = new PointF(c.getFloat(c.getColumnIndex("point_32x")), c.getFloat(c.getColumnIndex("point_32y")));
this.points[33] = new PointF(c.getFloat(c.getColumnIndex("point_33x")), c.getFloat(c.getColumnIndex("point_33y")));
// skip for now, unused and bad for performance ;-)
// byte[] image = c.getBlob(c.getColumnIndex("image"));
// if(image != null)
// {
// frame = BitmapFactory.decodeByteArray(image, 0, image.length);
// }
game.addHit(this);
}
public static RectF getBoundingboxForPoints(PointF[] points) {
// a bit of a hack to be as quick as possible
// we know which point is where on the face, however, the face might be tilted:
float[] minXes = {points[0].x,points[1].x,points[5].x};
float[] maxXes = {points[4].x,points[3].x,points[10].x};
float[] maxYs = {points[1].y,points[2].y,points[3].y};
float[] minYs = {points[5].y,points[6].y,points[7].y,points[8].y,points[9].y,points[10].y};
Arrays.sort(minXes);
Arrays.sort(maxXes);
Arrays.sort(maxYs);
Arrays.sort(minYs);
return new RectF(minXes[0], minYs[0], maxXes[maxXes.length-1], maxYs[maxYs.length-1]);
}
// to store in db
public static String bitmapToBase64(Bitmap bitmap) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();
return Base64.encodeToString(byteArray, Base64.DEFAULT);
}
// to retreive from db
public static Bitmap base64ToBitmap(String b64) {
byte[] imageAsBytes = Base64.decode(b64.getBytes(), Base64.DEFAULT);
return BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);
}
public byte[] getFrameAsByteArray() {
if(frame == null)
return null;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
frame.compress(Bitmap.CompressFormat.JPEG, 90, stream);
return stream.toByteArray();
}
public float calculateScore() {
float scored_value = emotions.get(target.emotion);
float required_value = target.value;
float diff = Math.abs(scored_value-required_value);
return 100 - diff;
}
public float calculateBonus() {
float scored_value = emotions.get(target.emotion);
float required_value = target.value;
float diff = Math.abs(scored_value-required_value);
float bonus = 0;
// precision score
if(diff < 25) {
bonus = ((25-diff)/25) * 50;
}
// double score if its exact!!
if(diff < 0.001) {
bonus += 50;
}
Log.e("HIT", "bonus: " + bonus + " (diff "+diff+")");
return bonus;
}
public boolean hasPrecisionBonus() {
return (this.bonus > 0);
}
}