Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        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;
        }