Skip to content

Commit

Permalink
Merge branch 'release/1.3.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
takuya-takeuchi committed Mar 8, 2020
2 parents c49143a + e4ee126 commit 5230393
Show file tree
Hide file tree
Showing 59 changed files with 1,611 additions and 386 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "src/DlibDotNet"]
path = src/DlibDotNet
url = https://github.com/takuya-takeuchi/DlibDotNet
url = https://github.com/takuya-takeuchi/DlibDotNet
44 changes: 23 additions & 21 deletions FaceRecognitionDotNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FaceDetection", "examples\F
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenCVSharpSample", "examples\OpenCVSharpSample\OpenCVSharpSample.csproj", "{3F6F21E5-DEF8-4F1A-BE8F-741A35B528D1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelenTraining", "examples\HelenTraining\HelenTraining.csproj", "{FCCD585F-1D3E-4AFB-9644-DAEC7B8CA6C4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FindFacesInBatches", "examples\FindFacesInBatches\FindFacesInBatches.csproj", "{5F7CB2DF-54E3-461F-9FA9-F8B4BAFC54AC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenderTraining", "examples\GenderTraining\GenderTraining.csproj", "{EAB3D0C4-D2E0-4F6A-A663-041B5584FF1F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgeTraining", "examples\AgeTraining\AgeTraining.csproj", "{8595BAC7-7EEC-49E6-9D78-01AFB15A30FD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FaceRecognitionDotNet.Tests", "test\FaceRecognitionDotNet.Tests\FaceRecognitionDotNet.Tests.csproj", "{28A36B74-6D83-47B4-9AD6-A252902DBC99}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomClassificationDemo", "examples\CustomClassificationDemo\CustomClassificationDemo.csproj", "{F4092804-340D-4553-B9E5-7C6555D317B7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{8C8838E0-B002-426F-9B25-4C1F65A6D33D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgeTraining", "tools\AgeTraining\AgeTraining.csproj", "{AF7429BE-0747-4E9A-AB2F-17480A8D485E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenderTraining", "tools\GenderTraining\GenderTraining.csproj", "{44781AB4-D08C-4FDA-92EF-55C7CE9D5A18}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelenTraining", "tools\HelenTraining\HelenTraining.csproj", "{86A8F7D7-E3D6-4478-856E-B0FA91F5ABFA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -63,22 +65,10 @@ Global
{3F6F21E5-DEF8-4F1A-BE8F-741A35B528D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F6F21E5-DEF8-4F1A-BE8F-741A35B528D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F6F21E5-DEF8-4F1A-BE8F-741A35B528D1}.Release|Any CPU.Build.0 = Release|Any CPU
{FCCD585F-1D3E-4AFB-9644-DAEC7B8CA6C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FCCD585F-1D3E-4AFB-9644-DAEC7B8CA6C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FCCD585F-1D3E-4AFB-9644-DAEC7B8CA6C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FCCD585F-1D3E-4AFB-9644-DAEC7B8CA6C4}.Release|Any CPU.Build.0 = Release|Any CPU
{5F7CB2DF-54E3-461F-9FA9-F8B4BAFC54AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F7CB2DF-54E3-461F-9FA9-F8B4BAFC54AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F7CB2DF-54E3-461F-9FA9-F8B4BAFC54AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F7CB2DF-54E3-461F-9FA9-F8B4BAFC54AC}.Release|Any CPU.Build.0 = Release|Any CPU
{EAB3D0C4-D2E0-4F6A-A663-041B5584FF1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EAB3D0C4-D2E0-4F6A-A663-041B5584FF1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAB3D0C4-D2E0-4F6A-A663-041B5584FF1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAB3D0C4-D2E0-4F6A-A663-041B5584FF1F}.Release|Any CPU.Build.0 = Release|Any CPU
{8595BAC7-7EEC-49E6-9D78-01AFB15A30FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8595BAC7-7EEC-49E6-9D78-01AFB15A30FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8595BAC7-7EEC-49E6-9D78-01AFB15A30FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8595BAC7-7EEC-49E6-9D78-01AFB15A30FD}.Release|Any CPU.Build.0 = Release|Any CPU
{28A36B74-6D83-47B4-9AD6-A252902DBC99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28A36B74-6D83-47B4-9AD6-A252902DBC99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28A36B74-6D83-47B4-9AD6-A252902DBC99}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -87,6 +77,18 @@ Global
{F4092804-340D-4553-B9E5-7C6555D317B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4092804-340D-4553-B9E5-7C6555D317B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4092804-340D-4553-B9E5-7C6555D317B7}.Release|Any CPU.Build.0 = Release|Any CPU
{AF7429BE-0747-4E9A-AB2F-17480A8D485E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF7429BE-0747-4E9A-AB2F-17480A8D485E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF7429BE-0747-4E9A-AB2F-17480A8D485E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF7429BE-0747-4E9A-AB2F-17480A8D485E}.Release|Any CPU.Build.0 = Release|Any CPU
{44781AB4-D08C-4FDA-92EF-55C7CE9D5A18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44781AB4-D08C-4FDA-92EF-55C7CE9D5A18}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44781AB4-D08C-4FDA-92EF-55C7CE9D5A18}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44781AB4-D08C-4FDA-92EF-55C7CE9D5A18}.Release|Any CPU.Build.0 = Release|Any CPU
{86A8F7D7-E3D6-4478-856E-B0FA91F5ABFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86A8F7D7-E3D6-4478-856E-B0FA91F5ABFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86A8F7D7-E3D6-4478-856E-B0FA91F5ABFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86A8F7D7-E3D6-4478-856E-B0FA91F5ABFA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -98,12 +100,12 @@ Global
{32599FBF-8E91-43BA-B0B6-38E3C7A02530} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{49ED9EF1-7E3E-4959-B152-52545B973906} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{3F6F21E5-DEF8-4F1A-BE8F-741A35B528D1} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{FCCD585F-1D3E-4AFB-9644-DAEC7B8CA6C4} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{5F7CB2DF-54E3-461F-9FA9-F8B4BAFC54AC} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{EAB3D0C4-D2E0-4F6A-A663-041B5584FF1F} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{8595BAC7-7EEC-49E6-9D78-01AFB15A30FD} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{28A36B74-6D83-47B4-9AD6-A252902DBC99} = {501D0145-416F-42A7-B636-02A4F783C97C}
{F4092804-340D-4553-B9E5-7C6555D317B7} = {FEEAC07F-70D7-4C12-B92C-153CEE0F2539}
{AF7429BE-0747-4E9A-AB2F-17480A8D485E} = {8C8838E0-B002-426F-9B25-4C1F65A6D33D}
{44781AB4-D08C-4FDA-92EF-55C7CE9D5A18} = {8C8838E0-B002-426F-9B25-4C1F65A6D33D}
{86A8F7D7-E3D6-4478-856E-B0FA91F5ABFA} = {8C8838E0-B002-426F-9B25-4C1F65A6D33D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4D44C572-D749-4A76-A199-8C598A08AE8A}
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ This package supports cross platform, Windows, Linux and MacOSX!!
|face_landmarks|FaceLandmarks|And support **Helen dataset** :warning:|
|face_locations|FaceLocations||
|load_image_file|LoadImageFile||
|-|CropFaces|Crop image with specified locations|
|-|LoadImage|From memory data|
|-|PredictAge|Use **Adience Benchmark Of Unfiltered Faces For Gender And Age Classification dataset** :warning:|
|-|PredictGender|Use **UTKFace dataset** :warning:|
Expand All @@ -51,9 +52,9 @@ You must train dataset by yourself.
I will **NOT** provide pretrained model file due to avoiding license issue.
You can check the following examples to train dataset.

* examples/AgeTraining
* examples/GenderTraining
* examples/HelenTraining
* tools/AgeTraining
* tools/GenderTraining
* tools/HelenTraining

## Demo

Expand Down
40 changes: 20 additions & 20 deletions examples/CustomClassificationDemo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Drawing;
using System.IO;
using System.Linq;
using FaceRecognitionDotNet;
using FaceRecognitionDotNet.Extensions;

namespace CustomClassificationDemo
{
Expand All @@ -21,29 +23,27 @@ private static void Main()
{
var box = fr.FaceLocations(image, model: Model.Cnn).FirstOrDefault();

using (var p = new Pen(Color.Red, bitmap.Width / 200f))
using (var p = new Pen(Color.Red, bitmap.Width / 200f))
g.DrawRectangle(p, box.Left, box.Top, box.Right - box.Left, box.Bottom - box.Top);

var ageRange = new[]
// load custom estimator
using (var ageEstimator = new SimpleAgeEstimator(Path.Combine("models", "adience-age-network.dat")))
using (var genderEstimator = new SimpleGenderEstimator(Path.Combine("models", "utkface-gender-network.dat")))
{
"(0, 2)",
"(4, 6)",
"(8, 13)",
"(15, 20)",
"(25, 32)",
"(38, 43)",
"(48, 53)",
"(60, 100)"
};
var age = ageRange[fr.PredictAge(image, box)];
var gender = fr.PredictGender(image, box);

var agePos = new PointF(box.Left + 10, box.Top + 10);
var genderPos = new PointF(box.Left + 10, box.Bottom - 50);
g.DrawString(gender.ToString(), SystemFonts.CaptionFont, Brushes.Blue, agePos );
g.DrawString(age, SystemFonts.CaptionFont, Brushes.Green, genderPos);

bitmap.Save("result.png");
fr.CustomAgeEstimator = ageEstimator;
fr.CustomGenderEstimator = genderEstimator;

var ageRange = ageEstimator.Groups.Select(range => $"({range.Start}, {range.End})").ToArray();
var age = ageRange[fr.PredictAge(image, box)];
var gender = fr.PredictGender(image, box);

var agePos = new PointF(box.Left + 10, box.Top + 10);
var genderPos = new PointF(box.Left + 10, box.Bottom - 50);
g.DrawString(gender.ToString(), SystemFonts.CaptionFont, Brushes.Blue, agePos);
g.DrawString(age, SystemFonts.CaptionFont, Brushes.Green, genderPos);

bitmap.Save("result.png");
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion nuget/nuspec/FaceRecognitionDotNet.ARM.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>FaceRecognitionDotNet.ARM</id>
<version>1.2.3.14</version>
<version>1.3.0.0</version>
<title>FaceRecognitionDotNet (for ARM)</title>
<authors>Takuya Takeuchi</authors>
<owners>Takuya Takeuchi</owners>
Expand Down
2 changes: 1 addition & 1 deletion nuget/nuspec/FaceRecognitionDotNet.CPU.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>FaceRecognitionDotNet</id>
<version>1.2.3.14</version>
<version>1.3.0.0</version>
<title>FaceRecognitionDotNet</title>
<authors>Takuya Takeuchi</authors>
<owners>Takuya Takeuchi</owners>
Expand Down
2 changes: 1 addition & 1 deletion nuget/nuspec/FaceRecognitionDotNet.CUDA100.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>FaceRecognitionDotNet.CUDA100</id>
<version>1.2.3.14</version>
<version>1.3.0.0</version>
<title>FaceRecognitionDotNet for CUDA 10.0</title>
<authors>Takuya Takeuchi</authors>
<owners>Takuya Takeuchi</owners>
Expand Down
2 changes: 1 addition & 1 deletion nuget/nuspec/FaceRecognitionDotNet.CUDA101.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>FaceRecognitionDotNet.CUDA101</id>
<version>1.2.3.14</version>
<version>1.3.0.0</version>
<title>FaceRecognitionDotNet for CUDA 10.1</title>
<authors>Takuya Takeuchi</authors>
<owners>Takuya Takeuchi</owners>
Expand Down
2 changes: 1 addition & 1 deletion nuget/nuspec/FaceRecognitionDotNet.CUDA92.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>FaceRecognitionDotNet.CUDA92</id>
<version>1.2.3.14</version>
<version>1.3.0.0</version>
<title>FaceRecognitionDotNet for CUDA 9.2</title>
<authors>Takuya Takeuchi</authors>
<owners>Takuya Takeuchi</owners>
Expand Down
2 changes: 1 addition & 1 deletion nuget/nuspec/FaceRecognitionDotNet.MKL.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>FaceRecognitionDotNet.MKL</id>
<version>1.2.3.14</version>
<version>1.3.0.0</version>
<title>FaceRecognitionDotNet for MKL</title>
<authors>Takuya Takeuchi</authors>
<owners>Takuya Takeuchi</owners>
Expand Down
57 changes: 57 additions & 0 deletions src/FaceRecognitionDotNet/Extensions/AgeEstimator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Collections.Generic;
using DlibDotNet;

namespace FaceRecognitionDotNet.Extensions
{

/// <summary>
/// An abstract base class that provides functionality to estimate human age from face image.
/// </summary>
public abstract class AgeEstimator : DisposableObject
{

#region Properties

/// <summary>
/// Gets the collection of age group this estimator returns in derived classes.
/// </summary>
public abstract AgeRange[] Groups
{
get;
}

#endregion

#region Methods

internal uint Predict(Image image, Location location)
{
return this.RawPredict(image.Matrix, location);
}

internal IDictionary<uint, float> PredictProbability(Image image, Location location)
{
return this.RawPredictProbability(image.Matrix, location);
}

/// <summary>
/// Returns an index of age group of face image correspond to specified location in specified image.
/// </summary>
/// <param name="matrix">The matrix contains a face.</param>
/// <param name="location">The location rectangle for a face.</param>
/// <returns>An index of age group of face image correspond to specified location in specified image.</returns>
public abstract uint RawPredict(MatrixBase matrix, Location location);

/// <summary>
/// Returns probabilities of age group of face image correspond to specified location in specified image.
/// </summary>
/// <param name="matrix">The matrix contains a face.</param>
/// <param name="location">The location rectangle for a face.</param>
/// <returns>Probabilities of age group of face image correspond to specified location in specified image.</returns>
public abstract IDictionary<uint, float> RawPredictProbability(MatrixBase matrix, Location location);

#endregion

}

}
47 changes: 47 additions & 0 deletions src/FaceRecognitionDotNet/Extensions/AgeRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace FaceRecognitionDotNet.Extensions
{

/// <summary>
/// Represents a range that has start and end age.
/// </summary>
public struct AgeRange
{

#region Constructors

/// <summary>
/// Instantiates a new <see cref="AgeRange"/> instance with the specified starting and ending ages.
/// </summary>
/// <param name="start">The inclusive age index of the range.</param>
/// <param name="end">The exclusive end age of the range.</param>
public AgeRange(int start, int end)
{
this.Start = start;
this.End = end;
}

#endregion

#region Properties

/// <summary>
/// Gets an age that represents the exclusive end of the range.
/// </summary>
public int End
{
get;
}

/// <summary>
/// Gets the inclusive start of the <see cref="T:FaceRecognitionDotNet.Extensions.AgeRange"/>.
/// </summary>
public int Start
{
get;
}

#endregion

}

}
44 changes: 44 additions & 0 deletions src/FaceRecognitionDotNet/Extensions/FaceLandmarkDetector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Collections.Generic;
using DlibDotNet;

namespace FaceRecognitionDotNet.Extensions
{

/// <summary>
/// An abstract base class that provides functionality to detect face parts locations from face image.
/// </summary>
public abstract class FaceLandmarkDetector : DisposableObject
{

#region Methods

internal FullObjectDetection Detect(Image image, Location location)
{
return this.RawDetect(image.Matrix, location);
}

internal IEnumerable<Dictionary<FacePart, IEnumerable<Point>>> GetLandmarks(IEnumerable<Point[]> landmarkTuples)
{
return this.RawGetLandmarks(landmarkTuples);
}

/// <summary>
/// Returns an object contains information of face parts corresponds to specified location in specified image.
/// </summary>
/// <param name="matrix">The matrix contains a face.</param>
/// <param name="location">The location rectangle for a face.</param>
/// <returns>An object contains information of face parts.</returns>
protected abstract FullObjectDetection RawDetect(MatrixBase matrix, Location location);

/// <summary>
/// Returns an enumerable collection of dictionary of face parts locations (eyes, nose, etc).
/// </summary>
/// <param name="landmarkTuples">The enumerable collection of face parts location.</param>
/// <returns>An enumerable collection of dictionary of face parts locations (eyes, nose, etc).</returns>
protected abstract IEnumerable<Dictionary<FacePart, IEnumerable<Point>>> RawGetLandmarks(IEnumerable<Point[]> landmarkTuples);

#endregion

}

}
Loading

0 comments on commit 5230393

Please sign in to comment.