public double ReadValue(IndicatorData data, DebugState debugState) { if (TryFindCircleInFullFrame(data, out var circle)) { var focus = data.Frame.Copy(Math2.CropCircle(circle, 10)); debugState.Add(focus); List <double> ret = new List <double>(); foreach (var line in GetLinesFromFocusImage(focus, circle, debugState)) { CvInvoke.Line(focus, line.P1, line.P2, new Bgr(Color.Yellow).MCvScalar, 2); var knots = ReadKnotsFromNeedleLine(line); if (IsValueInExpectedRange(knots)) { ret.Add(knots); } } return(CalculateResultFromAllResults(ret, debugState)); } else { debugState.SetError("No circles"); } return(double.NaN); }
public double ReadValue(IndicatorData data, DebugState debugState) { if (TryFindRollCircleInFullFrame(data, out CircleF rollIndicatorCicle)) { var FocusRect = Math2.CropCircle(rollIndicatorCicle, 10); var focus = data.Frame.SafeCopy(FocusRect); debugState.Add(focus); // Isolate the outside ring Mat maskInnerAlt = new Mat(focus.Size, DepthType.Cv8U, 3); maskInnerAlt.SetTo(new MCvScalar(1)); CvInvoke.Circle(maskInnerAlt, new Point(focus.Size.Width / 2, focus.Size.Height / 2), (int)(rollIndicatorCicle.Radius - (rollIndicatorCicle.Radius * 0.2)), new Bgr(Color.White).MCvScalar, -1); CvInvoke.Circle(maskInnerAlt, new Point(focus.Size.Width / 2, focus.Size.Height / 2), (int)(rollIndicatorCicle.Radius - (rollIndicatorCicle.Radius * 0.275)), new Bgr(Color.Black).MCvScalar, -1); var outerMovingRingOnly = focus.Copy(maskInnerAlt.ToImage <Gray, byte>()); var outerMovingRingWithoutBottom = outerMovingRingOnly.Copy(new Rectangle(0, 0, outerMovingRingOnly.Width, (int)(outerMovingRingOnly.Height))); // - (outerMovingRingOnly.Height * 0.29) var ring_hsv_unfiltered = outerMovingRingWithoutBottom.Convert <Hsv, byte>().InRange(new Hsv(20, 0, 85), new Hsv(180, 255, 255)); var ring_hsv = Utils.RemoveBlobs(ring_hsv_unfiltered, 1, 500); debugState.Add(outerMovingRingOnly); debugState.Add(outerMovingRingWithoutBottom); debugState.Add(ring_hsv); debugState.Add(ring_hsv_unfiltered); return(ReadRollAngleFromRingImage(ring_hsv, focus, debugState)); } else { debugState.SetError($"ROLL: Main circles"); } return(double.NaN); }
public double ReadValue(IndicatorData data, DebugState debugState) { if (TryFindCircleInFullFrame(data, out var circle)) { var focus = data.Frame.SafeCopy(Math2.CropCircle(circle, 15)); var vs_blackimg = focus.Convert <Hsv, byte>().DynLowInRange(dyn_lower, new Hsv(180, 255, 255)); debugState.Add(focus); debugState.Add(vs_blackimg); int margin = 10; var vspeedMask = new Mat(focus.Size, DepthType.Cv8U, 3); vspeedMask.SetTo(new MCvScalar(1)); CvInvoke.Circle(vspeedMask, Point.Round(new PointF(circle.Radius + margin, circle.Radius + margin)), (int)(circle.Radius - (circle.Radius * 0.1)), new Bgr(Color.White).MCvScalar, -1); vs_blackimg = vs_blackimg.Copy(vspeedMask.ToImage <Gray, byte>()); var vspeed_inner_only = vs_blackimg.Copy(new Rectangle(0, 0, vs_blackimg.Width / 2, vs_blackimg.Height)); debugState.Add(vspeed_inner_only); Rectangle center = GetCenterBoxFromImage(focus); foreach (var line in CvInvoke.HoughLinesP(vspeed_inner_only, 1, Math.PI / 45.0, 20, 20, 14)) { if (center.Contains(line.P1) || center.Contains(line.P2)) { CvInvoke.Line(focus, line.P1, line.P2, new Bgr(Color.Yellow).MCvScalar, 2); LineSegment2D needleLine; if (center.Contains(line.P1)) { needleLine = new LineSegment2D(line.P2, line.P1); } else { needleLine = new LineSegment2D(line.P1, line.P2); } var angle = (Math2.GetPolarHeadingFromLine(needleLine) - 270); // bias up to account for skew angle += 2.75; if (line.Length > 63) { debugState.SetError($"Rejected length: {line.Length}"); } return(angle); } } } return(double.NaN); }
public static bool TryFindRollCircleInFullFrame(IndicatorData data, out CircleF ret) { ret = default(CircleF); if (Timeline.Data[data.Id].Roll.ForIndicatorUse != null) { // We found our own hint, return it. ret = (CircleF)Timeline.Data[data.Id].Roll.ForIndicatorUse; return(true); } var localRect = MovementRect; if (data.Id > 0 && Timeline.Data[data.Id - 1] != null && Timeline.Data[data.Id - 1].Roll != null && Timeline.Data[data.Id - 1].Roll.ForIndicatorUse != null) { // Our hint from last time. localRect = Math2.CropCircle((CircleF)Timeline.Data[data.Id - 1].Roll.ForIndicatorUse, 10); } // Crop and blur var cropped_frame = data.Frame.SafeCopy(localRect).PyrUp().PyrDown(); var MovementFrameGray = new Mat(); CvInvoke.CvtColor(cropped_frame, MovementFrameGray, ColorConversion.Bgr2Gray); // Locate the attitude and possibly vertical speed indicators. var circles = CvInvoke.HoughCircles(MovementFrameGray, HoughType.Gradient, 2.0, 20, 10, 180, 60, 80); if (circles.Length == 0) { // Couldn't find initial circle return(false); } // Pick the topmost circle and crop. var rollIndicatorCicle = circles.OrderBy(c => c.Center.Y).First(); rollIndicatorCicle.Radius = 64; rollIndicatorCicle.Center = rollIndicatorCicle.Center.Add(localRect.Location); ret = rollIndicatorCicle; Timeline.Data[data.Id].Roll.ForIndicatorUse = ret; return(true); }
public double ReadValue(IndicatorData data, DebugState debugState) { if (TryFindCircleInFullFrame(data, out var circ)) { var focusRect = Math2.CropCircle(circ, 15); var focus = data.Frame.SafeCopy(focusRect); var focusHsv = focus.Convert <Hsv, byte>(); var focusHsvText = focusHsv.DynLowInRange(dyn_lower, new Hsv(180, 255, 255)); var focusHsvTriangleMask = focusHsv.InRange(new Hsv(0, 0, 0), new Hsv(180, 140, 255)); var focusHsvTextOnly = focusHsvText.Copy(focusHsvTriangleMask); debugState.Add(focus); var blobs = Utils.DetectAndFilterBlobs(focusHsvTextOnly, 25, 250). Where(b => b.Centroid.Y >= 5).OrderByDescending(b => b.Area).Take(4); var focusHsvOnlyBlobs = Utils.RemoveAllButBlobs(focusHsvTextOnly, blobs); debugState.Add(focusHsvOnlyBlobs); var parts = GetPacksFromImage(focusHsvOnlyBlobs, blobs, debugState); var ret = ComputeHeadingFromPacks(data.Id, parts, focus, debugState); if (!double.IsNaN(ret)) { // Adjust now that N and S are near-vertical and the blobs are more regular. ret = RefineAngle(ret, focusHsvOnlyBlobs); // Adjust based on the dots on the glareshield. ret += GetGlareShieldSkewAngle(focusRect, data, debugState); // Add a fixed cab skew to account for the vertical perspective. ret -= 1; ret = Math2.ClampAngle(ret); // Proof for the debug info. debugState.Add(focus.Rotate(ret, new Bgr(0, 0, 0))); return(CheckResultValidity(ret, data.Id)); } } else { debugState.SetError("Couldn't find initial circle."); } return(double.NaN); }
private static bool TryFindCircleInFullFrame(IndicatorData data, out CircleF ret) { ret = default(CircleF); if (RollIndicator.TryFindRollCircleInFullFrame(data, out var circle)) { circle.Center = new PointF(circle.Center.X + 140, circle.Center.Y + 70); circle.Radius = 55; var firstCrop = Math2.CropCircle(circle, 10); var focus = data.Frame.SafeCopy(firstCrop); var circles = CvInvoke.HoughCircles(focus.Convert <Hsv, byte>()[2], HoughType.Gradient, 2.0, 20, 10, 180, 45, 55); if (circles.Length == 1) { circles[0].Center = circles[0].Center.Add(firstCrop.Location); circles[0].Radius = 50; ret = circles[0]; return(true); } } return(false); }
private static bool TryFindCircleInFullFrame(IndicatorData data, out CircleF ret) { ret = default(CircleF); if (RollIndicator.TryFindRollCircleInFullFrame(data, out var circle)) { circle.Center = new PointF(circle.Center.X + 1055, circle.Center.Y - 20); circle.Radius = 70; var firstCrop = Math2.CropCircle(circle, 40); var focus = data.Frame.SafeCopy(firstCrop); var focusHsv = focus.Convert <Hsv, byte>().PyrUp().PyrDown(); var circles = CvInvoke.HoughCircles(focusHsv[2], HoughType.Gradient, 2.0, 80, 10, 80, 60, 80); if (circles.Length == 1) { var circ = circles[0]; circles[0].Center = circles[0].Center.Add(firstCrop.Location); circles[0].Radius = 64; ret = circles[0]; return(true); } } return(false); }
public double ReadValue(IndicatorData data, DebugState debugState) { if (TryFindCircleInFullFrame(data, out var circle)) { var focus = data.Frame.SafeCopy(Math2.CropCircle(circle, 15)); var vs_blackimg = focus.Convert <Hsv, byte>().DynLowInRange(dyn_lower, new Hsv(180, 255, 255)).PyrUp().PyrDown(); var markedup_frame = vs_blackimg.Convert <Bgr, byte>(); debugState.Add(focus); debugState.Add(vs_blackimg); debugState.Add(markedup_frame); var cannyEdges3 = new Mat(); CvInvoke.Canny(vs_blackimg, cannyEdges3, 10, 120); Mat dialatedCanny = new Mat(); CvInvoke.Dilate(cannyEdges3, dialatedCanny, null, new Point(-1, -1), 1, BorderType.Default, new Gray(0).MCvScalar); Rectangle center = GetCenterBoxFromImage(focus); CvInvoke.Rectangle(markedup_frame, center, new Bgr(Color.Red).MCvScalar, 1); var lines = CvInvoke.HoughLinesP(dialatedCanny, 1, Math.PI / 45.0, 20, 16, 0).OrderByDescending(l => l.Length); foreach (var line in lines) { CvInvoke.Line(markedup_frame, line.P1, line.P2, new Bgr(Color.Red).MCvScalar, 1); if (center.Contains(line.P1) || center.Contains(line.P2)) { LineSegment2D needleLine; if (center.Contains(line.P1)) { needleLine = new LineSegment2D(line.P2, line.P1); } else { needleLine = new LineSegment2D(line.P1, line.P2); } var angle = Math2.GetPolarHeadingFromLine(needleLine); var hundreds = Math.Round((angle / 360) * 999); CvInvoke.Line(focus, needleLine.P1, needleLine.P2, new Bgr(Color.Yellow).MCvScalar, 2); var candidates = new List <double>(); for (var i = 0; i < 9; i++) { candidates.Add(hundreds + (i * 1000)); } var ret = candidates.OrderBy(c => Math.Abs(c - Timeline.Altitude)).First(); if (!double.IsNaN(Timeline.Altitude)) { var delta = Math.Abs(ret - Timeline.Altitude); if (delta > 400) { debugState.SetError($"Bad value {delta} > 400"); return(double.NaN); } } else { return(0); } return(ret); } } } return(double.NaN); }