/// <summary> /// Returns an enumerable collection of dictionary of face parts locations (eyes, nose, etc) for each face in the image. /// </summary> /// <param name="faceImage">The image contains faces. The image can contain multiple faces.</param> /// <param name="faceLocations">The enumerable collection of location rectangle for faces. If specified null, method will find face locations.</param> /// <param name="model">The model of face detector.</param> /// <returns>An enumerable collection of dictionary of face parts locations (eyes, nose, etc).</returns> /// <exception cref="ArgumentNullException"><paramref name="faceImage"/> is null.</exception> /// <exception cref="ObjectDisposedException"><paramref name="faceImage"/> or this object is disposed.</exception> public IEnumerable <IDictionary <FacePart, IEnumerable <Point> > > FaceLandmark(Image faceImage, IEnumerable <Location> faceLocations = null, PredictorModel model = PredictorModel.Large) { if (faceImage == null) { throw new ArgumentNullException(nameof(faceImage)); } if (faceImage.IsDisposed) { throw new ObjectDisposedException(nameof(faceImage)); } if (this.IsDisposed) { throw new ObjectDisposedException(nameof(FaceEncoding)); } var landmarks = this.RawFaceLandmarks(faceImage, faceLocations, model); var landmarkTuples = landmarks.Select(landmark => Enumerable.Range(0, (int)landmark.Parts) .Select(index => new Point(landmark.GetPart((uint)index))).ToArray()); // For a definition of each point index, see https://cdn-images-1.medium.com/max/1600/1*AbEg31EgkbXSQehuNJBlWg.png switch (model) { case PredictorModel.Large: foreach (var landmarkTuple in landmarkTuples) { yield return new Dictionary <FacePart, IEnumerable <Point> > { { FacePart.Chin, Enumerable.Range(0, 17).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.LeftEyebrow, Enumerable.Range(17, 5).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.RightEyebrow, Enumerable.Range(22, 5).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.NoseBridge, Enumerable.Range(27, 5).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.NoseTip, Enumerable.Range(31, 5).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.LeftEye, Enumerable.Range(36, 6).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.RightEye, Enumerable.Range(42, 6).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.TopLip, Enumerable.Range(48, 7).Select(i => landmarkTuple[i]) .Concat(new [] { landmarkTuple[64] }) .Concat(new [] { landmarkTuple[63] }) .Concat(new [] { landmarkTuple[62] }) .Concat(new [] { landmarkTuple[61] }) .Concat(new [] { landmarkTuple[60] }) }, { FacePart.BottomLip, Enumerable.Range(54, 6).Select(i => landmarkTuple[i]) .Concat(new [] { landmarkTuple[48] }) .Concat(new [] { landmarkTuple[60] }) .Concat(new [] { landmarkTuple[67] }) .Concat(new [] { landmarkTuple[66] }) .Concat(new [] { landmarkTuple[65] }) .Concat(new [] { landmarkTuple[64] }) } } } ; break; case PredictorModel.Small: foreach (var landmarkTuple in landmarkTuples) { yield return new Dictionary <FacePart, IEnumerable <Point> > { { FacePart.NoseTip, Enumerable.Range(4, 1).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.LeftEye, Enumerable.Range(2, 2).Select(i => landmarkTuple[i]).ToArray() }, { FacePart.RightEye, Enumerable.Range(0, 2).Select(i => landmarkTuple[i]).ToArray() } } } ; break; default: throw new ArgumentOutOfRangeException(nameof(model), model, null); } }
private IEnumerable <FullObjectDetection> RawFaceLandmarks(Image img, IEnumerable <Location> faceLocations = null, PredictorModel model = PredictorModel.Large) { var method = this._FaceRecognition.GetType().GetMethod("RawFaceLandmarks", BindingFlags.Instance | BindingFlags.NonPublic); return(method.Invoke(this._FaceRecognition, new object[] { img, faceLocations, model }) as IEnumerable <FullObjectDetection>); }
private IEnumerable <FullObjectDetection> RawFaceLandmarks(Image faceImage, IEnumerable <Location> faceLocations = null, PredictorModel model = PredictorModel.Large) { IEnumerable <MModRect> tmp; if (faceLocations == null) { tmp = this.RawFaceLocations(faceImage); } else { tmp = faceLocations.Select(l => new MModRect { Rect = new Rectangle { Bottom = l.Bottom, Left = l.Left, Top = l.Top, Right = l.Right } }); } var posePredictor = this._PosePredictor68Point; if (model == PredictorModel.Small) { posePredictor = this._PosePredictor5Point; } foreach (var rect in tmp) { yield return(posePredictor.Detect(faceImage.Matrix, rect)); } }
private void FaceLandmark(string testName, PredictorModel model) { const int pointSize = 2; 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 landmarks = this._FaceRecognition.FaceLandmark(image, null, model).ToArray(); Assert.IsTrue(landmarks.Length > 1, $"{mode}"); foreach (var facePart in Enum.GetValues(typeof(FacePart)).Cast <FacePart>()) { using (var bitmap = System.Drawing.Image.FromFile(path)) { var draw = false; using (var g = Graphics.FromImage(bitmap)) foreach (var landmark in landmarks) { if (landmark.ContainsKey(facePart)) { draw = true; foreach (var p in landmark[facePart].ToArray()) { g.DrawEllipse(Pens.GreenYellow, p.X - pointSize, p.Y - pointSize, pointSize * 2, pointSize * 2); } } } if (draw) { var directory = Path.Combine(ResultDirectory, testName); Directory.CreateDirectory(directory); var dst = Path.Combine(directory, $"{facePart}-{mode}.bmp"); bitmap.Save(dst, ImageFormat.Bmp); } } } using (var bitmap = System.Drawing.Image.FromFile(path)) { using (var g = Graphics.FromImage(bitmap)) foreach (var landmark in landmarks) { foreach (var points in landmark.Values) { foreach (var p in points) { g.DrawEllipse(Pens.GreenYellow, p.X - pointSize, p.Y - pointSize, pointSize * 2, pointSize * 2); } } } var directory = Path.Combine(ResultDirectory, testName); Directory.CreateDirectory(directory); var dst = Path.Combine(directory, $"All-{mode}.bmp"); bitmap.Save(dst, ImageFormat.Bmp); } } } }