public static Point FindMouseNoseTip(IEnumerable <Point> points, IEnumerable <Point> contourPoints) { List <Point> headPoints = points.ToList(); List <Point> allContourPoints = contourPoints.ToList(); StraightLine vectorPointsLine = new StraightLine(headPoints[1], headPoints[3]); PointF closestPointToNose; double distance = vectorPointsLine.FindDistanceToSegment(headPoints[2], out closestPointToNose); Point closestIntPoint = new Point((int)closestPointToNose.X, (int)closestPointToNose.Y); StraightLine direction = new StraightLine(closestIntPoint, headPoints[2]); float targetExtensionDistance = 3; Point targetLinePoint1 = new Point((int)(vectorPointsLine.StartPoint.X + (direction.NormalizedVector * distance * targetExtensionDistance).X), (int)(vectorPointsLine.StartPoint.Y + (direction.NormalizedVector * distance * targetExtensionDistance).Y)); Point targetLinePoint2 = new Point((int)(vectorPointsLine.EndPoint.X + (direction.NormalizedVector * distance * targetExtensionDistance).X), (int)(vectorPointsLine.EndPoint.Y + (direction.NormalizedVector * distance * targetExtensionDistance).Y)); StraightLine targetLine = new StraightLine(targetLinePoint1, targetLinePoint2); int numberOfTargets = 5; float offset = targetLine.GetMagnitude() / numberOfTargets; float finalDist = 10000; Point nosePoint = new Point(); for (float currentTargetLength = 0; currentTargetLength <= targetLine.GetMagnitude(); currentTargetLength += offset) { Point currentTargetPoint = targetLine.DistanceFromStart(currentTargetLength); foreach (Point point in allContourPoints) { float dist = currentTargetPoint.Distance(point); if (dist < finalDist) { finalDist = dist; nosePoint = point; } } } return(nosePoint); }
public static AutomatedRodentTracker.Services.RBSK.RBSK GetStandardMouseRules() { RBSKRules mouseRules = new RBSKRules(); //Always make sure the number of parameters is correct first mouseRules.AddRule(new RBSKRule((x, s, b) => { if (x.Length != s.NumberOfPoints) { return(false); } return(true); })); //Rules regarding the points layout mouseRules.AddRule(new RBSKRule((x, s, b) => { PointF nosePoint = x[2]; PointF[] vectorPoints = { x[1], x[3] }; PointF[] rearPoints = { x[0], x[4] }; double gapDistance = s.GapDistance; //Calculate target areas double gapDistanceSquared = gapDistance * gapDistance; double targetHeadArea = 0.433f * gapDistanceSquared; //float targetArea = gapDistanceSquared + targetHeadArea; //Check total area //float area = MathExtension.PolygonArea(x); //if (area < targetArea / 1.5) //{ // return false; //} //check head area float headArea = MathExtension.PolygonArea(new[] { vectorPoints[0], nosePoint, vectorPoints[1] }); if (headArea < targetHeadArea / 2) { return(false); } //Check which side the points lie on PointSideVector result = MathExtension.FindSide(vectorPoints[0], vectorPoints[1], nosePoint); if (result == PointSideVector.On) { return(false); } PointSideVector rearResult1 = MathExtension.FindSide(vectorPoints[0], vectorPoints[1], rearPoints[0]); PointSideVector rearResult2 = MathExtension.FindSide(vectorPoints[0], vectorPoints[1], rearPoints[1]); //If the points are on the line then continue if (rearResult1 == PointSideVector.On || rearResult2 == PointSideVector.On) { return(false); } //Make sure the rear points are on the opposite side to the nose point if (!(rearResult1 == rearResult2 && rearResult1 != result)) { return(false); } //Check rear points are correctly aligned with the center line PointF vectorMidPoint = new PointF((vectorPoints[0].X + vectorPoints[1].X) / 2, (vectorPoints[0].Y + vectorPoints[1].Y) / 2); rearResult1 = MathExtension.FindSide(nosePoint, vectorMidPoint, rearPoints[0]); rearResult2 = MathExtension.FindSide(nosePoint, vectorMidPoint, rearPoints[1]); if (rearResult1 == rearResult2) { return(false); } StraightLine centerLine = new StraightLine(nosePoint, vectorMidPoint); PointF targetRearMidPoint = centerLine.DistanceFromEndFloat(-s.GapDistance); centerLine = new StraightLine(nosePoint, targetRearMidPoint); double rearDist1 = centerLine.FindDistanceToSegment(rearPoints[0]); if (rearDist1 < s.GapDistance / 3) { return(false); } rearDist1 = centerLine.FindDistanceToSegment(rearPoints[1]); if (rearDist1 < s.GapDistance / 3) { return(false); } //The points are correctly aligned, make sure it's covering black pixels int blackCounter = 0; int whiteCounter = 0; StraightLine line = new StraightLine(vectorPoints[0], vectorPoints[1]); double distance = line.GetMagnitude(); float increment = (float)distance / 10.0f; for (int j = 1; j < 9; j++) { Point pointToCheck = line.DistanceFromStart(j * increment); if (b[pointToCheck].Intensity <= 120) { blackCounter++; } else { whiteCounter++; } } if (whiteCounter > blackCounter) { return(false); } //Don't want the distance to be too great between the vector points //double distance = vectorPoints[0].Distance(vectorPoints[1]); //double distance = Math.Sqrt((vectorPoints[1].X - vectorPoints[0].X) + (vectorPoints[1].Y - vectorPoints[0].Y)); if (distance > 1.4f * gapDistance) { return(false); } //Rear distance must fall between a certain range double rearDistance = rearPoints[0].Distance(rearPoints[1]); if (rearDistance > 2.5f * gapDistance) { return(false); } if (rearDistance < 1.2 * gapDistance) { return(false); } return(true); })); RBSKRules advancedRules = new RBSKRules(); advancedRules.AddRule(new RBSKRule((x, s, b) => { Point intNosePoint = x[2].ToPoint(); Point intVectorPoint1 = x[1].ToPoint(); Point intVectorPoint2 = x[3].ToPoint(); Image <Gray, Byte> mask = new Image <Gray, byte>(b.Cols, b.Rows, new Gray(0)); mask.FillConvexPoly(new[] { intNosePoint, intVectorPoint1, intVectorPoint2 }, new Gray(255), LineType.FourConnected); double avgIntensity = b.GetAverage(mask).Intensity; if (avgIntensity > 10) { return(false); } return(true); })); //Create probability funcation RBSKProbability rbskProbability = new RBSKProbability((p, s) => { PointF[] points = p; if (points.Length != 5) { return(0); } //float gapDistanceSquared = s.GapDistance*s.GapDistance; StraightLine line = new StraightLine(points[1], points[3]); //Need to normalize the line double targetNoseDistance = 0.866d * s.GapDistance; double actualNoseDistance = line.FindDistanceToSegment(points[2]); double noseProbability; if (targetNoseDistance > actualNoseDistance) { noseProbability = actualNoseDistance / targetNoseDistance; } else { noseProbability = targetNoseDistance / actualNoseDistance; } //float targetHeadArea = 0.433f * gapDistanceSquared; //float targetHeadArea = (float)MathExtension.PolygonArea(new[] //{ // new Point(0, 0), // new Point((int)s.GapDistance, 0), // new Point((int)(s.GapDistance/2), (int)(s.GapDistance*0.866f)), //}); //float actualHeadArea = MathExtension.PolygonArea(new[] //{ // points[1], points[2], points[3] //}); //float areaProbability; //if (targetHeadArea > actualHeadArea) //{ // areaProbability = actualHeadArea / targetHeadArea; //} //else //{ // areaProbability = targetHeadArea / actualHeadArea; //} return(noseProbability);// * areaProbability; }); return(new AutomatedRodentTracker.Services.RBSK.RBSK(mouseRules, advancedRules, new RBSKSettings(5), rbskProbability)); }