Beispiel #1
0
        public static MatchError ComputeMouthDentError(
            DatabaseFin unknownFin,
            DatabaseFin databaseFin,
            MatchOptions options)
        {
            if (unknownFin == null)
            {
                throw new ArgumentNullException(nameof(unknownFin));
            }

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

            var maxError = new MatchError {
                Error = 1
            };

            if (databaseFin.FinOutline?.FeatureSet?.Features.ContainsKey(Features.FeatureType.HasMouthDent) != true ||
                unknownFin.FinOutline?.FeatureSet?.Features.ContainsKey(Features.FeatureType.BrowCurvature) != true)
            {
                return(maxError);
            }

            var unknownHasMouthDent  = unknownFin.FinOutline?.FeatureSet?.Features[Features.FeatureType.HasMouthDent].Value;
            var databaseHasMouthDent = databaseFin.FinOutline?.FeatureSet?.Features[Features.FeatureType.HasMouthDent].Value;

            if (unknownHasMouthDent == null || databaseHasMouthDent == null)
            {
                return(maxError);
            }

            return(new MatchError
            {
                Error = Math.Abs(unknownHasMouthDent.Value - databaseHasMouthDent.Value)
            });
        }
Beispiel #2
0
        //*******************************************************************
        //
        // float Match::matchSingleFin(int registrationMethod, int regSegmentsUsed,
        //                             bool categoryToMatch[], bool useFullFinError,
        //                             bool useAbsoluteOffsets)
        //
        //    Attempts to match unknown fin to a single database fin.  The
        //    current fin is mDatabase->getItem(mCurrentFin). The match_method
        //    parameter determines which of several outline mapping and
        //    error between match techniques is used.
        //
        //    now modified to match ONLY those database fins with category designation
        //    indicated in categoryToMatch array
        //
        //    ***055ER
        //    the new useFullFinError parameter indicates whether or not to use the
        //    entire outlines in the final calculation of the error measure.  When false,
        //    only the portion of the outlines between the adjusted leadingeEdgeBegin and
        //    trailingEdgeEnd points is used. When true, the fin mapping is done using
        //    various subsets of the outlines (and errors derived from same), but the
        //    final error (measure of mismatch) uses all outline points from each fin.
        //    This parameter does not affect the original and the trim by 1/10th percent
        //    matching techniques, which always use the entire outline in error calculations
        //
        //    ***1.3
        //    New parameter useAbsoluteOffsets, wen true, causes function to step through
        //    the database absolute offset list so that fins are matched in the actual
        //    order that they are stored in the database.  This is used ONLY when MATCH
        //    QUEUES are being processed, and it keeps the fin numbers correct even if the
        //    database is later modified.
        //
        public float MatchSingleIndividual(List <Category> categoriesToMatch)
        {
            if (MatchFactors == null || MatchFactors.Count < 1)
            {
                throw new Exception("Match factors haven't been set yet!");
            }

            var stopWatch = System.Diagnostics.Stopwatch.StartNew();

            int matchIndex = 0;

            lock (locker)
            {
                // If we have any factors missing updateOutlines, but we know what
                // the delegate should be, fill them in
                if (CurrentFinIndex == 0 && _updateOutlines != null && MatchFactors.Any(mf => mf.MatchFactorType == MatchFactorType.Outline && mf.UpdateOutlines == null))
                {
                    foreach (var matchFactor in MatchFactors.Where(mf => mf.MatchFactorType == MatchFactorType.Outline && mf.UpdateOutlines == null))
                    {
                        matchFactor.UpdateOutlines = _updateOutlines;
                    }
                }

                // TODO?
                //if (CurrentFinIndex >= Database.AllFins.Count)
                //    return 100.0f;

                matchIndex       = CurrentFinIndex;
                CurrentFinIndex += 1;
            }

            DatabaseFin thisDBFin = Database.AllFins[matchIndex];

            bool tryMatch = categoriesToMatch.Exists(c => c.Name.ToLower() == thisDBFin.DamageCategory.ToLower());

            if (tryMatch)
            {
                // TODO: This isn't done quite right yet
                MatchError matchErrorResult = new MatchError();
                double     errorBetweenFins = 0.0;

                List <MatchFactorError> rawError = new List <MatchFactorError>();

                int factorIndex = 0;
                try
                {
                    foreach (var factor in MatchFactors)
                    {
                        var factorResult = factor.FindErrorBetweenIndividuals(UnknownFin, thisDBFin);

                        if (factor.MatchFactorType == MatchFactorType.Outline)
                        {
                            Vector <double> saveRawRatios = null;
                            if (matchErrorResult.RawRatios != null)
                            {
                                saveRawRatios = matchErrorResult.RawRatios;
                            }

                            Vector <double> saveRHat = null;
                            if (matchErrorResult.RHat != null)
                            {
                                saveRHat = matchErrorResult.RHat;
                            }

                            Vector <double> saveDBRHat = null;
                            if (matchErrorResult.DBRHat != null)
                            {
                                saveDBRHat = matchErrorResult.DBRHat;
                            }

                            Vector <double> saveDBRawRatios = null;
                            if (matchErrorResult.DBRawRatios != null)
                            {
                                saveDBRawRatios = matchErrorResult.DBRawRatios;
                            }

                            matchErrorResult = factorResult;

                            if (factorResult.Contour1 != null)
                            {
                                UnknownFin.FinOutline.RemappedChainPoints = factorResult.Contour1;
                            }

                            if (saveRawRatios != null)
                            {
                                matchErrorResult.RawRatios = saveRawRatios;
                            }
                            if (saveRHat != null)
                            {
                                matchErrorResult.RHat = saveRHat;
                            }
                            if (saveDBRawRatios != null)
                            {
                                matchErrorResult.DBRawRatios = saveDBRawRatios;
                            }
                            if (saveDBRHat != null)
                            {
                                matchErrorResult.DBRHat = saveDBRHat;
                            }
                        }
                        else
                        {
                            matchErrorResult.RawRatios   = factorResult.RawRatios;
                            matchErrorResult.RHat        = factorResult.RHat;
                            matchErrorResult.DBRawRatios = factorResult.DBRawRatios;
                            matchErrorResult.DBRHat      = factorResult.DBRHat;
                        }

                        // We're going to rescale this later -- should probably remove this
                        // errorBetweenFins += factor.Weight * result.Error;
                        var matchFactorError = new MatchFactorError
                        {
                            FactorIndex = factorIndex,
                            Error       = factorResult.Error,
                            Weight      = factor.Weight
                        };

                        rawError.Add(matchFactorError);

                        lock (locker)
                        {
                            RawErrorTracking.Add(matchFactorError);
                        }

                        factorIndex += 1;
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);
                }

                // Now, store the result
                Result r = new Result(
                    matchErrorResult.Contour1, //***005CM
                    matchErrorResult.Contour2, //***005CM
                    thisDBFin.ID,
                    // TODO - This image filename stuff is a little ugly.
                    (string.IsNullOrEmpty(thisDBFin.OriginalImageFilename)) ? thisDBFin.ImageFilename : thisDBFin.OriginalImageFilename,
                    thisDBFin.ThumbnailFilenameUri,
                    matchIndex,
                    rawError,
                    errorBetweenFins,
                    thisDBFin.IDCode,
                    thisDBFin.Name,
                    thisDBFin.DamageCategory,
                    thisDBFin.DateOfSighting,
                    thisDBFin.LocationCode);

                if (matchErrorResult.RHat != null)
                {
                    r.RHat = matchErrorResult.RHat;
                }

                if (matchErrorResult.RawRatios != null)
                {
                    r.RawRatios = matchErrorResult.RawRatios;
                }

                if (matchErrorResult.DBRHat != null)
                {
                    r.DBRHat = matchErrorResult.DBRHat;
                }

                if (matchErrorResult.DBRawRatios != null)
                {
                    r.DBRawRatios = matchErrorResult.DBRawRatios;
                }

                //***1.1 - set indices of beginning, tip and end points used in mapping
                r.SetMappingControlPoints(
                    matchErrorResult.Contour1ControlPoint1, matchErrorResult.Contour1ControlPoint2, matchErrorResult.Contour1ControlPoint3,  // beginning, tip & end of unknown fin
                    matchErrorResult.Contour2ControlPoint1, matchErrorResult.Contour2ControlPoint2, matchErrorResult.Contour2ControlPoint3); // beginning, tip & end of database fin

                stopWatch.Stop();

                lock (locker)
                {
                    MatchResults.AddResult(r);
                    MatchResults.TimeTaken += stopWatch.ElapsedMilliseconds;
                }
            }

            lock (locker)
            {
                int numberDone = MatchResults.Count;

                if (numberDone >= Database.AllFins.Count)
                {
                    if (RawErrorTracking != null && RawErrorTracking.Count > 0)
                    {
                        // Now that we're through matching, let's rescale the errors
                        Dictionary <int, float> scaleFactors = new Dictionary <int, float>();

                        foreach (var idx in RawErrorTracking.Select(r => r.FactorIndex).Distinct())
                        {
                            double minError = RawErrorTracking.Where(r => r.FactorIndex == idx).Min(r => r.Error);
                            double maxError = RawErrorTracking.Where(r => r.FactorIndex == idx).Max(r => r.Error);

                            // Force minError to 0 if it's not <= already
                            if (minError > 0)
                            {
                                minError = 0;
                            }

                            scaleFactors[idx] = (float)(1 / (maxError - minError));
                        }

                        foreach (var result in MatchResults.Results)
                        {
                            if (result.RawError != null && result.RawError.Count > 0)
                            {
                                double scaledError = 0.0;

                                foreach (var raw in result.RawError)
                                {
                                    scaledError += scaleFactors[raw.FactorIndex] * raw.Error * raw.Weight;
                                }

                                result.Error      = scaledError;
                                result.Confidence = 1.0f - scaledError;

                                // For rounding issues so we prevent seeing "-0" in the UI
                                if (result.Confidence < 0)
                                {
                                    result.Confidence = 0;
                                }
                            }
                        }
                    }

                    return(1.0f);
                }

                return((float)numberDone / Database.AllFins.Count);
            }
        }