Read Emotions API part one.

Introduction

Android is one of the most popular operating systems for mobile. In this article, I will show you how to identify emotions with the help of Microsoft Emotions API.
Requirements
Steps to be followed
Carefully follow these steps to use Emotions API in Android application using Android Studio. I've included the source code below.
Step 1
Go to activity_main.xml and click the text bottom. This XML file contains the designing code for the Android app. Into the activity_main.xml file, copy and paste the below code.
Activity_main.xml code
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
  4. android:paddingRight="@dimen/activity_horizontal_margin"
  5. android:paddingTop="@dimen/activity_vertical_margin"
  6. android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
  7. <LinearLayout
  8. android:orientation="vertical"
  9. android:layout_width="fill_parent"
  10. android:layout_height="fill_parent"
  11. android:weightSum="1">
  12. <Button
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:text="Recognize Image"
  16. android:id="@+id/button_recognize"
  17. android:layout_gravity="center_horizontal"
  18. android:onClick="activityRecognize" />
  19. <TextView
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content"
  22. android:layout_marginTop="20dp"
  23. android:text="Microsoft will receive the images you upload and may use them to improve Emotion API and related services. By submitting an image, you confirm that you have consent from everyone in it."/>
  24. </LinearLayout>
  25. </RelativeLayout>
Android
Step 2
Create new activity_recognize.xml file (File ⇒ New ⇒Activity⇒Empty_activity).
Go to activity_recognize.xml and click the text bottom. This XML file contains the designing code for the Android app. In activity_recognize.xml, copy and paste the below code.
activity_recognize.xml code
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
  4. android:paddingRight="@dimen/activity_horizontal_margin"
  5. android:paddingTop="@dimen/activity_vertical_margin"
  6. android:paddingBottom="@dimen/activity_vertical_margin"
  7. tools:context="ganeshannt.emotionapi.RecognizeActivity">
  8. <LinearLayout
  9. android:orientation="vertical"
  10. android:layout_width="fill_parent"
  11. android:layout_height="fill_parent"
  12. android:weightSum="1">
  13. <TextView
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. android:layout_margin="4dp"
  17. android:text="Select an image to analyze"/>
  18. <LinearLayout
  19. android:orientation="horizontal"
  20. android:layout_width="fill_parent"
  21. android:layout_height="wrap_content">
  22. <Button
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:text="Select Image"
  26. android:id="@+id/buttonSelectImage"
  27. android:onClick="selectImage"/>
  28. <ImageView
  29. android:id="@+id/selectedImage"
  30. android:layout_width="200dp"
  31. android:layout_height="200dp"
  32. android:layout_toRightOf="@+id/image_control"
  33. android:layout_toEndOf="@+id/image_control"
  34. android:background="#E0E0E0" />
  35. </LinearLayout>
  36. <LinearLayout
  37. android:orientation="horizontal"
  38. android:layout_width="match_parent"
  39. android:layout_height="wrap_content"
  40. android:layout_gravity="right"
  41. android:layout_weight="1.03">
  42. <EditText
  43. android:layout_width="wrap_content"
  44. android:layout_height="match_parent"
  45. android:inputType="textMultiLine"
  46. android:ems="10"
  47. android:id="@+id/editTextResult"
  48. android:layout_weight="1" />
  49. </LinearLayout>
  50. </LinearLayout>
  51. </RelativeLayout>
Android
Step 3
Create a new activity_select_image.xml file (File ⇒ New ⇒Activity⇒Empty_activity).
Go to activity_select_image.xml and click the text bottom. Here, copy and paste the below code.
activity_select_image.xml code
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:paddingLeft="@dimen/activity_horizontal_margin"
  6. android:paddingRight="@dimen/activity_horizontal_margin"
  7. android:paddingTop="@dimen/activity_vertical_margin"
  8. android:paddingBottom="@dimen/activity_vertical_margin"
  9. android:baselineAligned="false"
  10. android:orientation="vertical"
  11. tools:context="ganeshannt.emotionapi.helper.SelectImageActivity">
  12. <RelativeLayout android:layout_width="match_parent"
  13. android:layout_height="match_parent"
  14. android:layout_weight="2">
  15. <TextView
  16. android:id="@+id/info"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:layout_centerHorizontal="true"
  20. android:layout_above="@+id/button_take_a_photo"
  21. android:layout_gravity="center" />
  22. <Button
  23. android:id="@+id/button_take_a_photo"
  24. android:layout_width="match_parent"
  25. android:layout_height="wrap_content"
  26. android:text="@string/take_photo"
  27. android:layout_centerHorizontal="true"
  28. android:layout_alignParentBottom="true"
  29. android:onClick="takePhoto"
  30. style="@style/ButtonStyle" />
  31. </RelativeLayout>
  32. <RelativeLayout android:layout_width="match_parent"
  33. android:layout_height="match_parent"
  34. android:layout_weight="1">
  35. <Button
  36. android:id="@+id/button_select_a_photo_in_album"
  37. android:layout_width="match_parent"
  38. android:layout_height="wrap_content"
  39. android:text="@string/select_image_in_album"
  40. android:layout_centerHorizontal="true"
  41. android:layout_centerVertical="true"
  42. android:onClick="selectImageInAlbum"
  43. style="@style/ButtonStyle" />
  44. </RelativeLayout>
  45. </LinearLayout>
