Skip to content

Commit

Permalink
feet: add FaceRecognition.CropFaces and Image.Save method
Browse files Browse the repository at this point in the history
  • Loading branch information
takuya-takeuchi committed Mar 8, 2020
1 parent 146121a commit 9765e23
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 3 deletions.
1 change: 1 addition & 0 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 Down
47 changes: 47 additions & 0 deletions src/FaceRecognitionDotNet/FaceRecognition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,53 @@ public static FaceRecognition Create(string directory)
return new FaceRecognition(directory);
}

/// <summary>
/// Crop a specified image with enumerable collection of face locations.
/// </summary>
/// <param name="image">The image contains a face.</param>
/// <param name="locations">The enumerable collection of location rectangle for faces.</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"><paramref name="image"/> or <paramref name="locations"/> is null.</exception>
/// <exception cref="ObjectDisposedException"><paramref name="image"/> is disposed.</exception>
public static IEnumerable<Image> CropFaces(Image image, IEnumerable<Location> locations)
{
if (image == null)
throw new ArgumentNullException(nameof(image));
if (locations == null)
throw new ArgumentNullException(nameof(locations));

image.ThrowIfDisposed();

foreach (var location in locations)
{
var rect = new Rectangle(location.Left, location.Top, location.Right, location.Bottom);
var dPoint = new[]
{
new DPoint(rect.Left, rect.Top),
new DPoint(rect.Right, rect.Top),
new DPoint(rect.Left, rect.Bottom),
new DPoint(rect.Right, rect.Bottom),
};

var width = (int)rect.Width;
var height = (int)rect.Height;

switch (image.Mode)
{
case Mode.Rgb:
var rgb = image.Matrix as Matrix<RgbPixel>;
yield return new Image(DlibDotNet.Dlib.ExtractImage4Points(rgb, dPoint, width, height),
Mode.Rgb);
break;
case Mode.Greyscale:
var gray = image.Matrix as Matrix<byte>;
yield return new Image(DlibDotNet.Dlib.ExtractImage4Points(gray, dPoint, width, height),
Mode.Rgb);
break;
}
}
}

/// <summary>
/// Compare a face encoding to a known face encoding and get a euclidean distance for comparison face.
/// </summary>
Expand Down
30 changes: 30 additions & 0 deletions src/FaceRecognitionDotNet/Image.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using DlibDotNet;

namespace FaceRecognitionDotNet
Expand Down Expand Up @@ -62,6 +63,35 @@ public int Width

#region Methods

/// <summary>
/// Saves this <see cref="Image"/> to the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file to which to save this <see cref="Image"/>.</param>
/// <param name="format">The <see cref="ImageFormat"/> for this <see cref="Image"/>.</param>
/// <exception cref="ArgumentNullException"><paramref name="filename"/> is null.</exception>
public void Save(string filename, ImageFormat format)
{
if (filename == null)
throw new ArgumentNullException(nameof(filename));

var directory = Path.GetDirectoryName(filename);
if (!Directory.Exists(directory) && !string.IsNullOrWhiteSpace(directory))
Directory.CreateDirectory(directory);

switch (format)
{
case ImageFormat.Bmp:
DlibDotNet.Dlib.SaveBmp(this._Matrix, filename);
break;
case ImageFormat.Jpeg:
DlibDotNet.Dlib.SaveJpeg(this._Matrix, filename);
break;
case ImageFormat.Png:
DlibDotNet.Dlib.SavePng(this._Matrix, filename);
break;
}
}

#region Overrides

/// <summary>
Expand Down
27 changes: 27 additions & 0 deletions src/FaceRecognitionDotNet/ImageFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace FaceRecognitionDotNet
{

/// <summary>
/// Specifies the file format of the image.
/// </summary>
public enum ImageFormat
{

/// <summary>
/// Specifies that the bitmap (BMP) image format.
/// </summary>
Bmp,

/// <summary>
/// Specifies that the Joint Photographic Experts Group (JPEG) image format.
/// </summary>
Jpeg,

/// <summary>
/// Specifies that the W3C Portable Network Graphics (PNG) image format.
/// </summary>
Png,

}

}
38 changes: 38 additions & 0 deletions src/FaceRecognitionDotNet/docs/FaceRecognitionDotNet.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions src/FaceRecognitionDotNet/docs/ja/FaceRecognitionDotNet.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 41 additions & 3 deletions test/FaceRecognitionDotNet.Tests/FaceRecognitionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,44 @@ public void CompareFacesTrue()
Assert.True(false, "Assert check did not execute");
}

