Kstars

focusstars.cpp
1 #include "focusstars.h"
2 #include "ekos/guide/internalguide/starcorrespondence.h"
3 #include <ekos_focus_debug.h>
4 
5 namespace Ekos
6 {
7 
8 namespace
9 {
10 
11 using 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?
18 double 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.
49 int matchStars(const QList<Edge> &stars1, const QList<Edge> &stars2, int mainStar1,
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 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  auto gsPosition = corr.find(stars2, maxDistance, &starMap, false, minFraction);
65 
66  // Grab the two sets of stars.
67  const int s2Size = starMap.size();
68  int numAssociated = 0;
69  QList<Edge> edges1, edges2;
70  for (int s2 = 0; s2 < s2Size; s2++)
71  {
72  const int s1 = starMap[s2];
73  if (s1 >= 0)
74  {
75  numAssociated++;
76  edges1.append(stars1[s1]);
77  edges2.append(stars2[s2]);
78  }
79  }
80  *stars1Filtered = FocusStars(edges1);
81  *stars2Filtered = FocusStars(edges2);
82 
83  // debug
84  double corrError = correspondenceRmsError(corr, stars2, starMap, gsPosition);
85  QString debugStr = QString("matchStars: Inputs sized %1 %2 found %3 matches, RMS dist %4")
86  .arg(stars1.size()).arg(stars2.size()).arg(numAssociated).arg(corrError, 0, 'f', 1);
87  qCDebug(KSTARS_EKOS_FOCUS) << debugStr;
88 
89  return numAssociated;
90 }
91 
92 bool filterFocusStars(const FocusStars &stars1, const FocusStars &stars2, double maxDistance, FocusStars *filtered1,
93  FocusStars *filtered2)
94 {
95  int size1 = stars1.getStars().size();
96  int size2 = stars2.getStars().size();
97 
98  // This section limits the process to the first 100 stars, for computational reasons,
99  // just in case there is an input with a large number of stars.
100  constexpr int maxNumStars = 100;
101  QList<Edge> s1;
102  const QList<Edge> *s1ptr = &(stars1.getStars());
103  if (size1 > maxNumStars)
104  {
105  for (int i = 0; i < maxNumStars; i++)
106  s1.append(stars1.getStars()[i]);
107  s1ptr = &s1;
108  size1 = maxNumStars;
109  }
110  QList<Edge> s2;
111  const QList<Edge> *s2ptr = &(stars2.getStars());
112  if (size2 > maxNumStars)
113  {
114  for (int i = 0; i < maxNumStars; i++)
115  s2.append(stars2.getStars()[i]);
116  s2ptr = &s2;
117  size2 = maxNumStars;
118  }
119 
120  // If we have at least 10 matching stars, or 45% of the smallest star set, that's fine.
121  const int sufficientMatches = std::min(10, static_cast<int>(0.45 * std::min(size1, size2)));
122 
123  // Pick upto 5 different seed stars, if we need them.
124  // Those are the stars from stars1 that are used in the StarCorrespondence algorithm.
125  int maxMatches = 0;
126  srand(time(0));
127  FocusStars f1, f2;
128  for (int i = 0; i < 5; ++i)
129  {
130  const int seed = rand() % size1;
131  int numMatches = matchStars(*s1ptr, *s2ptr, seed, maxDistance, &f1, &f2);
132  if (numMatches > maxMatches)
133  {
134  *filtered1 = f1;
135  *filtered2 = f2;
136  maxMatches = numMatches;
137  if (numMatches >= sufficientMatches) break;
138  }
139  }
140  return (maxMatches > 1);
141 }
142 
143 } // namespace
144 
145 
146 FocusStars::FocusStars(const QList<Edge *> edges, double maxDist)
147  : maxDistance(maxDist), initialized(true)
148 {
149  // Copy the memory--can't depend on it sticking around.
150  for (const auto &edge : edges)
151  stars.append(*edge);
152 }
153 
154 FocusStars::FocusStars(const QList<Edge> edges, double maxDist)
155  : maxDistance(maxDist), initialized(true)
156 {
157  // Copy the memory--can't depend on it sticking around.
158  for (const auto &edge : edges)
159  stars.append(edge);
160 }
161 
162 // Fitsdata does a bit of processing, removing saturated stars,
163 // removing extremes, but all this is now being done in stellarsolver.
164 // Just computing the median HFR.
165 double FocusStars::getHFR() const
166 {
167  if (!initialized)
168  return -1;
169 
170  if (computedHFR >= 0)
171  return computedHFR;
172  if (stars.size() == 0) return -1;
173  std::vector<double> values;
174  for (auto &star : stars)
175  values.push_back(star.HFR);
176  const int middle = values.size() / 2;
177  std::nth_element(values.begin(), values.begin() + middle, values.end());
178  computedHFR = values[middle];
179  return computedHFR;
180 }
181 
182 bool FocusStars::commonHFR(const FocusStars &referenceStars, double *thisHFR, double *referenceHFR) const
183 {
184  if (!initialized)
185  return -1;
186 
187  FocusStars commonStars, commonReferenceStars;
188  bool ok = filterFocusStars(*this, referenceStars, maxDistance, &commonStars, &commonReferenceStars);
189  if (!ok) return false;
190  *thisHFR = commonStars.getHFR();
191  *referenceHFR = commonReferenceStars.getHFR();
192 
193  if (*thisHFR < 0 || *referenceHFR < 0 || commonStars.getStars().size() == 0 ||
194  commonReferenceStars.getStars().size() == 0)
195  return false;
196 
197  return true;
198 }
199 
200 void FocusStars::printStars(const QString &label) const
201 {
202  if (label.size() > 0) fprintf(stderr, "%s\n{", label.toLatin1().data());
203  bool first = true;
204  for (const auto &star : getStars())
205  {
206  fprintf(stderr, "%s{%6.1f,%6.1f, %5.2f}", first ? "" : ", ", star.x, star.y, star.HFR);
207  first = false;
208  }
209  fprintf(stderr, "}\n");
210 }
211 
212 double FocusStars::relativeHFR(const FocusStars &referenceStars, double referenceHFR) const
213 {
214  if (!initialized)
215  return -1;
216 
217  double hfrCommon, refHfrCommon;
218  if (!commonHFR(referenceStars, &hfrCommon, &refHfrCommon))
219  {
220  qCDebug(KSTARS_EKOS_FOCUS) << "Couldn't get a relative HFR, punted!";
221  // Scale the reference hfr by the HFR ratio when we can't find common stars.
222  return (getHFR() / referenceStars.getHFR()) * referenceHFR;
223  }
224 
225  if (hfrCommon < 0 || refHfrCommon < 0) return -1;
226 
227  QString debugStr = QString("RelativeHFR: sizes: %7 %8 hfr: (%1 (%2) / %3 (%4)) * %5 = %6")
228  .arg(hfrCommon, 0, 'f', 2).arg(getHFR(), 0, 'f', 2).arg(refHfrCommon, 0, 'f', 2)
229  .arg(referenceStars.getHFR(), 0, 'f', 2).arg(referenceHFR, 0, 'f', 2)
230  .arg((hfrCommon / refHfrCommon) * referenceHFR, 0, 'f', 2)
231  .arg(getStars().size()).arg(referenceStars.getStars().size());
232  qCDebug(KSTARS_EKOS_FOCUS) << debugStr;
233 
234  return (hfrCommon / refHfrCommon) * referenceHFR;
235 }
236 
237 } // namespace
void append(const T &value)
int size() const const
Ekos is an advanced Astrophotography tool for Linux. It is based on a modular extensible framework to...
Definition: align.cpp:70
QByteArray toLatin1() const const
int size() const const
QString label(StandardShortcut id)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
int size() const const
float x() const const
float y() const const
QVector< V > values(const QMultiHash< K, V > &c)
char * data()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Aug 8 2022 04:13:20 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.