Warning, file /education/kstars/kstars/ekos/focus/focusfwhm.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2023 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QList> 0010 #include "../fitsviewer/fitsstardetector.h" 0011 #include "fitsviewer/fitsview.h" 0012 #include "fitsviewer/fitsdata.h" 0013 #include "curvefit.h" 0014 #include "../ekos.h" 0015 #include <ekos_focus_debug.h> 0016 0017 0018 namespace Ekos 0019 { 0020 0021 // This class performs FWHM processing on the passed in FITS image 0022 0023 class FocusFWHM 0024 { 0025 public: 0026 0027 FocusFWHM(Mathematics::RobustStatistics::ScaleCalculation scaleCalc); 0028 ~FocusFWHM(); 0029 0030 template <typename T> 0031 void processFWHM(const T &imageBuffer, const QList<Edge *> &focusStars, const QSharedPointer<FITSData> &imageData, 0032 std::unique_ptr<CurveFitting> &starFitting, 0033 double *FWHM, double *weight) 0034 { 0035 CurveFitting::StarParams starParams, starParams2; 0036 std::vector<double> FWHMs, R2s; 0037 0038 auto skyBackground = imageData->getSkyBackground(); 0039 auto stats = imageData->getStatistics(); 0040 0041 // Setup a vector for each of the stars to be processed 0042 QVector<StarBox> stars; 0043 StarBox star; 0044 0045 for (int s = 0; s < focusStars.size(); s++) 0046 { 0047 int starSize = focusStars[s]->numPixels; 0048 0049 // If the star size is invalid then ignore this star 0050 if (starSize <= 0) 0051 continue; 0052 0053 // factor scales a box around the star to use in fitting the Gaussian 0054 // too big and it wastes processing resource and since there is no deblending, it will also result 0055 // in more star exclusions. Too small and the gaussian won't fit properly. On the Simulator 1.4 is good. 0056 constexpr double factor = 1.4; 0057 int width = factor * 2 * sqrt(starSize / M_PI); 0058 int height = width; 0059 0060 // Width x height box centred on star centroid 0061 star.star = s; 0062 star.isValid = true; 0063 star.start.first = focusStars[s]->x - width / 2.0; 0064 star.end.first = focusStars[s]->x + width / 2.0; 0065 star.start.second = focusStars[s]->y - height / 2.0; 0066 star.end.second = focusStars[s]->y + height / 2.0; 0067 0068 // Check star box does not go over image edge, drop star if so 0069 if (star.start.first < 0 || star.end.first > stats.width || star.start.second < 0 || star.end.second > stats.height) 0070 continue; 0071 0072 stars.push_back(star); 0073 } 0074 0075 // Ideally we would deblend where another star encroaches into this star's box 0076 // For now we'll just exclude stars in this situation by marking isValid as false 0077 for (int s1 = 0; s1 < stars.size(); s1++) 0078 { 0079 if (!stars[s1].isValid) 0080 continue; 0081 0082 for (int s2 = s1 + 1; s2 < stars.size(); s2++) 0083 { 0084 if (!stars[s2].isValid) 0085 continue; 0086 0087 if (boxOverlap(stars[s1].start, stars[s1].end, stars[s2].start, stars[s2].end)) 0088 { 0089 stars[s1].isValid = false; 0090 stars[s2].isValid = false; 0091 } 0092 } 0093 } 0094 0095 // We have the list of stars to process now so iterate through the list fitting a curve, etc 0096 for (int s = 0; s < stars.size(); s++) 0097 { 0098 if (!stars[s].isValid) 0099 continue; 0100 0101 starParams.background = skyBackground.mean; 0102 starParams.peak = focusStars[stars[s].star]->val; 0103 starParams.centroid_x = focusStars[stars[s].star]->x - stars[s].start.first; 0104 starParams.centroid_y = focusStars[stars[s].star]->y - stars[s].start.second; 0105 starParams.HFR = focusStars[stars[s].star]->HFR; 0106 starParams.theta = 0.0; 0107 starParams.FWHMx = -1; 0108 starParams.FWHMy = -1; 0109 starParams.FWHM = -1; 0110 0111 starFitting->fitCurve3D(imageBuffer, stats.width, stars[s].start, stars[s].end, starParams, CurveFitting::FOCUS_GAUSSIAN, 0112 false); 0113 if (starFitting->getStarParams(CurveFitting::FOCUS_GAUSSIAN, &starParams2)) 0114 { 0115 starParams2.centroid_x += stars[s].start.first; 0116 starParams2.centroid_y += stars[s].start.second; 0117 double R2 = starFitting->calculateR2(CurveFitting::FOCUS_GAUSSIAN); 0118 if (R2 >= 0.25) 0119 { 0120 // Filter stars - 0.25 works OK on Sim 0121 FWHMs.push_back(starParams2.FWHM); 0122 R2s.push_back(R2); 0123 0124 qCDebug(KSTARS_EKOS_FOCUS) << "Star" << s << " R2=" << R2 0125 << " x=" << focusStars[s]->x << " vs " << starParams2.centroid_x 0126 << " y=" << focusStars[s]->y << " vs " << starParams2.centroid_y 0127 << " HFR=" << focusStars[s]->HFR << " FWHM=" << starParams2.FWHM 0128 << " Background=" << skyBackground.mean << " vs " << starParams2.background 0129 << " Peak=" << focusStars[s]->val << "vs" << starParams2.peak; 0130 } 0131 } 0132 } 0133 0134 if (FWHMs.size() == 0) 0135 { 0136 *FWHM = INVALID_STAR_MEASURE; 0137 *weight = 0.0; 0138 } 0139 else 0140 { 0141 // There are many ways to compute a robust location. Using data on the simulator there wasn't much to choose 0142 // between the Location measures available in RobustStatistics, so will use basic 2 Sigma Clipping 0143 double FWHM_sc = Mathematics::RobustStatistics::ComputeLocation(Mathematics::RobustStatistics::LOCATION_SIGMACLIPPING, 0144 FWHMs, 2.0); 0145 double R2_median = Mathematics::RobustStatistics::ComputeLocation(Mathematics::RobustStatistics::LOCATION_MEDIAN, 0146 R2s, 2.0); 0147 double FWHMweight = Mathematics::RobustStatistics::ComputeWeight(m_ScaleCalc, FWHMs); 0148 0149 qCDebug(KSTARS_EKOS_FOCUS) << "Original Stars=" << focusStars.size() 0150 << " Processed=" << stars.size() 0151 << " Solved=" << FWHMs.size() 0152 << " R2 min/max/median=" << *std::min_element(R2s.begin(), R2s.end()) 0153 << "/" << *std::max_element(R2s.begin(), R2s.end()) 0154 << "/" << R2_median 0155 << " FWHM=" << FWHM_sc 0156 << " Weight=" << FWHMweight; 0157 0158 *FWHM = FWHM_sc; 0159 *weight = FWHMweight; 0160 } 0161 } 0162 0163 static double constexpr INVALID_STAR_MEASURE = -1.0; 0164 0165 private: 0166 0167 bool boxOverlap(const QPair<int, int> b1Start, const QPair<int, int> b1End, const QPair<int, int> b2Start, 0168 const QPair<int, int> b2End); 0169 0170 // Structure to hold parameters for box around a star for FWHM calcs 0171 struct StarBox 0172 { 0173 int star; 0174 bool isValid; 0175 QPair<int, int> start; // top left of box. x = first element, y = second element 0176 QPair<int, int> end; // bottom right of box. x = first element, y = second element 0177 }; 0178 0179 Mathematics::RobustStatistics::ScaleCalculation m_ScaleCalc; 0180 }; 0181 }