Ejemplo n.º 1
0
        private double ReadKnotsFromNeedleLine(LineSegment2D line)
        {
            var polarAngleOfNeedle = Math2.ClampAngle(Math2.GetPolarHeadingFromLine(line) - 4); // Skew angle.

            // 0-360 deg -> 0-180 kt
            var knots = (polarAngleOfNeedle / 2);

            if (knots > 175)
            {
                knots = 0;
            }
            if (knots < 0)
            {
                knots = 0;
            }
            return(knots);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        double ComputeHeadingFromPacks(int frameId, IEnumerable <BlobPack> packs, Image <Bgr, Byte> compass_frame, DebugState debugState)
        {
            var frame       = Timeline.Data[frameId];
            var my_extended = new ExtendedData();

            frame.Heading.ForIndicatorUse = my_extended;

            var    choices      = new List <Tuple <double, double, string, Image <Gray, byte> > >();
            double unused_angle = 0;

            var p = packs.OrderByDescending(px => px.BlobRationAngle);

            foreach (var pack in packs)
            {
                var b = pack.BlobBox;
                b.Inflate(2, 2);

                var small_angle = pack.BlobRationAngle;
                var str         = ResolveTextFromPreviousFrame(frameId, small_angle);

                if (string.IsNullOrWhiteSpace(str))
                {
                    str = GetText(pack.BlobImage, debugState);
                }

                if (str == "N" || str == "E" || str == "S" || str == "W")
                {
                    small_angle = 360 - Math.Abs(small_angle);
                    double new_heading = 0;
                    switch (str)
                    {
                    case "N":
                        my_extended.LastN = pack.BlobRationAngle;
                        new_heading       = small_angle;
                        CvInvoke.Rectangle(compass_frame, b, new Bgr(Color.Blue).MCvScalar, 1);
                        break;

                    case "E":
                        my_extended.LastE = pack.BlobRationAngle;
                        new_heading       = (small_angle + 90);
                        CvInvoke.Rectangle(compass_frame, b, new Bgr(Color.Yellow).MCvScalar, 1);
                        break;

                    case "S":
                        my_extended.LastS = pack.BlobRationAngle;
                        new_heading       = (small_angle + 180);
                        CvInvoke.Rectangle(compass_frame, b, new Bgr(Color.Red).MCvScalar, 1);
                        break;

                    case "W":
                        my_extended.LastW = pack.BlobRationAngle;
                        new_heading       = (small_angle + 270);
                        CvInvoke.Rectangle(compass_frame, b, new Bgr(Color.Lime).MCvScalar, 1);
                        break;
                    }

                    new_heading = Math2.ClampAngle(new_heading);
                    choices.Add(new Tuple <double, double, string, Image <Gray, byte> >(new_heading, small_angle, str, pack.BlobImage));
                }
                else
                {
                    unused_angle = pack.BlobRationAngle;
                }
            }

            // Fill in exactly one missing quadrant.
            if (choices.Count == 3 && packs.Count() == 4)
            {
                var letters = new List <string>()
                {
                    "N", "E", "S", "W"
                };
                foreach (var c in choices)
                {
                    letters.Remove(c.Item3);
                }

                var o_angle = unused_angle;
                unused_angle = 360 - Math.Abs(unused_angle);

                double new_heading = 0;
                var    str         = letters.First();
                switch (str)
                {
                case "N":
                    my_extended.LastN = o_angle;
                    new_heading       = unused_angle;
                    break;

                case "E":
                    my_extended.LastE = o_angle;
                    new_heading       = (unused_angle + 90);
                    break;

                case "S":
                    my_extended.LastS = o_angle;
                    new_heading       = (unused_angle + 180);
                    break;

                case "W":
                    my_extended.LastW = o_angle;
                    new_heading       = (unused_angle + 270);
                    break;
                }

                new_heading = Math2.ClampAngle(new_heading);
                choices.Add(new Tuple <double, double, string, Image <Gray, byte> >(new_heading, (int)unused_angle, str, null));
            }

            if (choices.Count == 4)
            {
                // Exclude invalid combinations
                if (choices.Where(ct => ct.Item3 == "N").Count() > 1)
                {
                    debugState.SetError("Bad N");
                    return(double.NaN);
                }
                if (choices.Where(ct => ct.Item3 == "E").Count() > 1)
                {
                    debugState.SetError("Bad E");
                    return(double.NaN);
                }
                if (choices.Where(ct => ct.Item3 == "S").Count() > 1)
                {
                    debugState.SetError("Bad S");
                    return(double.NaN);
                }
                if (choices.Where(ct => ct.Item3 == "W").Count() > 1)
                {
                    debugState.SetError("Bad W");
                    return(double.NaN);
                }

                var p1 = Math2.AddAngles(choices[0].Item1, choices[1].Item1);
                var p2 = Math2.AddAngles(choices[2].Item1, choices[3].Item1);
                return(Math2.AddAngles(p1, p2));
            }
            else
            {
                debugState.SetError($"Bad choices {choices.Count}");
            }
            return(double.NaN);
        }