public IMaskHolder GetMasks(Point[] body, PointF headPoint, PointF leftPoint, PointF rightPoint, Size maxSize, double headDistanceThreshold, double[] distances, double[] lineDistances, Image <Bgr, byte> debugImg) { IMaskHolder maskHolder = ModelResolver.Resolve <IMaskHolder>(); PointF com = leftPoint.MidPoint(rightPoint); Vector forwardVec = new Vector(headPoint.X - com.X, headPoint.Y - com.Y); Vector leftVec = new Vector(forwardVec.Y, -forwardVec.X); Vector rightVec = new Vector(-forwardVec.Y, forwardVec.X); leftVec.Normalize(); rightVec.Normalize(); List <Point> leftPoints = new List <Point>(), rightPoints = new List <Point>(); double headValue = MathExtension.GetSide(leftPoint, rightPoint, headPoint); foreach (Point point in body) { //Find if value is on same side as nose double pointSide = MathExtension.GetSide(leftPoint, rightPoint, point); if ((headValue < 0 && pointSide > 0) || (headValue > 0 && pointSide < 0)) { continue; } //Make sure value is far enough from nose tip //if (point.Distance(headPoint) < headDistanceThreshold) //{ // continue; //} //Find if value is on left or right double d = MathExtension.GetSide(com, headPoint, point); if (d > 0) { leftPoints.Add(point); } else { rightPoints.Add(point); } } maskHolder.LeftPoints = new List <Point[]>(); maskHolder.RightPoints = new List <Point[]>(); maskHolder.LeftPoints.Add(leftPoints.ToArray()); maskHolder.RightPoints.Add(rightPoints.ToArray()); if (leftPoints.Count == 0 || rightPoints.Count == 0) { return(null); } ImageViewer.Show(debugImg); //Order them by closest to headPoint Point[] orderedLeftPoints = OrderPointsByBiggestGap(leftPoints, headPoint.ToPoint()); Point[] orderedRightPoints = OrderPointsByBiggestGap(rightPoints, headPoint.ToPoint()); debugImg.DrawPolyline(orderedRightPoints, false, new Bgr(Color.Red)); debugImg.DrawPolyline(orderedLeftPoints, false, new Bgr(Color.Red)); debugImg.Draw(new LineSegment2DF(com, headPoint), new Bgr(Color.Yellow), 2); ImageViewer.Show(debugImg); //We now have a list of the points that need to go left and points that need to go right for (int i = 1; i < distances.Length; i++) { double d1 = distances[i - 1]; double d2 = distances[i]; Point[] extendedLeftPoints1 = ExtendPointsOutwards(orderedLeftPoints, leftVec, d1, 0, 0, maxSize.Width, maxSize.Height).Where(x => x.Distance(headPoint) >= headDistanceThreshold).ToArray(); Point[] extendedLeftPoints2 = ExtendPointsOutwards(orderedLeftPoints, leftVec, d2, 0, 0, maxSize.Width, maxSize.Height).Where(x => x.Distance(headPoint) >= headDistanceThreshold).ToArray(); Point[] extendedRightPoints1 = ExtendPointsOutwards(orderedRightPoints, rightVec, d1, 0, 0, maxSize.Width, maxSize.Height).Where(x => x.Distance(headPoint) >= headDistanceThreshold).ToArray(); Point[] extendedRightPoints2 = ExtendPointsOutwards(orderedRightPoints, rightVec, d2, 0, 0, maxSize.Width, maxSize.Height).Where(x => x.Distance(headPoint) >= headDistanceThreshold).ToArray(); debugImg.DrawPolyline(extendedRightPoints1, false, new Bgr(Color.Yellow)); debugImg.DrawPolyline(extendedRightPoints2, false, new Bgr(Color.Red)); debugImg.DrawPolyline(extendedLeftPoints1, false, new Bgr(Color.Yellow)); debugImg.DrawPolyline(extendedLeftPoints2, false, new Bgr(Color.Red)); ImageViewer.Show(debugImg); //Generate curved portions double startAngle = Math.Atan2(leftVec.Y, leftVec.X); Point[] ePoints = GetCircularSegmentPoints(startAngle, Math.PI / 2, d1, 180, headPoint.ToPoint()).Reverse().ToArray(); extendedLeftPoints1 = extendedLeftPoints1.Concat(ePoints.Reverse()).ToArray(); ePoints = GetCircularSegmentPoints(startAngle, Math.PI / 2, d2, 180, headPoint.ToPoint()).Reverse().ToArray(); extendedLeftPoints2 = extendedLeftPoints2.Concat(ePoints.Reverse()).ToArray(); startAngle = Math.Atan2(rightVec.Y, rightVec.X); ePoints = GetCircularSegmentPoints(startAngle, -Math.PI / 2, d1, 180, headPoint.ToPoint()).Reverse().ToArray(); extendedRightPoints1 = extendedRightPoints1.Concat(ePoints.Reverse()).ToArray(); ePoints = GetCircularSegmentPoints(startAngle, -Math.PI / 2, d2, 180, headPoint.ToPoint()).Reverse().ToArray(); extendedRightPoints2 = extendedRightPoints2.Concat(ePoints.Reverse()).ToArray(); //Reverse the second set of points Point[] leftMask = extendedLeftPoints1.Concat(extendedLeftPoints2.Reverse()).ToArray(); Point[] rightMask = extendedRightPoints1.Concat(extendedRightPoints2.Reverse()).ToArray(); double lower = d1 < d2 ? d1 : d2; double upper = d1 < d2 ? d2 : d1; maskHolder.AddMask(leftMask, rightMask, lower, upper); } //Generate lines for (int i = 0; i < lineDistances.Length; i++) { double dist = lineDistances[i]; Point[] extendedLeftPoints1 = ExtendPointsOutwards(orderedLeftPoints, leftVec, dist, 0, 0, maxSize.Width, maxSize.Height); Point[] extendedRightPoints1 = ExtendPointsOutwards(orderedRightPoints, rightVec, dist, 0, 0, maxSize.Width, maxSize.Height); maskHolder.LeftPoints.Add(extendedLeftPoints1); maskHolder.RightPoints.Add(extendedRightPoints1); //Generate curved portions double startAngle = Math.Atan2(leftVec.Y, leftVec.X); Point[] ePoints = GetCircularSegmentPoints(startAngle, Math.PI / 2, dist, 180, headPoint.ToPoint()).Reverse().ToArray(); //maskHolder.LeftPoints.Add(ePoints); extendedLeftPoints1 = extendedLeftPoints1.Concat(ePoints.Reverse()).ToArray(); startAngle = Math.Atan2(rightVec.Y, rightVec.X); ePoints = GetCircularSegmentPoints(startAngle, -Math.PI / 2, dist, 180, headPoint.ToPoint()).Reverse().ToArray(); //maskHolder.RightPoints.Add(ePoints); extendedRightPoints1 = extendedRightPoints1.Concat(ePoints.Reverse()).ToArray(); maskHolder.AddLine(extendedLeftPoints1, extendedRightPoints1, dist); } return(maskHolder); }