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)); }
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; }
/// <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)); }
/// <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); }
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; }
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; }
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; }
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); }
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 }); }
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(); } }
/// <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); }
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); } }
/// <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); }
// 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); }