Example #1
0
        public int FindTip(Chain chain, FloatContour chainPoints, int highPointPaddingLeft = DefaultTipHighPointPadding, int highPointPaddingRight = DefaultTipHighPointPadding)
        {
            //***0041TIP - JHS new section below
            // Finding higest point on fin
            // Remember image is upside down so high point has minimum Y value
            int   highPointId = -1;
            float highPointY  = 10000.0f;

            for (int ptId = 0; ptId < chainPoints.Length; ptId++)
            {
                if (chainPoints[ptId].Y < highPointY)
                {
                    highPointY  = chainPoints[ptId].Y;
                    highPointId = ptId;
                }
                else if (chainPoints[ptId].Y < highPointY + 3.0)
                {
                    // until we drop more than 3 units back down the fin
                    // keep advancing the highPointId.  That way, we
                    // find the rightmost "essentially highest" point
                    // on the outline
                    highPointId = ptId;
                }
            }

            return(FindTip(chain, highPointId, highPointPaddingLeft, highPointPaddingRight));
        }
Example #2
0
 public Result(
     FloatContour unknown,        //  005CM
     FloatContour db,             //  005CM
     long databaseID,
     string filename,             //  001DB
     string thumbnailFilenameUri, //  1.0
     int position,
     List <MatchFactorError> rawError,
     double error,
     string idcode,
     string name,
     string damage,
     string date,
     string location
     )
     : this(unknown,
            db,
            databaseID,
            filename,
            thumbnailFilenameUri,
            position,
            error,
            idcode,
            name,
            damage,
            date,
            location)
 {
     RawError = rawError;
 }
Example #3
0
        /// <summary>
        /// Finds the tip of the nose.  It relies mostly on the base FindTip, which also looks at the Y
        /// positions of the outline to narrow down the search area (looks for the highest points, which
        /// are the lowest Y numbers).  We want to allow the bear head to be traced sideways, but the Y
        /// coordinates of the tip of the nose won't be near the top in that case.  However, since the start
        /// of the head and the end are somewhat similar in most cases, we're going to rotate the contour
        /// so the begining and end are at a particular angle, so that the tip of the nose is at the highest
        /// point in Y coordinates.
        ///
        /// The padding is for a second run.  Sometimes, the under nose dent is a really high max, so if we
        /// find the max way too close to our tip position after finding that point, we have likely misplaced
        /// the tip of the nose, so we run this again with padding.
        /// </summary>
        /// <param name="chain">Chain code of the outline</param>
        /// <param name="chainPoints">FloatContour points on the outline</param>
        /// <param name="highPointPaddingLeft">Padding for our search area to the "left" of the high Y point</param>
        /// <param name="highPointPaddingRight">Padding for our search area to the "right" of the high Y point</param>
        /// <returns>Index of the position of the tip of the nose</returns>
        public int FindTipOfNose(Chain chain,
                                 FloatContour chainPoints,
                                 int highPointPaddingLeft  = DefaultTipHighPointPadding,
                                 int highPointPaddingRight = DefaultTipHighPointPadding)
        {
            float currentAngle = chainPoints[0].FindAngle(chainPoints.Points[chainPoints.Length - 1]);

            float degreesToRotate = DesiredAngleForTipDetection - currentAngle;

            FloatContour rotatedContour = chainPoints.Rotate(chainPoints[0], degreesToRotate);

            return(FindTip(chain, rotatedContour, highPointPaddingLeft, highPointPaddingRight));
        }