Android
Step 4
create three (name: helper)android package folder
(java->>new->>folder->>package folder).
Step 5
Into helper folder create file(class name:MainActivity, RecognizeActivity ) (File ⇒ New ⇒Java class).
Into the MainActivity.java copy and paste the below code.java programming is the backend language for Android. Do not replace your package name otherwise, the app will not run.
MainActivity.java code
  1. package ganeshannt.emotionapi;
  2. import android.app.AlertDialog;
  3. import android.content.Intent;
  4. import android.support.v7.app.ActionBarActivity;
  5. import android.os.Bundle;
  6. import android.view.Menu;
  7. import android.view.MenuItem;
  8. import android.view.View;
  9. public class MainActivity extends ActionBarActivity {
  10. @Override
  11. protected void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_main);
  14. if (getString(R.string.subscription_key).startsWith("Please")) {
  15. new AlertDialog.Builder(this)
  16. .setTitle(getString(R.string.add_subscription_key_tip_title))
  17. .setMessage(getString(R.string.add_subscription_key_tip))
  18. .setCancelable(false)
  19. .show();
  20. }
  21. }
  22. @Override
  23. public boolean onCreateOptionsMenu(Menu menu) {
  24. // Inflate the menu; this adds items to the action bar if it is present.
  25. getMenuInflater().inflate(R.menu.menu_main, menu);
  26. return true;
  27. }
  28. public void activityRecognize(View v) {
  29. Intent intent = new Intent(this, RecognizeActivity.class);
  30. startActivity(intent);
  31. }
  32. @Override
  33. public boolean onOptionsItemSelected(MenuItem item) {
  34. // Handle action bar item clicks here. The action bar will
  35. // automatically handle clicks on the Home/Up button, so long
  36. // as you specify a parent activity in AndroidManifest.xml.
  37. int id = item.getItemId();
  38. //noinspection SimplifiableIfStatement
  39. if (id == R.id.action_settings) {
  40. return true;
  41. }
  42. return super.onOptionsItemSelected(item);
  43. }
  44. }
