/// <summary> /// Detects light sources on the input image using hysteresis thresholding. Requires input image to be astrometrically reduced. /// </summary> /// <param name="Input">Input image.</param> /// <returns>A list of detections.</returns> public List <ImageDetection> Detect(Image Input) { Detections = new List <DotDetection>(); PositionDependentExtractor <DotDetector> Extractor = DetectSources; Extractor.Run(this, Input, Parameters); List <ImageDetection> Mdect = Detections.Select((x) => StandardDetectionFactory.CreateDetection(Input, x.Pixels, x.PixelValues)).ToList(); foreach (ImageDetection m in Mdect) { m.SetResetProperty(new PairingProperties() { IsDotDetection = true }); } return(Mdect); }
/// <summary> /// Attempts to recover a detection on a given image, comparing with the entire set of exposures. /// </summary> /// <returns><c>true</c>, if detection was recovered, <c>false</c> otherwise.</returns> /// <param name="DetPos">Position of the detection to recover.</param> /// <param name="Img">Image on which to recover.</param> /// <param name="Radius">Maximum radius of the detection.</param> /// <param name="InputImages">Input images.</param> /// <param name="Recovered">Recovered detection.</param> public bool RecoverDetection(Position DetPos, Image Img, double Radius, IEnumerable <Image> InputImages, out ImageDetection Recovered) { Recovered = null; DotDetector.DotDetection dd = Recover(DetPos.PP, Radius, Img); if (dd.Pixels.Count < MinPix) { return(false); } int NoiseCnt = 0; int FixedCnt = 0; foreach (Image img in InputImages) { /* Noise scanner -- same position in pixel coordinates */ DotDetector.DotDetection detN = Recover(dd.Barycenter, Radius, img); PixelPoint npp = img.Transform.GetPixelPoint(Img.Transform.GetEquatorialPoint(dd.Barycenter)); /* Star scanner -- same position in equatorial coordinates */ DotDetector.DotDetection detF = Recover(npp, Radius, img); if (detN.Pixels.Count > NoisePixelThreshold * dd.Pixels.Count) { NoiseCnt++; } if (detF.Flux > StarFluxThreshold * dd.Flux) { EquatorialPoint org = DetPos.EP; EquatorialPoint nw = img.Transform.GetEquatorialPoint(detF.Barycenter); if ((org ^ nw) < MinMoveArcSec) { FixedCnt++; } } } if (NoiseCnt > CrossMatchRemove) { return(false); } if (FixedCnt > CrossMatchRemove) { return(false); } Recovered = StandardDetectionFactory.CreateDetection(Img, dd.Pixels, dd.PixelValues); return(true); }
/// <summary> /// The segment detector function. It calls the RLHT scorer and if line segments are sensed, it calls the LineAnalyzer to find the source blobs. /// </summary> /// <param name="Input">Input data.</param> /// <param name="Position">Position of the input data array in the image.</param> /// <param name="Data">Bag of algorithm parameters and data.</param> static void LTD_RLHT(double[,] Input, SchedCore.ImageSegmentPosition Position, LongTrailData Data) { /* Extracts the size of the input data */ int Height = Input.GetLength(0), Width = Input.GetLength(1); double Diagonal = Math.Sqrt(Width * Width + Height * Height); /* Initialize VPool */ lock (Data.AgData.VPool) if (Data.AgData.VPool.Constructor == null) { Data.AgData.VPool.Constructor = () => new List <Vector>(); } /* Applies the RLHT algorithm */ Data.AgData.StrongValueFunction = (x) => ThresholdComputer(x, Data, Diagonal); var Result = RLHT.SmartSkipRLHT(Input, Data.ImageParameters, Data.AgData); /* Prepare common data for the LineAnalyzer */ bool[,] Mask = new bool[Height, Width]; double SST = Data.SegmentSelectThreshold * Data.Sigma, SDT = Data.SegmentDropThreshold * Data.Sigma; int MIB = Data.MaxInterblobDistance, SW = Data.ScanWidth, pX = (int)Position.Alignment.X, pY = (int)Position.Alignment.Y; if (Data.DropCrowdedRegion) /* If the region is too crowded, it's very likely to be some luminous residue - for example star halos */ { if (Result.StrongPoints.Count > Diagonal) /* There is no deep meaning between this comparison; a reasonable Diagonal seems to correspond to a reasonable number of lines */ { goto clear_end; } } /* Analyze each possible trail line and store the detections */ foreach (Vector vx in Result.StrongPoints) { var z = LineAnalyzer.AnalyzeLine(Input, Mask, Height, Width, vx.X, vx.Y, SST, SDT, MIB, SW, pX, pY); lock (Data.Results) Data.Results.AddRange(z.Select((x) => StandardDetectionFactory.CreateDetection(Data.RunningImage, x.Points, x.PointValues))); } clear_end: /* Release resources */ Result.StrongPoints.Clear(); Data.AgData.HTPool.Release(); Data.AgData.VPool.Release(); }
/// <summary> /// Match detections and merge those that seem to belong to the same object. /// </summary> /// <param name="RawDetections">Input set of detections.</param> /// <param name="MaxDistance">Maximum distance possible between two detections part of the same object.</param> /// <param name="MixMatch">Number of overlapping pixels before two detections are considered part of the same object.</param> /// <param name="PSFMatch">Distance between the barycenters of 2 detections before they are considered the same (for external detections mostly).</param> public static void MatchDetections(List <ImageDetection> RawDetections, double MaxDistance, int MixMatch, double PSFMatch) { int i, j; List <HashSet <PixelPoint> > LHP = RawDetections.Select((x) => x.TryFetchProperty(out ObjectPoints op) ? new HashSet <PixelPoint>(op.PixelPoints) : null).ToList(); List <PairingProperties> PairPropList = RawDetections.Select((x) => x.TryFetchProperty(out PairingProperties Prop) ? Prop : null).ToList(); for (i = 0; i < RawDetections.Count; i++) { for (j = i + 1; j < RawDetections.Count; j++) { /* Must be two detections captured at the same time */ if (RawDetections[i].Time.Time != RawDetections[j].Time.Time) { continue; } /* Check distance */ double D0 = (RawDetections[i].Barycenter.PP ^ RawDetections[j].Barycenter.PP); double D1 = (RawDetections[i].FetchProperty <ObjectSize>().PixelEllipse.SemiaxisMajor + RawDetections[j].FetchProperty <ObjectSize>().PixelEllipse.SemiaxisMajor); if (D0 - D1 > MaxDistance) { continue; } HashSet <PixelPoint> PixPi = LHP[i], PixPj = LHP[j]; bool FlagAnyCond = false; /* If there are MinPix overlapping pixels, merge detections */ if (PixPi != null & PixPj != null) { if (PixPi.Overlaps(PixPj)) { FlagAnyCond = true; } if (!FlagAnyCond) { /* Detections that are somewhat linear are checked for colinearity with others */ IEnumerable <PixelPoint> Plist = PixPi.Concat(PixPj); LinearRegression.LinearRegressionParameters pc = LinearRegression.ComputeLinearRegression(Plist); LinearRegression.LinearRegressionParameters p1 = LinearRegression.ComputeLinearRegression(PixPi); LinearRegression.LinearRegressionParameters p2 = LinearRegression.ComputeLinearRegression(PixPj); if (Math.Abs(pc.PearsonR) > Math.Abs(p1.PearsonR) && Math.Abs(pc.PearsonR) > Math.Abs(p2.PearsonR) && Math.Abs(pc.PearsonR) < Math.Abs(p1.PearsonR) + Math.Abs(p2.PearsonR)) { FlagAnyCond = true; } } } if (D0 < PSFMatch) { FlagAnyCond = true; } /* If any merging condition is satisfied, merge the detections */ if (FlagAnyCond) { if (LHP[i] != null & LHP[j] != null) { LHP[i].UnionWith(LHP[j]); } else if (LHP[i] == null) { LHP[i] = LHP[j]; } if (PairPropList[i] != null && PairPropList[j] != null) { PairPropList[i].Algorithm |= PairPropList[i].Algorithm; } LHP.RemoveAt(j); RawDetections.RemoveAt(j); PairPropList.RemoveAt(j); j--; } } } for (i = 0; i < LHP.Count; i++) { if (LHP[i] != null) { try { RawDetections[i] = StandardDetectionFactory.CreateDetection(RawDetections[i].ParentImage, LHP[i]); if (PairPropList[i] != null) { RawDetections[i].SetResetProperty(PairPropList[i]); } } catch { RawDetections.RemoveAt(i); PairPropList.RemoveAt(i); LHP.RemoveAt(i); i--; } } } }