private static Mat ExtractFace(Mat img, FaceCorners corners) { double widthA = Math.Sqrt(Math.Pow(corners.BottomRight.X - corners.BottomLeft.X, 2) + Math.Pow(corners.BottomRight.Y - corners.BottomLeft.Y, 2)); double widthB = Math.Sqrt(Math.Pow(corners.TopRight.X - corners.TopLeft.X, 2) + Math.Pow(corners.TopRight.Y - corners.TopLeft.Y, 2)); double maxWidth = Math.Max(widthA, widthB); double heightA = Math.Sqrt(Math.Pow(corners.TopRight.X - corners.BottomRight.X, 2) + Math.Pow(corners.TopRight.Y - corners.BottomRight.Y, 2)); double heightB = Math.Sqrt(Math.Pow(corners.TopLeft.X - corners.BottomLeft.X, 2) + Math.Pow(corners.TopLeft.Y - corners.BottomLeft.Y, 2)); double maxHeight = Math.Max(heightA, heightB); var a = Array.ConvertAll(corners.Points, p => (PointF)p); var perspectiveTransformationMatrix = CvInvoke.GetPerspectiveTransform(new VectorOfPointF(a), new VectorOfPointF(new[] { new PointF(0, 0), new PointF((int)maxWidth - 1, 0), new PointF((int)maxWidth - 1, (int)maxHeight - 1), new PointF(0, (int)maxHeight - 1), })); var warped = new Mat((int)maxWidth, (int)maxHeight, DepthType.Cv32F, 1); CvInvoke.WarpPerspective(img, warped, perspectiveTransformationMatrix, new Size((int)maxWidth, (int)maxHeight)); return(warped); }
private static FaceCorners FindFaceCorners(Mat img, VectorOfKeyPoint trackedFeatures) { var rect = CvInvoke.BoundingRectangle(Utils.GetPointsVector(trackedFeatures)); var edges = new Mat(); CvInvoke.Canny(img, edges, 0.1, 99); var contours = new VectorOfVectorOfPoint(); var hierarchy = new Mat(); var matchedContours = new List <VectorOfPoint>(); CvInvoke.FindContours(edges, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { var approx = new Mat(); CvInvoke.ApproxPolyDP(contours[i], approx, 9, true); var approxMat = new Matrix <double>(approx.Rows, approx.Cols, approx.DataPointer); double a = Math.Abs(CvInvoke.ContourArea(approx)); if (approxMat.Rows == 4 && Math.Abs(CvInvoke.ContourArea(approx)) > 3000 && CvInvoke.IsContourConvex(approx)) { matchedContours.Add(contours[i]); } } var contoursArray = matchedContours.ToArray().SelectMany(c => c.ToArray()).ToArray(); var contour = matchedContours.FirstOrDefault(); var bbox = CvInvoke.BoundingRectangle(contour); int minX = contoursArray.Min(p => p.X); int maxX = contoursArray.Max(p => p.X); if (!(maxX - minX > 2.9 * bbox.Width)) { return(new FaceCorners()); } while (true) { bool sutisfied = contoursArray.All(p => p.X > rect.X && p.Y > rect.Y && p.X < (rect.X + rect.Width) && p.Y < (rect.Y + rect.Height)); if (sutisfied) { break; } if (contoursArray.Any(c => c.X < rect.X)) { rect.X -= 5; } if (contoursArray.Any(c => c.Y < rect.Y)) { rect.Y -= 5; } if (contoursArray.Any(c => c.X > (rect.X + rect.Width))) { rect.Width += 5; } if (contoursArray.Any(c => c.Y > (rect.Y + rect.Height))) { rect.Height += 5; } } var rectPoints = new[] { rect.Location, new PointF(rect.X, rect.Y + rect.Height), new PointF(rect.X + rect.Width, rect.Y), new PointF(rect.X + rect.Width, rect.Y + rect.Height) }; var points2D = Array.ConvertAll(rectPoints, Point.Round); var corners = new FaceCorners(points2D); return(corners); }