Step 6
Into the RecognizeActivity.java copy and paste the below code.java programming is the backend language for Android. Do not replace your package name, otherwise, the app will not run.
RecognizeActivity.java code
  1. package ganeshannt.emotionapi;
  2. import android.content.Intent;
  3. import android.graphics.Bitmap;
  4. import android.graphics.Canvas;
  5. import android.graphics.Color;
  6. import android.graphics.Paint;
  7. import android.graphics.drawable.BitmapDrawable;
  8. import android.net.Uri;
  9. import android.os.AsyncTask;
  10. import android.os.Bundle;
  11. import android.support.v7.app.ActionBarActivity;
  12. import android.util.Log;
  13. import android.view.Menu;
  14. import android.view.MenuItem;
  15. import android.view.View;
  16. import android.widget.Button;
  17. import android.widget.EditText;
  18. import android.widget.ImageView;
  19. import com.google.gson.Gson;
  20. import com.microsoft.projectoxford.emotion.EmotionServiceClient;
  21. import com.microsoft.projectoxford.emotion.EmotionServiceRestClient;
  22. import com.microsoft.projectoxford.emotion.contract.FaceRectangle;
  23. import com.microsoft.projectoxford.emotion.contract.RecognizeResult;
  24. import com.microsoft.projectoxford.emotion.rest.EmotionServiceException;
  25. import com.microsoft.projectoxford.emotionsample.helper.ImageHelper;
  26. import com.microsoft.projectoxford.face.FaceServiceRestClient;
  27. import com.microsoft.projectoxford.face.contract.Face;
  28. import java.io.ByteArrayInputStream;
  29. import java.io.ByteArrayOutputStream;
  30. import java.io.IOException;
  31. import java.util.List;
  32. public class RecognizeActivity extends ActionBarActivity {
  33. // Flag to indicate which task is to be performed.
  34. private static final int REQUEST_SELECT_IMAGE = 0;
  35. // The button to select an image
  36. private Button mButtonSelectImage;
  37. // The URI of the image selected to detect.
  38. private Uri mImageUri;
  39. // The image selected to detect.
  40. private Bitmap mBitmap;
  41. // The edit to show status and result.
  42. private EditText mEditText;
  43. private EmotionServiceClient client;
  44. @Override
  45. protected void onCreate(Bundle savedInstanceState) {
  46. super.onCreate(savedInstanceState);
  47. setContentView(R.layout.activity_recognize);
  48. if (client == null) {
  49. client = new EmotionServiceRestClient(getString(R.string.subscription_key));
  50. }
  51. mButtonSelectImage = (Button) findViewById(R.id.buttonSelectImage);
  52. mEditText = (EditText) findViewById(R.id.editTextResult);
  53. }
  54. @Override
  55. public boolean onCreateOptionsMenu(Menu menu) {
  56. // Inflate the menu; this adds items to the action bar if it is present.
  57. getMenuInflater().inflate(R.menu.menu_recognize, menu);
  58. return true;
  59. }
  60. @Override
  61. public boolean onOptionsItemSelected(MenuItem item) {
  62. // Handle action bar item clicks here. The action bar will
  63. // automatically handle clicks on the Home/Up button, so long
  64. // as you specify a parent activity in AndroidManifest.xml.
  65. int id = item.getItemId();
  66. //noinspection SimplifiableIfStatement
  67. if (id == R.id.action_settings) {
  68. return true;
  69. }
  70. return super.onOptionsItemSelected(item);
  71. }
  72. public void doRecognize() {
  73. mButtonSelectImage.setEnabled(false);
  74. // Do emotion detection using auto-detected faces.
  75. try {
  76. new doRequest(false).execute();
  77. } catch (Exception e) {
  78. mEditText.append("Error encountered. Exception is: " + e.toString());
  79. }
  80. String faceSubscriptionKey = getString(R.string.faceSubscription_key);
  81. if (faceSubscriptionKey.equalsIgnoreCase("Please_add_the_face_subscription_key_here")) {
  82. mEditText.append("\n\nThere is no face subscription key in res/values/strings.xml. Skip the sample for detecting emotions using face rectangles\n");
  83. } else {
  84. // Do emotion detection using face rectangles provided by Face API.
  85. try {
  86. new doRequest(true).execute();
  87. } catch (Exception e) {
  88. mEditText.append("Error encountered. Exception is: " + e.toString());
  89. }
  90. }
  91. }
  92. // Called when the "Select Image" button is clicked.
  93. public void selectImage(View view) {
  94. mEditText.setText("");
  95. Intent intent;
  96. intent = new Intent(RecognizeActivity.this, com.microsoft.projectoxford.emotionsample.helper.SelectImageActivity.class);
  97. startActivityForResult(intent, REQUEST_SELECT_IMAGE);
  98. }
  99. // Called when image selection is done.
  100. @Override
  101. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  102. Log.d("RecognizeActivity", "onActivityResult");
  103. switch (requestCode) {
  104. case REQUEST_SELECT_IMAGE:
  105. if (resultCode == RESULT_OK) {
  106. // If image is selected successfully, set the image URI and bitmap.
  107. mImageUri = data.getData();
  108. mBitmap = ImageHelper.loadSizeLimitedBitmapFromUri(
  109. mImageUri, getContentResolver());
  110. if (mBitmap != null) {
  111. // Show the image on screen.
  112. ImageView imageView = (ImageView) findViewById(R.id.selectedImage);
  113. imageView.setImageBitmap(mBitmap);
  114. // Add detection log.
  115. Log.d("RecognizeActivity", "Image: " + mImageUri + " resized to " + mBitmap.getWidth()
  116. + "x" + mBitmap.getHeight());
  117. doRecognize();
  118. }
  119. }
  120. break;
  121. default:
  122. break;
  123. }
  124. }
  125. private List<RecognizeResult> processWithAutoFaceDetection() throws EmotionServiceException, IOException {
  126. Log.d("emotion", "Start emotion detection with auto-face detection");
  127. Gson gson = new Gson();
  128. // Put the image into an input stream for detection.
  129. ByteArrayOutputStream output = new ByteArrayOutputStream();
  130. mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
  131. ByteArrayInputStream inputStream = new ByteArrayInputStream(output.toByteArray());
  132. long startTime = System.currentTimeMillis();
  133. // -----------------------------------------------------------------------
  134. // KEY SAMPLE CODE STARTS HERE
  135. // -----------------------------------------------------------------------
  136. List<RecognizeResult> result = null;
  137. //
  138. // Detect emotion by auto-detecting faces in the image.
  139. //
  140. result = this.client.recognizeImage(inputStream);
  141. String json = gson.toJson(result);
  142. Log.d("result", json);
  143. Log.d("emotion", String.format("Detection done. Elapsed time: %d ms", (System.currentTimeMillis() - startTime)));
  144. // -----------------------------------------------------------------------
  145. // KEY SAMPLE CODE ENDS HERE
  146. // -----------------------------------------------------------------------
  147. return result;
  148. }
  149. private List<RecognizeResult> processWithFaceRectangles() throws EmotionServiceException, com.microsoft.projectoxford.face.rest.ClientException, IOException {
  150. Log.d("emotion", "Do emotion detection with known face rectangles");
  151. Gson gson = new Gson();
  152. // Put the image into an input stream for detection.
  153. ByteArrayOutputStream output = new ByteArrayOutputStream();
  154. mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
  155. ByteArrayInputStream inputStream = new ByteArrayInputStream(output.toByteArray());
  156. long timeMark = System.currentTimeMillis();
  157. Log.d("emotion", "Start face detection using Face API");
  158. FaceRectangle[] faceRectangles = null;
  159. String faceSubscriptionKey = getString(R.string.faceSubscription_key);
  160. FaceServiceRestClient faceClient = new FaceServiceRestClient(faceSubscriptionKey);
  161. Face faces[] = faceClient.detect(inputStream, false, false, null);
  162. Log.d("emotion", String.format("Face detection is done. Elapsed time: %d ms", (System.currentTimeMillis() - timeMark)));
  163. if (faces != null) {
  164. faceRectangles = new FaceRectangle[faces.length];
  165. for (int i = 0; i < faceRectangles.length; i++) {
  166. // Face API and Emotion API have different FaceRectangle definition. Do the conversion.
  167. com.microsoft.projectoxford.face.contract.FaceRectangle rect = faces[i].faceRectangle;
  168. faceRectangles[i] = new com.microsoft.projectoxford.emotion.contract.FaceRectangle(rect.left, rect.top, rect.width, rect.height);
  169. }
  170. }
  171. List<RecognizeResult> result = null;
  172. if (faceRectangles != null) {
  173. inputStream.reset();
  174. timeMark = System.currentTimeMillis();
  175. Log.d("emotion", "Start emotion detection using Emotion API");
  176. // -----------------------------------------------------------------------
  177. // KEY SAMPLE CODE STARTS HERE
  178. // -----------------------------------------------------------------------
  179. result = this.client.recognizeImage(inputStream, faceRectangles);
  180. String json = gson.toJson(result);
  181. Log.d("result", json);
  182. // -----------------------------------------------------------------------
  183. // KEY SAMPLE CODE ENDS HERE
  184. // -----------------------------------------------------------------------
  185. Log.d("emotion", String.format("Emotion detection is done. Elapsed time: %d ms", (System.currentTimeMillis() - timeMark)));
  186. }
  187. return result;
  188. }
  189. private class doRequest extends AsyncTask<String, String, List<RecognizeResult>> {
  190. // Store error message
  191. private Exception e = null;
  192. private boolean useFaceRectangles = false;
  193. public doRequest(boolean useFaceRectangles) {
  194. this.useFaceRectangles = useFaceRectangles;
  195. }
  196. @Override
  197. protected List<RecognizeResult> doInBackground(String... args) {
  198. if (this.useFaceRectangles == false) {
  199. try {
  200. return processWithAutoFaceDetection();
  201. } catch (Exception e) {
  202. this.e = e; // Store error
  203. }
  204. } else {
  205. try {
  206. return processWithFaceRectangles();
  207. } catch (Exception e) {
  208. this.e = e; // Store error
  209. }
  210. }
  211. return null;
  212. }
  213. @Override
  214. protected void onPostExecute(List<RecognizeResult> result) {
  215. super.onPostExecute(result);
  216. // Display based on error existence
  217. if (this.useFaceRectangles == false) {
  218. mEditText.append("\n\nRecognizing emotions with auto-detected face rectangles...\n");
  219. } else {
  220. mEditText.append("\n\nRecognizing emotions with existing face rectangles from Face API...\n");
  221. }
  222. if (e != null) {
  223. mEditText.setText("Error: " + e.getMessage());
  224. this.e = null;
  225. } else {
  226. if (result.size() == 0) {
  227. mEditText.append("No emotion detected :(");
  228. } else {
  229. Integer count = 0;
  230. // Covert bitmap to a mutable bitmap by copying it
  231. Bitmap bitmapCopy = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
  232. Canvas faceCanvas = new Canvas(bitmapCopy);
  233. faceCanvas.drawBitmap(mBitmap, 0, 0, null);
  234. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  235. paint.setStyle(Paint.Style.STROKE);
  236. paint.setStrokeWidth(5);
  237. paint.setColor(Color.RED);
  238. for (RecognizeResult r : result) {
  239. mEditText.append(String.format("\nFace #%1$d \n", count));
  240. mEditText.append(String.format("\t anger: %1$.5f\n", r.scores.anger));
  241. mEditText.append(String.format("\t contempt: %1$.5f\n", r.scores.contempt));
  242. mEditText.append(String.format("\t disgust: %1$.5f\n", r.scores.disgust));
  243. mEditText.append(String.format("\t fear: %1$.5f\n", r.scores.fear));
  244. mEditText.append(String.format("\t happiness: %1$.5f\n", r.scores.happiness));
  245. mEditText.append(String.format("\t neutral: %1$.5f\n", r.scores.neutral));
  246. mEditText.append(String.format("\t sadness: %1$.5f\n", r.scores.sadness));
  247. mEditText.append(String.format("\t surprise: %1$.5f\n", r.scores.surprise));
  248. mEditText.append(String.format("\t face rectangle: %d, %d, %d, %d", r.faceRectangle.left, r.faceRectangle.top, r.faceRectangle.width, r.faceRectangle.height));
  249. faceCanvas.drawRect(r.faceRectangle.left,
  250. r.faceRectangle.top,
  251. r.faceRectangle.left + r.faceRectangle.width,
  252. r.faceRectangle.top + r.faceRectangle.height,
  253. paint);
  254. count++;
  255. }
  256. ImageView imageView = (ImageView) findViewById(R.id.selectedImage);
  257. imageView.setImageDrawable(new BitmapDrawable(getResources(), mBitmap));
  258. }
  259. mEditText.setSelection(0);
  260. }
  261. mButtonSelectImage.setEnabled(true);
  262. }
  263. }
  264. }
