Kstars

focusfwhm.h
1/*
2 SPDX-FileCopyrightText: 2023
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#pragma once
8
9#include <QList>
10#include "../fitsviewer/fitsstardetector.h"
11#include "fitsviewer/fitsview.h"
12#include "fitsviewer/fitsdata.h"
13#include "curvefit.h"
14#include "../ekos.h"
15#include <ekos_focus_debug.h>
16
17
18namespace Ekos
19{
20
21// This class performs FWHM processing on the passed in FITS image
22
23class FocusFWHM
24{
25 public:
26
27 FocusFWHM(Mathematics::RobustStatistics::ScaleCalculation scaleCalc);
28 ~FocusFWHM();
29
30 template <typename T>
31 void processFWHM(const T &imageBuffer, const QList<Edge *> &focusStars, const QSharedPointer<FITSData> &imageData,
32 std::unique_ptr<CurveFitting> &starFitting,
33 double *FWHM, double *weight)
34 {
35 CurveFitting::StarParams starParams, starParams2;
36 std::vector<double> FWHMs, R2s;
37
38 auto skyBackground = imageData->getSkyBackground();
39 auto stats = imageData->getStatistics();
40
41 // Setup a vector for each of the stars to be processed
42 QVector<StarBox> stars;
43 StarBox star;
44
45 for (int s = 0; s < focusStars.size(); s++)
46 {
47 int starSize = focusStars[s]->numPixels;
48
49 // If the star size is invalid then ignore this star
50 if (starSize <= 0)
51 continue;
52
53 // factor scales a box around the star to use in fitting the Gaussian
54 // too big and it wastes processing resource and since there is no deblending, it will also result
55 // in more star exclusions. Too small and the gaussian won't fit properly. On the Simulator 1.4 is good.
56 constexpr double factor = 1.4;
57 int width = factor * 2 * sqrt(starSize / M_PI);
58 int height = width;
59
60 // Width x height box centred on star centroid
61 star.star = s;
62 star.isValid = true;
63 star.start.first = focusStars[s]->x - width / 2.0;
64 star.end.first = focusStars[s]->x + width / 2.0;
65 star.start.second = focusStars[s]->y - height / 2.0;
66 star.end.second = focusStars[s]->y + height / 2.0;
67
68 // Check star box does not go over image edge, drop star if so
69 if (star.start.first < 0 || star.end.first > stats.width || star.start.second < 0 || star.end.second > stats.height)
70 continue;
71
72 stars.push_back(star);
73 }
74
75 // Ideally we would deblend where another star encroaches into this star's box
76 // For now we'll just exclude stars in this situation by marking isValid as false
77 for (int s1 = 0; s1 < stars.size(); s1++)
78 {
79 if (!stars[s1].isValid)
80 continue;
81
82 for (int s2 = s1 + 1; s2 < stars.size(); s2++)
83 {
84 if (!stars[s2].isValid)
85 continue;
86
87 if (boxOverlap(stars[s1].start, stars[s1].end, stars[s2].start, stars[s2].end))
88 {
89 stars[s1].isValid = false;
90 stars[s2].isValid = false;
91 }
92 }
93 }
94
95 // We have the list of stars to process now so iterate through the list fitting a curve, etc
96 for (int s = 0; s < stars.size(); s++)
97 {
98 if (!stars[s].isValid)
99 continue;
100
101 starParams.background = skyBackground.mean;
102 starParams.peak = focusStars[stars[s].star]->val;
103 starParams.centroid_x = focusStars[stars[s].star]->x - stars[s].start.first;
104 starParams.centroid_y = focusStars[stars[s].star]->y - stars[s].start.second;
105 starParams.HFR = focusStars[stars[s].star]->HFR;
106 starParams.theta = 0.0;
107 starParams.FWHMx = -1;
108 starParams.FWHMy = -1;
109 starParams.FWHM = -1;
110
111 starFitting->fitCurve3D(imageBuffer, stats.width, stars[s].start, stars[s].end, starParams, CurveFitting::FOCUS_GAUSSIAN,
112 false);
113 if (starFitting->getStarParams(CurveFitting::FOCUS_GAUSSIAN, &starParams2))
114 {
115 starParams2.centroid_x += stars[s].start.first;
116 starParams2.centroid_y += stars[s].start.second;
117 double R2 = starFitting->calculateR2(CurveFitting::FOCUS_GAUSSIAN);
118 if (R2 >= 0.25)
119 {
120 // Filter stars - 0.25 works OK on Sim
121 FWHMs.push_back(starParams2.FWHM);
122 R2s.push_back(R2);
123
124 qCDebug(KSTARS_EKOS_FOCUS) << "Star" << s << " R2=" << R2
125 << " x=" << focusStars[s]->x << " vs " << starParams2.centroid_x
126 << " y=" << focusStars[s]->y << " vs " << starParams2.centroid_y
127 << " HFR=" << focusStars[s]->HFR << " FWHM=" << starParams2.FWHM
128 << " Background=" << skyBackground.mean << " vs " << starParams2.background
129 << " Peak=" << focusStars[s]->val << "vs" << starParams2.peak;
130 }
131 }
132 }
133
134 if (FWHMs.size() == 0)
135 {
136 *FWHM = INVALID_STAR_MEASURE;
137 *weight = 0.0;
138 }
139 else
140 {
141 // There are many ways to compute a robust location. Using data on the simulator there wasn't much to choose
142 // between the Location measures available in RobustStatistics, so will use basic 2 Sigma Clipping
143 double FWHM_sc = Mathematics::RobustStatistics::ComputeLocation(Mathematics::RobustStatistics::LOCATION_SIGMACLIPPING,
144 FWHMs, 2.0);
145 double R2_median = Mathematics::RobustStatistics::ComputeLocation(Mathematics::RobustStatistics::LOCATION_MEDIAN,
146 R2s, 2.0);
147 double FWHMweight = Mathematics::RobustStatistics::ComputeWeight(m_ScaleCalc, FWHMs);
148
149 qCDebug(KSTARS_EKOS_FOCUS) << "Original Stars=" << focusStars.size()
150 << " Processed=" << stars.size()
151 << " Solved=" << FWHMs.size()
152 << " R2 min/max/median=" << *std::min_element(R2s.begin(), R2s.end())
153 << "/" << *std::max_element(R2s.begin(), R2s.end())
154 << "/" << R2_median
155 << " FWHM=" << FWHM_sc
156 << " Weight=" << FWHMweight;
157
158 *FWHM = FWHM_sc;
159 *weight = FWHMweight;
160 }
161 }
162
163 static double constexpr INVALID_STAR_MEASURE = -1.0;
164
165 private:
166
167 bool boxOverlap(const QPair<int, int> b1Start, const QPair<int, int> b1End, const QPair<int, int> b2Start,
168 const QPair<int, int> b2End);
169
170 // Structure to hold parameters for box around a star for FWHM calcs
171 struct StarBox
172 {
173 int star;
174 bool isValid;
175 QPair<int, int> start; // top left of box. x = first element, y = second element
176 QPair<int, int> end; // bottom right of box. x = first element, y = second element
177 };
178
179 Mathematics::RobustStatistics::ScaleCalculation m_ScaleCalc;
180};
181}
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:79
bool isValid(QStringView ifopt)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:48:26 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.