Example #4
0
        /// <summary>
        /// Finds the depth of the nasion, or the distance from the nasion to the line
        /// created by the brow and the offset nose position.  The contour is scaled to
        /// a magic number first so that these distances are hopefully comparable between
        /// samples.
        /// </summary>
        /// <param name="chainPoints"></param>
        /// <param name="browPosition"></param>
        /// <param name="nasionPosition"></param>
        /// <param name="offsetTipOfNose"></param>
        /// <returns></returns>
        public double FindDepthOfNasion(FloatContour chainPoints, int browPosition, int nasionPosition, int offsetTipOfNose)
        {
            if (chainPoints == null)
            {
                throw new ArgumentNullException(nameof(chainPoints));
            }

            if (browPosition < 0 || browPosition > nasionPosition)
            {
                throw new ArgumentOutOfRangeException(nameof(browPosition));
            }

            if (nasionPosition < 0 || nasionPosition > offsetTipOfNose)
            {
                throw new ArgumentOutOfRangeException(nameof(nasionPosition));
            }

            if (offsetTipOfNose < 0 || offsetTipOfNose >= chainPoints.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(offsetTipOfNose));
            }

            double currentPositionDistance = MathHelper.GetDistance(chainPoints[browPosition].X,
                                                                    chainPoints[browPosition].Y, chainPoints[offsetTipOfNose].X, chainPoints[offsetTipOfNose].Y);

            float ratio = (float)(CurvatureLengthNormalizationLength / currentPositionDistance);

            PointF scaledNasionPosition = new PointF(chainPoints[nasionPosition].X * ratio, chainPoints[nasionPosition].Y * ratio);

            FloatContour scaledContour = new FloatContour();

            for (int i = browPosition; i <= offsetTipOfNose; i++)
            {
                scaledContour.AddPoint(chainPoints[i].X * ratio, chainPoints[i].Y * ratio);
            }

            scaledContour = scaledContour.EvenlySpaceContourPoints(CurvatureEvenSpace);

            // Now we're going to fit a simple line to our start and end points
            float slope     = (scaledContour[scaledContour.Length - 1].Y - scaledContour[0].Y) / (scaledContour[scaledContour.Length - 1].X - scaledContour[0].X);
            float intercept = scaledContour[0].Y - slope * scaledContour[0].X;

            // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
            var nasionDistance = Math.Abs(slope * scaledNasionPosition.X - scaledNasionPosition.Y + intercept) /
                                 Math.Sqrt(Math.Pow(slope, 2) + 1 /* (-1 squared) */);

            Trace.WriteLine("Nasion depth: " + nasionDistance);

            return(nasionDistance);
        }
Example #5
0
        public Result(
            FloatContour unknown,        //  005CM
            FloatContour db,             //  005CM
            long databaseID,
            string filename,             //  001DB
            string thumbnailFilenameUri, //  1.0
            int position,
            double error,
            string idcode,
            string name,
            string damage,
            string date,
            string location
            )
        {
            unknownContour = new FloatContour(unknown); //  1.3 - Mem Leak - make copies now
            dbContour      = new FloatContour(db);      //  1.3 - Mem Leak - make copies now
            DatabaseID     = databaseID;
            ImageFilename  = filename;                  //  001DB
            Position       = position;
            Error          = error;
            if (error >= 0.0 && error <= 1.0)
            {
                Confidence = 1.0f - error;
                if (Confidence < 0.0)
                {
                    Confidence = 0.0;
                }
            }
            IDCode            = idcode;
            Name              = name;
            DamageCategory    = damage;
            DateOfSighting    = date;
            LocationCode      = location;
            Rank              = 0; //  1.5
            UnkShiftedLEBegin = 0; //  1.1 - following indices set to defaults by constructor
            UnkShiftedTip     = 0;
            UnkShiftedTEEnd   = 0;
            DBShiftedLEBegin  = 0;
            DBShiftedTip      = 0;
            DBShiftedTEEnd    = 0;

            ThumbnailFilenameUri = thumbnailFilenameUri;
        }
Example #6
0
        public FinFeatureSet(Chain chain, FloatContour chainPoints)
            : this()
        {
            int tipPos   = FindTip(chain, chainPoints);
            int notchPos = FindNotch(chain, tipPos);
            int beginLE  = FindBeginLE(chain, tipPos);
            int endLE    = FindEndLE(chain, beginLE, tipPos);
            int endTE    = FindPointOfInflection(chain, tipPos);

            FeaturePoints[FeaturePointType.Tip].Position               = tipPos;
            FeaturePoints[FeaturePointType.Notch].Position             = notchPos;
            FeaturePoints[FeaturePointType.LeadingEdgeBegin].Position  = beginLE;
            FeaturePoints[FeaturePointType.LeadingEdgeEnd].Position    = endLE;
            FeaturePoints[FeaturePointType.PointOfInflection].Position = endTE;

            double leAngle = FindLEAngle(chain, tipPos, endLE);

            Features[FeatureType.LeadingEdgeAngle].Value = leAngle;
        }
Example #7
0
 public Result(Result r)
 {
     DatabaseID           = r.DatabaseID;
     ImageFilename        = r.ImageFilename;
     Position             = r.Position;
     Error                = r.Error;
     Confidence           = r.Confidence;
     IDCode               = r.IDCode;
     Name                 = r.Name;
     DamageCategory       = r.DamageCategory;
     LocationCode         = r.LocationCode;
     Rank                 = r.Rank; //  1.5
     unknownContour       = new FloatContour(r.unknownContour);
     dbContour            = new FloatContour(r.dbContour);
     UnkShiftedLEBegin    = r.UnkShiftedLEBegin;
     UnkShiftedTip        = r.UnkShiftedTip;
     UnkShiftedTEEnd      = r.UnkShiftedTEEnd;
     DBShiftedLEBegin     = r.DBShiftedLEBegin;
     DBShiftedTip         = r.DBShiftedTip;
     DBShiftedTEEnd       = r.DBShiftedTEEnd;
     ThumbnailFilenameUri = r.ThumbnailFilenameUri;
 }
Example #8
0
        public static float[] PredictCoordinates(Bitmap image, FloatContour chainPoints, double scale)
        {
            Trace.WriteLine("Predicting coordinates with " + AppSettings.MLModelFilename + " model using Emgu.TF.Lite / TensorFlow Lite");

            var model = new MLModel(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), AppSettings.MLModelFilename));

            var mlImage   = ConvertDatabaseFinToMLImage(image, chainPoints, scale);
            var directBmp = new DirectBitmap(mlImage.Image);

            //var floatArray = directBmp.ToScaledRGBFloatArray();

            // This must match what the model expects. E.g., this is what Keras on TF for Resnet uses:
            var floatArray = directBmp.ToScaledTensorFlowRGBPreprocessInput();

            var coordinates = model.Run(floatArray);

            Trace.WriteLine("Raw predicted coordinates:");

            // Scale/translate the coordinates back to the original image
            for (int i = 0; i < coordinates.Length; i++)
            {
                Trace.Write(" " + coordinates[i]);
                if (i % 2 == 0)
                {
                    coordinates[i] = (float)((coordinates[i] / mlImage.XRatio + mlImage.XMin) * scale);
                }
                else
                {
                    coordinates[i] = (float)((coordinates[i] / mlImage.YRatio + mlImage.YMin) * scale);
                }
            }

            Trace.WriteLine(" ");

            // Rescale the coordinates back to the original
            return(coordinates);
        }
Example #9
0
        public static MLImage ConvertDatabaseFinToMLImage(Bitmap image, FloatContour contour, double scale)
        {
            int xMin = (int)Math.Floor(contour.MinX() / scale);
            int yMin = (int)Math.Floor(contour.MinY() / scale);
            int xMax = (int)Math.Ceiling(contour.MaxX() / scale);
            int yMax = (int)Math.Ceiling(contour.MaxY() / scale);

            // Figure out the ratio
            var resizeRatioX = (float)ImageWidth / (xMax - xMin);
            var resizeRatioY = (float)ImageHeight / (yMax - yMin);

            if (resizeRatioX > resizeRatioY)
            {
                // We're X constrained, so expand the X
                var extra = ((yMax - yMin) - (xMax - xMin)) * ((float)ImageWidth / ImageHeight);
                xMin -= (int)Math.Round(extra / 2);
                xMax += (int)Math.Round(extra / 2);

                if (xMin < 0)
                {
                    xMax += (0 - xMin);
                    xMin  = 0;
                }

                if (xMax > image.Width)
                {
                    xMin -= xMax - image.Width;
                    xMax  = image.Width;
                }

                if (xMin < 0)
                {
                    xMin = 0;
                }
                if (xMax > image.Width)
                {
                    xMax = image.Width;
                }
            }
            else
            {
                // We're Y constrained, so expand the Y
                var extra = ((xMax - xMin) - (yMax - yMin)) * ((float)ImageHeight / ImageWidth);
                yMin -= (int)Math.Round(extra / 2);
                yMax += (int)Math.Round(extra / 2);

                if (yMin < 0)
                {
                    yMax += (0 - yMin);
                    yMin  = 0;
                }

                if (yMax > image.Height)
                {
                    yMin -= yMax - image.Height;
                    yMax  = image.Height;
                }

                if (yMin < 0)
                {
                    yMin = 0;
                }
                if (yMax > image.Height)
                {
                    yMax = image.Height;
                }
            }

            var workingImage = BitmapHelper.CropBitmap(image,
                                                       xMin, yMin,
                                                       xMax, yMax);

            // We've hopefully already corrected for the aspect ratio above
            workingImage = BitmapHelper.ResizeBitmap(workingImage, ImageWidth, ImageHeight);

            float xRatio = (float)ImageWidth / (xMax - xMin);
            float yRatio = (float)ImageHeight / (yMax - yMin);

            return(new MLImage
            {
                Image = workingImage,
                XMin = xMin,
                XMax = xMax,
                YMin = yMin,
                YMax = yMax,
                XRatio = xRatio,
                YRatio = yRatio
            });
        }