Step 7
As we need to make network requests, we need to add INTERNET permission in AndroidManifest.xml.Add the below code into the AndroidManifest.xml.
AndroidManifest.xml code
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="ganeshannt.emotionapi" >
  4. <uses-permission android:name="android.permission.INTERNET" />
  5. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  6. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  7. <application
  8. android:allowBackup="true"
  9. android:icon="@mipmap/ic_launcher"
  10. android:label="@string/app_name"
  11. android:theme="@style/AppTheme" >
  12. <activity
  13. android:name="com.microsoft.projectoxford.emotionsample.MainActivity"
  14. android:label="@string/app_name" >
  15. <intent-filter>
  16. <action android:name="android.intent.action.MAIN" />
  17. <category android:name="android.intent.category.LAUNCHER" />
  18. </intent-filter>
  19. </activity>
  20. <activity
  21. android:name="com.microsoft.projectoxford.emotionsample.RecognizeActivity"
  22. android:label="@string/title_activity_analyze"
  23. android:parentActivityName="com.microsoft.projectoxford.emotionsample.MainActivity" >
  24. <meta-data
  25. android:name="android.support.PARENT_ACTIVITY"
  26. android:value="com.microsoft.projectoxford.emotionsample.MainActivity" />
  27. </activity>
  28. <activity
  29. android:name="com.microsoft.projectoxford.emotionsample.helper.SelectImageActivity"
  30. android:label="@string/select_an_image"
  31. android:screenOrientation="portrait" />
  32. </application>
  33. </manifest>
Step 8
This is our user interface of the application. Click the make project option.
Android
Step 9
Run the application then choose the virtual machine then click ok.
Android
Deliverables
Here the emotion was successfully detected using emotion API created and executed in the Android app.
Android
Android
Android
Android
Android
Don’t forget to like and follow me. If you have any doubts just comment below.