Example #1
0
        public override void NextFrame(int frameNo, IAstroImage astroImage)
        {
            IsTrackedSuccessfully = false;

            // For each of the non manualy positioned Tracked objects do a PSF fit in the area of its previous location
            for (int i = 0; i < m_TrackedObjectGroups.Count; i++)
            {
                TrackedObjectGroup objectGroup = m_TrackedObjectGroups[i];
                objectGroup.NextFrame();

                if (objectGroup.TrackLater)
                {
                    // Group position will be determined after the rest of the stars are found
                }
                else
                {
                    if (objectGroup.IsSingleObject)
                    {
                        TrackedObjectLight trackedObject = (TrackedObjectLight) objectGroup.SingleObject;
                        uint[,] pixels = astroImage.GetPixelsArea(objectGroup.SingleObjectLastCenter.X, objectGroup.SingleObjectLastCenter.Y, 17);
                        var fit = new PSFFit(objectGroup.SingleObjectLastCenter.X, objectGroup.SingleObjectLastCenter.Y);
                        fit.FittingMethod = PSFFittingMethod.NonLinearFit;
                        fit.Fit(pixels);

                        if (fit.IsSolved)
                        {
                            if (fit.Certainty < GUIDING_STAR_MIN_CERTAINTY)
                            {
                                trackedObject.SetIsTracked(false, NotMeasuredReasons.ObjectCertaintyTooSmall);
                            }
                            else if (fit.FWHM < STELLAR_OBJECT_MIN_FWHM || fit.FWHM > STELLAR_OBJECT_MAX_FWHM)
                            {
                                trackedObject.SetIsTracked(false, NotMeasuredReasons.FWHMOutOfRange);
                            }
                            else if (TangraConfig.Settings.Tracking.CheckElongation && fit.ElongationPercentage > STELLAR_OBJECT_MAX_ELONGATION)
                            {
                                trackedObject.SetIsTracked(false, NotMeasuredReasons.ObjectTooElongated);
                            }
                            else
                            {
                                trackedObject.SetTrackedObjectMatch(fit);
                                trackedObject.SetIsTracked(true, NotMeasuredReasons.TrackedSuccessfully);
                            }
                        }
                    }
                    else
                    {
                        string dbg = "";

                        int areaCenterX = (objectGroup.LastCenterObject1.X + objectGroup.LastCenterObject2.X) / 2;
                        int areaCenterY = (objectGroup.LastCenterObject1.Y + objectGroup.LastCenterObject2.Y) / 2;

                        uint[,] pixels = astroImage.GetPixelsArea(areaCenterX, areaCenterY, 35);
                        var doubleFit = new DoublePSFFit(areaCenterX, areaCenterY);

                        int x1 = objectGroup.LastCenterObject1.X - areaCenterX + 17;
                        int y1 = objectGroup.LastCenterObject1.Y - areaCenterY + 17;
                        int x2 = objectGroup.LastCenterObject2.X - areaCenterX + 17;
                        int y2 = objectGroup.LastCenterObject2.Y - areaCenterY + 17;

                        if (TangraConfig.Settings.Photometry.PsfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel)
                            doubleFit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel;
                        doubleFit.Fit(pixels, x1, y1, x2, y2);

                        if (doubleFit.IsSolved)
                        {
                            PSFFit fit1 = doubleFit.GetGaussian1();
                            PSFFit fit2 = doubleFit.GetGaussian2();

                            TrackedObjectLight trackedObject1;
                            TrackedObjectLight trackedObject2;

                            bool groupIdentified = objectGroup.IdentifyObjects(fit1, fit2, GUIDING_STAR_MIN_CERTAINTY, out trackedObject1, out trackedObject2);
                            if (!groupIdentified)
                            {
                                dbg += "Ni-";
                                objectGroup.SetIsTracked(false, NotMeasuredReasons.PSFFittingFailed);

                                //Bitmap bmp = new Bitmap(100, 200);
                                //using (Graphics g = Graphics.FromImage(bmp))
                                //{
                                //	doubleFit.DrawInternalPoints(g, new Rectangle(0, 0, 100, 200), 5, 5, Brushes.Lime, Brushes.Yellow, 8);
                                //	g.Save();
                                //}
                                //bmp.Save(@"D:\Hristo\mutual_double_fit.bmp");
                                m_FailedGroupFits++;
                            }
                            else
                            {
                                PSFFit[] fits = new PSFFit[] { fit1, fit2 };
                                TrackedObjectLight[] trackedObjects = new TrackedObjectLight[] { trackedObject1, trackedObject2 };

                                int tooSmallCertainties = 0;
                                int errors = 0;

                                for (int j = 0; j < 2; j++)
                                {
                                    PSFFit fit = fits[j];
                                    TrackedObjectLight trackedObject = trackedObjects[j];

                                    if (fit.Certainty < GUIDING_STAR_MIN_CERTAINTY)
                                    {
                                        tooSmallCertainties++;
                                        trackedObject.SetIsTracked(true, NotMeasuredReasons.TrackedSuccessfully);
                                        dbg += "TsGs-";
                                    }
                                    else if (fit.FWHM < STELLAR_OBJECT_MIN_FWHM || fit.FWHM > STELLAR_OBJECT_MAX_FWHM)
                                    {
                                        trackedObject.SetIsTracked(false, NotMeasuredReasons.FWHMOutOfRange);
                                        dbg += "Fw-";
                                        errors++;
                                    }
                                    else if (TangraConfig.Settings.Tracking.CheckElongation && fit.ElongationPercentage > STELLAR_OBJECT_MAX_ELONGATION)
                                    {
                                        trackedObject.SetIsTracked(false, NotMeasuredReasons.ObjectTooElongated);
                                        dbg += "Elo-";
                                        errors++;
                                    }
                                    else
                                    {
                                        trackedObject.SetIsTracked(true, NotMeasuredReasons.TrackedSuccessfully);
                                        dbg += "Ts-";
                                    }
                                }

                                if (tooSmallCertainties == 2)
                                {
                                    trackedObjects[0].SetIsTracked(false, NotMeasuredReasons.ObjectCertaintyTooSmall);
                                    trackedObjects[1].SetIsTracked(false, NotMeasuredReasons.ObjectCertaintyTooSmall);
                                    errors++;
                                    m_FailedGroupFits++;
                                    dbg += "Uncer-";
                                }

                                if (errors == 0)
                                {
                                    if (objectGroup.CheckIdentifiedObjects(fits[0].XCenter, fits[1].XCenter, fits[0].YCenter, fits[1].YCenter))
                                    {
                                        trackedObjects[0].SetTrackedObjectMatch(fits[0]);
                                        trackedObjects[1].SetTrackedObjectMatch(fits[1]);
                                        m_FailedGroupFits = 0;
                                        dbg += "Id-";

                                        double dist = ImagePixel.ComputeDistance(fits[0].XCenter, fits[1].XCenter, fits[0].YCenter, fits[1].YCenter);
                                        if (dist < 2)
                                        {
                                            Trace.WriteLine("TOO CLOSE");
                                        }

                                        if (dist > 16)
                                        {
                                            Trace.WriteLine("TOO FAR");
                                        }
                                    }
                                    else
                                    {
                                        dbg += "NoId-";
                                    }
                                }
                            }
                        }
                        else
                            dbg += "NoSlv-";

                        objectGroup.ValidatePosition();
                        Trace.WriteLine(dbg);
                    }
                }
            }

            bool atLeastOneGroupLocated = false;

            for (int i = 0; i < m_TrackedObjectGroups.Count; i++)
            {
                TrackedObjectGroup trackedGroup = m_TrackedObjectGroups[i];

                if (!trackedGroup.IsSingleObject && trackedGroup.LastCenterObject1 != null && trackedGroup.LastCenterObject2 != null)
                {
                    Trace.WriteLine(string.Format("({0}, {1}, {2}) ({3},{4},{5}) [{6},{7}]",
                        trackedGroup.LastCenterObject1.XDouble, trackedGroup.LastCenterObject1.YDouble, trackedGroup.LastCenterObject1.Brightness,
                        trackedGroup.LastCenterObject2.XDouble, trackedGroup.LastCenterObject2.YDouble, trackedGroup.LastCenterObject2.Brightness,
                        trackedGroup.LastCenterObject1.XDouble - trackedGroup.LastCenterObject2.XDouble, trackedGroup.LastCenterObject1.YDouble - trackedGroup.LastCenterObject2.YDouble));
                }

                bool containsFullyDisappearingTarget = trackedGroup.ContainsOcultedStar && m_IsFullDisappearance;

                if (!containsFullyDisappearingTarget && trackedGroup.IsLocated)
                    atLeastOneGroupLocated = true;

                if (!containsFullyDisappearingTarget)
                    continue;

                int numReferences = 0;
                double x_double;
                double y_double;

                if (trackedGroup.IsSingleObject && m_IsFullDisappearance)
                {
                    // This is the case for single fully disappearing targets
                    double totalX = 0;
                    double totalY = 0;
                    numReferences = 0;

                    for (int j = 0; j < m_TrackedObjectGroups.Count; j++)
                    {
                        TrackedObjectGroup referenceGroup = (TrackedObjectGroup)m_TrackedObjectGroups[j];
                        if (referenceGroup.IsLocated)
                        {
                            totalX += (trackedGroup.BrigherOriginalObject.ApertureStartingX - referenceGroup.BrigherOriginalObject.ApertureStartingX) + referenceGroup.BrigherObjectLastCenter.XDouble;
                            totalY += (trackedGroup.BrigherOriginalObject.ApertureStartingY - referenceGroup.BrigherOriginalObject.ApertureStartingY) + referenceGroup.BrigherObjectLastCenter.YDouble;
                            numReferences++;
                            atLeastOneGroupLocated = true;
                        }
                    }

                    x_double = totalX / numReferences;
                    y_double = totalY / numReferences;
                }
                else
                {
                    // The fully disappearing target is in a group. The other target would have been located. We use the last known position of the other targets
                    numReferences = 1;
                    x_double = trackedGroup.NonOccultedObjectLastCenter.XDouble;
                    y_double = trackedGroup.NonOccultedObjectLastCenter.YDouble;
                }

                if (numReferences == 0)
                {
                    trackedGroup.SetIsTracked(false, NotMeasuredReasons.FitSuspectAsNoGuidingStarsAreLocated);
                }
                else
                {
                    int x = (int)(Math.Round(x_double));
                    int y = (int)(Math.Round(y_double));

                    uint[,] pixels = astroImage.GetPixelsArea(x, y, 35);

                    if (trackedGroup.IsSingleObject)
                    {
                        PSFFit fit = new PSFFit(x, y);

                        fit.Fit(pixels);

                        if (fit.IsSolved && fit.Certainty > STELLAR_OBJECT_MIN_CERTAINTY)
                        {
                            trackedGroup.SingleObject.SetIsTracked(true, NotMeasuredReasons.TrackedSuccessfully);
                            trackedGroup.SingleObject.SetTrackedObjectMatch(fit);
                        }
                        else if (m_IsFullDisappearance)
                            trackedGroup.SingleObject.SetIsTracked(false, NotMeasuredReasons.FullyDisappearingStarMarkedTrackedWithoutBeingFound);
                        else
                            trackedGroup.SingleObject.SetIsTracked(false, NotMeasuredReasons.ObjectCertaintyTooSmall);
                    }
                    else
                    {
                        string dbg = "";
                        DoublePSFFit doubleFit = new DoublePSFFit(x, y);

                        int x1 = trackedGroup.LastCenterObject1.X - x + 17;
                        int y1 = trackedGroup.LastCenterObject1.Y - y + 17;
                        int x2 = trackedGroup.LastCenterObject2.X - x + 17;
                        int y2 = trackedGroup.LastCenterObject2.Y - y + 17;

                        if (TangraConfig.Settings.Photometry.PsfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel)
                            doubleFit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel;

                        doubleFit.Fit(pixels, x1, y1, x2, y2);

                        if (doubleFit.IsSolved)
                        {
                            PSFFit fit1 = doubleFit.GetGaussian1();
                            PSFFit fit2 = doubleFit.GetGaussian2();
                            IImagePixel center1 = null;
                            IImagePixel center2 = null;
                            TrackedObjectLight trackedObject1;
                            TrackedObjectLight trackedObject2;

                            bool resortToBrightness = false;
                            bool groupIdentified = trackedGroup.IdentifyObjects(fit1, fit2, GUIDING_STAR_MIN_CERTAINTY, out trackedObject1, out trackedObject2);
                            if (!groupIdentified && m_IsFullDisappearance)
                            {
                                dbg += "ReBr::";
                                groupIdentified = trackedGroup.IdentifyBrightObject(fit1, fit2, STELLAR_OBJECT_MIN_CERTAINTY, out trackedObject1, out trackedObject2, out center1, out center2);
                                resortToBrightness = true;
                            }

                            if (!groupIdentified)
                            {
                                trackedGroup.SetIsTracked(false, NotMeasuredReasons.PSFFittingFailed);
                                dbg += "PsF::";
                            }
                            else
                            {
                                PSFFit[] fits = new PSFFit[] { fit1, fit2 };
                                IImagePixel[] centers = new IImagePixel[] { center1, center2 };
                                TrackedObjectLight[] trackedObjects = new TrackedObjectLight[] { trackedObject1, trackedObject2 };

                                bool objectCheckSuccessful = resortToBrightness
                                    ? trackedGroup.CheckIdentifiedObjects(center1.XDouble, center2.XDouble, center1.YDouble, center2.YDouble)
                                    : trackedGroup.CheckIdentifiedObjects(fits[0].XCenter, fits[1].XCenter, fits[0].YCenter, fits[1].YCenter);

                                if (objectCheckSuccessful)
                                {
                                    dbg += "ChS::";
                                    bool atLeastOneOK = (fit1.IsSolved && fit1.Certainty > GUIDING_STAR_MIN_CERTAINTY) || (fit2.IsSolved && fit2.Certainty > GUIDING_STAR_MIN_CERTAINTY);
                                    double dist = ImagePixel.ComputeDistance(fit1.XCenter, fit2.XCenter, fit1.YCenter, fit2.YCenter);

                                    if (!atLeastOneOK || ((dist < 2 || dist > 16) && !resortToBrightness))
                                    {
                                        trackedGroup.SetIsTracked(false, NotMeasuredReasons.PSFFittingFailed);
                                    }

                                    int cntOk = 0;
                                    for (int j = 0; j < 2; j++)
                                    {
                                        PSFFit fit = fits[j];
                                        IImagePixel center = centers[j];
                                        TrackedObjectLight trackedObject = trackedObjects[j];

                                        if (fit.IsSolved && fit.Certainty > STELLAR_OBJECT_MIN_CERTAINTY)
                                        {
                                            if (resortToBrightness && trackedObject.IsOccultedStar)
                                            {
                                                trackedObject.SetIsTracked(true, NotMeasuredReasons.FullyDisappearingStarMarkedTrackedWithoutBeingFound, center, fit.Certainty);
                                                dbg += "OccDi::";
                                            }
                                            else
                                            {
                                                trackedObject.SetTrackedObjectMatch(fit);
                                                trackedObject.SetIsTracked(true, NotMeasuredReasons.TrackedSuccessfully);
                                                dbg += "TrSuc::";
                                            }

                                            cntOk++;
                                        }
                                        else if (m_IsFullDisappearance && trackedObject.IsOccultedStar)
                                        {
                                            trackedObject.SetIsTracked(false, NotMeasuredReasons.FullyDisappearingStarMarkedTrackedWithoutBeingFound, resortToBrightness ? center : null, 1);
                                            dbg += "BadCerSuc::";
                                        }
                                        else
                                        {
                                            trackedObject.SetIsTracked(false, NotMeasuredReasons.ObjectCertaintyTooSmall, resortToBrightness ? center : null, resortToBrightness ? fit.Certainty : (double?)null);
                                            dbg += "BadCerNOSuc::";
                                        }
                                    }

                                    if (cntOk == 2)
                                    {
                                        m_FailedGroupFits = 0;
                                    }
                                }
                                else
                                {
                                    trackedObjects[0].SetIsTracked(false, NotMeasuredReasons.FailedToLocateAfterDistanceCheck);
                                    trackedObjects[1].SetIsTracked(false, NotMeasuredReasons.FailedToLocateAfterDistanceCheck);
                                    m_FailedGroupFits++;
                                    dbg += "ChU::";
                                }
                            }
                        }
                        else
                        {
                            m_FailedGroupFits++;
                            dbg += "NoFi::";
                        }

                        trackedGroup.ValidatePosition();
                        Trace.WriteLine(dbg);
                    }
                }
            }

            IsTrackedSuccessfully = atLeastOneGroupLocated;

            if (IsTrackedSuccessfully)
                RefinedAverageFWHM = m_TrackedObjects.Cast<TrackedObjectLight>().Average(x => x.RefinedFWHM);

            if (m_FailedGroupFits > 10)
            {
                Trace.WriteLine("ERR~10+");
            }
        }
        private void CalculateTwoObjectsPSFs()
        {
            if (m_AutoDoubleCenter != null)
            {
                m_Center = new ImagePixel(m_AutoDoubleCenter);
                m_X1Start = m_AutoDoubleX1Start;
                m_Y1Start = m_AutoDoubleY1Start;
                m_X2Start = m_AutoDoubleX2Start;
                m_Y2Start = m_AutoDoubleY2Start;
                m_ProcessingPixels = m_AstroImage.GetMeasurableAreaPixels(m_Center.X, m_Center.Y, 35);
                m_DisplayPixels = m_AstroImage.GetMeasurableAreaDisplayBitmapPixels(m_Center.X, m_Center.Y, 35);
            }

            if (!m_UserPeakMode &&
                !FirstObjectPeakDefined() && !SecondObjectPeakDefined() &&
                !LocatePeaks())
            {
                m_UserPeakMode = true;

                MessageBox.Show(
                    this,
                    "Please click on the image to define the center of each of the two objects.",
                    "Tangra",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Question);

                picTarget1Pixels.Cursor = Cursors.Cross;

                UpdateViews();

                return;
            }

            if (!FirstObjectPeakDefined() || !SecondObjectPeakDefined())
            {
                MessageBox.Show(
                    this,
                    "Cannot locate two objects.",
                    "Tangra",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }

            var psfFit = new DoublePSFFit(m_Center.X, m_Center.Y);
            if (TangraConfig.Settings.Photometry.PsfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel)
                psfFit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel;
            psfFit.Fit(m_ProcessingPixels, m_X1Start, m_Y1Start, m_X2Start, m_Y2Start);

            if (psfFit.IsSolved)
            {
                m_DoubleGaussian = psfFit;
                m_FWHM = (float)psfFit.FWHM;
                m_X0 = psfFit.X0_Matrix;
                m_Y0 = psfFit.Y0_Matrix;

                m_FWHM1 = (float)psfFit.FWHM1;
                m_FWHM2 = (float)psfFit.FWHM2;
                m_X1 = psfFit.X1_Matrix;
                m_Y1 = psfFit.Y1_Matrix;
                m_X2 = psfFit.X2_Matrix;
                m_Y2 = psfFit.Y2_Matrix;
                m_X1Center = (float)psfFit.X1Center;
                m_Y1Center = (float)psfFit.Y1Center;
                m_X2Center = (float)psfFit.X2Center;
                m_Y2Center = (float)psfFit.Y2Center;

                if (m_Aperture1 == null)
                {
                    if (TangraConfig.Settings.Photometry.SignalApertureUnitDefault == TangraConfig.SignalApertureUnit.FWHM)
                        m_Aperture1 = (float)(psfFit.FWHM1 * TangraConfig.Settings.Photometry.DefaultSignalAperture);
                    else
                        m_Aperture1 = (float)(TangraConfig.Settings.Photometry.DefaultSignalAperture);
                }
                else if (
                    TangraConfig.Settings.Photometry.SignalApertureUnitDefault == TangraConfig.SignalApertureUnit.FWHM &&
                    m_Aperture1 < (float)(psfFit.FWHM1 * TangraConfig.Settings.Photometry.DefaultSignalAperture))
                {
                    // When the default aperture size is in FWHM we always use the largest aperture so far
                    m_Aperture1 = (float)(psfFit.FWHM1 * TangraConfig.Settings.Photometry.DefaultSignalAperture);
                }

                if (m_Aperture2 == null)
                {
                    if (TangraConfig.Settings.Photometry.SignalApertureUnitDefault == TangraConfig.SignalApertureUnit.FWHM)
                        m_Aperture2 = (float)(psfFit.FWHM2 * TangraConfig.Settings.Photometry.DefaultSignalAperture);
                    else
                        m_Aperture2 = (float)(TangraConfig.Settings.Photometry.DefaultSignalAperture);
                }
                else if (
                    TangraConfig.Settings.Photometry.SignalApertureUnitDefault == TangraConfig.SignalApertureUnit.FWHM &&
                    m_Aperture2 < (float)(psfFit.FWHM2 * TangraConfig.Settings.Photometry.DefaultSignalAperture))
                {
                    // When the default aperture size is in FWHM we always use the largest aperture so far
                    m_Aperture2 = (float) (psfFit.FWHM2*TangraConfig.Settings.Photometry.DefaultSignalAperture);
                }

                if (m_Aperture1 > m_Aperture2) m_Aperture2 = m_Aperture1;
                if (m_Aperture2 > m_Aperture1) m_Aperture1 = m_Aperture2;

                nudAperture1.SetNUDValue(m_Aperture1.Value);

                m_Aperture = null;
                m_Gaussian = null;
            }
        }
        private bool IsGoodDoubleObjectFit(Tuple<int, int, uint> object1, Tuple<int, int, uint> object2)
        {
            var doubleFit = new DoublePSFFit(100, 100);
            if (TangraConfig.Settings.Photometry.PsfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel)
                doubleFit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel;
            doubleFit.Fit(m_ProcessingPixels, object1.Item1, object1.Item2, object2.Item1, object2.Item2);

            if (doubleFit.IsSolved &&
                Math.Abs(doubleFit.FWHM1 - doubleFit.FWHM2) < Math.Max(1, Math.Min(doubleFit.FWHM1, doubleFit.FWHM2)*0.25) &&
                doubleFit.IAmplitude1 > 0 && doubleFit.IAmplitude2 > 0)
            {
                double imaxRatio = doubleFit.IAmplitude1 / doubleFit.IAmplitude2;
                if (imaxRatio > 1) imaxRatio = 1 / imaxRatio;

                if (imaxRatio >= 0.25)
                {
                    // We require at least 1:4 ratio in the maximums for the auto-detection to accept that it has found correctly two objects

                    double distance = ImagePixel.ComputeDistance(object1.Item1, object2.Item1, object1.Item2, object2.Item2);

                    if (distance > doubleFit.FWHM1 && distance > doubleFit.FWHM2)
                    {
                        // We also require at least a FWHM distance between centers for automatic detection
                        m_X1Start = object1.Item1;
                        m_Y1Start = object1.Item2;
                        m_X2Start = object2.Item1;
                        m_Y2Start = object2.Item2;

                        return true;
                    }
                }

                return false;
            }

            return false;
        }
Example #4
0
        public NotMeasuredReasons MeasureObject(
            IImagePixel center,
            uint[,] data,
            uint[,] backgroundPixels,
			int bpp,
            TangraConfig.PreProcessingFilter filter,
            TangraConfig.PhotometryReductionMethod reductionMethod,
			TangraConfig.PsfQuadrature psfQuadrature,
            TangraConfig.PsfFittingMethod psfFittingMethod,
            float aperture,
            double refinedFWHM,
            float refinedAverageFWHM,
			IMeasurableObject measurableObject,
			IImagePixel[] objectsInGroup,
			float[] aperturesInGroup,
            bool fullDisappearance)
        {
            // NOTE: This is how the center of the pixel area passed in data and background arrays is determined
            // TODO: Pass the center as an argument
            int centerX = (int)Math.Round(center.XDouble);
            int centerY = (int)Math.Round(center.YDouble);

            float msrX0 = (float)center.XDouble;
            float msrY0 = (float)center.YDouble;

            float bgAnnulusFactor = 1;

            switch (filter)
            {
                case TangraConfig.PreProcessingFilter.LowPassFilter:
                    data = ImageFilters.LowPassFilter(data, bpp, true);
                    backgroundPixels = ImageFilters.LowPassFilter(backgroundPixels, bpp, true);
                    break;
                case TangraConfig.PreProcessingFilter.LowPassDifferenceFilter:
                    data = ImageFilters.LowPassDifferenceFilter(data, bpp, true);
                    backgroundPixels = ImageFilters.LowPassDifferenceFilter(backgroundPixels, bpp, true);
                    break;
                default:
                    break;
            }

            float modelFWHM = float.NaN;
            if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel)
            {
                if (TangraConfig.Settings.Photometry.UseUserSpecifiedFWHM)
                    modelFWHM = TangraConfig.Settings.Photometry.UserSpecifiedFWHM;
                else
                    modelFWHM = refinedAverageFWHM;
            }

            DoublePSFFit doublefit = null;
            PSFFit fit = null;
            IBackgroundModelProvider backgroundModel = null;

            // 1 - Fit a PSF to the current obejct
            if (objectsInGroup != null && objectsInGroup.Length == 2)
            {
                // 1A - When this is a star group
                int x1 = (int) Math.Round((data.GetLength(0)/2) + objectsInGroup[0].XDouble - center.XDouble);
                int y1 = (int) Math.Round((data.GetLength(0)/2) + objectsInGroup[0].YDouble - center.YDouble);
                int x2 = (int) Math.Round((data.GetLength(0)/2) + objectsInGroup[1].XDouble - center.XDouble);
                int y2 = (int) Math.Round((data.GetLength(0)/2) + objectsInGroup[1].YDouble - center.YDouble);
                doublefit = new DoublePSFFit(centerX, centerY);

                if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel &&
                    !float.IsNaN(modelFWHM))
                {
                    doublefit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel;
                    doublefit.SetAveragedModelFWHM(modelFWHM);
                }

                doublefit.Fit(data, x1, y1, x2, y2);

                PSFFit star1 = doublefit.GetGaussian1();
                PSFFit star2 = doublefit.GetGaussian2();

                if (m_BackgroundMethod == TangraConfig.BackgroundMethod.Background3DPolynomial)
                {
                    var bg3dFit = new Background3DPolynomialFit();
                    bg3dFit.Fit(data, star1, star2);

                    doublefit.Fit(data, bg3dFit, x1, y1, x2, y2);

                    star1 = doublefit.GetGaussian1();
                    star2 = doublefit.GetGaussian2();
                    backgroundModel = bg3dFit;
                }

                double d1 = ImagePixel.ComputeDistance(measurableObject.Center.XDouble, doublefit.X1Center, measurableObject.Center.YDouble, doublefit.Y1Center);
                double d2 = ImagePixel.ComputeDistance(measurableObject.Center.XDouble, doublefit.X2Center, measurableObject.Center.YDouble, doublefit.Y2Center);

                fit = (d1 < d2) ? star1 : star2;

                if (reductionMethod == TangraConfig.PhotometryReductionMethod.AperturePhotometry)
                {
                    // NOTE: If aperture photometry is used, we measure the double object in a single larger aperture centered at the middle
                    double alpha = Math.Atan((star2.YCenter - star1.YCenter) / (star2.XCenter - star1.XCenter));

                    float dx = (float)((star1.FWHM - star2.FWHM) * Math.Cos(alpha));
                    float dy = (float)((star1.FWHM - star2.FWHM) * Math.Sin(alpha));

                    msrX0 = (float)(star1.XCenter - star1.FWHM + star2.XCenter + star2.FWHM) / 2.0f - dx;
                    msrY0 = (float)(star1.YCenter - star1.FWHM + star2.YCenter + star2.FWHM) / 2.0f - dy;

                    aperture = aperturesInGroup.Sum();
                    bgAnnulusFactor = 0.67f;
                }
            }
            else if (reductionMethod != TangraConfig.PhotometryReductionMethod.AperturePhotometry)
            {
                // 1B - When this is a single star
                fit = new PSFFit(centerX, centerY);

                if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel &&
                    !float.IsNaN(modelFWHM))
                {
                    fit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel;
                    fit.SetAveragedModelFWHM(modelFWHM);
                }

                fit.Fit(data, measurableObject.PsfFittingMatrixSize);

                if (m_BackgroundMethod == TangraConfig.BackgroundMethod.Background3DPolynomial)
                {
                    // If 3D Poly Background is used then fit the background, and supply it to the PSF Fitting
                    var bg3dFit = new Background3DPolynomialFit();
                    bg3dFit.Fit(backgroundPixels, fit, null);

                    backgroundModel = bg3dFit;

                    if (psfFittingMethod != TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel)
                        /* 3D Poly modelling works in a direct fit only with non-linear fitting */
                        fit.Fit(backgroundPixels, bg3dFit, measurableObject.PsfFittingMatrixSize);
                }
            }
            else if (
                reductionMethod == TangraConfig.PhotometryReductionMethod.AperturePhotometry &&
                m_BackgroundMethod == TangraConfig.BackgroundMethod.Background3DPolynomial)
            {
                // 1C - Single star with aperture photometry and 3D Poly Background
                var bg3dFit = new Background3DPolynomialFit();
                bg3dFit.Fit(backgroundPixels, (float)(centerX - msrX0 + 17), (float)(centerY - msrY0 + 17), 2 * aperture);

                backgroundModel = bg3dFit;
            }

            // 2 - Do the actual photometric measurements (signal and background) based on the selected methods
            if (reductionMethod == TangraConfig.PhotometryReductionMethod.PsfPhotometry)
            {
                // 2A - PSF Photometry
                if (TangraConfig.Settings.Photometry.PsfFittingMethod == TangraConfig.PsfFittingMethod.DirectNonLinearFit)
                {
                    return DoNonLinearProfileFittingPhotometry(
                        fit,
                        data, centerX, centerY, msrX0, msrY0,
                        aperture,
                        measurableObject.PsfFittingMatrixSize,
                        psfQuadrature == TangraConfig.PsfQuadrature.NumericalInAperture,
                        measurableObject.IsOccultedStar && fullDisappearance,
                        backgroundPixels,
                        measurableObject.MayHaveDisappeared,
                        refinedFWHM,
                        bgAnnulusFactor);
                }
                else if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel)
                {
                    return DoLinearProfileFittingOfAveragedMoodelPhotometry(
                        fit,
                        data, centerX, centerY, msrX0, msrY0, modelFWHM,
                        aperture,
                        measurableObject.PsfFittingMatrixSize,
                        psfQuadrature == TangraConfig.PsfQuadrature.NumericalInAperture,
                        measurableObject.IsOccultedStar && fullDisappearance,
                        backgroundPixels,
                        measurableObject.MayHaveDisappeared,
                        bgAnnulusFactor, backgroundModel);
                }
                else
                    throw new NotImplementedException();
            }
            else if (reductionMethod == TangraConfig.PhotometryReductionMethod.AperturePhotometry)
            {
                return DoAperturePhotometry(
                    data, centerX, centerY, msrX0, msrY0,
                    aperture,
                    measurableObject.PsfFittingMatrixSize,
                    backgroundPixels, bgAnnulusFactor, backgroundModel,
                    measurableObject.Center.X, measurableObject.Center.Y);
            }
            else if (reductionMethod == TangraConfig.PhotometryReductionMethod.OptimalExtraction)
            {
                return DoOptimalExtractionPhotometry(
                    fit,
                    data, centerX, centerY, msrX0, msrY0,
                    aperture,
                    measurableObject.PsfFittingMatrixSize,
                    measurableObject.IsOccultedStar && fullDisappearance,
                    backgroundPixels,
                    measurableObject.MayHaveDisappeared,
                    refinedFWHM, bgAnnulusFactor);
            }
            else
                throw new ArgumentOutOfRangeException("reductionMethod");
        }