public AstrometricSolutionImpl(LeastSquareFittedAstrometry astrometry, StarMagnitudeFit photometry, AstrometricState state, FieldSolveContext fieldSolveContext, MeasurementContext measurementContext) { StarCatalog = fieldSolveContext.StarCatalogueFacade.CatalogNETCode; UtcTime = fieldSolveContext.UtcTime; FrameNoOfUtcTime = fieldSolveContext.FrameNoOfUtcTime; AutoLimitMagnitude = (float)fieldSolveContext.AutoLimitMagnitude; ResolvedFocalLength = (float)fieldSolveContext.FocalLength; if (astrometry != null) { ResolvedCenterRADeg = (float)astrometry.RA0Deg; ResolvedCenterDEDeg = (float)astrometry.DE0Deg; StdDevRAArcSec = (float)astrometry.StdDevRAArcSec; StdDevDEArcSec = (float)astrometry.StdDevDEArcSec; ArcSecsInPixel = 1 / astrometry.GetDistanceInPixels(1); } else { ResolvedCenterRADeg = float.NaN; ResolvedCenterDEDeg = float.NaN; StdDevRAArcSec = float.NaN; StdDevDEArcSec = float.NaN; ArcSecsInPixel = 0; } if (state.SelectedObject != null) { m_UserObject = new TangraUserObjectImpl(); m_UserObject.RADeg = (float)state.SelectedObject.RADeg; m_UserObject.DEDeg = (float)state.SelectedObject.DEDeg; m_UserObject.X = (float)state.SelectedObject.X0; m_UserObject.Y = (float)state.SelectedObject.Y0; if (state.IdentifiedObjects != null && state.IdentifiedObjects.Count == 1) { foreach (IIdentifiedObject idObj in state.IdentifiedObjects) { if (AngleUtility.Elongation(idObj.RAHours * 15.0, idObj.DEDeg, state.SelectedObject.RADeg, state.SelectedObject.DEDeg) * 3600 < 120) { m_UserObject.ResolvedName = idObj.ObjectName; break; } } } } InstrumentalDelay = measurementContext.InstrumentalDelay; InstrumentalDelayUnits = measurementContext.InstrumentalDelayUnits.ToString(); FrameTimeType = measurementContext.FrameTimeType.ToString(); IntegratedFramesCount = measurementContext.IntegratedFramesCount; IntegratedExposureSeconds = measurementContext.IntegratedExposureSeconds; AavIntegration = measurementContext.AavIntegration; AavStackedMode = measurementContext.AavStackedMode; VideoFileFormat = measurementContext.VideoFileFormat.ToString(); NativeVideoFormat = measurementContext.NativeVideoFormat; if (!string.IsNullOrEmpty(state.IdentifiedObjectToMeasure)) { ObjectDesignation = MPCObsLine.GetObjectCode(state.IdentifiedObjectToMeasure); } else if (state.IdentifiedObjects != null && state.IdentifiedObjects.Count == 1) { ObjectDesignation = MPCObsLine.GetObjectCode(state.IdentifiedObjects[0].ObjectName); } ObservatoryCode = fieldSolveContext.ObsCode; CatalogueCode = measurementContext.StarCatalogueFacade.CatalogNETCode; m_MeasurementsImpl = new List <TangraAstrometricMeasurementImpl>(); if (state.Measurements != null) { foreach (var mea in state.Measurements) { m_MeasurementsImpl.Add(new TangraAstrometricMeasurementImpl() { DEDeg = mea.DEDeg, RADeg = mea.RADeg, FrameNo = mea.FrameNo, SolutionUncertaintyRACosDEArcSec = mea.SolutionUncertaintyRACosDEArcSec, SolutionUncertaintyDEArcSec = mea.SolutionUncertaintyDEArcSec, FWHMArcSec = mea.FWHMArcSec, Detection = mea.Detection, SNR = mea.SNR, UncorrectedTimeStamp = mea.FrameTimeStamp, Mag = mea.Mag }); } } m_MatchedStarImpl = new List <TangraMatchedStarImpl>(); if (astrometry != null) { foreach (PlateConstStarPair pair in astrometry.FitInfo.AllStarPairs) { if (pair.FitInfo.UsedInSolution) { var star = new TangraMatchedStarImpl() { X = (float)pair.x, Y = (float)pair.y, RADeg = (float)pair.RADeg, DEDeg = (float)pair.DEDeg, StarNo = pair.StarNo, ExcludedForHighResidual = pair.FitInfo.ExcludedForHighResidual, ResidualRAArcSec = (float)pair.FitInfo.ResidualRAArcSec, ResidualDEArcSec = (float)pair.FitInfo.ResidualDEArcSec, DetectionCertainty = (float)pair.DetectionCertainty, PSFAmplitude = (int)pair.Intensity, IsSaturated = pair.IsSaturated, Mag = (float)pair.Mag }; TangraCatalogStarImpl catStar = null; IStar catalogStar = fieldSolveContext.CatalogueStars.Find(s => s.StarNo == pair.StarNo); if (catalogStar != null) { if (catalogStar is UCAC4Entry) { catStar = new TangraAPASSStar(); } else { catStar = new TangraCatalogStarImpl(); } catStar.StarNo = catalogStar.StarNo; catStar.MagR = (float)catalogStar.MagR; catStar.MagV = (float)catalogStar.MagV; catStar.MagB = (float)catalogStar.MagB; catStar.Mag = (float)catalogStar.Mag; if (catalogStar is UCAC3Entry) { UCAC3Entry ucac3Star = (UCAC3Entry)catalogStar; catStar.MagJ = (float)(ucac3Star.jmag * 0.001); catStar.MagK = (float)(ucac3Star.kmag * 0.001); catStar.RAJ2000Deg = (float)ucac3Star.RACat; catStar.DEJ2000Deg = (float)ucac3Star.DECat; } else if (catalogStar is UCAC2Entry) { UCAC2Entry ucac2Star = (UCAC2Entry)catalogStar; catStar.MagJ = (float)(ucac2Star._2m_J * 0.001); catStar.MagK = (float)(ucac2Star._2m_Ks * 0.001); catStar.RAJ2000Deg = (float)ucac2Star.RACat; catStar.DEJ2000Deg = (float)ucac2Star.DECat; } else if (catalogStar is NOMADEntry) { NOMADEntry nomadStar = (NOMADEntry)catalogStar; catStar.MagJ = (float)(nomadStar.m_J * 0.001); catStar.MagK = (float)(nomadStar.m_K * 0.001); catStar.RAJ2000Deg = (float)nomadStar.RACat; catStar.DEJ2000Deg = (float)nomadStar.DECat; } else if (catalogStar is UCAC4Entry) { UCAC4Entry ucac4Star = (UCAC4Entry)catalogStar; catStar.MagJ = (float)(ucac4Star.MagJ); catStar.MagK = (float)(ucac4Star.MagK); catStar.RAJ2000Deg = (float)ucac4Star.RACat; catStar.DEJ2000Deg = (float)ucac4Star.DECat; ((TangraAPASSStar)catStar).B = (float)ucac4Star.MagB; ((TangraAPASSStar)catStar).V = (float)ucac4Star.MagV; ((TangraAPASSStar)catStar).g = (float)ucac4Star.Mag_g; ((TangraAPASSStar)catStar).r = (float)ucac4Star.Mag_r; ((TangraAPASSStar)catStar).i = (float)ucac4Star.Mag_i; ((TangraAPASSStar)catStar).e_B = ucac4Star.apase_B * 0.001f; ((TangraAPASSStar)catStar).e_V = ucac4Star.apase_V * 0.001f; ((TangraAPASSStar)catStar).e_g = ucac4Star.apase_g * 0.001f; ((TangraAPASSStar)catStar).e_r = ucac4Star.apase_r * 0.001f; ((TangraAPASSStar)catStar).e_i = ucac4Star.apase_i * 0.001f; } } star.CatalogStar = catStar; if (photometry != null) { IStar photometryStar = photometry.StarNumbers.FirstOrDefault(s => s.StarNo == pair.StarNo); if (photometryStar != null) { int idx = photometry.StarNumbers.IndexOf(photometryStar); star.Intensity = (float)photometry.Intencities[idx]; star.IsSaturated = photometry.SaturatedFlags[idx]; star.MeaSignalMethod = ConvertSignalMethod(photometry.MeaSignalMethod); star.MeaBackgroundMethod = ConvertBackgroundMethod(photometry.MeaBackgroundMethod); star.MeaSingleApertureSize = photometry.MeaSingleAperture; star.MeaBackgroundPixelCount = photometry.MeaBackgroundPixelCount; star.MeaSaturationLevel = photometry.MeaSaturationLevel; } } m_MatchedStarImpl.Add(star); } } } }
public Bitmap ResolveObjects( TangraConfig.PhotometryReductionMethod photometryReductionMethod, TangraConfig.PsfQuadrature psfQuadrature, TangraConfig.PsfFittingMethod psfFittingMethod, TangraConfig.BackgroundMethod backgroundMethod, TangraConfig.PreProcessingFilter filter, Guid magnitudeBandId, Rectangle osdRectangleToExclude, Rectangle rectToInclude, bool limitByInclusion, IAstrometrySettings astrometrySettings, ObjectResolverSettings objectResolverSettings) { m_AstrometrySettings = astrometrySettings; StarMap starMap = new StarMap( astrometrySettings.PyramidRemoveNonStellarObject, astrometrySettings.MinReferenceStarFWHM, astrometrySettings.MaxReferenceStarFWHM, astrometrySettings.MaximumPSFElongation, astrometrySettings.LimitReferenceStarDetection); starMap.FindBestMap(StarMapInternalConfig.Default, m_Image, osdRectangleToExclude, rectToInclude, limitByInclusion); float r0 = 0; m_MagnitudeFit = StarMagnitudeFit.PerformFit( m_AstrometryController, m_VideoController, m_Image.Pixelmap.BitPixCamera, m_Image.Pixelmap.MaxSignalValue, m_Astrometry.FitInfo, photometryReductionMethod, psfQuadrature, psfFittingMethod, backgroundMethod, filter, m_Stars, magnitudeBandId, 1.0f, TangraConfig.KnownCameraResponse.Undefined, null, null, null, ref r0); m_BackgroundFlux = m_MagnitudeFit.GetBackgroundIntencity(); m_BackgroundMag = m_MagnitudeFit.GetMagnitudeForIntencity(m_BackgroundFlux); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Trace.WriteLine(string.Format("Plate FWHM: {0}", 2 * Math.Sqrt(Math.Log(2)) * r0)); } PeakPixelResolver resolver = new PeakPixelResolver(m_Image); resolver.ResolvePeakPixels(osdRectangleToExclude, rectToInclude, limitByInclusion, objectResolverSettings.ExcludeEdgeAreaPixels, objectResolverSettings.MinDistanceBetweenPeakPixels); List <double> identifiedMagnitudes = new List <double>(); List <double> identifiedR0s = new List <double>(); m_IdentifiedObjects.Clear(); m_UidentifiedObjects.Clear(); foreach (KeyValuePair <int, int> peakPixel in resolver.PeakPixels.Keys) { int x = peakPixel.Key; int y = peakPixel.Value; bool isSaturated; double intencity = m_MagnitudeFit.GetIntencity(new ImagePixel(255, x, y), out isSaturated); double magnitude = m_MagnitudeFit.GetMagnitudeForIntencity(intencity); if (magnitude < m_MaxMagForAstrometry) { double RADeg, DEDeg; PSFFit fit; starMap.GetPSFFit(x, y, PSFFittingMethod.NonLinearFit, out fit); if (fit.IMax < 0) { continue; } if (fit.IMax < fit.I0) { continue; } if (fit.Certainty < objectResolverSettings.MinCertainty) { continue; } if (fit.FWHM < objectResolverSettings.MinFWHM) { continue; } if (fit.IMax - fit.I0 < objectResolverSettings.MinAmplitude) { continue; } m_Astrometry.GetRADEFromImageCoords(fit.XCenter, fit.YCenter, out RADeg, out DEDeg); // All stars closer than 2 arcsec to this position List <IStar> matchingStars = m_Stars.Where(s => Math.Abs(AngleUtility.Elongation(s.RADeg, s.DEDeg, RADeg, DEDeg) * 3600.0) < objectResolverSettings.MaxStarMatchMagDif).ToList(); bool identified = false; if (matchingStars.Count >= 1) { foreach (IStar star in matchingStars) { if (objectResolverSettings.MaxStarMatchMagDif >= Math.Abs(magnitude - star.Mag)) { // The star is identified. Do we care more? if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Trace.WriteLine(string.Format("STAR ({0}, {1}) No -> {2}; Mag -> {3} (Expected: {4}); R0 = {5}", x, y, star.StarNo, magnitude.ToString("0.00"), star.Mag.ToString("0.00"), fit.R0.ToString("0.0"))); } identifiedMagnitudes.Add(magnitude); identifiedR0s.Add(fit.R0); m_IdentifiedObjects.Add(fit, star); identified = true; break; } } } if (matchingStars.Count == 0 || !identified) { // The object is not in the star database // TODO: Test for hot pixel. Match to hot pixel profile from the brightest pixel in the area m_UidentifiedObjects.Add(fit, magnitude); } } else { // Don't bother with too faint objects } } if (m_IdentifiedObjects.Count > 0) { double mean = identifiedR0s.Average(); double variance = 0; foreach (double rr0 in identifiedR0s) { variance += (rr0 - mean) * (rr0 - mean); } variance = Math.Sqrt(variance / (m_IdentifiedObjects.Count - 1)); double minR0 = mean - variance; double maxR0 = mean + variance; identifiedMagnitudes.Sort(); double maxStarMag = identifiedMagnitudes[Math.Max(0, (int)Math.Truncate(0.9 * identifiedMagnitudes.Count))]; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Trace.WriteLine(string.Format("Max Star Mag: {0}; R0 ({1}, {2})", maxStarMag.ToString("0.00"), minR0.ToString("0.0"), maxR0.ToString("0.0"))); } // NOTE: The R0 exclusion may ignore bright comets ! m_UnknownObjects = m_UidentifiedObjects .Where(p => p.Value < maxStarMag && p.Key.R0 >= minR0 && p.Key.R0 <= maxR0) .ToDictionary(p => p.Key, p => p.Value); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { foreach (PSFFit obj in m_UnknownObjects.Keys) { Trace.WriteLine(string.Format("UNK: ({0}, {1}) Mag -> {2}; R0 = {3}", obj.XCenter.ToString("0.0"), obj.YCenter.ToString("0.0"), m_UnknownObjects[obj].ToString("0.00"), obj.R0.ToString("0.0"))); } } } Bitmap bitmap = m_Image.Pixelmap.CreateDisplayBitmapDoNotDispose(); using (Graphics g = Graphics.FromImage(bitmap)) { foreach (PSFFit star in m_IdentifiedObjects.Keys) { float x = (float)star.XCenter; float y = (float)star.YCenter; g.DrawEllipse(Pens.GreenYellow, x - 5, y - 5, 10, 10); } foreach (PSFFit star in m_UnknownObjects.Keys) { float x = (float)star.XCenter; float y = (float)star.YCenter; g.DrawEllipse(Pens.Tomato, x - 8, y - 8, 16, 16); } g.Save(); } return(bitmap); }
public FocalLengthFit ComputeFocalLengthFit() { if (m_FocalLengthFit != null) { return(m_FocalLengthFit); } List <DistSolveEntry> entries = new List <DistSolveEntry>(); for (int i = 0; i < m_Pairs.Count; i++) { if (!m_Pairs[i].FitInfo.UsedInSolution) { continue; } if (m_Pairs[i].FitInfo.ExcludedForHighResidual) { continue; } for (int j = 0; j < m_Pairs.Count; j++) { if (i == j) { continue; } if (!m_Pairs[j].FitInfo.UsedInSolution) { continue; } if (m_Pairs[j].FitInfo.ExcludedForHighResidual) { continue; } DistSolveEntry entry = new DistSolveEntry(); entry.DX = Math.Abs(m_Pairs[i].x - m_Pairs[j].x); entry.DY = Math.Abs(m_Pairs[i].y - m_Pairs[j].y); entry.StarNo1 = m_Pairs[i].StarNo; entry.StarNo2 = m_Pairs[j].StarNo; // NOTE: two ways of computing distances - by vx,vy,vz and Elongation() //entry.DistRadians = Math.Acos(m_Pairs[i].VX * m_Pairs[j].VX + m_Pairs[i].VY * m_Pairs[j].VY + m_Pairs[i].VZ * m_Pairs[j].VZ); double elong = AngleUtility.Elongation(m_Pairs[i].RADeg, m_Pairs[i].DEDeg, m_Pairs[j].RADeg, m_Pairs[j].DEDeg); entry.DistRadians = elong * Math.PI / 180.0; if (entry.DX == 0 || entry.DY == 0) { continue; } entries.Add(entry); } } SafeMatrix A = new SafeMatrix(entries.Count, 2); SafeMatrix X = new SafeMatrix(entries.Count, 1); int numStars = 0; foreach (DistSolveEntry entry in entries) { A[numStars, 0] = entry.DX * entry.DX; A[numStars, 1] = entry.DY * entry.DY; X[numStars, 0] = entry.DistRadians * entry.DistRadians; numStars++; } // Insufficient stars to solve the plate if (numStars < 3) { return(null); } SafeMatrix a_T = A.Transpose(); SafeMatrix aa = a_T * A; SafeMatrix aa_inv = aa.Inverse(); SafeMatrix bx = (aa_inv * a_T) * X; double a = bx[0, 0]; double b = bx[1, 0]; double residualSum = 0; int numResiduals = 0; foreach (DistSolveEntry entry in entries) { entry.ResidualRadians = entry.DistRadians - Math.Sqrt(a * entry.DX * entry.DX + b * entry.DY * entry.DY); entry.ResidualPercent = entry.ResidualRadians * 100.0 / entry.DistRadians; entry.ResidualArcSec = 3600.0 * entry.ResidualRadians * 180.0 / Math.PI; numResiduals++; residualSum += entry.ResidualRadians * entry.ResidualRadians; } double variance = Math.Sqrt(residualSum / (numResiduals - 1)); return(new FocalLengthFit(a, b, variance, entries)); }
internal static List <SearchZone> GetZones(double raDeg, double deDeg, double radiusDeg) { raDeg = AngleUtility.Range(raDeg, 360); List <SearchZone> zones = new List <SearchZone>(); double deFrom = deDeg - radiusDeg / 2.0; double deTo = deDeg + radiusDeg / 2.0;; if (deFrom < -90) { deTo = deDeg + Math.Max(Math.Abs(deFrom + 90), radiusDeg / 2.0); deFrom = -90; } else if (deTo > 90) { deFrom = 90 - Math.Max(Math.Abs(deTo - 90), radiusDeg / 2.0); deTo = 90; } double aspect = Math.Cos(Math.Max(Math.Abs(deFrom), Math.Abs(deTo)) * Math.PI / 180); double raFrom = raDeg - (radiusDeg / (2.0 * aspect)); double raTo = raDeg + (radiusDeg / (2.0 * aspect)); if (raTo - raFrom > 360) { raFrom = 0; raTo = 360; } if (raFrom < 0) { // 2 zones: raFrom..360; 0..raTo raFrom = AngleUtility.Range(raFrom, 360); zones.Add(new SearchZone { RAFrom = raFrom, RATo = 360, DEFrom = deFrom, DETo = deTo }); zones.Add(new SearchZone { RAFrom = 0, RATo = raTo, DEFrom = deFrom, DETo = deTo }); } else if (raTo > 360) { // 2 zones: raFrom..360; 0..raTo raTo = AngleUtility.Range(raTo, 360); zones.Add(new SearchZone { RAFrom = raFrom, RATo = 360, DEFrom = deFrom, DETo = deTo }); zones.Add(new SearchZone { RAFrom = 0, RATo = raTo, DEFrom = deFrom, DETo = deTo }); } else { zones.Add(new SearchZone { RAFrom = raFrom, RATo = raTo, DEFrom = deFrom, DETo = deTo }); } return(zones); }
public ThreeStarAstrometry(AstroPlate image, Dictionary <ImagePixel, IStar> userStarIdentification, int tolerance) { if (userStarIdentification.Count != 3) { throw new InvalidOperationException(); } Image = image; UserStars = userStarIdentification.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); double a0 = userStarIdentification.Values.Average(x => x.RADeg) * DEG_TO_RAD; double d0 = userStarIdentification.Values.Average(x => x.DEDeg) * DEG_TO_RAD; double corr = double.MaxValue; int attempts = 0; do { SafeMatrix AX = new SafeMatrix(3, 3); SafeMatrix X = new SafeMatrix(3, 1); SafeMatrix AY = new SafeMatrix(3, 3); SafeMatrix Y = new SafeMatrix(3, 1); int i = 0; foreach (var pixel in userStarIdentification.Keys) { IStar star = userStarIdentification[pixel]; double a = star.RADeg * DEG_TO_RAD; double d = star.DEDeg * DEG_TO_RAD; AX[i, 0] = pixel.XDouble; AX[i, 1] = pixel.YDouble; AX[i, 2] = 1; AY[i, 0] = pixel.XDouble; AY[i, 1] = pixel.YDouble; AY[i, 2] = 1; X[i, 0] = Math.Cos(d) * Math.Sin(a - a0) / (Math.Cos(d0) * Math.Cos(d) * Math.Cos(a - a0) + Math.Sin(d0) * Math.Sin(d)); Y[i, 0] = (Math.Cos(d0) * Math.Sin(d) - Math.Cos(d) * Math.Sin(d0) * Math.Cos(a - a0)) / (Math.Sin(d0) * Math.Sin(d) + Math.Cos(d0) * Math.Cos(d) * Math.Cos(a - a0)); i++; } SafeMatrix a_T = AX.Transpose(); SafeMatrix aa = a_T * AX; SafeMatrix aa_inv = aa.Inverse(); SafeMatrix bx = (aa_inv * a_T) * X; m_A = bx[0, 0]; m_B = bx[1, 0]; m_C = bx[2, 0]; a_T = AY.Transpose(); aa = a_T * AY; aa_inv = aa.Inverse(); bx = (aa_inv * a_T) * Y; m_D = bx[0, 0]; m_E = bx[1, 0]; m_F = bx[2, 0]; m_A0Rad = a0; m_D0Rad = d0; double ra_c, de_c; GetRADEFromImageCoords(Image.CenterXImage, Image.CenterYImage, out ra_c, out de_c); corr = AngleUtility.Elongation(ra_c, de_c, a0 * RAD_TO_DEG, d0 * RAD_TO_DEG) * 3600; a0 = ra_c * DEG_TO_RAD; d0 = de_c * DEG_TO_RAD; attempts++; }while (corr > tolerance && attempts < MAX_ATTEMPTS); Success = corr <= tolerance; }
/// <summary> /// /// </summary> /// <param name="v"></param> /// <returns></returns> public double Angle(Vector2D v) { return(AngleUtility.Diff(v.Angle(), Angle())); }