File indexing completed on 2024-05-12 15:23:44

0001 /*
0002     SPDX-FileCopyrightText: 2020 Hy Murveit <hy@murveit.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QObject>
0010 #include <QList>
0011 #include <QVector>
0012 #include <QVector2D>
0013 
0014 #include "fitsviewer/fitsdata.h"
0015 #include "vect.h"
0016 
0017 /*
0018  * This class is useful to track a guide star by noting its position relative to other stars.
0019  * It is intended to be resilient to translation, a bit of positional noise, and slight field rotation.
0020  * The class is initialized with a set of reference (x,y) positions from stars, where one is
0021  * designated a guide star. Then, given a set of new input star positions, it determines a mapping
0022  * of the new stars to the references. Some reference stars may not be in the new star group, and
0023  * there may be new stars that don't appear in the references. However, the guide star must appear
0024  * in both sets for this to be successful.
0025  */
0026 
0027 class StarCorrespondence
0028 {
0029     public:
0030         // Initializes with reference stars.
0031         // One of the stars with index guideStar is a special "guide star".
0032         StarCorrespondence(const QList<Edge> &stars, int guideStar);
0033         StarCorrespondence();
0034         ~StarCorrespondence() {}
0035 
0036         // If the default constructor was called, then initialize must be called with the
0037         // reference star positions and the index in stars of the guideStar.
0038         void initialize(const QList<Edge> &stars, int guideStar);
0039 
0040         // Clears the references.
0041         void reset();
0042 
0043         // Associate the input stars with the reference stars.
0044         // StarMap[i] will contain the index of a reference star that corresponds to the ith star.
0045         // Some input stars may have no reference (starMap->at(i) == -1), and some references may
0046         // not correspond to any input stars. There will be no star-reference mapping with
0047         // distance longer than maxDistance. If adapt is true, the input positions are used
0048         // to incrementally adapt the reference positions.
0049         Edge find(const QList<Edge> &stars, double maxDistance, QVector<int> *starMap, bool adapt = true, double minFraction = 0.5);
0050 
0051         // Returns the number of reference stars.
0052         int size() const
0053         {
0054             return references.size();
0055         }
0056 
0057         // Return a reference to the ith reference star. Caller's responsiblity
0058         // to make sure i >= 0 && i < references.size();
0059         // Recompute the reference coordinates as we may adapt them.
0060         Edge reference(int i) const
0061         {
0062             Edge star = references[i];
0063             star.x = references[guideStarIndex].x + guideStarOffsets[i].x;
0064             star.y = references[guideStarIndex].y + guideStarOffsets[i].y;
0065             return star;
0066         }
0067         QVector2D offset(int i) const
0068         {
0069             QVector2D offset;
0070             offset.setX(guideStarOffsets[i].x);
0071             offset.setY(guideStarOffsets[i].y);
0072             return offset;
0073         }
0074 
0075         int guideStar() const
0076         {
0077             return guideStarIndex;
0078         }
0079 
0080         void setAllowMissingGuideStar(bool value = true)
0081         {
0082             allowMissingGuideStar = value;
0083         }
0084 
0085         void setImageSize(int width, int height)
0086         {
0087             imageWidth = width;
0088             imageHeight = height;
0089         }
0090 
0091         int getNumReferencesFound() const
0092         {
0093             return m_NumReferencesFound;
0094         }
0095 
0096     private:
0097         // The Offsets structure is used to keep the positions of the reference stars
0098         // relative to the guide star.
0099         struct Offsets
0100         {
0101             double x;  // The x position of the star (in pixels), relative to the guide star.
0102             double y;  // The y position of the star (in pixels), relative to the guide star.
0103 
0104             Offsets(double x_, double y_) : x(x_), y(y_) {}
0105             Offsets() : x(0), y(0) {}  // RPi compiler required this constructor.
0106         };
0107 
0108         // Update the reference-star offsets given the new star positions.
0109         // The adaption is similar to a 25-sample moving average.
0110         void initializeAdaptation();
0111         void adaptOffsets(const QList<Edge> &stars, const QVector<int> &starMap);
0112 
0113         // Utility used by find. Useful for iterating when the guide star is missing.
0114         int findInternal(const QList<Edge> &stars, double maxDistance, QVector<int> *starMap,
0115                          int guideStarIndex, const QVector<Offsets> &offsets,
0116                          int *numFound, int *numNotFound, double minFraction) const;
0117 
0118         // Used to when guide star is missing. Creates offsets as if other stars were the guide star.
0119         void makeOffsets(const QVector<Offsets> &offsets, QVector<Offsets> *targetOffsets, int targetStar) const;
0120 
0121         // When the guide star is missing, but star correspondence was successful, use the positions
0122         // of the stars that were found to create a virtual guide star--inferring a guide star position
0123         // using the offsets from the (unfound) guide star to the stars that were found.
0124         // Offsets are offsets that were created for a new "substitude guide star".
0125         // StarMap is the map made for that substitude by findInternal().
0126         // Offset is the offset from the original guide star to that substitute guide star.
0127         Edge inventStarPosition(const QList<Edge> &stars, const QVector<int> &starMap,
0128                                 QVector<Offsets> offsets, Offsets offset) const;
0129 
0130         // Finds the star closest to x,y. Returns the index in sortedStars.
0131         // sortedStars should be sorted in x, which allows for a speedup in search.
0132         int findClosestStar(double x, double y, const QList<Edge> sortedStars,
0133                             double maxDistance, double *distance) const;
0134 
0135         // The offsets of the reference stars relative to the guide star.
0136         QVector<Offsets> guideStarOffsets;
0137 
0138         // Size stats for the reference stars.
0139         QVector<float> referenceSums;
0140         QVector<float> referenceNumPixels;
0141 
0142         QList<Edge> references;    // The original reference stars.
0143         int guideStarIndex;        // The index of the guide star in references.
0144         bool initialized = false;  // Set to true once the references and guideStar index has been set.
0145 
0146         // If this is true, it will attempt star correspondence even if the guide star is missing.
0147         bool allowMissingGuideStar { false };
0148 
0149         // IIR filter parameter used to adapt offsets.
0150         double alpha;
0151 
0152         // Setting imageWidth and height can speed up searching for stars in an image
0153         // by eliminating positions far outside the image.
0154         int imageWidth { 100000000 };
0155         int imageHeight { 100000000 };
0156 
0157         // Number of references found in last call to find().
0158         int m_NumReferencesFound { 0 };
0159 
0160         // A copy of the original reference offsets used so that the values don't move too far.
0161         QVector<Offsets> originalGuideStarOffsets;
0162 };
0163