Example #10
0
        public static FeatureSet Create(FeatureSetType featuresType, Bitmap image, double scale, Chain chain, FloatContour chainPoints)
        {
            switch (featuresType)
            {
            case FeatureSetType.DorsalFin:
                if (chain == null || chainPoints == null)
                {
                    return(new FinFeatureSet());
                }

                return(new FinFeatureSet(chain, chainPoints));

            case FeatureSetType.Bear:
                if (chain == null || chainPoints == null)
                {
                    return(new BearFeatureSet());
                }

                return(new BearFeatureSet(image, scale, chain, chainPoints));

            default:
                throw new NotImplementedException();
            }
        }
Example #11
0
        /// <summary>
        /// Tries to find the position of the upper lip on the outline.  If there's a mouth dent,
        /// it'll return that (and set the output parameter hasMouthDent to true).  If there isn't,
        /// it'll return the greatest max to the right of the mouth dent.
        /// </summary>
        /// <param name="chain"></param>
        /// <param name="chainPoints"></param>
        /// <param name="underNoseDentPosition"></param>
        /// <param name="hasMouthDent"></param>
        /// <param name="mouthDentPosition"></param>
        /// <returns></returns>
        public int FindUpperLip(Chain chain, FloatContour chainPoints, int underNoseDentPosition, out bool hasMouthDent, out int bottomLipProtrusion)
        {
            if (chain == null)
            {
                throw new ArgumentNullException(nameof(chain));
            }

            if (underNoseDentPosition < 0 || underNoseDentPosition > chain.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(underNoseDentPosition));
            }

            hasMouthDent = false;

            int numPointsAfterNoseDent = (int)Math.Round((chain.Length - underNoseDentPosition) * (1.0f - UpperLipEndPadding));

            // We're going to transform the whole chain
            int numPoints = chain.Length;

            // First, make a copy without the first value in the chain,
            // since the first value skews the rest of the chain and is
            // unnecessary for our purposes here
            double[] src = new double[numPoints - 1];

            Array.Copy(chain.Data, 1, src, 0, numPoints - 1);

            int nextPowOfTwo = MathHelper.NextPowerOfTwo(numPoints - 1);

            // Now set up the variables needed to perform a wavelet transform on the chain
            double[,] continuousResult = new double[UpperLipNumTransformsForMin + 1, nextPowOfTwo];
            WIRWavelet.WL_FrwtVector(src,
                                     ref continuousResult,
                                     numPoints - 1,
                                     UpperLipNumTransformsForMin,
                                     WaveletUtil.MZLowPassFilter,
                                     WaveletUtil.MZHighPassFilter);

            for (int i = 1; i <= UpperLipNumTransformsForMin; i++)
            {
                for (int j = 0; j < numPoints - 1; j++)
                {
                    continuousResult[i, j] *= WaveletUtil.NormalizationCoeff(i);
                }
            }

            double[] modMax = new double[numPoints - 1];

            for (int k = 0; k < numPoints - 1; k++)
            {
                continuousResult[UpperLipNumTransformsForMin, k] *= WaveletUtil.NormalizationCoeff(UpperLipNumTransformsForMin);
            }

            double[] continousExtract = WaveletUtil.Extract1DArray(continuousResult, UpperLipNumTransformsForMin, numPoints - 1);
            WaveletUtil.ModulusMaxima(continousExtract, ref modMax, numPoints - 1);

            // Now, let's see if we have any mins at the top transform level.  If we do, we probably have a mouth dent. If we don't,
            // we might not.
            for (int k = numPointsAfterNoseDent + underNoseDentPosition; k > underNoseDentPosition; k--)
            {
                if (modMax[k] < 0.0)
                {
                    hasMouthDent = true;
                    break;
                }
            }

            int mouthDentPosition = 0;

            if (hasMouthDent)
            {
                mouthDentPosition = FindNotch(chain, underNoseDentPosition + UpperLipTipPadding);

                // Check where it found the mouth dent -- if it's too close to the end, it's likely that it's
                // not the mouth, but something like the neck/etc.
                if (mouthDentPosition < underNoseDentPosition + numPointsAfterNoseDent)
                {
                    bottomLipProtrusion = FindTip(chain, mouthDentPosition + 20, mouthDentPosition - underNoseDentPosition - UpperLipTipPadding, UpperLipTipPadding);
                    return(mouthDentPosition);
                }
            }

            // Fake the mouth dent position as a starting point for finding the biggest max in the area
            mouthDentPosition = underNoseDentPosition + numPointsAfterNoseDent;

            int upperLipPosition = FindTip(chain, mouthDentPosition, mouthDentPosition - underNoseDentPosition - UpperLipTipPadding, UpperLipTipPadding);

            // These are fallback positions, so they're going to be off if we hit this if statement.
            if (upperLipPosition < underNoseDentPosition)
            {
                upperLipPosition = (int)Math.Round(mouthDentPosition + numPointsAfterNoseDent / 2.0f);
            }

            bottomLipProtrusion = upperLipPosition;

            return(upperLipPosition);
        }
