From 05b7597ea1f256ca08efee87098105d58f0a1975 Mon Sep 17 00:00:00 2001 From: Chris Thrasher Date: Tue, 10 Apr 2018 20:37:05 -0700 Subject: [PATCH] Remove deprecated Emotion API (#7) Emotion API calls are now made through the Face API. --- README.md | 4 +- .../BasicConsoleSample.csproj | 4 +- Windows/BasicConsoleSample/packages.config | 2 +- Windows/LiveCameraSample/Aggregation.cs | 6 +- Windows/LiveCameraSample/App.config | 6 -- .../LiveCameraSample/LiveCameraSample.csproj | 4 +- Windows/LiveCameraSample/MainWindow.xaml | 21 ++--- Windows/LiveCameraSample/MainWindow.xaml.cs | 93 ++++++++----------- .../Properties/Settings.Designer.cs | 40 +------- .../Properties/Settings.settings | 9 -- Windows/LiveCameraSample/Visualization.cs | 5 +- Windows/LiveCameraSample/packages.config | 3 +- Windows/VideoFrameAnalyzer/FrameGrabber.cs | 2 +- 13 files changed, 63 insertions(+), 136 deletions(-) diff --git a/README.md b/README.md index 28c93e4..dd084d4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ This sample contains a library, along with two applications, for analyzing video 1. Get API keys for the Vision APIs from [microsoft.com/cognitive][Sign-Up]. For video frame analysis, the applicable APIs are: - [Computer Vision API][] - - [Emotion API][] - [Face API][] 2. Open the sample in Visual Studio 2015, build and run the sample applications: - For BasicConsoleSample, the Face API key is hard-coded directly in [BasicConsoleSample/Program.cs](Windows/BasicConsoleSample/Program.cs). @@ -18,7 +17,6 @@ This sample contains a library, along with two applications, for analyzing video [Sign-Up]: https://www.microsoft.com/cognitive-services/en-us/sign-up [Computer Vision API]: https://www.microsoft.com/cognitive-services/en-us/computer-vision-api -[Emotion API]: https://www.microsoft.com/cognitive-services/en-us/emotion-api [Face API]: https://www.microsoft.com/cognitive-services/en-us/face-api ## Using the VideoFrameAnalyzer Library @@ -26,7 +24,7 @@ This sample contains a library, along with two applications, for analyzing video You can start using the library with only a few lines of code: ```csharp // Create Face API Client. -FaceServiceClient faceClient = new FaceServiceClient(""); +FaceServiceClient faceClient = new FaceServiceClient("",""); // Create grabber, with analysis type Face[]. FrameGrabber grabber = new FrameGrabber(); // Set up Face API call, which returns a Face[]. Simply encodes image and submits to Face API. diff --git a/Windows/BasicConsoleSample/BasicConsoleSample.csproj b/Windows/BasicConsoleSample/BasicConsoleSample.csproj index 27a43d8..3d38375 100644 --- a/Windows/BasicConsoleSample/BasicConsoleSample.csproj +++ b/Windows/BasicConsoleSample/BasicConsoleSample.csproj @@ -40,8 +40,8 @@ ..\packages\Microsoft.ProjectOxford.Common.1.0.324\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Common.dll True - - ..\packages\Microsoft.ProjectOxford.Face.1.3.0\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Microsoft.ProjectOxford.Face.dll + + ..\packages\Microsoft.ProjectOxford.Face.1.4.0\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Microsoft.ProjectOxford.Face.dll True diff --git a/Windows/BasicConsoleSample/packages.config b/Windows/BasicConsoleSample/packages.config index e6084d1..122e192 100644 --- a/Windows/BasicConsoleSample/packages.config +++ b/Windows/BasicConsoleSample/packages.config @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/Windows/LiveCameraSample/Aggregation.cs b/Windows/LiveCameraSample/Aggregation.cs index 5ee8c1a..40777c5 100644 --- a/Windows/LiveCameraSample/Aggregation.cs +++ b/Windows/LiveCameraSample/Aggregation.cs @@ -31,9 +31,9 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -using Microsoft.ProjectOxford.Emotion.Contract; using System.Linq; using Microsoft.ProjectOxford.Face.Contract; +using Microsoft.ProjectOxford.Common.Contract; using System; using System.Collections.Generic; @@ -41,12 +41,12 @@ namespace LiveCameraSample { internal class Aggregation { - public static Tuple GetDominantEmotion(Microsoft.ProjectOxford.Common.Contract.EmotionScores scores) + public static Tuple GetDominantEmotion(EmotionScores scores) { return scores.ToRankedList().Select(kv => new Tuple(kv.Key, kv.Value)).First(); } - public static string SummarizeEmotion(Microsoft.ProjectOxford.Common.Contract.EmotionScores scores) + public static string SummarizeEmotion(EmotionScores scores) { var bestEmotion = Aggregation.GetDominantEmotion(scores); return string.Format("{0}: {1:N1}", bestEmotion.Item1, bestEmotion.Item2); diff --git a/Windows/LiveCameraSample/App.config b/Windows/LiveCameraSample/App.config index fe73bff..c93fcb8 100644 --- a/Windows/LiveCameraSample/App.config +++ b/Windows/LiveCameraSample/App.config @@ -28,9 +28,6 @@ - - - @@ -43,9 +40,6 @@ 0 - - 0 - 0 diff --git a/Windows/LiveCameraSample/LiveCameraSample.csproj b/Windows/LiveCameraSample/LiveCameraSample.csproj index 97c7f54..f481b6a 100644 --- a/Windows/LiveCameraSample/LiveCameraSample.csproj +++ b/Windows/LiveCameraSample/LiveCameraSample.csproj @@ -46,8 +46,8 @@ ..\packages\Microsoft.ProjectOxford.Emotion.1.0.336\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Emotion.dll True - - ..\packages\Microsoft.ProjectOxford.Face.1.3.0\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Microsoft.ProjectOxford.Face.dll + + ..\packages\Microsoft.ProjectOxford.Face.1.4.0\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Microsoft.ProjectOxford.Face.dll True diff --git a/Windows/LiveCameraSample/MainWindow.xaml b/Windows/LiveCameraSample/MainWindow.xaml index 8e03ff4..b9def98 100644 --- a/Windows/LiveCameraSample/MainWindow.xaml +++ b/Windows/LiveCameraSample/MainWindow.xaml @@ -49,22 +49,17 @@ - - - - - - - - - - - - + + + + + + + + - diff --git a/Windows/LiveCameraSample/MainWindow.xaml.cs b/Windows/LiveCameraSample/MainWindow.xaml.cs index c2e1731..157e63c 100644 --- a/Windows/LiveCameraSample/MainWindow.xaml.cs +++ b/Windows/LiveCameraSample/MainWindow.xaml.cs @@ -31,14 +31,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -using Microsoft.ProjectOxford.Emotion; -using Microsoft.ProjectOxford.Emotion.Contract; -using Microsoft.ProjectOxford.Face; -using Microsoft.ProjectOxford.Face.Contract; -using Microsoft.ProjectOxford.Vision; -using Newtonsoft.Json; -using OpenCvSharp; -using OpenCvSharp.Extensions; using System; using System.Collections.Generic; using System.Diagnostics; @@ -48,7 +40,13 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; using System.Windows.Navigation; +using Newtonsoft.Json; +using OpenCvSharp; +using OpenCvSharp.Extensions; using VideoFrameAnalyzer; +using Common = Microsoft.ProjectOxford.Common; +using FaceAPI = Microsoft.ProjectOxford.Face; +using VisionAPI = Microsoft.ProjectOxford.Vision; namespace LiveCameraSample { @@ -57,9 +55,8 @@ namespace LiveCameraSample /// public partial class MainWindow : System.Windows.Window { - private EmotionServiceClient _emotionClient = null; - private FaceServiceClient _faceClient = null; - private VisionServiceClient _visionClient = null; + private FaceAPI.FaceServiceClient _faceClient = null; + private VisionAPI.VisionServiceClient _visionClient = null; private readonly FrameGrabber _grabber = null; private static readonly ImageEncodingParam[] s_jpegParams = { new ImageEncodingParam(ImwriteFlags.JpegQuality, 60) @@ -132,9 +129,9 @@ namespace LiveCameraSample { string apiName = ""; string message = e.Exception.Message; - var faceEx = e.Exception as FaceAPIException; - var emotionEx = e.Exception as Microsoft.ProjectOxford.Common.ClientException; - var visionEx = e.Exception as Microsoft.ProjectOxford.Vision.ClientException; + var faceEx = e.Exception as FaceAPI.FaceAPIException; + var emotionEx = e.Exception as Common.ClientException; + var visionEx = e.Exception as VisionAPI.ClientException; if (faceEx != null) { apiName = "Face"; @@ -178,8 +175,11 @@ namespace LiveCameraSample // Encode image. var jpg = frame.Image.ToMemoryStream(".jpg", s_jpegParams); // Submit image to API. - var attrs = new List { FaceAttributeType.Age, - FaceAttributeType.Gender, FaceAttributeType.HeadPose }; + var attrs = new List { + FaceAPI.FaceAttributeType.Age, + FaceAPI.FaceAttributeType.Gender, + FaceAPI.FaceAttributeType.HeadPose + }; var faces = await _faceClient.DetectAsync(jpg, returnFaceAttributes: attrs); // Count the API call. Properties.Settings.Default.FaceAPICallCount++; @@ -196,44 +196,33 @@ namespace LiveCameraSample // Encode image. var jpg = frame.Image.ToMemoryStream(".jpg", s_jpegParams); // Submit image to API. - Emotion[] emotions = null; + FaceAPI.Contract.Face[] faces = null; // See if we have local face detections for this image. var localFaces = (OpenCvSharp.Rect[])frame.UserData; - if (localFaces == null) + if (localFaces == null || localFaces.Count() > 0) { // If localFaces is null, we're not performing local face detection. // Use Cognigitve Services to do the face detection. - Properties.Settings.Default.EmotionAPICallCount++; - emotions = await _emotionClient.RecognizeAsync(jpg); - } - else if (localFaces.Count() > 0) - { - // If we have local face detections, we can call the API with them. - // First, convert the OpenCvSharp rectangles. - var rects = localFaces.Select( - f => new Microsoft.ProjectOxford.Common.Rectangle - { - Left = f.Left, - Top = f.Top, - Width = f.Width, - Height = f.Height - }); - Properties.Settings.Default.EmotionAPICallCount++; - emotions = await _emotionClient.RecognizeAsync(jpg, rects.ToArray()); + Properties.Settings.Default.FaceAPICallCount++; + faces = await _faceClient.DetectAsync( + jpg, + /* returnFaceId= */ false, + /* returnFaceLandmarks= */ false, + new FaceAPI.FaceAttributeType[1] { FaceAPI.FaceAttributeType.Emotion }); } else { // Local face detection found no faces; don't call Cognitive Services. - emotions = new Emotion[0]; + faces = new FaceAPI.Contract.Face[0]; } // Output. return new LiveCameraResult { - Faces = emotions.Select(e => CreateFace(e.FaceRectangle)).ToArray(), + Faces = faces.Select(e => CreateFace(e.FaceRectangle)).ToArray(), // Extract emotion scores from results. - EmotionScores = emotions.Select(e => e.Scores).ToArray() + EmotionScores = faces.Select(e => e.FaceAttributes.Emotion).ToArray() }; } @@ -376,13 +365,11 @@ namespace LiveCameraSample // Clean leading/trailing spaces in API keys. Properties.Settings.Default.FaceAPIKey = Properties.Settings.Default.FaceAPIKey.Trim(); - Properties.Settings.Default.EmotionAPIKey = Properties.Settings.Default.EmotionAPIKey.Trim(); Properties.Settings.Default.VisionAPIKey = Properties.Settings.Default.VisionAPIKey.Trim(); // Create API clients. - _faceClient = new FaceServiceClient(Properties.Settings.Default.FaceAPIKey, Properties.Settings.Default.FaceAPIHost); - _emotionClient = new EmotionServiceClient(Properties.Settings.Default.EmotionAPIKey, Properties.Settings.Default.EmotionAPIHost); - _visionClient = new VisionServiceClient(Properties.Settings.Default.VisionAPIKey, Properties.Settings.Default.VisionAPIHost); + _faceClient = new FaceAPI.FaceServiceClient(Properties.Settings.Default.FaceAPIKey, Properties.Settings.Default.FaceAPIHost); + _visionClient = new VisionAPI.VisionServiceClient(Properties.Settings.Default.VisionAPIKey, Properties.Settings.Default.VisionAPIHost); // How often to analyze. _grabber.TriggerAnalysisOnInterval(Properties.Settings.Default.AnalysisInterval); @@ -418,11 +405,11 @@ namespace LiveCameraSample e.Handled = true; } - private Face CreateFace(FaceRectangle rect) + private FaceAPI.Contract.Face CreateFace(FaceAPI.Contract.FaceRectangle rect) { - return new Face + return new FaceAPI.Contract.Face { - FaceRectangle = new FaceRectangle + FaceRectangle = new FaceAPI.Contract.FaceRectangle { Left = rect.Left, Top = rect.Top, @@ -432,11 +419,11 @@ namespace LiveCameraSample }; } - private Face CreateFace(Microsoft.ProjectOxford.Vision.Contract.FaceRectangle rect) + private FaceAPI.Contract.Face CreateFace(VisionAPI.Contract.FaceRectangle rect) { - return new Face + return new FaceAPI.Contract.Face { - FaceRectangle = new FaceRectangle + FaceRectangle = new FaceAPI.Contract.FaceRectangle { Left = rect.Left, Top = rect.Top, @@ -446,11 +433,11 @@ namespace LiveCameraSample }; } - private Face CreateFace(Microsoft.ProjectOxford.Common.Rectangle rect) + private FaceAPI.Contract.Face CreateFace(Common.Rectangle rect) { - return new Face + return new FaceAPI.Contract.Face { - FaceRectangle = new FaceRectangle + FaceRectangle = new FaceAPI.Contract.FaceRectangle { Left = rect.Left, Top = rect.Top, @@ -460,7 +447,7 @@ namespace LiveCameraSample }; } - private void MatchAndReplaceFaceRectangles(Face[] faces, OpenCvSharp.Rect[] clientRects) + private void MatchAndReplaceFaceRectangles(FaceAPI.Contract.Face[] faces, OpenCvSharp.Rect[] clientRects) { // Use a simple heuristic for matching the client-side faces to the faces in the // results. Just sort both lists left-to-right, and assume a 1:1 correspondence. @@ -482,7 +469,7 @@ namespace LiveCameraSample { // convert from OpenCvSharp rectangles OpenCvSharp.Rect r = sortedClientRects[i]; - sortedResultFaces[i].FaceRectangle = new FaceRectangle { Left = r.Left, Top = r.Top, Width = r.Width, Height = r.Height }; + sortedResultFaces[i].FaceRectangle = new FaceAPI.Contract.FaceRectangle { Left = r.Left, Top = r.Top, Width = r.Width, Height = r.Height }; } } } diff --git a/Windows/LiveCameraSample/Properties/Settings.Designer.cs b/Windows/LiveCameraSample/Properties/Settings.Designer.cs index c1bbfe5..410171f 100644 --- a/Windows/LiveCameraSample/Properties/Settings.Designer.cs +++ b/Windows/LiveCameraSample/Properties/Settings.Designer.cs @@ -14,9 +14,9 @@ namespace LiveCameraSample.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - + public static Settings Default { get { return defaultInstance; @@ -35,18 +35,6 @@ namespace LiveCameraSample.Properties { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string EmotionAPIKey { - get { - return ((string)(this["EmotionAPIKey"])); - } - set { - this["EmotionAPIKey"] = value; - } - } - [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("")] @@ -95,18 +83,6 @@ namespace LiveCameraSample.Properties { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("0")] - public int EmotionAPICallCount { - get { - return ((int)(this["EmotionAPICallCount"])); - } - set { - this["EmotionAPICallCount"] = value; - } - } - [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("0")] @@ -152,18 +128,6 @@ namespace LiveCameraSample.Properties { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("https://westus.api.cognitive.microsoft.com/emotion/v1.0")] - public string EmotionAPIHost { - get { - return ((string)(this["EmotionAPIHost"])); - } - set { - this["EmotionAPIHost"] = value; - } - } - [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("https://westus.api.cognitive.microsoft.com/vision/v1.0")] diff --git a/Windows/LiveCameraSample/Properties/Settings.settings b/Windows/LiveCameraSample/Properties/Settings.settings index 50e267a..81bfdb9 100644 --- a/Windows/LiveCameraSample/Properties/Settings.settings +++ b/Windows/LiveCameraSample/Properties/Settings.settings @@ -5,9 +5,6 @@ - - - @@ -20,9 +17,6 @@ 0 - - 0 - 0 @@ -35,9 +29,6 @@ https://westus.api.cognitive.microsoft.com/face/v1.0 - - https://westus.api.cognitive.microsoft.com/emotion/v1.0 - https://westus.api.cognitive.microsoft.com/vision/v1.0 diff --git a/Windows/LiveCameraSample/Visualization.cs b/Windows/LiveCameraSample/Visualization.cs index 3e934f8..aad7891 100644 --- a/Windows/LiveCameraSample/Visualization.cs +++ b/Windows/LiveCameraSample/Visualization.cs @@ -41,8 +41,7 @@ using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using Microsoft.ProjectOxford.Common.Contract; -using Microsoft.ProjectOxford.Emotion.Contract; -using Microsoft.ProjectOxford.Face.Contract; +using FaceAPI = Microsoft.ProjectOxford.Face.Contract; using Microsoft.ProjectOxford.Vision.Contract; namespace LiveCameraSample @@ -102,7 +101,7 @@ namespace LiveCameraSample return DrawOverlay(baseImage, drawAction); } - public static BitmapSource DrawFaces(BitmapSource baseImage, Microsoft.ProjectOxford.Face.Contract.Face[] faces, EmotionScores[] emotionScores, string[] celebName) + public static BitmapSource DrawFaces(BitmapSource baseImage, FaceAPI.Face[] faces, EmotionScores[] emotionScores, string[] celebName) { if (faces == null) { diff --git a/Windows/LiveCameraSample/packages.config b/Windows/LiveCameraSample/packages.config index 5596448..daea75a 100644 --- a/Windows/LiveCameraSample/packages.config +++ b/Windows/LiveCameraSample/packages.config @@ -4,8 +4,7 @@ - - + diff --git a/Windows/VideoFrameAnalyzer/FrameGrabber.cs b/Windows/VideoFrameAnalyzer/FrameGrabber.cs index 194d893..3599f78 100644 --- a/Windows/VideoFrameAnalyzer/FrameGrabber.cs +++ b/Windows/VideoFrameAnalyzer/FrameGrabber.cs @@ -90,7 +90,7 @@ namespace VideoFrameAnalyzer /// The analysis function. /// This example shows how to provide an analysis function using a lambda expression. /// - /// var client = new EmotionServiceClient("subscription key"); + /// var client = new FaceServiceClient("subscription key", "api root"); /// var grabber = new FrameGrabber(); /// grabber.AnalysisFunction = async (frame) => { return await client.RecognizeAsync(frame.Image.ToMemoryStream(".jpg")); }; ///