7 #include <unordered_map> 
   17     const unsigned char *, 
const Stars &stars, 
const Catalog &catalog, 
const Camera &)
 const {
 
   21     unsigned int randomSeed = 123456;
 
   22     for (
int i = 0; i < (int)stars.size(); i++) {
 
   23         result.push_back(
StarIdentifier(i, rand_r(&randomSeed) % catalog.size()));
 
   30     const unsigned char *database, 
const Stars &stars, 
const Catalog &catalog, 
const Camera &camera)
 const {
 
   35     if (databaseBuffer == NULL) {
 
   41     for (
int i = 0; i < (int)stars.size(); i++) {
 
   42         std::vector<int16_t> votes(catalog.size(), 0);
 
   44         for (
int j = 0; j < (int)stars.size(); j++) {
 
   47                 std::vector<bool> votedInPair(catalog.size(), 
false);
 
   51                 decimal lowerBoundRange = greatCircleDistance - tolerance;
 
   52                 decimal upperBoundRange = greatCircleDistance + tolerance;
 
   53                 const int16_t *upperBoundSearch;
 
   55                     lowerBoundRange, upperBoundRange, &upperBoundSearch);
 
   57                 for (
const int16_t *k = lowerBoundSearch; k != upperBoundSearch; k++) {
 
   58                     if ((k - lowerBoundSearch) % 2 == 0) {
 
   59                         decimal actualAngle = 
AngleUnit(catalog[*k].spatial, catalog[*(k+1)].spatial);
 
   60                         assert(actualAngle <= greatCircleDistance + tolerance * 2);
 
   61                         assert(actualAngle >= greatCircleDistance - tolerance * 2);
 
   63                     if (!votedInPair[*k] || 
true) {
 
   69                         votedInPair[*k] = 
true;
 
   76         int16_t maxVotes = votes[0];
 
   78         for (
int v = 1; v < (int)votes.size(); v++) {
 
   79             if (votes[v] > maxVotes) {
 
  101         identified.push_back(newStar);
 
  108     std::vector<int16_t> verificationVotes(identified.size(), 0);
 
  109     for (
int i = 0; i < (int)identified.size(); i++) {
 
  111         for (
int j = i + 1; j < (int)identified.size(); j++) {
 
  113             CatalogStar first = catalog[identified[i].catalogIndex];
 
  114             CatalogStar second = catalog[identified[j].catalogIndex];
 
  117             Star firstIdentified = stars[identified[i].starIndex];
 
  118             Star secondIdentified = stars[identified[j].starIndex];
 
  126                 verificationVotes[i]++;
 
  127                 verificationVotes[j]++;
 
  132     int maxVotes = verificationVotes.size() > 0 ? verificationVotes[0] : 0;
 
  133     for (
int v = 1; v < (int)verificationVotes.size(); v++) {
 
  134         if (verificationVotes[v] > maxVotes) {
 
  135             maxVotes = verificationVotes[v];
 
  143     int thresholdVotes = maxVotes * 3 / 4;
 
  144     printf(
"Verification threshold: %d\n", thresholdVotes);
 
  145     for (
int i = 0; i < (int)verificationVotes.size(); i++) {
 
  146         if (verificationVotes[i] > thresholdVotes) {
 
  147             verified.push_back(identified[i]);
 
  176         : pairs(NULL), end(NULL) { };
 
  185         : pairs(pairs), end(end), involving(involving) {
 
  187         assert((end-pairs)%2 == 0);
 
  188         ForwardUntilInvolving();
 
  201         ForwardUntilInvolving();
 
  223     const int16_t *pairs;
 
  229     void ForwardUntilInvolving() {
 
  230         while (pairs != end) {
 
  231             if (pairs[0] == involving) {
 
  235             if (pairs[1] == involving) {
 
  245     std::vector<int16_t> result;
 
  247         result.push_back(*it);
 
  260     std::unordered_multimap<int16_t, int16_t> result;
 
  261     for (
const int16_t *p = pairs; p != end; p += 2) {
 
  262         result.emplace(p[0], p[1]);
 
  263         result.emplace(p[1], p[0]);
 
  281     for (
const auto &otherPair : identifiedStarsInRange) {
 
  282         decimal curAngleFrom90 = VerticalAnglesToAngleFrom90(otherPair.first, angleFromVertical);
 
  290     identifiedStarsInRange.emplace_back(angleFromVertical, starId);
 
  300     std::vector<IRUnidentifiedCentroid *> *centroids, 
const Star &star, 
const Camera &camera,
 
  308     std::vector<std::vector<IRUnidentifiedCentroid *>::iterator> result;
 
  309     for (
auto it = centroids->begin(); it != centroids->end(); ++it) {
 
  311         decimal angleCos = ourSpatial * theirSpatial;
 
  312         if (angleCos >= minCos && angleCos <= maxCos) {
 
  313             result.push_back(it);
 
  351                                    std::vector<IRUnidentifiedCentroid *> *aboveThresholdCentroids,
 
  352                                    std::vector<IRUnidentifiedCentroid *> *belowThresholdCentroids,
 
  357     std::vector<int16_t> nowBelowThreshold; 
 
  360         (*centroidIt)->AddIdentifiedStar(starId, stars);
 
  361         if ((*centroidIt)->bestAngleFrom90 <= angleFrom90Threshold) {
 
  362             belowThresholdCentroids->push_back(*centroidIt);
 
  363             nowBelowThreshold.push_back((*centroidIt)->index);
 
  367     aboveThresholdCentroids->erase(std::remove_if(aboveThresholdCentroids->begin(), aboveThresholdCentroids->end(),
 
  369             return std::find(nowBelowThreshold.begin(), nowBelowThreshold.end(), centroid->index) != nowBelowThreshold.end();
 
  370         }), aboveThresholdCentroids->end());
 
  386                                        int16_t catalogIndex1, int16_t catalogIndex2,
 
  390     const int16_t *query1End;
 
  391     const int16_t *query1 = db.
FindPairsExact(catalog, distance1-tolerance, distance1+tolerance, &query1End);
 
  393     const Vec3 &spatial1 = catalog[catalogIndex1].spatial;
 
  394     const Vec3 &spatial2 = catalog[catalogIndex2].spatial;
 
  399     std::vector<int16_t> result;
 
  405         Vec3 candidateSpatial = catalog[*candidateIt].spatial;
 
  410         if (!(angle2 >= distance2-tolerance && angle2 <= distance2+tolerance)) {
 
  415         decimal spectralTorch = cross * candidateSpatial;
 
  418         if (spectralTorch <= 0) {
 
  423         result.push_back(*candidateIt);
 
  430                                                       std::vector<IRUnidentifiedCentroid *> *belowThresholdCentroids) {
 
  431     if (!belowThresholdCentroids->empty()) {
 
  432         auto result = belowThresholdCentroids->back();
 
  433         belowThresholdCentroids->pop_back();
 
  438     auto bestAboveThreshold = std::min_element(aboveThresholdCentroids->begin(), aboveThresholdCentroids->end(),
 
  440             return a->bestAngleFrom90 < b->bestAngleFrom90;
 
  444     if (bestAboveThreshold != aboveThresholdCentroids->end() && (*bestAboveThreshold)->bestAngleFrom90 < 10) {
 
  445         auto result = *bestAboveThreshold;
 
  446         aboveThresholdCentroids->erase(bestAboveThreshold);
 
  467 #ifdef LOST_DEBUG_PERFORMANCE 
  468     auto startTimestamp = std::chrono::steady_clock::now();
 
  471     std::vector<IRUnidentifiedCentroid> allUnidentifiedCentroids;
 
  472     std::vector<IRUnidentifiedCentroid *> aboveThresholdUnidentifiedCentroids;
 
  473     std::vector<IRUnidentifiedCentroid *> belowThresholdUnidentifiedCentroids;
 
  474     allUnidentifiedCentroids.reserve(stars.size());
 
  475     for (
size_t i = 0; i < stars.size(); i++) {
 
  479     aboveThresholdUnidentifiedCentroids.reserve(allUnidentifiedCentroids.size());
 
  480     for (
size_t i = 0; i < allUnidentifiedCentroids.size(); i++) {
 
  482         if (std::find_if(identifiers->begin(), identifiers->end(),
 
  483             [&allUnidentifiedCentroids, i](
const StarIdentifier &identifier) {
 
  484                 return identifier.starIndex == allUnidentifiedCentroids[i].index;
 
  485             }) == identifiers->end()) {
 
  487             aboveThresholdUnidentifiedCentroids.push_back(&allUnidentifiedCentroids[i]);
 
  499     for (
const auto &starId : *identifiers) {
 
  501                                       &aboveThresholdUnidentifiedCentroids, &belowThresholdUnidentifiedCentroids,
 
  507     int numExtraIdentifiedStars = 0;
 
  510     while (!belowThresholdUnidentifiedCentroids.empty() || !aboveThresholdUnidentifiedCentroids.empty()) {
 
  513         if (nextUnidentifiedCentroid == NULL) {
 
  527         std::vector<int16_t> candidates =
 
  540         if (candidates.size() != 1) { 
 
  541             if (candidates.size() > 1) {
 
  542                 std::cerr << 
"WARNING: Multiple catalog stars matched during identify remaining stars. This should be rare." << std::endl;
 
  546             identifiers->emplace_back(nextUnidentifiedCentroid->
index, candidates[0]);
 
  550                                           &aboveThresholdUnidentifiedCentroids, &belowThresholdUnidentifiedCentroids,
 
  556             ++numExtraIdentifiedStars;
 
  561     assert(belowThresholdUnidentifiedCentroids.empty());
 
  563 #ifdef LOST_DEBUG_PERFORMANCE 
  564     auto endTimestamp = std::chrono::steady_clock::now();
 
  565     std::cout << 
"IdentifyRemainingStarsPairDistance took " << std::chrono::duration_cast<std::chrono::microseconds>(endTimestamp - startTimestamp).count() << 
"us" << std::endl;
 
  568     return numExtraIdentifiedStars;
 
  572     const unsigned char *database, 
const Stars &stars, 
const Catalog &catalog, 
const Camera &camera)
 const {
 
  577     if (databaseBuffer == NULL || stars.size() < 4) {
 
  578         std::cerr << 
"Not enough stars, or database missing." << std::endl;
 
  592     int numStars = (int)stars.size();
 
  594     int across = floor(sqrt(numStars))*2;
 
  595     int halfwayAcross = floor(sqrt(numStars)/2);
 
  596     long totalIterations = 0;
 
  598     int jMax = numStars - 3;
 
  599     for (
int jIter = 0; jIter < jMax; jIter++) {
 
  600         int dj = 1+(jIter+halfwayAcross)%jMax;
 
  602         int kMax = numStars-dj-2;
 
  603         for (
int kIter = 0; kIter < kMax; kIter++) {
 
  604             int dk = 1+(kIter+across)%kMax;
 
  606             int rMax = numStars-dj-dk-1;
 
  607             for (
int rIter = 0; rIter < rMax; rIter++) {
 
  608                 int dr = 1+(rIter+halfwayAcross)%rMax;
 
  610                 int iMax = numStars-dj-dk-dr-1;
 
  611                 for (
int iIter = 0; iIter <= iMax; iIter++) {
 
  612                     int i = (iIter + iMax/2)%(iMax+1); 
 
  615                     if (++totalIterations > cutoff) {
 
  616                         std::cerr << 
"Cutoff reached." << std::endl;
 
  624                     assert(i != j && j != k && k != r && i != k && i != r && j != r);
 
  640                     decimal expectedMismatches = expectedMismatchesConstant
 
  643                         / std::max(std::max(iSinInner, jSinInner), kSinInner);
 
  645                     if (expectedMismatches > maxMismatchProbability) {
 
  646                         std::cout << 
"skip: mismatch prob." << std::endl;
 
  653                     bool spectralTorch = iSpatial.
CrossProduct(jSpatial)*kSpatial > 0;
 
  667 #define _CHECK_DISTANCE(_dist) if (_dist < vectorDatabase.MinDistance() + tolerance || _dist > vectorDatabase.MaxDistance() - tolerance) { continue; } 
  673 #undef _CHECK_DISTANCE 
  675                     const int16_t *ijEnd, *ikEnd, *irEnd;
 
  676                     const int16_t *
const ijQuery = vectorDatabase.
FindPairsLiberal(ijDist - tolerance, ijDist + tolerance, &ijEnd);
 
  677                     const int16_t *
const ikQuery = vectorDatabase.
FindPairsLiberal(ikDist - tolerance, ikDist + tolerance, &ikEnd);
 
  678                     const int16_t *
const irQuery = vectorDatabase.
FindPairsLiberal(irDist - tolerance, irDist + tolerance, &irEnd);
 
  683                     int iMatch = -1, jMatch = -1, kMatch = -1, rMatch = -1;
 
  684                     for (
const int16_t *iCandidateQuery = ijQuery; iCandidateQuery != ijEnd; iCandidateQuery++) {
 
  685                         int iCandidate = *iCandidateQuery;
 
  687                         int jCandidate = (iCandidateQuery - ijQuery) % 2 == 0
 
  689                             : iCandidateQuery[-1];
 
  691                         const Vec3 &iCandidateSpatial = catalog[iCandidate].spatial;
 
  692                         const Vec3 &jCandidateSpatial = catalog[jCandidate].spatial;
 
  696                         for (
auto kCandidateIt = ikMap.equal_range(iCandidate); kCandidateIt.first != kCandidateIt.second; kCandidateIt.first++) {
 
  698                             int kCandidate = kCandidateIt.first->second;
 
  699                             Vec3 kCandidateSpatial = catalog[kCandidate].spatial;
 
  700                             bool candidateSpectralTorch = ijCandidateCross*kCandidateSpatial > 0;
 
  702                             if (candidateSpectralTorch != spectralTorch) {
 
  708                             if (jkCandidateDist < jkDist - tolerance || jkCandidateDist > jkDist + tolerance) {
 
  715                             for (
auto rCandidateIt = irMap.equal_range(iCandidate); rCandidateIt.first != rCandidateIt.second; rCandidateIt.first++) {
 
  716                                 int rCandidate = rCandidateIt.first->second;
 
  717                                 const Vec3 &rCandidateSpatial = catalog[rCandidate].spatial;
 
  720                                 if (jrCandidateDist < jrDist - tolerance || jrCandidateDist > jrDist + tolerance) {
 
  723                                 krCandidateDist = 
AngleUnit(kCandidateSpatial, rCandidateSpatial);
 
  724                                 if (krCandidateDist < krDist - tolerance || krCandidateDist > krDist + tolerance) {
 
  738                                     std::cerr << 
"Pyramid not unique, skipping..." << std::endl;
 
  748                         std::cout.precision(6);
 
  749                         std::cout << 
"Matched unique pyramid!" << std::endl << 
"Expected mismatches: " << std::scientific << expectedMismatches << std::endl << std::fixed;
 
  756                         printf(
"Identified an additional %d stars.\n", numAdditionallyIdentified);
 
  757                         assert(numAdditionallyIdentified == (
int)identified.size()-4);
 
  768     std::cerr << 
"Tried all pyramids; none matched." << std::endl;
 
A full description of a camera. Enough information to reconstruct the camera matrix and then some.
Vec3 CameraToSpatial(const Vec2 &) const
Gives a point in 3d space that could correspond to the given vector, using the same coordinate system...
A star from the Bright Star Catalog.
Vec3 spatial
The point on the unit sphere where the star lies.
StarIdentifiers Go(const unsigned char *database, const Stars &, const Catalog &, const Camera &) const
Actualy perform the star idenification. This is the "main" function for StarIdAlgorithm.
StarIdentifiers Go(const unsigned char *database, const Stars &, const Catalog &, const Camera &) const
Actualy perform the star idenification. This is the "main" function for StarIdAlgorithm.
unidentified centroid used in IdentifyRemainingStarsPairDistance The "angles" through here are "trian...
const Star * star
Index into list of all centroids.
StarIdentifier bestStar1
For the pair of other centroids forming the triangular angle closest to 90 degrees,...
void AddIdentifiedStar(const StarIdentifier &starId, const Stars &stars)
When a centroid within range of this centroid is identified, call this function.
StarIdentifier bestStar2
One star corresponding to bestAngleFrom90.
int16_t index
The other star corresponding to bestAngleFrom90.
const unsigned char * SubDatabasePointer(int32_t magicValue) const
MultiDatabase memory layout:
Given a list of star pairs, finds all those pairs which involve a certain star.
PairDistanceInvolvingIterator(const int16_t *pairs, const int16_t *end, int16_t involving)
The main constructor.
int16_t operator*() const
Access the curent pair.
PairDistanceInvolvingIterator & operator++()
Move to the next matching pair.
bool HasValue()
Whether the iterator is currently on a value. (false if iteration is complete)
PairDistanceInvolvingIterator()
Create a "past-the-end" iterator.
A database storing distances between pairs of stars.
decimal MinDistance() const
Lower bound on stored star pair distances.
static const int32_t kMagicValue
Magic value to use when storing inside a MultiDatabase.
const int16_t * FindPairsExact(const Catalog &, decimal min, decimal max, const int16_t **end) const
const int16_t * FindPairsLiberal(decimal min, decimal max, const int16_t **end) const
Return at least all the star pairs whose inter-star distance is between min and max.
decimal MaxDistance() const
Upper bound on stored star pair distances.
StarIdentifiers Go(const unsigned char *database, const Stars &, const Catalog &, const Camera &) const
Actualy perform the star idenification. This is the "main" function for StarIdAlgorithm.
A "centroid" detected in an image.
Vec2 position
The (x,y) pixel coordinates in the image (top left is 0,0)
Records that a certain Star (detected in the image) corresponds to a certain CatalogStar.
int catalogIndex
An index into an array of CatalogStar objects.
int starIndex
An index into an array of Star objects.
Three dimensional vector with decimaling point components.
Vec3 Normalize() const
Create a vector pointing in the same direction with magnitude 1.
Vec3 CrossProduct(const Vec3 &) const
Usual vector cross product.
#define DECIMAL_POW(base, power)
#define DECIMAL_ATAN2(x, y)
const decimal kAngleFrom90SoftThreshold
std::vector< StarIdentifier > StarIdentifiers
std::vector< Star > Stars
decimal AngleUnit(const Vec3 &vec1, const Vec3 &vec2)
Calculate the inner angle, in radians, between two /unit/ vectors.
std::vector< int16_t > ConsumeInvolvingIterator(PairDistanceInvolvingIterator it)
decimal Angle(const Vec3 &vec1, const Vec3 &vec2)
Calculate the inner angle, in radians, between two vectors.
std::vector< std::vector< IRUnidentifiedCentroid * >::iterator > FindUnidentifiedCentroidsInRange(std::vector< IRUnidentifiedCentroid * > *centroids, const Star &star, const Camera &camera, decimal minDistance, decimal maxDistance)
Return all the unidentified centroids within the requested distance bounds from star
int IdentifyRemainingStarsPairDistance(StarIdentifiers *, const Stars &, const PairDistanceKVectorDatabase &, const Catalog &, const Camera &, decimal tolerance)
Given some identified stars, attempt to identify the rest.
decimal DecimalModulo(decimal x, decimal mod)
Given a decimal, find it "modulo" another decimal, in the true mathematical sense (not remainder).
std::vector< int16_t > IdentifyThirdStar(const PairDistanceKVectorDatabase &db, const Catalog &catalog, int16_t catalogIndex1, int16_t catalogIndex2, decimal distance1, decimal distance2, decimal tolerance)
Given two already-identified centroids, and the distance from each to an as-yet unidentified third ce...
std::unordered_multimap< int16_t, int16_t > PairDistanceQueryToMap(const int16_t *pairs, const int16_t *end)
Given the result of a pair-distance kvector query, build a hashmultimap of stars to other stars that ...
std::vector< CatalogStar > Catalog
IRUnidentifiedCentroid * SelectNextUnidentifiedCentroid(std::vector< IRUnidentifiedCentroid * > *aboveThresholdCentroids, std::vector< IRUnidentifiedCentroid * > *belowThresholdCentroids)
void AddToAllUnidentifiedCentroids(const StarIdentifier &starId, const Stars &stars, std::vector< IRUnidentifiedCentroid * > *aboveThresholdCentroids, std::vector< IRUnidentifiedCentroid * > *belowThresholdCentroids, decimal minDistance, decimal maxDistance, decimal angleFrom90Threshold, const Camera &camera)
Given a list of unidentified centroids not yet at the soft threshold, and a list of unidentified cent...
#define _CHECK_DISTANCE(_dist)
A two dimensional vector with decimaling point components.