3#include <cairo/cairo.h>
36 std::cerr <<
"WARNING: output contains binary contents. Not printed to terminal." << std::endl;
44 std::fstream *
fs =
new std::fstream();
59 std::vector<CatalogStar>
result;
73 #ifdef LOST_FLOAT_MODE
74 std::string
format =
"%f|%f|%d|%c|%d.%d";
76 std::string
format =
"%lf|%lf|%d|%c|%d.%d";
94#ifndef DEFAULT_BSC_PATH
95#define DEFAULT_BSC_PATH "bright-star-catalog.tsv"
101 static std::vector<CatalogStar> catalog;
110 return a.spatial.x < b.spatial.x;
112 for (
int i = catalog.size()-1; i > 0; i--) {
113 if ((catalog[i].spatial - catalog[i-1].spatial).Magnitude() <
DECIMAL(5
e-5)) {
114 if (catalog[i].magnitude > catalog[i-1].magnitude) {
115 catalog.erase(catalog.begin() + i);
117 catalog.erase(catalog.begin() + i - 1);
134 puts(
"Can't convert weird image formats to grayscale.");
141 result =
new unsigned char[width*height];
144 for (
int i = 0; i < height * width; i++) {
148 (
pixel>>16 &0xFF) *0.21 +
149 (
pixel>>8 &0xFF) *0.71 +
150 (
pixel &0xFF) *0.07);
157 const int width,
const int height) {
163 for (
long i = 0; i < width * height; i++) {
165 resultData[i] = (image[i] << 16) + (image[i] << 8) + (image[i]);
228 metadata += std::to_string(stars.size()) +
" centroids ";
230 if (starIds !=
NULL) {
248 metadata += std::to_string(starIds->size()) +
" identified ";
251 if (attitude !=
NULL) {
291 long numBins =
values.kvectorNumDistanceBins;
296 std::cerr <<
"No database builder selected -- no database generated." << std::endl;
305 os <<
"camera_focal_length " << camera.
FocalLength() << std::endl
306 <<
"camera_fov " << camera.
Fov() << std::endl
307 <<
"camera_resolution_x " << camera.
XResolution() << std::endl
308 <<
"camera_resolution_y " << camera.
YResolution() << std::endl;
320 if ((
values.pixelSize != -1) ^ (
values.focalLength != 0)) {
321 std::cerr <<
"ERROR: Exactly one of --pixel-size or --focal-length were set." << std::endl;
327 std::cerr <<
"ERROR: Both focal length and FOV were provided. We only need one of the two methods (pixel size + focal length, or fov) to determine fov, please only provide one." << std::endl;
331 if (
values.pixelSize == -1) {
367 : camera(camera), catalog(catalog) {
375 delete[] image.
image;
488 std::default_random_engine *
rng,
506 : camera(camera), attitude(attitude), catalog(catalog) {
518 std::cerr <<
"WARNING: oversampling was not a perfect square. Rounding up to "
541 for (
int i = 0; i < numFalseStars; i++) {
587 expectedStars.push_back(star);
590 expectedStarIds.push_back(
StarIdentifier(expectedStars.size()-1, i));
675 imageData = std::vector<unsigned char>(image.
width*image.
height);
676 image.
image = imageData.data();
677 for (
int i = 0; i < image.
width * image.
height; i++) {
695 std::cout <<
"ERROR: One of the pixels had too many photons. Generated image would not be physically accurate, exiting." << std::endl;
715static Attitude RandomAttitude(std::default_random_engine*
pReng) {
762 for (
int i = 0; i <
values.generate; i++) {
766 if (
values.generateRandomAttitudes) {
778 values.generateCentroidsOnly,
779 values.generateZeroMagPhotons,
780 values.generateSpreadStdDev,
781 values.generateSaturationPhotons,
782 values.generateDarkCurrent,
783 values.generateReadNoiseStdDev,
786 values.generateReadoutTime,
788 values.generateOversampling,
789 values.generateNumFalseStars,
790 (
values.generateFalseMinMag * 100),
791 (
values.generateFalseMaxMag * 100),
792 (
values.generateCutoffMag * 100),
793 values.generatePerturbationStddev);
795 result.push_back(std::unique_ptr<PipelineInput>(
curr));
824 unsigned char *database)
826 if (centroidAlgorithm) {
827 this->centroidAlgorithm = std::unique_ptr<CentroidAlgorithm>(centroidAlgorithm);
829 if (starIdAlgorithm) {
830 this->starIdAlgorithm = std::unique_ptr<StarIdAlgorithm>(starIdAlgorithm);
832 if (attitudeEstimationAlgorithm) {
833 this->attitudeEstimationAlgorithm = std::unique_ptr<AttitudeEstimationAlgorithm>(attitudeEstimationAlgorithm);
836 this->database = std::unique_ptr<unsigned char[]>(database);
851 if (
values.centroidAlgo ==
"dummy") {
853 }
else if (
values.centroidAlgo ==
"cog") {
855 }
else if (
values.centroidAlgo ==
"iwcog") {
857 }
else if (
values.centroidAlgo !=
"") {
858 std::cout <<
"Illegal centroid algorithm." << std::endl;
863 if (
values.centroidMagFilter > 0)
result.centroidMinMagnitude =
values.centroidMagFilter;
864 if (
values.centroidFilterBrightest > 0)
result.centroidMinStars =
values.centroidFilterBrightest;
867 if (
values.databasePath !=
"") {
869 fs.open(
values.databasePath, std::fstream::in | std::fstream::binary);
874 std::cerr <<
"Error reading database! " <<
strerror(
errno) << std::endl;
877 std::cerr <<
"Reading " <<
length <<
" bytes of database" << std::endl;
878 result.database = std::unique_ptr<unsigned char[]>(
new unsigned char[
length]);
880 std::cerr <<
"Done" << std::endl;
883 if (
values.idAlgo ==
"dummy") {
885 }
else if (
values.idAlgo ==
"gv") {
887 }
else if (
values.idAlgo ==
"py") {
889 }
else if (
values.idAlgo !=
"") {
890 std::cout <<
"Illegal id algorithm." << std::endl;
894 if (
values.attitudeAlgo ==
"dqm") {
896 }
else if (
values.attitudeAlgo ==
"triad") {
897 result.attitudeEstimationAlgorithm = std::unique_ptr<AttitudeEstimationAlgorithm>(
new TriadAlgorithm());
898 }
else if (
values.attitudeAlgo ==
"quest") {
899 result.attitudeEstimationAlgorithm = std::unique_ptr<AttitudeEstimationAlgorithm>(
new QuestAlgorithm());
900 }
else if (
values.attitudeAlgo !=
"") {
901 std::cout <<
"Illegal attitude algorithm." << std::endl;
931 std::cerr <<
"WARNING: That database does not include a catalog. Proceeding with the full catalog." << std::endl;
941 std::chrono::time_point<std::chrono::steady_clock>
start = std::chrono::steady_clock::now();
946 std::chrono::time_point<std::chrono::steady_clock> end = std::chrono::steady_clock::now();
947 result.centroidingTimeNs = std::chrono::duration_cast<std::chrono::nanoseconds>(end -
start).count();
951 if (centroidMinStars > 0
963 assert(star.magnitude >= 0);
976 }
else if (centroidAlgorithm) {
977 std::cerr <<
"ERROR: Centroid algorithm specified, but no input image to run it on." << std::endl;
981 if (starIdAlgorithm && database && inputStars &&
input.InputCamera()) {
983 std::chrono::time_point<std::chrono::steady_clock>
start = std::chrono::steady_clock::now();
985 result.starIds = std::unique_ptr<StarIdentifiers>(
new std::vector<StarIdentifier>(
986 starIdAlgorithm->Go(database.get(), *inputStars,
result.catalog, *
input.InputCamera())));
988 std::chrono::time_point<std::chrono::steady_clock> end = std::chrono::steady_clock::now();
989 result.starIdTimeNs = std::chrono::duration_cast<std::chrono::nanoseconds>(end -
start).count();
991 inputStarIds =
result.starIds.get();
992 }
else if (starIdAlgorithm) {
993 std::cerr <<
"ERROR: Star ID algorithm specified but cannot run because database, centroids, or camera are missing." << std::endl;
997 if (attitudeEstimationAlgorithm && inputStarIds &&
input.InputCamera()) {
999 std::chrono::time_point<std::chrono::steady_clock>
start = std::chrono::steady_clock::now();
1001 result.attitude = std::unique_ptr<Attitude>(
1002 new Attitude(attitudeEstimationAlgorithm->Go(*
input.InputCamera(), *inputStars,
result.catalog, *inputStarIds)));
1004 std::chrono::time_point<std::chrono::steady_clock> end = std::chrono::steady_clock::now();
1005 result.attitudeEstimationTimeNs = std::chrono::duration_cast<std::chrono::nanoseconds>(end -
start).count();
1006 }
else if (attitudeEstimationAlgorithm) {
1007 std::cerr <<
"ERROR: Attitude estimation algorithm set, but either star IDs or camera are missing. One reason this can happen: Setting a centroid algorithm and attitude algorithm, but no star-id algorithm -- that can't work because the input star-ids won't properly correspond to the output centroids!" << std::endl;
1016 std::vector<PipelineOutput>
result;
1019 for (
const std::unique_ptr<PipelineInput> &
input :
inputs) {
1064 std::multimap<int, int>
result;
1066 for (
int i = 0; i < (
int)
one.size(); i++) {
1067 std::vector<std::pair<decimal, int>>
closest;
1068 for (
int k = 0; k < (
int)
two.size(); k++) {
1075 for (
const std::pair<decimal, int> &
pair :
closest) {
1103 result.numExtraCentroids++;
1106 result.numCorrectCentroids++;
1137 const Stars &expectedStars,
const Stars &inputStars) {
1162 for (
int i = 0; i < (
int)inputStars.size(); i++) {
1216 const std::vector<PipelineOutput> &,
1221 std::ostream *
os = (std::ostream *)
closure;
1227static void PipelineComparatorPlotRawInput(std::ostream &
os,
1229 const std::vector<PipelineOutput> &,
1230 const PipelineOptions &) {
1239static void PipelineComparatorPlotInput(std::ostream &
os,
1241 const std::vector<PipelineOutput> &,
1242 const PipelineOptions &) {
1252 0.0, 1.0, 0.0, 0.6);
1257static void PipelineComparatorPlotExpected(std::ostream &
os,
1259 const std::vector<PipelineOutput> &,
1260 const PipelineOptions &) {
1270 0.2, 0.5, 1.0, 0.7);
1276static void PipelineComparatorCentroids(std::ostream &
os,
1278 const std::vector<PipelineOutput> &
actual,
1279 const PipelineOptions &
values) {
1285 for (
int i = 0; i <
size; i++) {
1292 os <<
"centroids_num_correct " <<
result.numCorrectCentroids << std::endl
1293 <<
"centroids_num_extra " <<
result.numExtraCentroids << std::endl
1294 <<
"centroids_mean_error " <<
result.meanError << std::endl;
1297static void PrintCentroids(
const std::string &
prefix,
1300 const std::vector<Stars> &
starses,
1313 for (
int i = 0; i < (
int)stars.size(); i++) {
1314 os <<
prefix <<
"_centroid_" << i <<
"_x " << stars[i].position.x << std::endl;
1315 os <<
prefix <<
"_centroid_" << i <<
"_y " << stars[i].position.y << std::endl;
1317 for (
const StarIdentifier &
starId : *starIds) {
1318 if (
starId.starIndex == i) {
1319 os <<
prefix <<
"_centroid_" << i <<
"_id " << catalog[
starId.catalogIndex].name << std::endl;
1328static void PipelineComparatorPrintExpectedCentroids(std::ostream &
os,
1330 const std::vector<PipelineOutput> &,
1331 const PipelineOptions &) {
1339 PrintCentroids(
"expected",
1346static void PipelineComparatorPrintInputCentroids(std::ostream &
os,
1348 const std::vector<PipelineOutput> &,
1349 const PipelineOptions &) {
1357 PrintCentroids(
"input",
1364static void PipelineComparatorPrintActualCentroids(std::ostream &
os,
1366 const std::vector<PipelineOutput> &
actual,
1367 const PipelineOptions &
values) {
1375 PrintCentroids(
"actual",
1379 actual[0].starIds.get());
1389 auto end =
range.second;
1396 for (
const StarIdentifier &
starId : *
expected[0]->ExpectedStarIds()) {
1400 std::cout <<
"actual_centroid_" << i <<
"_expected_id_" << j <<
" " <<
expectedName << std::endl;
1413 const std::vector<PipelineOutput> &
actual,
1417 for (
int i = 0; i < (
int)stars.size(); i++) {
1436static void PipelineComparatorPlotOutput(std::ostream &
os,
1438 const std::vector<PipelineOutput> &
actual,
1439 const PipelineOptions &) {
1449 1.0, 0.0, 0.0, 0.5);
1455static void PipelineComparatorStarIds(std::ostream &
os,
1457 const std::vector<PipelineOutput> &
actual,
1458 const PipelineOptions &
values) {
1474 values.centroidCompareThreshold, *
expected[i]->ExpectedStars(), inputStars);
1477 os <<
"starid_num_correct " <<
comparison.numCorrect << std::endl;
1478 os <<
"starid_num_incorrect " <<
comparison.numIncorrect << std::endl;
1479 os <<
"starid_num_total " <<
comparison.numTotal << std::endl;
1495static void PrintAttitude(std::ostream &
os,
const std::string &
prefix,
const Attitude &attitude) {
1496 if (attitude.IsKnown()) {
1497 os <<
prefix <<
"attitude_known 1" << std::endl;
1499 EulerAngles
spherical = attitude.ToSpherical();
1504 Quaternion
q = attitude.GetQuaternion();
1505 os <<
prefix <<
"attitude_i " <<
q.i << std::endl;
1506 os <<
prefix <<
"attitude_j " <<
q.j << std::endl;
1507 os <<
prefix <<
"attitude_k " <<
q.k << std::endl;
1508 os <<
prefix <<
"attitude_real " <<
q.real << std::endl;
1511 os <<
prefix <<
"attitude_known 0" << std::endl;
1516static void PipelineComparatorPrintAttitude(std::ostream &
os,
1518 const std::vector<PipelineOutput> &
actual,
1519 const PipelineOptions &) {
1522 PrintAttitude(
os,
"", *
actual[0].attitude);
1525static void PipelineComparatorPrintExpectedAttitude(std::ostream &
os,
1527 const std::vector<PipelineOutput> &,
1528 const PipelineOptions &) {
1531 PrintAttitude(
os,
"expected_", *
expected[0]->ExpectedAttitude());
1535static void PipelineComparatorAttitude(std::ostream &
os,
1537 const std::vector<PipelineOutput> &
actual,
1538 const PipelineOptions &
values) {
1547 int numIncorrect = 0;
1550 if (
actual[i].attitude->IsKnown()) {
1574static void PrintTimeStats(std::ostream &
os,
const std::string &
prefix,
const std::vector<long long> &
times) {
1581 for (
int i = 0; i < (
int)
times.size(); i++) {
1584 min = std::min(min,
times[i]);
1585 max = std::max(max,
times[i]);
1598 os <<
prefix <<
"_min_ns " << min << std::endl;
1599 os <<
prefix <<
"_max_ns " << max << std::endl;
1604static void PipelineComparatorPrintSpeed(std::ostream &
os,
1606 const std::vector<PipelineOutput> &
actual,
1607 const PipelineOptions &) {
1612 for (
int i = 0; i < (
int)
actual.size(); i++) {
1614 if (
actual[i].centroidingTimeNs > 0) {
1618 if (
actual[i].starIdTimeNs > 0) {
1622 if (
actual[i].attitudeEstimationTimeNs > 0) {
1704 const std::vector<PipelineOutput> &
actual,
1706 if (
actual.size() == 0) {
1707 std::cerr <<
"ERROR: No output! Did you specify any input images? Try --png or --generate." << std::endl;
1715#define LOST_PIPELINE_COMPARE(precondition, errmsg, comparator, path, isBinary) do { \
1716 if (precondition) { \
1717 UserSpecifiedOutputStream pos(path, isBinary); \
1718 comparator(pos.Stream(), expected, actual, values); \
1720 std::cerr << "ERROR: Comparator not applicable: " << errmsg << std::endl; \
1725 if (
values.plotRawInput !=
"") {
1727 "--plot-raw-input requires exactly 1 input image, but " + std::to_string(
expected.size()) +
" many were provided.",
1728 PipelineComparatorPlotRawInput,
values.plotRawInput,
true);
1731 if (
values.plotInput !=
"") {
1733 "--plot-input requires exactly 1 input image, and for centroids to be available on that input image. " + std::to_string(
expected.size()) +
" many input images were provided.",
1734 PipelineComparatorPlotInput,
values.plotInput,
true);
1736 if (
values.plotExpected !=
"") {
1738 "--plot-expected-input requires exactly 1 input image, and for expected centroids to be available on that input image. " + std::to_string(
expected.size()) +
" many input images were provided.",
1739 PipelineComparatorPlotExpected,
values.plotExpected,
true);
1741 if (
values.plotOutput !=
"") {
1743 "--plot-output requires exactly 1 output image, and for either centroids or star IDs to be available on that output image. " + std::to_string(
actual.size()) +
" many output images were provided.",
1744 PipelineComparatorPlotOutput,
values.plotOutput,
true);
1746 if (
values.printExpectedCentroids !=
"") {
1748 "--print-expected-centroids requires at least 1 input with expected centroids. " + std::to_string(
expected.size()) +
" many input images were provided.",
1749 PipelineComparatorPrintExpectedCentroids,
values.printExpectedCentroids,
false);
1751 if (
values.printInputCentroids !=
"") {
1753 "--print-input-centroids requires at least 1 input with centroids. " + std::to_string(
expected.size()) +
" many input images were provided.",
1754 PipelineComparatorPrintInputCentroids,
values.printInputCentroids,
false);
1756 if (
values.printActualCentroids !=
"") {
1758 "--print-actual-centroids requires at least 1 output image, and for centroids to be available on the output images. " + std::to_string(
actual.size()) +
" many output images were provided.",
1759 PipelineComparatorPrintActualCentroids,
values.printActualCentroids,
false);
1761 if (
values.plotCentroidIndices !=
"") {
1763 "--plot-centroid-indices requires exactly 1 input with image. " + std::to_string(
expected.size()) +
" many inputs were provided.",
1766 if (
values.compareCentroids !=
"") {
1768 "--compare-centroids requires at least 1 output image, and for expected centroids to be available on the input image. " + std::to_string(
actual.size()) +
" many output images were provided.",
1769 PipelineComparatorCentroids,
values.compareCentroids,
false);
1771 if (
values.compareStarIds !=
"") {
1773 "--compare-star-ids requires at least 1 output image, and for expected star IDs and centroids to be available on the input image. " + std::to_string(
actual.size()) +
" many output images were provided.",
1774 PipelineComparatorStarIds,
values.compareStarIds,
false);
1776 if (
values.printAttitude !=
"") {
1778 "--print-attitude requires exactly 1 output image, and for attitude to be available on that output image. " + std::to_string(
actual.size()) +
" many output images were provided.",
1779 PipelineComparatorPrintAttitude,
values.printAttitude,
false);
1781 if (
values.printExpectedAttitude !=
"") {
1783 "--print-expected-attitude requires exactly 1 input image, and for expected attitude to be available on that input image. " + std::to_string(
expected.size()) +
" many input images were provided.",
1784 PipelineComparatorPrintExpectedAttitude,
values.printExpectedAttitude,
false);
1786 if (
values.compareAttitudes !=
"") {
1788 "--compare-attitudes requires at least 1 output image, and for expected attitude to be available on the input image. " + std::to_string(
actual.size()) +
" many output images were provided.",
1789 PipelineComparatorAttitude,
values.compareAttitudes,
false);
1791 if (
values.printSpeed !=
"") {
1794 "--print-speed requires at least 1 output image. " + std::to_string(
actual.size()) +
" many output images were provided.",
1795 PipelineComparatorPrintSpeed,
values.printSpeed,
false);
1798#undef LOST_PIPELINE_COMPARE
An attitude estimation algorithm estimates the orientation of the camera based on identified stars.
The attitude (orientation) of a spacecraft.
EulerAngles ToSpherical() const
Get the euler angles from the attitude, converting from whatever format is stored.
Vec3 Rotate(const Vec3 &) const
Convert a vector from the reference frame to the body frame.
Quaternion GetQuaternion() const
Get the quaternion representing the attitude, converting from whatever format is stored.
A full description of a camera. Enough information to reconstruct the camera matrix and then some.
Vec2 SpatialToCamera(const Vec3 &) const
Converts from a 3D point in space to a 2D point on the camera sensor.
bool InSensor(const Vec2 &vector) const
Returns whether a given pixel is actually in the camera's field of view.
int XResolution() const
Width of the sensor in pixels.
int YResolution() const
Height of the sensor in pixels.
decimal Fov() const
Horizontal field of view in radians.
decimal FocalLength() const
Focal length in pixels.
A star from the Bright Star Catalog.
A simple, fast, and pretty decent centroid algorithm.
An algorithm that detects the (x,y) coordinates of bright points in an image, called "centroids".
The result of comparing actual and expected centroids Used for debugging and benchmarking.
decimal numExtraCentroids
Stars in actual but not expected.
decimal numCorrectCentroids
Number of actual stars within the centroiding threshold of an expected star.
decimal meanError
Average distance from actual to expected centroids (in pixels) Only correct centroids are considered ...
Commannd line options when using the database command.
A slow but reliable attitude estimation algorithm.
A centroid algorithm for debugging that returns random centroids.
A star-id algorithm that returns random results. For debugging.
A "human-readable" way to represent a 3d rotation or orientation.
A star used in simulated image generation. Contains extra data about how to simulate the star.
decimal peakBrightness
the brightness density per time unit at the center of the star. 0.0 is black, 1.0 is white.
GeneratedStar(Star star, decimal peakBrightness, Vec2 motionBlurDelta)
Vec2 delta
(only meaningful with motion blur) Where the star will appear one time unit in the future.
A star-id algorithm based on assigning votes for each centroid-catalog pair then choosing the highest...
An 8-bit grayscale 2d image.
unsigned char * image
The raw pixel data in the image.
A more complicated centroid algorithm which doesn't perform much better than CenterOfGravityAlgorithm...
static const int32_t kMagicValue
Magic value to use when storing inside a MultiDatabase.
A set of algorithms that describes all or part of the star-tracking "pipeline".
PipelineOutput Go(const PipelineInput &)
Run all stages of a pipeline.
The command line options passed when running a pipeline.
The "de facto" star-id algorithm used in many real-world missions.
A quaternion is a common way to represent a 3d rotation.
A faster and just as accurate attitude estimator as the Davenport Q algorithm.
A "centroid" detected in an image.
Vec2 position
The (x,y) pixel coordinates in the image (top left is 0,0)
A star idenification algorithm.
Records that a certain Star (detected in the image) corresponds to a certain CatalogStar.
A fast attitude estimator which only takes into account information from two stars.
~UserSpecifiedOutputStream()
UserSpecifiedOutputStream(std::string filePath, bool isBinary)
Create a PromptedOutputStream which will output to the given file.
Three dimensional vector with decimaling point components.
#define DECIMAL_POW(base, power)
#define LOST_PIPELINE_COMPARE(precondition, errmsg, comparator, path, isBinary)
decimal FovToFocalLength(decimal xFov, decimal xResolution)
CentroidComparison CentroidComparisonsCombine(std::vector< CentroidComparison > comparisons)
unsigned char * SurfaceToGrayscaleImage(cairo_surface_t *cairoSurface)
Convert a colored Cairo image surface into a row-major array of grayscale pixels.
decimal FocalLengthFromOptions(const PipelineOptions &values, int xResolution)
Calculate the focal length, in pixels, based on the given command line options.
const int32_t kCatalogMagicValue
std::vector< StarIdentifier > StarIdentifiers
void SerializeCatalog(SerializeContext *ser, const Catalog &catalog, bool inclMagnitude, bool inclName)
Serialize the catalog to buffer.
Catalog DeserializeCatalog(DeserializeContext *des, bool *inclMagnitudeReturn, bool *inclNameReturn)
Deserialize a catalog.
const Catalog & CatalogRead()
Read and parse the full catalog from disk. If called multiple times, will re-use the first result.
decimal MagToBrightness(int mag)
returns some relative brightness measure, which is proportional to the total number of photons receiv...
std::vector< Star > Stars
decimal DegToRad(decimal deg)
PipelineInputList(* PipelineInputFactory)()
Quaternion SphericalToQuaternion(decimal ra, decimal dec, decimal roll)
Return a quaternion that will reorient the coordinate axes so that the x-axis points at the given rig...
decimal RadToDeg(decimal rad)
void PipelineComparatorPlotCentroidIndices(std::ostream &os, const PipelineInputList &expected, const std::vector< PipelineOutput > &actual, const PipelineOptions &)
Plot an annotated image where centroids are annotated with their centroid index.
PipelineInputList GetPngPipelineInput(const PipelineOptions &values)
Create a PngPipelineInput using command line options.
std::vector< CatalogStar > BscParse(std::string tsvPath)
Parse the bright star catalog from the TSV file on disk.
void SurfacePlot(std::string description, cairo_surface_t *cairoSurface, const Stars &stars, const StarIdentifiers *starIds, const Catalog *catalog, const Attitude *attitude, double red, double green, double blue, double alpha, bool rawStarIndexes=false)
Plot information about an image onto the image using Cairo.
StarIdComparison StarIdsCompare(const StarIdentifiers &expected, const StarIdentifiers &actual, const Catalog &expectedCatalog, const Catalog &actualCatalog, decimal centroidThreshold, const Stars &expectedStars, const Stars &inputStars)
Compare expected and actual star identifications.
void SerializePairDistanceKVector(SerializeContext *ser, const Catalog &catalog, decimal minDistance, decimal maxDistance, long numBins)
Serialize a pair-distance KVector into buffer.
void SerializePrimitive(SerializeContext *ser, const T &val)
std::vector< MultiDatabaseEntry > MultiDatabaseDescriptor
void(* PipelineComparator)(std::ostream &os, const PipelineInputList &, const std::vector< PipelineOutput > &, const PipelineOptions &)
MultiDatabaseDescriptor GenerateDatabases(const Catalog &catalog, const DatabaseOptions &values)
Appropriately create descriptors for all requested databases according to command-line options.
SerializeContext serFromDbValues(const DatabaseOptions &values)
std::vector< std::unique_ptr< PipelineInput > > PipelineInputList
PipelineInputList GetPipelineInput(const PipelineOptions &values)
Come up with a list of pipeline inputs based on command line options.
void PipelineComparison(const PipelineInputList &expected, const std::vector< PipelineOutput > &actual, const PipelineOptions &values)
Print or otherwise analyze the results of (perhaps multiple) runs of a star tracking pipeline.
Pipeline SetPipeline(const PipelineOptions &values)
Create a pipeline from command line options.
CentroidComparison CentroidsCompare(decimal threshold, const Stars &expected, const Stars &actual)
Compare expected and actual centroids.
PipelineInputList GetGeneratedPipelineInput(const PipelineOptions &values)
Create a GeneratedPipelineInput based on the command line options in values
std::vector< CatalogStar > Catalog
cairo_surface_t * GrayscaleImageToSurface(const unsigned char *image, const int width, const int height)
std::ostream & operator<<(std::ostream &os, const Camera &camera)
Print information about the camera in machine and human-readable form.
The result of running a pipeline.
The result of comparing an actual star identification with the true star idenification,...
A two dimensional vector with decimaling point components.
decimal MagnitudeSq() const
The square of the magnitude.
decimal Magnitude() const