Beispiel #1
0
        public Match(
            DatabaseFin unknownFin,
            DarwinDatabase db,
            UpdateDisplayOutlinesDelegate updateOutlines)
        {
            if (unknownFin == null)
            {
                throw new ArgumentNullException(nameof(unknownFin));
            }

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

            UnknownFin      = new DatabaseFin(unknownFin);
            Database        = db;
            _updateOutlines = updateOutlines;

            CurrentFinIndex = 0;

            MatchResults = new MatchResults(unknownFin.IDCode, unknownFin?.FinFilename, db?.Filename);
        }
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);
            }
        }
Beispiel #3
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);
        }