Detect and Blur Faces with .NET Core and Face API

Today I’ll show you how to create a small console application that will Detect and Blur Faces with .NET Core and Face API.

First be aware of the following prerequisites:

You will also need an Azure Cognitive Services Face API account and the correct set of access keys. (Start here: Subscribe in seconds if you need a Cognitive Service Account and here for the Documentation)

Now let’s start:

1. Create a folder for your new project


Open a command promt an run

1mkdir projectoxford

2. Create the project


1cd projectoxford
2dotnet new

3. Create a settings file


Create an appsettings.json file to hold your Face API Key (remember to replace the values with those from your Cognitive Service account):

1{
2  "FaceAPIKey": "[Your key here]"
3}

4. Modify the project file


Modify the project.json to add the Microsoft.ProjectOxford.Face dependency and also specify that the appsettings.json file must be copied to the output (buildOptions section) so it becomes available to the application once you build it.

We’ll be needing ImageProcessorCore to process the image (System.Drawing is not available in .NET Core) and also the extensions and tools to work with configuration files and user secrets.

 1{
 2  "userSecretsId": "cmendible3-dotnetcore.samples-projectOxford",
 3  "version": "1.0.0-*",
 4  "buildOptions": {
 5    "debugType": "portable",
 6    "emitEntryPoint": true,
 7    "copyToOutput": { 
 8      "include": "appsettings.json"
 9    }
10  },
11  "dependencies": {
12    "Microsoft.Extensions.Configuration": "1.0.0",
13    "Microsoft.Extensions.Configuration.Json": "1.0.0",
14    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
15    "Microsoft.ProjectOxford.Face": "1.1.0",
16    "System.Runtime.Serialization.Primitives": "4.1.1",
17    "ImageProcessorCore": "1.0.0-alpha-966"
18  },
19  "tools": {
20    "Microsoft.Extensions.SecretManager.Tools": "1.0.0-*"
21  },
22  "frameworks": {
23    "netcoreapp1.0": {
24      "dependencies": {
25        "Microsoft.NETCore.App": {
26          "type": "platform",
27          "version": "1.0.0"
28        }
29      },
30      "imports": "dnxcore50"
31    }
32  }
33}

6. Add ImageProcessorCore package source


ImageProcessorCore is in alpha stage and packages are available via MyGet so add NuGet.config file with the following content:

1<?xml version="1.0" encoding="utf-8"?>
2<configuration>
3  <packageSources>
4    <add key="imageprocessor" value="https://www.myget.org/F/imageprocessor/api/v3/index.json" protocolVersion="3" />
5  </packageSources>
6</configuration>

7. Restore packages


You just modified the project.json file with new dependencies and added the NuGet.config file so please restore the packages with the following command:

1dotnet restore

8. Modify Program.cs


Replace the contents of the Program.cs file with the following code

  1namespace ConsoleApplication
  2{
  3    using System;
  4    using System.IO;
  5    using System.Linq;
  6    using System.Threading.Tasks;
  7    using ImageProcessorCore;
  8    using Microsoft.Extensions.Configuration;
  9    using Microsoft.ProjectOxford.Face;
 10    using Microsoft.ProjectOxford.Face.Contract;
 11
 12    public class Program
 13    {
 14        /// <summary>
 15        /// Let's detect and blur some faces!
 16        /// </summary>
 17        /// 
 18        public static void Main(string[] args)
 19        {
 20            // The name of the source image.
 21            const string sourceImage = "faces.jpg";
 22
 23            // The name of the destination image
 24            const string destinationImage = "detectedfaces.jpg";
 25
 26            // Get the configuration
 27            var configuration = BuildConfiguration();
 28
 29            // Detect the faces in the source file
 30            DetectFaces(sourceImage, configuration["FaceAPIKey"])
 31                .ContinueWith((task) =>
 32                {
 33                    // Save the result of the detection
 34                    var faceRects = task.Result;
 35
 36                    Console.WriteLine($"Detected {faceRects.Length} faces");
 37
 38                    // Blur the detected faces and save in another file
 39                    BlurFaces(faceRects, sourceImage, destinationImage);
 40
 41                    Console.WriteLine($"Done!!!");
 42                });
 43
 44            Console.ReadLine();
 45        }
 46
 47        /// <summary>
 48        /// Build the confguration
 49        /// </summary>
 50        /// <returns>Returns the configuration</returns>
 51        private static IConfigurationRoot BuildConfiguration()
 52        {
 53            // Enable to app to read json setting files
 54            var builder = new ConfigurationBuilder()
 55                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
 56
 57#if DEBUG
 58            // We use user secrets in Debug mode so API keys are not uploaded to source control 
 59            builder.AddUserSecrets("cmendible3-dotnetcore.samples-projectOxford");
 60#endif
 61
 62            return builder.Build();
 63        }
 64
 65        /// <summary>
 66        /// Blur the detected faces from de source image.
 67        /// </summary>
 68        /// 
 69        /// 
 70        /// 
 71        private static void BlurFaces(FaceRectangle[] faceRects, string sourceImage, string destinationImage)
 72        {
 73            if (File.Exists(destinationImage))
 74            {
 75                File.Delete(destinationImage);
 76            }
 77
 78            if (faceRects.Length > 0)
 79            {
 80                using (FileStream stream = File.OpenRead("faces.jpg"))
 81                using (FileStream output = File.OpenWrite(destinationImage))
 82                {
 83                    var image = new Image<Color, uint>(stream);
 84
 85                    // Blur every detected face
 86                    foreach (var faceRect in faceRects)
 87                    {
 88                        var rectangle = new Rectangle(
 89                            faceRect.Left,
 90                            faceRect.Top,
 91                            faceRect.Width,
 92                            faceRect.Height);
 93
 94                        image = image.BoxBlur(20, rectangle);
 95                    }
 96
 97                    image.SaveAsJpeg(output);
 98                }
 99            }
100
101        }
102
103        /// <summary>
104        /// Detect faces calling the Face API
105        /// </summary>
106        /// 
107        /// 
108        /// <returns>Detected faces rectangles</returns>
109        private static async Task<FaceRectangle[]> DetectFaces(string imageFilePath, string apiKey)
110        {
111            var faceServiceClient = new FaceServiceClient(apiKey);
112
113            try
114            {
115                using (Stream imageFileStream = File.OpenRead(imageFilePath))
116                {
117                    var faces = await faceServiceClient.DetectAsync(imageFileStream);
118                    var faceRects = faces.Select(face => face.FaceRectangle);
119                    return faceRects.ToArray();
120                }
121            }
122            catch (Exception)
123            {
124                return new FaceRectangle[0];
125            }
126        }
127    }
128}

9. Build


Build and run the application with the following command

1dotnet run

10. Expected results


Command line should read

1Detected 26 faces
2Done!!!

The new detectedfaces.jpg file should look like this:

You can get the code here: https://github.com/cmendible/dotnetcore.samples/tree/main/projectoxford

Hope it helps!


Step by step: Entity Framework Core and Shadow Properties
Benefits and Risks You Need to Know about Cloud Computing
comments powered by Disqus