Commit 926c6515 authored by Carlos Andrés Carrero Saldarriaga's avatar Carlos Andrés Carrero Saldarriaga
Browse files

First working version

parent f8eadde8
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
using GAP.FaceDetection.Models;
using GAP.FaceDetection.Services;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
namespace GAP.FaceDetection.Functions
{
public class FaceDetection
{
private readonly IFaceDetection _faceDetection;
public FaceDetection(IFaceDetection faceDetection) => _faceDetection = faceDetection;
[Function(nameof(DetectFacesInImageUrlFunction))]
public async Task<HttpResponseData> DetectFacesInImageUrlFunction(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData requestData,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("DetectFace");
var personImage = await requestData.GetJsonBody<FacesPicture>();
logger.LogInformation("Initiating HTTP request with image url: {ImageUrl}", JsonSerializer.Serialize(personImage));
var detectedFaces = await _faceDetection.GetHumanFacesFromPictureUrl(personImage.ImageUrl);
var response = requestData.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(detectedFaces);
return response;
}
}
}
\ No newline at end of file
......@@ -7,8 +7,13 @@
<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.0.1" OutputItemType="Analyzer"/>
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.0.0"/>
<PackageReference Include="Azure.Identity" Version="1.4.1" />
<PackageReference Include="Microsoft.Azure.CognitiveServices.Vision.Face" Version="2.8.0-preview.1" />
<PackageReference Include="Microsoft.Azure.Core.NewtonsoftJson" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Core" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.0.1" OutputItemType="Analyzer" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
......
namespace GAP.FaceDetection.Models
{
public class FacesPicture
{
public string ImageUrl { get; set; }
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
namespace GAP.FaceDetection.Models
{
public class HumanFace
{
public Guid? FaceId { get; set; }
public double? Age { get; set; }
public string Gender { get; set; }
public string Glasses { get; set; }
public double? SmileConfidence { get; set; }
public HumanFaceBlur Blur { get; set; }
public HumanFaceMask Mask { get; set; }
public HumanFacialHair FacialHair { get; set; }
public HumanHeadPose HeadPose { get; set; }
public HumanFaceEmotion Emotion { get; set; }
public HumanHair Hair { get; set; }
public HumanMakeup Makeup { get; set; }
public HumanFaceOcclusion Occlusion { get; set; }
public HumanFaceExposure Exposure { get; set; }
public HumanFaceNoise Noise { get; set; }
public IEnumerable<HumanFaceAccessory> Accessories { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFaceAccessory
{
public double Confidence { get; set; }
public string Description { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFaceBlur
{
public double Confidence { get; set; }
public string Level { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFaceEmotion
{
public double AngerConfidence { get; set; }
public double ContemptConfidence { get; set; }
public double DisgustConfidence { get; set; }
public double FearConfidence { get; set; }
public double HappinessConfidence { get; set; }
public double NeutralConfidence { get; set; }
public double SadnessConfidence { get; set; }
public double SurpriseConfidence { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFaceExposure
{
public string Level { get; set; }
public double Confidence { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFaceMask
{
public string Type { get; set; }
public bool NoseAndMouthCovered { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFaceNoise
{
public string Level { get; set; }
public double Confidence { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFaceOcclusion
{
public bool ForeheadOccluded { get; set; }
public bool EyeOccluded { get; set; }
public bool MouthOccluded { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanFacialHair
{
public double MoustacheConfidence { get; set; }
public double BeardConfidence { get; set; }
public double SideburnsConfidence { get; set; }
}
}
\ No newline at end of file
using System.Collections.Generic;
namespace GAP.FaceDetection.Models
{
public class HumanHair
{
public double BaldConfidence { get; set; }
public bool Invisible { get; set; }
public IEnumerable<HumanHairColor> Color { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanHairColor
{
public string Description { get; set; }
public double Confidence { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanHeadPose
{
public double Roll { get; set; }
public double Yaw { get; set; }
public double Pitch { get; set; }
}
}
\ No newline at end of file
namespace GAP.FaceDetection.Models
{
public class HumanMakeup
{
public bool EyeMakeup { get; set; }
public bool LipMakeup { get; set; }
}
}
\ No newline at end of file
using System.Threading.Tasks;
using GAP.FaceDetection.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace GAP.FaceDetection
......@@ -9,6 +11,11 @@ namespace GAP.FaceDetection
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(serviceCollection =>
{
serviceCollection.AddSingleton<IAppSettings, AppConfiguration>();
serviceCollection.AddScoped<IFaceDetection, FaceDetectionService>();
})
.Build();
await host.RunAsync();
......
using System;
namespace GAP.FaceDetection.Services
{
public class AppConfiguration : IAppSettings
{
public string FaceApiKey => Environment.GetEnvironmentVariable("FaceApiPrimaryKey");
public string FaceApiUrl => Environment.GetEnvironmentVariable("FaceApiEndpoint");
}
}
\ No newline at end of file
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GAP.FaceDetection.Models;
using Microsoft.Azure.CognitiveServices.Vision.Face;
using Microsoft.Azure.CognitiveServices.Vision.Face.Models;
namespace GAP.FaceDetection.Services
{
public class FaceDetectionService : IFaceDetection
{
private const string RecognitionModel4 = RecognitionModel.Recognition04;
private readonly IFaceClient _faceClient;
public FaceDetectionService(IAppSettings appSettings) =>
_faceClient = new FaceClient(new ApiKeyServiceClientCredentials(appSettings.FaceApiKey)) { Endpoint = appSettings.FaceApiUrl };
public async Task<IEnumerable<HumanFace>> GetHumanFacesFromPictureUrl(string imageUrl)
{
var detectedFaces = await GetDetectedFacesAsync(imageUrl);
return GetHumanFaces(detectedFaces);
}
private async Task<IList<DetectedFace>> GetDetectedFacesAsync(string imageUrl)
{
var detectedFacesHttpOperationResponse = await _faceClient.Face.DetectWithUrlWithHttpMessagesAsync(
url: imageUrl,
returnFaceId: true,
returnFaceLandmarks: true,
returnFaceAttributes: new List<FaceAttributeType>
{
FaceAttributeType.Accessories, FaceAttributeType.Age, FaceAttributeType.Emotion, FaceAttributeType.Exposure,
FaceAttributeType.FacialHair, FaceAttributeType.Gender, FaceAttributeType.Glasses, FaceAttributeType.Hair,
FaceAttributeType.HeadPose, FaceAttributeType.Makeup, FaceAttributeType.Noise, FaceAttributeType.Occlusion,
FaceAttributeType.Smile
},
detectionModel: DetectionModel.Detection01,
recognitionModel: RecognitionModel4);
return detectedFacesHttpOperationResponse.Response.IsSuccessStatusCode
? detectedFacesHttpOperationResponse.Body
: new List<DetectedFace>();
}
private IEnumerable<HumanFace> GetHumanFaces(IEnumerable<DetectedFace> detectedFaces)
{
return detectedFaces
.Select(detectedFace => new HumanFace
{
FaceId = detectedFace.FaceId,
Age = detectedFace.FaceAttributes.Age,
Gender = detectedFace.FaceAttributes.Gender.ToString(),
SmileConfidence = detectedFace.FaceAttributes.Smile * 100,
Glasses = detectedFace.FaceAttributes.Glasses.ToString(),
Blur = GetFaceBlur(detectedFace),
Mask = GetFaceMask(detectedFace),
FacialHair = GetFacialHair(detectedFace),
HeadPose = GetHeadPose(detectedFace),
Emotion = GetEmotion(detectedFace),
Hair = GetHair(detectedFace),
Makeup = GetMakeup(detectedFace),
Occlusion = GetOcclusion(detectedFace),
Accessories = GetFaceAccessories(detectedFace),
Exposure = GetExposure(detectedFace),
Noise = GetNoise(detectedFace)
}).ToList();
}
private HumanFaceBlur GetFaceBlur(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Blur != default)
return new HumanFaceBlur
{
Confidence = detectedFace.FaceAttributes.Blur.Value * 100,
Level = detectedFace.FaceAttributes.Blur.BlurLevel.ToString()
};
return new HumanFaceBlur();
}
private HumanFaceMask GetFaceMask(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Mask != default)
return new HumanFaceMask
{
Type = detectedFace.FaceAttributes.Mask.Type.ToString(),
NoseAndMouthCovered = detectedFace.FaceAttributes.Mask.NoseAndMouthCovered
};
return new HumanFaceMask();
}
private HumanFacialHair GetFacialHair(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.FacialHair != default)
return new HumanFacialHair
{
MoustacheConfidence = detectedFace.FaceAttributes.FacialHair.Moustache * 100,
BeardConfidence = detectedFace.FaceAttributes.FacialHair.Beard * 100,
SideburnsConfidence = detectedFace.FaceAttributes.FacialHair.Sideburns * 100
};
return new HumanFacialHair();
}
private HumanHeadPose GetHeadPose(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.HeadPose != default)
return new HumanHeadPose
{
Roll = detectedFace.FaceAttributes.HeadPose.Roll,
Yaw = detectedFace.FaceAttributes.HeadPose.Yaw,
Pitch = detectedFace.FaceAttributes.HeadPose.Pitch
};
return new HumanHeadPose();
}
private HumanFaceEmotion GetEmotion(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Emotion != default)
return new HumanFaceEmotion
{
AngerConfidence = detectedFace.FaceAttributes.Emotion.Anger * 100,
ContemptConfidence = detectedFace.FaceAttributes.Emotion.Contempt * 100,
DisgustConfidence = detectedFace.FaceAttributes.Emotion.Disgust * 100,
FearConfidence = detectedFace.FaceAttributes.Emotion.Fear * 100,
HappinessConfidence = detectedFace.FaceAttributes.Emotion.Happiness * 100,
NeutralConfidence = detectedFace.FaceAttributes.Emotion.Neutral * 100,
SadnessConfidence = detectedFace.FaceAttributes.Emotion.Sadness * 100,
SurpriseConfidence = detectedFace.FaceAttributes.Emotion.Surprise * 100,
};
return new HumanFaceEmotion();
}
private HumanHair GetHair(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Hair != default)
return new HumanHair
{
BaldConfidence = detectedFace.FaceAttributes.Hair.Bald * 100,
Invisible = detectedFace.FaceAttributes.Hair.Invisible,
Color = GetPossibleHairColors(detectedFace)
};
return new HumanHair();
}
private IEnumerable<HumanHairColor> GetPossibleHairColors(DetectedFace detectedFace)
{
var possibleHairColors = new List<HumanHairColor>();
if (detectedFace.FaceAttributes.Hair != default)
{
possibleHairColors.AddRange(detectedFace.FaceAttributes.Hair.HairColor
.Select(hairColor => new HumanHairColor
{
Confidence = hairColor.Confidence * 100,
Description = hairColor.Color.ToString()
}));
}
return possibleHairColors;
}
private HumanMakeup GetMakeup(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Makeup != default)
return new HumanMakeup
{
EyeMakeup = detectedFace.FaceAttributes.Makeup.EyeMakeup,
LipMakeup = detectedFace.FaceAttributes.Makeup.LipMakeup
};
return new HumanMakeup();
}
private HumanFaceOcclusion GetOcclusion(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Occlusion != default)
return new HumanFaceOcclusion
{
ForeheadOccluded = detectedFace.FaceAttributes.Occlusion.ForeheadOccluded,
EyeOccluded = detectedFace.FaceAttributes.Occlusion.EyeOccluded,
MouthOccluded = detectedFace.FaceAttributes.Occlusion.MouthOccluded
};
return new HumanFaceOcclusion();
}
private IEnumerable<HumanFaceAccessory> GetFaceAccessories(DetectedFace detectedFace)
{
var faceAccessories = detectedFace.FaceAttributes.Accessories;
return faceAccessories.Select(accessory => new HumanFaceAccessory
{
Confidence = accessory.Confidence * 100,
Description = accessory.Type.ToString()
}).ToList();
}
private HumanFaceExposure GetExposure(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Exposure != default)
return new HumanFaceExposure
{
Confidence = detectedFace.FaceAttributes.Exposure.Value * 100,
Level = detectedFace.FaceAttributes.Exposure.ExposureLevel.ToString()
};
return new HumanFaceExposure();
}
private HumanFaceNoise GetNoise(DetectedFace detectedFace)
{
if (detectedFace.FaceAttributes.Noise != default)
return new HumanFaceNoise
{
Confidence = detectedFace.FaceAttributes.Noise.Value * 100,
Level = detectedFace.FaceAttributes.Noise.NoiseLevel.ToString()
};
return new HumanFaceNoise();
}
}
}
\ No newline at end of file
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker.Http;
namespace GAP.FaceDetection.Services
{
public static class HttpExtensions
{
public static async Task<TModel> GetJsonBody<TModel>(this HttpRequestData request)
{
var requestBody = await request.ReadAsStringAsync();
return requestBody != default ?
JsonSerializer.Deserialize<TModel>(requestBody, GetSerializationOptions()) :
default;
}
private static JsonSerializerOptions GetSerializationOptions() =>
new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
ReferenceHandler = ReferenceHandler.Preserve,
PropertyNameCaseInsensitive = true
};
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment