/// <summary> /// Parses a Source Extractor catalog file. /// </summary> /// <returns>The detections in the catalog.</returns> /// <param name="Lines">Catalog file lines.</param> /// <param name="AssociatedImage">Image to which the catalog is associated to.</param> public static List <ImageDetection> ParseSEFile(IEnumerable <string> Lines, FitsImage AssociatedImage) { List <string> ColList = new List <string>(); Dictionary <string, int> Columns = new Dictionary <string, int>(); List <ObsEntry> Entries = new List <ObsEntry>(); foreach (string Line in Lines) { if (Line[0] == '#') { string[] Hdata = Line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); if (Hdata[0] != "#") { throw new FormatException("Cannot understand SE file"); } int CNum = int.Parse(Hdata[1]) - 1; string CName = Hdata[2]; ColList.Add(CName); Columns.Add(CName, CNum); } else { string[] Ldata = Line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); ObsEntry Entry = new ObsEntry(); Entry.Flux = Parse(Columns, Ldata, "FLUX_AUTO"); Entry.Mag = Parse(Columns, Ldata, "MAG_AUTO"); Entry.X = Parse(Columns, Ldata, "X_IMAGE").Value; Entry.Y = Parse(Columns, Ldata, "Y_IMAGE").Value; Entry.RA = Parse(Columns, Ldata, "ALPHA_J2000").Value; Entry.Dec = Parse(Columns, Ldata, "DELTA_J2000").Value; Entry.FWHM = Parse(Columns, Ldata, "FWHM_IMAGE"); Entry.Ellipticity = Parse(Columns, Ldata, "ELLIPTICITY"); Entry.A = Parse(Columns, Ldata, "A_IMAGE"); Entry.B = Parse(Columns, Ldata, "B_IMAGE"); Entry.Flags = (int)Parse(Columns, Ldata, "FLAGS"); if (!Entry.Flags.HasValue || Entry.Flags.Value < 4) { Entries.Add(Entry); } } } List <ImageDetection> Detections = Entries.Select((x) => Transform(x, AssociatedImage)).ToList(); return(Detections); }
private void DetectionDebugMap(string RunDir, int i, List <ImageDetection> LocalDetectionList, FitsImage DetectionSource) { FICHV Header = DetectionSource.CopyHeader().ChangeBitPix(16); MMapFitsFile DeOutput = MMapFitsFile.OpenWriteFile(RunDir + "DOutMap" + i.ToString() + ".fits", Header.Header); FitsImage DeOutIm = new FitsImage(DeOutput); var DeData = DeOutIm.LockData(new System.Drawing.Rectangle(0, 0, (int)DetectionSource.Width, (int)DetectionSource.Height), false, false); foreach (ImageDetection xi in LocalDetectionList) { int kat = 200 + LocalDetectionList.IndexOf(xi); if (xi.TryFetchProperty(out ObjectPoints pts)) { foreach (var pt in pts.PixelPoints) { try { DeData.Data[(int)pt.Y, (int)pt.X] = kat; } catch { break; } } } } DeOutIm.ExitLock(DeData); Logger("Exported detections map"); }
public void RunPipeline <T>(PositionDependentMap <T> Map, string Name, int Number, ref FitsImage Pipeline, T Argument, AlgorithmRunParameters Parameters) { bool Value = EnsureImage(Name, Number, out FitsImage Result); if (!Value) { Map.Run(Argument, Pipeline, Result, Parameters); } Result.GetProperty <ImageSource>().AddToSet(Pipeline, Name); Pipeline = Result; LogHookImage(!Value, Name, Number); }
public List <ImageDetection> RunDetector(Func <FitsImage, List <ImageDetection> > Detector, FitsImage Image, string DetectorName, DetectionAlgorithm Algo) { var Detections = Detector(Image); if (Detections.Count > MaxDetections) { LogMessage(DetectorName, "Too many detections. Check detector settings."); return(new List <ImageDetection>()); } foreach (var d in Detections) { if (d.TryFetchProperty(out PairingProperties pp)) { pp.Algorithm = Algo; } else { d.AppendProperty(new PairingProperties() { Algorithm = Algo }); } } AllDetections.AddRange(Detections); AllDetectionCenters.AddRange(Detections.Select((x) => x.Barycenter.EP)); LogHookDetection(DetectorName, Detections.Count); return(Detections); }
static ImageDetection Transform(ObsEntry Entry, FitsImage AssociatedImage) { EquatorialPoint eqp = new EquatorialPoint() { RA = Entry.RA / 180 * Math.PI, Dec = Entry.Dec / 180 * Math.PI }; PixelPoint pp = new PixelPoint() { X = Entry.X, Y = Entry.Y }; Position p = new Position(eqp, pp); ImageDetection det = new ImageDetection(p, AssociatedImage.GetProperty <ObservationTime>(), AssociatedImage); bool Ellipse = false; ObjectSize sz = new ObjectSize(); if (Entry.A.HasValue && Entry.B.HasValue) { sz.PixelEllipse = new SourceEllipse() { SemiaxisMajor = Entry.A.Value, SemiaxisMinor = Entry.B.Value }; Ellipse = true; } else if (Entry.FWHM.HasValue && Entry.Ellipticity.HasValue) { sz.PixelEllipse = new SourceEllipse() { SemiaxisMajor = Entry.FWHM.Value / Math.Sqrt(1 - Entry.Ellipticity.Value), SemiaxisMinor = Entry.FWHM.Value * Math.Sqrt(1 - Entry.Ellipticity.Value), }; Ellipse = true; } if (Ellipse) { if (Entry.EllipseTheta.HasValue) { sz.PixelEllipse.SemiaxisMajorAngle = Entry.EllipseTheta.Value / 180 * Math.PI; } det.AppendProperty(sz); } PairingProperties pprop = new PairingProperties() { IsDotDetection = Ellipse && (sz.PixelEllipse.SemiaxisMajor < 2 * sz.PixelEllipse.SemiaxisMinor), IsPaired = false, PearsonR = 0, StarPolluted = false, Algorithm = DetectionAlgorithm.SourceExtractor }; det.AppendProperty(pprop); if (Entry.Flux.HasValue) { ObjectPhotometry oph = new ObjectPhotometry() { Flux = Entry.Flux.Value, Magnitude = Entry.Mag.Value }; det.AppendProperty(oph); } return(det); }
public List <Tracklet> AnalyzeCCD(PipelineArguments Args) { Logger("Setting up pipeline"); /* Deal with incorrect SWARP flux scaling */ SWarpScaling.ApplyTransform = CorrectSWARP; string RunDir = Args.RunDir; if (!Directory.Exists(RunDir)) { Directory.CreateDirectory(RunDir); } /* Read input images and preprocess for poisson noise */ int ImageCount = Args.Inputs.Length; FitsImage[] FirstProcess = new FitsImage[ImageCount]; double[] PFW = PipelineHelperFunctions.LinearizedPoissonKernel(PoissonRadius); Step.StepPipeline sp = new Step.StepPipeline(StandardBITPIX, RunDir, Args.Inputs.Length, MaxDetections); sp.LogHookImage = LogImage; sp.LogHookDetection = LogDet; sp.LogMessage = LogMessage; bool HasBadpix = Args.Badpixel != null; Logger("Begining to run the pipeline"); var zpTask = System.Threading.Tasks.Task <Dictionary <IO.Image, double> > .Factory.StartNew(() => CalibrateZP(Args.Inputs)); var skTask = System.Threading.Tasks.Task <bool> .Factory.StartNew(() => PrecacheSkyBot(Args.Inputs)); BitArray[] map = PipelineHelperFunctions.ExtractBadpixel(Args.Badpixel, Logger); for (int i = 0; i < ImageCount; i++) { FitsImage Pipeline = Args.Inputs[i]; Pipeline.GetProperty <ImageSource>().AddToSet(Pipeline, "Original"); sp.SetModel(i, Pipeline, new List <IO.ImageProperties>() { Pipeline.GetProperty <ObservationTime>() }); if (!UseCoreFilter) { sp.RunPipeline(RestrictedMean.RestrictedMeanFilter, "Poisson", i, ref Pipeline, PFW, RestrictedMean.Parameters(PoissonRadius)); } else if (HasBadpix) { sp.RunPipeline(CoreFilter.Filter, "Poisson", i, ref Pipeline, new CoreFilter.CoreFilterParameters(PFW, map), CoreFilter.Parameters(PoissonRadius)); } else { throw new ArgumentException("Must specify Badpixel files if trying to run with CoreFilter"); } if (Operations.HasFlag(EnabledOperations.Normalization)) { if (!sp.EnsureImage("Normalized", i, out FitsImage Normalized)) { Point4Distance p4d = new Point4Distance(Pipeline, Normalized, NormalizationMeshSize); Logger("Generated Normalized image " + i); } else { Logger("Found Normalized image " + i); } Normalized.GetProperty <ImageSource>().AddToSet(Args.Inputs[i], "Normalized"); Pipeline = Normalized; } FirstProcess[i] = Pipeline; } /* Create the central median */ string CentralPath = Path.Combine(RunDir, "Central.fits"); if (!sp.EnsureCentralImage("Central", out FitsImage Central)) { HardMedians.MultiImageMedian.Run(null, FirstProcess, Central, HardMedians.MultiImageMedianParameters); Logger("Generated Central image"); } else { Logger("Found Central image"); } Logger("Computed the multi-image median"); /* Prepare the mask, slow object detector, trail detector, weights for second median filtering, etc. */ ImageStatistics CentralStats = new ImageStatistics(Central); if (Args.Clipped) { CentralStats = new ImageStatistics(Central, CentralStats.ZeroLevel, 2 * CentralStats.StDev); } StarData StarList = new StarData(); ComputeDetectorData(Central, CentralStats, StarList, out MaskByMedian.MaskProperties MaskProp, out DotDetector SlowDetector, out LongTrailDetector.LongTrailData LTD); if (Args.Clipped) { SlowDetector.HighThresholdMultiplier *= 2; SlowDetector.LowThresholdMultiplier *= 2; } DetectionReducer dr = new DetectionReducer() { PairingRadius = 0.7 }; if (Operations.HasFlag(EnabledOperations.SourceExtractor)) { try { dr.LoadStars(StarList.FixedStarList); } catch (Exception ex) { throw new ArgumentException("Could not read detections from SE catalog.", ex); } dr.GeneratePool(); } Logger("Set up detectors"); List <ImageDetection> FullDetectionsList = new List <ImageDetection>(); double[] FMW2 = PipelineHelperFunctions.LinearizedMedianKernel(); LTLimit ltl = new LTLimit() { MinPix = TrailMinPix }; RipFilter rf = new RipFilter() { SigmaTop = 30 }; Logger("Ready for final image processing and detection"); for (int i = 0; i < ImageCount; i++) { List <ImageDetection> LocalDetectionList = new List <ImageDetection>(); FitsImage DetectionSource = FirstProcess[i]; if (Operations.HasFlag(EnabledOperations.Masking)) { sp.RunPipeline(MaskByMedian.Masker, "Masked", i, ref DetectionSource, MaskProp, MaskByMedian.Parameters); } if (Operations.HasFlag(EnabledOperations.SecondMedian)) { sp.RunPipeline(HardMedians.WeightedMedian, "Second Median", i, ref DetectionSource, FMW2, HardMedians.WeightedMedianParameters(SecMedRadius)); } ImageStatistics SecMedStat = new ImageStatistics(DetectionSource); if (Operations.HasFlag(EnabledOperations.LongTrailDetector)) { var Dets = sp.RunDetector((FitsImage img) => { LongTrailDetector.PrepareAlgorithmForImage(img, SecMedStat, ref LTD); LongTrailDetector.Algorithm.Run(LTD, DetectionSource, LongTrailDetector.Parameters); return(LTD.Results); }, DetectionSource, "Trail", DetectionAlgorithm.Trail); LocalDetectionList.AddRange(Dets); } if (Operations.HasFlag(EnabledOperations.BlobDetector)) { var Dets = sp.RunDetector(SlowDetector.Detect, DetectionSource, "Blob", DetectionAlgorithm.Blob); LocalDetectionList.AddRange(Dets); } if (Operations.HasFlag(EnabledOperations.SourceExtractor)) { var dts = sp.RunDetector((arg) => { List <ImageDetection> Dets = ExtraIO.SourceExtractor.ParseSEFile(Args.CatalogData[i], Args.Inputs[i]); Dets = Dets.Where((x) => x.FetchProperty <ObjectPhotometry>().Flux > 300).ToList(); var ND = dr.Reduce(Dets); return(ND); }, DetectionSource, "SE", DetectionAlgorithm.SourceExtractor); LocalDetectionList.AddRange(dts); } if (Operations.HasFlag(EnabledOperations.OutputDetectionMap)) { DetectionDebugMap(RunDir, i, LocalDetectionList, DetectionSource); } rf.ImgMean = SecMedStat.ZeroLevel; rf.ImgSigma = SecMedStat.StDev; var NLDL = sp.RunFilters(LocalDetectionList, "LocalToGlobal", ltl, rf); Logger("Total " + NLDL.Count + " detections."); FullDetectionsList.AddRange(NLDL); } Logger("Filtering and pairing detections..."); LinearityThresholdFilter LTF = new LinearityThresholdFilter() { MaxLineThickness = MaxLineThickness }; List <ImageDetection> FilteredDetections = sp.RunFilters(FullDetectionsList, "MainFilter", LTF); StarList.MarkStarCrossed(FilteredDetections, StarCrossRadiusM, StarCrossMinFlux); if (Args.CCDBadzone != null) { FilteredDetections = sp.RunFilters(FilteredDetections, "Badzone", Args.CCDBadzone); } Logger("Before PrePair " + FilteredDetections.Count); PrePair.MatchDetections(FilteredDetections, MaxPairmatchDistance, MixMatch, SameArcSep); Logger("Left with " + FilteredDetections.Count + " detections"); LinePoolSimple lps = new LinePoolSimple() { MaxLinErrorArcSec = MaxResidual, SearchExtraSmall = SmallExtraSearchRadius, SearchExtraBig = BigExtraSearchRadius }; lps.LoadDetections(FilteredDetections); lps.GeneratePool(); var Pairings = lps.FindTracklets(); sp.NotePairings(FilteredDetections, Pairings); Logger("Found " + Pairings.Count + " raw tracklets"); LinearityTest lintest = new LinearityTest(); StaticFilter stf = new StaticFilter(); TotalError te = new TotalError(); var TK2List = sp.RunFilters(Pairings, "Tracklet Filtering", stf, te); Logger("After filtering: " + TK2List.Count + " candidate objects found"); sp.LogDetections(Path.Combine(RunDir, "detlog.txt")); Dictionary <IO.Image, double> ZP = zpTask.Result; skTask.Wait(); var Recovered = RecoverTracklets(TK2List, Args.Inputs, Path.Combine(RunDir, "reclog.txt"), ZP); TrackletsDeduplication.Deduplicate(Recovered, 1.0); Logger("Recovered " + Recovered.Count + " candidate objects"); PairSkyBot(Recovered, SkyBoTDistance, Args.FieldName, Args.CCDNumber, Args.Inputs, sp); return(Recovered); }