[Fact]
public void CropFaces()
{
const string testName = nameof(this.CropFaces);

var path = Path.Combine(ImageDirectory, TwoPersonFile);
if (!File.Exists(path))
{
var binary = new HttpClient().GetByteArrayAsync($"{TwoPersonUrl}/{TwoPersonFile}").Result;

Directory.CreateDirectory(ImageDirectory);
File.WriteAllBytes(path, binary);
}

foreach (var mode in new[] { Mode.Rgb, Mode.Greyscale })
{
using (var image = FaceRecognition.LoadImageFile(path, mode))
{
var locations = this._FaceRecognition.FaceLocations(image).ToArray();
Assert.True(locations.Length == 2, $"{mode}");

var images = FaceRecognition.CropFaces(image, locations).ToArray();
for (var index = 1; index <= images.Length; index++)
{
var croppedImage = images[index - 1];

var directory = Path.Combine(ResultDirectory, testName);
Directory.CreateDirectory(directory);

var dst = Path.Combine(directory, $"{mode}-{index}.jpg");
croppedImage.Save(dst, ImageFormat.Jpeg);

croppedImage.Dispose();
}
}
}
}

[Fact]
public void CreateFail1()
{
Expand Down Expand Up @@ -1734,7 +1772,7 @@ private void FaceLandmark(string testName, PredictorModel model, bool useKnownLo
Directory.CreateDirectory(directory);

var dst = Path.Combine(directory, $"{facePart}-{mode}-known_{useKnownLocation}.bmp");
bitmap.Save(dst, ImageFormat.Bmp);
bitmap.Save(dst, System.Drawing.Imaging.ImageFormat.Bmp);
}
}

Expand All @@ -1752,7 +1790,7 @@ private void FaceLandmark(string testName, PredictorModel model, bool useKnownLo
Directory.CreateDirectory(directory);

var dst = Path.Combine(directory, $"All-{mode}-known_{useKnownLocation}.bmp");
bitmap.Save(dst, ImageFormat.Bmp);
bitmap.Save(dst, System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
Expand Down Expand Up @@ -1786,7 +1824,7 @@ private void FaceLocation(string testName, int numberOfTimesToUpsample, Model mo
Directory.CreateDirectory(directory);

var dst = Path.Combine(directory, $"All-{mode}-{numberOfTimesToUpsample}.bmp");
bitmap.Save(dst, ImageFormat.Bmp);
bitmap.Save(dst, System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
Expand Down
43 changes: 43 additions & 0 deletions test/FaceRecognitionDotNet.Tests/ImageText.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.IO;
using Xunit;

namespace FaceRecognitionDotNet.Tests
{

public class ImageTest
{

#region Fields

private const string ResultDirectory = "Result";

#endregion

[Fact]
public void Save()
{
const string testName = nameof(this.Save);

var targets = new[]
{
new { Name = "saved.bmp", Format = ImageFormat.Bmp },
new { Name = "saved.jpg", Format = ImageFormat.Jpeg },
new { Name = "saved.png", Format = ImageFormat.Png },
};

using (var img = FaceRecognition.LoadImageFile(Path.Combine("TestImages", "obama.jpg")))
{
var directory = Path.Combine(ResultDirectory, testName);
Directory.CreateDirectory(directory);

foreach (var target in targets)
{
var path = Path.Combine(directory, target.Name);
img.Save(path, target.Format);
}
}
}

}

}
1 change: 1 addition & 0 deletions tools/HelenTraining/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using DlibDotNet;
using FaceRecognitionDotNet;
using Microsoft.Extensions.CommandLineUtils;
using ImageFormat = System.Drawing.Imaging.ImageFormat;
using Point = DlibDotNet.Point;

namespace HelenTraining
Expand Down

0 comments on commit 9765e23

Please sign in to comment.