Example #12
0
        public BearFeatureSet(Bitmap image, double scale, Chain chain, FloatContour chainPoints)
            : this()
        {
            if (chain == null)
            {
                throw new ArgumentNullException(nameof(chain));
            }

            if (chainPoints == null)
            {
                throw new ArgumentNullException(nameof(chainPoints));
            }

            if (chainPoints.Length < 5)
            {
                throw new Exception("FloatContour isn't long enough to find feature points");
            }

            int tipPosition           = FindTipOfNose(chain, chainPoints);
            int underNoseDentPosition = FindUnderNoseDent(chain, tipPosition);

            if (underNoseDentPosition - tipPosition < TipNotchMinDistance)
            {
                // If the tip and under nose dent are too close together, it's likely we have a really curved nose indent.
                // Let's try to find the tip again with a bit of padding
                tipPosition = FindTipOfNose(chain, chainPoints, DefaultTipHighPointPadding, TipNotchMinDistance);
            }

            try
            {
                int nasionPos = FindNasion(chain, tipPosition);
                int beginLE   = FindBeginLE(chain, tipPosition);
                int endLE     = FindEndLE(chain, beginLE, tipPosition);
                int endTE     = FindPointOfInflection(chain, tipPosition);

                bool hasMouthDent;
                int  bottomLipProtrusion;
                int  upperLipPosition = FindUpperLip(chain, chainPoints, underNoseDentPosition, out hasMouthDent, out bottomLipProtrusion);

                int browPosition = FindBrow(chain, beginLE, nasionPos);
                //int chinPosition = FindChin(chain, tipPosition);

                FeaturePoints[FeaturePointType.LeadingEdgeBegin].Position = beginLE;
                FeaturePoints[FeaturePointType.Brow].Position             = browPosition;
                FeaturePoints[FeaturePointType.LeadingEdgeEnd].Position   = endLE;
                FeaturePoints[FeaturePointType.Nasion].Position           = nasionPos;
                FeaturePoints[FeaturePointType.Tip].Position                 = tipPosition;
                FeaturePoints[FeaturePointType.Notch].Position               = underNoseDentPosition;
                FeaturePoints[FeaturePointType.UpperLip].Position            = upperLipPosition;
                FeaturePoints[FeaturePointType.BottomLipProtrusion].Position = bottomLipProtrusion;
                //FeaturePoints[FeaturePointType.Chin].Position = chinPosition;
                FeaturePoints[FeaturePointType.PointOfInflection].Position = endTE;

                Features[FeatureType.HasMouthDent].Value = (hasMouthDent) ? 1.0 : 0.0;

                // Find the curvature between the brow and a spot near the nose. The reason for the padding is to try
                // to avoid taking the upturned noses some bears have into account.
                int curvatureTipPosition = tipPosition - CurvatureTipPadding;

                // Fallback to prevent an error.  We're going to get an error of 0 or close to it if we fall to this.
                if (curvatureTipPosition <= browPosition)
                {
                    curvatureTipPosition = browPosition + 1;
                    Trace.WriteLine("Fallback tip position to find curvature.");
                }
                Features[FeatureType.BrowCurvature].Value = FindCurvature(chainPoints, browPosition, curvatureTipPosition);
                Features[FeatureType.NasionDepth].Value   = FindDepthOfNasion(chainPoints, browPosition, nasionPos, curvatureTipPosition);

                if (Options.CurrentUserOptions.FindCoordinateFeatures)
                {
                    var coordinates = MLSupport.PredictCoordinates(image, chainPoints, scale);

                    CoordinateFeaturePoints[FeaturePointType.Eye].Coordinate = new Point((int)Math.Round(coordinates[0]), (int)Math.Round(coordinates[1]));
                    CoordinateFeaturePoints[FeaturePointType.NasalLateralCommissure].Coordinate = new Point((int)Math.Round(coordinates[2]), (int)Math.Round(coordinates[3]));
                }

                // Fake the eye & nasal fold for right now (this at least gets the features on the display so we can move them)
                //CoordinateFeaturePoints[FeaturePointType.Eye].Coordinate = new Point((int)chainPoints[nasionPos].X - 60, (int)chainPoints[nasionPos].Y + 20);
                //CoordinateFeaturePoints[FeaturePointType.NasalLateralCommissure].Coordinate = new Point((int)chainPoints[tipPosition].X - 60, (int)chainPoints[tipPosition].Y + 60);
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }
Example #13
0
        /// <summary>
        /// Find a rough approximation of the curvature of a FloatContour.
        /// Scales the contour length for the first and second positions to a benchmark
        /// and then finds the mean squared error between that contour and a line fit
        /// between the first and second points.
        /// </summary>
        /// <param name="chainPoints"></param>
        /// <param name="firstPosition"></param>
        /// <param name="secondPosition"></param>
        /// <returns></returns>
        public double FindCurvature(FloatContour chainPoints, int firstPosition, int secondPosition)
        {
            if (chainPoints == null)
            {
                throw new ArgumentNullException(nameof(chainPoints));
            }

            if (firstPosition < 0 || firstPosition > secondPosition)
            {
                throw new ArgumentOutOfRangeException(nameof(firstPosition));
            }

            if (secondPosition < 0 || secondPosition >= chainPoints.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(secondPosition));
            }

            //// Fit a spline to our points
            //var spline = CubicSpline.InterpolateNatural(
            //    chainPoints.Points.Skip(beginningOfLeadingEdge)
            //                      .Take(nasionPosition - beginningOfLeadingEdge)
            //                      .Select(p => (double)p.X),
            //    chainPoints.Points.Skip(beginningOfLeadingEdge)
            //                      .Take(nasionPosition - beginningOfLeadingEdge)
            //                      .Select(p => (double)p.Y));

            //const int column_width = 10;
            //for (int i = beginningOfLeadingEdge; i < nasionPosition; i++)
            //{
            //    double dydx = spline.Differentiate2(chainPoints[i].X);
            //}

            //CurvatureLengthNormalizationLength

            double currentPositionDistance = MathHelper.GetDistance(chainPoints[firstPosition].X,
                                                                    chainPoints[firstPosition].Y, chainPoints[secondPosition].X, chainPoints[secondPosition].Y);

            float ratio = (float)(CurvatureLengthNormalizationLength / currentPositionDistance);

            FloatContour scaledContour = new FloatContour();

            for (int i = firstPosition; i <= secondPosition; i++)
            {
                scaledContour.AddPoint(chainPoints[i].X * ratio, chainPoints[i].Y * ratio);
            }

            scaledContour = scaledContour.EvenlySpaceContourPoints(CurvatureEvenSpace);

            //double checkDistance = MathHelper.GetDistance(scaledContour[0].X, scaledContour[0].Y,
            //    scaledContour[scaledContour.Length - 1].X, scaledContour[scaledContour.Length - 1].Y);

            // Now we're going to fit a simple line to our start and end points
            float slope     = (scaledContour[scaledContour.Length - 1].Y - scaledContour[0].Y) / (scaledContour[scaledContour.Length - 1].X - scaledContour[0].X);
            float intercept = scaledContour[0].Y - slope * scaledContour[0].X;

            double squaredError = 0f;

            // And find the mean squared error of the Y distance between the line and the contour
            foreach (var p in scaledContour.Points)
            {
                squaredError += Math.Pow(p.Y - (p.X * slope + intercept), 2);
            }

            double meanSquaredError = squaredError / scaledContour.Length;

            Trace.WriteLine("Curvature MSE: " + meanSquaredError.ToString("N2"));

            return(meanSquaredError);
        }
