Kstars

focusstars.cpp
1#include "focusstars.h"
2#include "ekos/guide/internalguide/starcorrespondence.h"
3#include <ekos_focus_debug.h>
4
5namespace Ekos
6{
7
8namespace
9{
10
11using Ekos::FocusStars;
12
13// Debug code to print out how well the star correspondence matched.
14// Compares the star correspondence offsets from the detected "guide star position"
15// with the actual detected stars. Note, those offsets were just taken from the
16// first star set's detected stars.
17// Move to star correspondence?
18double correspondenceRmsError(const StarCorrespondence &corr, const QList<Edge> &stars2,
19 const QVector<int> &starMap, GuiderUtils::Vector gsPosition)
20{
21 const int s2Size = starMap.size();
22 double sumSq2 = 0;
23 int num = 0;
24 for (int s2 = 0; s2 < s2Size; s2++)
25 {
26 const int s1 = starMap[s2];
27 if (s1 >= 0)
28 {
29 // Compute the RMS association distance.
30 double x2 = stars2[s2].x;
31 double y2 = stars2[s2].y;
32
33 QVector2D offset = corr.offset(s1);
34 double x1 = gsPosition.x + offset.x();
35 double y1 = gsPosition.y + offset.y();
36 double dSq = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
37 sumSq2 += dSq;
38 num++;
39 }
40 }
41 return sqrt(sumSq2 / num);
42}
43
44// Use StarCorrespondence to find a common set of stars between stars1 and stars2.
45// Use mainStar1 as the "guideStar" or really the central star. We look for the pattern
46// of stars around that star. It is an index into stars1. If this star is missing from stars2,
47// StarCorrespondence could recover, but ideally it exists in both.
48// Returns two FocusStars objects containing the sets of corresponding stars.
50 double maxDistance, FocusStars *stars1Filtered, FocusStars *stars2Filtered)
51{
52 // minFraction is the fraction of the stars passed into StarCorrespondence (i.e. in stars1)
53 // that must be found in stars2. Ideally, star1 would be a smaller list, but instead we simply
54 // adjust minFraction.
55 // Goal is to get 45% of the stars in the smaller star set (or more).
56 int minStars = std::min(stars1.size(), stars2.size());
57 int desiredStars = 0.45 * minStars;
58 const double minFraction = static_cast<double>(desiredStars) / stars1.size();
59
60 // Do the star correspondence
61 QVector<int> starMap;
62 StarCorrespondence corr(stars1, mainStar1);
63 corr.setAllowMissingGuideStar(true);
64 Edge gStar = corr.find(stars2, maxDistance, &starMap, false, minFraction);
65 GuiderUtils::Vector gsPosition(gStar.x, gStar.y, 0);
66
67 // Grab the two sets of stars.
68 const int s2Size = starMap.size();
69 int numAssociated = 0;
71 for (int s2 = 0; s2 < s2Size; s2++)
72 {
73 const int s1 = starMap[s2];
74 if (s1 >= 0)
75 {
77 edges1.append(stars1[s1]);
78 edges2.append(stars2[s2]);
79 }
80 }
81 *stars1Filtered = FocusStars(edges1);
82 *stars2Filtered = FocusStars(edges2);
83
84 // debug
86 QString debugStr = QString("matchStars: Inputs sized %1 %2 found %3 matches, RMS dist %4")
87 .arg(stars1.size()).arg(stars2.size()).arg(numAssociated).arg(corrError, 0, 'f', 1);
88 qCDebug(KSTARS_EKOS_FOCUS) << debugStr;
89
90 return numAssociated;
91}
92
93bool filterFocusStars(const FocusStars &stars1, const FocusStars &stars2, double maxDistance, FocusStars *filtered1,
94 FocusStars *filtered2)
95{
96 int size1 = stars1.getStars().size();
97 int size2 = stars2.getStars().size();
98
99 // This section limits the process to the first 100 stars, for computational reasons,
100 // just in case there is an input with a large number of stars.
101 constexpr int maxNumStars = 100;
103 const QList<Edge> *s1ptr = &(stars1.getStars());
104 if (size1 > maxNumStars)
105 {
106 for (int i = 0; i < maxNumStars; i++)
107 s1.append(stars1.getStars()[i]);
108 s1ptr = &s1;
110 }
112 const QList<Edge> *s2ptr = &(stars2.getStars());
113 if (size2 > maxNumStars)
114 {
115 for (int i = 0; i < maxNumStars; i++)
116 s2.append(stars2.getStars()[i]);
117 s2ptr = &s2;
119 }
120
121 // If we have at least 10 matching stars, or 45% of the smallest star set, that's fine.
122 const int sufficientMatches = std::min(10, static_cast<int>(0.45 * std::min(size1, size2)));
123
124 // Pick upto 5 different seed stars, if we need them.
125 // Those are the stars from stars1 that are used in the StarCorrespondence algorithm.
126 int maxMatches = 0;
127 srand(time(0));
128 FocusStars f1, f2;
129 for (int i = 0; i < 5; ++i)
130 {
131 const int seed = rand() % size1;
132 int numMatches = matchStars(*s1ptr, *s2ptr, seed, maxDistance, &f1, &f2);
133 if (numMatches > maxMatches)
134 {
135 *filtered1 = f1;
136 *filtered2 = f2;
137 maxMatches = numMatches;
138 if (numMatches >= sufficientMatches) break;
139 }
140 }
141 return (maxMatches > 1);
142}
143
144} // namespace
145
146
147FocusStars::FocusStars(const QList<Edge *> edges, double maxDist)
148 : maxDistance(maxDist), initialized(true)
149{
150 // Copy the memory--can't depend on it sticking around.
151 for (const auto &edge : edges)
152 stars.append(*edge);
153}
154
155FocusStars::FocusStars(const QList<Edge> edges, double maxDist)
156 : maxDistance(maxDist), initialized(true)
157{
158 // Copy the memory--can't depend on it sticking around.
159 for (const auto &edge : edges)
160 stars.append(edge);
161}
162
163// Fitsdata does a bit of processing, removing saturated stars,
164// removing extremes, but all this is now being done in stellarsolver.
165// Just computing the median HFR.
166double FocusStars::getHFR() const
167{
168 if (!initialized)
169 return -1;
170
171 if (computedHFR >= 0)
172 return computedHFR;
173 if (stars.size() == 0) return -1;
174 std::vector<double> values;
175 for (auto &star : stars)
176 values.push_back(star.HFR);
177 const int middle = values.size() / 2;
178 std::nth_element(values.begin(), values.begin() + middle, values.end());
179 computedHFR = values[middle];
180 return computedHFR;
181}
182
183bool FocusStars::commonHFR(const FocusStars &referenceStars, double *thisHFR, double *referenceHFR) const
184{
185 if (!initialized)
186 return -1;
187
189 bool ok = filterFocusStars(*this, referenceStars, maxDistance, &commonStars, &commonReferenceStars);
190 if (!ok) return false;
191 *thisHFR = commonStars.getHFR();
193
194 if (*thisHFR < 0 || *referenceHFR < 0 || commonStars.getStars().size() == 0 ||
195 commonReferenceStars.getStars().size() == 0)
196 return false;
197
198 return true;
199}
200
201void FocusStars::printStars(const QString &label) const
202{
203 if (label.size() > 0) fprintf(stderr, "%s\n{", label.toLatin1().data());
204 bool first = true;
205 for (const auto &star : getStars())
206 {
207 fprintf(stderr, "%s{%6.1f,%6.1f, %5.2f}", first ? "" : ", ", star.x, star.y, star.HFR);
208 first = false;
209 }
210 fprintf(stderr, "}\n");
211}
212
213double FocusStars::relativeHFR(const FocusStars &referenceStars, double referenceHFR) const
214{
215 if (!initialized)
216 return -1;
217
218 double hfrCommon, refHfrCommon;
219 if (!commonHFR(referenceStars, &hfrCommon, &refHfrCommon))
220 {
221 qCDebug(KSTARS_EKOS_FOCUS) << "Couldn't get a relative HFR, punted!";
222 // Scale the reference hfr by the HFR ratio when we can't find common stars.
223 return (getHFR() / referenceStars.getHFR()) * referenceHFR;
224 }
225
226 if (hfrCommon < 0 || refHfrCommon < 0) return -1;
227
228 QString debugStr = QString("RelativeHFR: sizes: %7 %8 hfr: (%1 (%2) / %3 (%4)) * %5 = %6")
229 .arg(hfrCommon, 0, 'f', 2).arg(getHFR(), 0, 'f', 2).arg(refHfrCommon, 0, 'f', 2)
230 .arg(referenceStars.getHFR(), 0, 'f', 2).arg(referenceHFR, 0, 'f', 2)
231 .arg((hfrCommon / refHfrCommon) * referenceHFR, 0, 'f', 2)
232 .arg(getStars().size()).arg(referenceStars.getStars().size());
233 qCDebug(KSTARS_EKOS_FOCUS) << debugStr;
234
236}
237
238} // namespace
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:78
QString label(StandardShortcut id)
char * data()
QString arg(Args &&... args) const const
qsizetype size() const const
QByteArray toLatin1() const const
float x() const const
float y() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.