Example #14
0
        //  1.1 - the following functions used in MatchQueue context

        public static MatchResults Load(string fileName, out DarwinDatabase db, out DatabaseFin databaseFin)
        {
            MatchResults result = new MatchResults();

            db          = null;
            databaseFin = null;

            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }

            if (!File.Exists(fileName))
            {
                throw new ArgumentOutOfRangeException(nameof(fileName));
            }

            var lines = File.ReadAllLines(fileName);

            if (lines.Length < 6 || !lines[0].StartsWith("Results for ID:"))
            {
                return(result);
            }

            result._finID = lines[0].Substring(lines[0].LastIndexOf(":") + 1).Trim();

            result.TracedFinFile = lines[1].Substring(lines[1].IndexOf(":") + 1).Trim();
            result.DatabaseFile  = lines[2].Substring(lines[2].IndexOf(":") + 1).Trim();

            db = CatalogSupport.OpenDatabase(result.DatabaseFile, Options.CurrentUserOptions.DefaultCatalogScheme, false);

            //***2.2 - if we can, determine if database path has just changed drive letter
            // or some part of path that is a prefix to the SurveyArea.  If the database
            // is in the same SurveyArea and has the same database name, then we can
            // proceed with the building of the MatchResults
            //int p = mDatabaseFile.find("surveyAreas");
            //string rqdAreaAndDB = mDatabaseFile.substr(p);  // survey area and database name
            //string rqdPreamble = mDatabaseFile.substr(0, p);    // strip it to get preamble

            //string currentDBFile = db->getFilename();
            //p = currentDBFile.find("surveyAreas");
            //string currentAreaAndDB = currentDBFile.substr(p); // survey area and catalog name
            //string currentPreamble = currentDBFile.substr(0, p); // strip it to get preamble

            //if (db.Filename.ToLower() != DatabaseFile.ToLower())
            //{
            //    //cout << mDatabaseFile << endl;
            //    //cout << rqdPreamble << "   " << rqdAreaAndDB << endl;
            //    //cout << currentDBFile << endl;
            //    //cout << currentPreamble << "   " << currentAreaAndDB << endl;

            //    if (currentAreaAndDB == rqdAreaAndDB)
            //    {
            //        string msg = "The Survey Area and Catalog for the match results appear corrrect,\n";
            //        msg += "but the path to DARWIN's home folder seems to have changed.\n";
            //        msg += "Is it OK to open the indicated catalog in the current location\n";
            //        msg += "as shown below?\n\n";
            //        msg += (currentPreamble + rqdAreaAndDB);

            //        Trace.WriteLine(msg);
            //        //ErrorDialog *err = new ErrorDialog(msg);
            //        //err->show();

            //        //***2.2 - path possibly has to be fixed to FIN file as well
            //        if ((currentDBFile != mDatabaseFile) && (currentAreaAndDB == rqdAreaAndDB))
            //        {
            //            //add preamble of current DARWINHOME to FINs relative location
            //            p = mTracedFinFile.find("surveyAreas");
            //            string currentFinAreaPlus = mTracedFinFile.substr(p);
            //            mTracedFinFile = currentPreamble + currentFinAreaPlus;
            //            cout << mTracedFinFile << endl;
            //        }
            //    }
            //    else
            //    {
            //        string msg = "The WRONG database is currently loaded for viewing these results ...\n\n";
            //        msg += "LOADED DB:\n    " + db->getFilename() + "\n\n";
            //        msg += "REQUIRED DB:\n    " + mDatabaseFile + "\n\n";
            //        msg += "Please load the required database from the main window\n";
            //        msg += "and then reload the desired results file.";

            //        //ErrorDialog *err = new ErrorDialog(msg);
            //        //err->show();
            //        //***2.22 - replacing own ErrorDialog with GtkMessageDialogs
            //        GtkWidget* errd = gtk_message_dialog_new(NULL,
            //                                GTK_DIALOG_DESTROY_WITH_PARENT,
            //                                GTK_MESSAGE_ERROR,
            //                                GTK_BUTTONS_CLOSE,
            //                                msg.c_str());
            //        gtk_dialog_run(GTK_DIALOG(errd));
            //        gtk_widget_destroy(errd);
            //        return NULL;
            //    }
            //}

            DatabaseFin unkFin = CatalogSupport.OpenFinz(result.TracedFinFile);

            // get match info on each matched database fin
            // After skipping some of the headers
            for (int i = 6; i < lines.Length; i++)
            {
                string line = lines[i];

                int pos = line.IndexOf("\t");
                //string rank = line.Substring(0, pos);
                line = line.Substring(pos + 1);

                pos = line.IndexOf("\t");
                string error = line.Substring(0, pos);
                line = line.Substring(pos + 1);

                pos = line.IndexOf("\t");
                string dbFinID = line.Substring(0, pos);
                line = line.Substring(pos + 1);

                //cout << "dbFinID[" << dbFinID << "]"; //*** 2.2 - show for now

                string numStr;
                int
                    dbFinPosition,
                    uBegin, uTip, uEnd,
                    dbBegin, dbTip, dbEnd;

                pos           = line.IndexOf("\t");
                numStr        = line.Substring(0, pos);
                line          = line.Substring(pos + 1);
                dbFinPosition = int.Parse(numStr);
                //cout << "[" << dbFinPosition << "]" << endl; //*** 2.2 - show for now

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                uBegin = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << uBegin << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                uTip   = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << uTip << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                uEnd   = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << uEnd << "]";

                pos     = line.IndexOf("\t");
                numStr  = line.Substring(0, pos);
                dbBegin = int.Parse(numStr);
                line    = line.Substring(pos + 1);
                //cout << "[" << dbBegin << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                dbTip  = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << dbTip << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                dbEnd  = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << dbEnd << "]";

                //string damage = line;
                //cout << "[" << damage << "]" << endl;

                // The position is written starting at 1, but our index is 0 based
                DatabaseFin thisDBFin = db.AllFins[dbFinPosition - 1];

                // TODO: Should this throw an exception instead?
                if (thisDBFin.IDCode != dbFinID)
                {
                    Trace.WriteLine("Disaster " + thisDBFin.IDCode + " " + dbFinID);
                }

                FloatContour mappedUnknownContour = unkFin.FinOutline.ChainPoints.MapContour(
                    unkFin.FinOutline.ChainPoints[uTip],
                    unkFin.FinOutline.ChainPoints[uBegin],
                    unkFin.FinOutline.ChainPoints[uEnd],
                    thisDBFin.FinOutline.ChainPoints[dbTip],
                    thisDBFin.FinOutline.ChainPoints[dbBegin],
                    thisDBFin.FinOutline.ChainPoints[dbEnd]);

                Result r = new Result(
                    mappedUnknownContour,                 //***1.3 - Mem Leak - constructor make copy now
                    thisDBFin.FinOutline.ChainPoints,     //***1.3 - Mem Leak - constructor make copy now
                    thisDBFin.ID,
                    // TODO - This image filename stuff is a little ugly.
                    (string.IsNullOrEmpty(thisDBFin.OriginalImageFilename)) ? thisDBFin.ImageFilename : thisDBFin.OriginalImageFilename,
                    thisDBFin.ThumbnailFilenameUri,
                    dbFinPosition - 1,     // position of fin in database
                    double.Parse(error),
                    thisDBFin.IDCode,
                    thisDBFin.Name,
                    thisDBFin.DamageCategory,
                    thisDBFin.DateOfSighting,
                    thisDBFin.LocationCode);

                r.SetMappingControlPoints(
                    uBegin, uTip, uEnd,      // beginning, tip & end of unknown fin
                    dbBegin, dbTip, dbEnd);  // beginning, tip & end of database fin

                result.Results.Add(r);
            }

            databaseFin = unkFin;
            result.SetRankings();
            return(result);
        }