LOST 0.0.1
LOST: Open-source Star Tracker
Loading...
Searching...
No Matches
centroiders.cpp
Go to the documentation of this file.
1#include "centroiders.hpp"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include <cmath>
8#include <vector>
9#include <iostream>
10#include <unordered_map>
11#include <unordered_set>
12
13#include "decimal.hpp"
14
15namespace lost {
16
17// DUMMY
18
19std::vector<Star> DummyCentroidAlgorithm::Go(unsigned char *, int imageWidth, int imageHeight) const {
20 std::vector<Star> result;
21
22 unsigned int randomSeed = 123456;
23 for (int i = 0; i < numStars; i++) {
25 }
26
27 return result;
28}
29
30// a poorly designed thresholding algorithm
31int BadThreshold(unsigned char *image, int imageWidth, int imageHeight) {
32 //loop through entire array, find sum of magnitudes
33 long totalMag = 0;
34 for (long i = 0; i < imageHeight * imageWidth; i++) {
35 totalMag += image[i];
36 }
37 return (((totalMag/(imageHeight * imageWidth)) + 1) * 15) / 10;
38}
39
40// a more sophisticated thresholding algorithm, not tailored to star images
41int OtsusThreshold(unsigned char *image, int imageWidth, int imageHeight) {
42 // code here, duh
44 //decimal top = 255;
45 decimal sumB = 0;
46 decimal sum1 = 0;
47 decimal wB = 0;
48 decimal maximum = 0;
49 int level = 0;
50 // make the histogram (array length 256)
51 int histogram[256];
52
53 memset(histogram, 0, sizeof(int)*256);
54
55 for (long i = 0; i < total; i++) {
56 histogram[image[i]]++;
57 }
58 for (int i = 0; i < 256; i ++) {
59 sum1 += i * histogram[i];
60 }
61 for (int i = 0; i < 256; i ++) {
62 decimal wF = total - wB;
63 //std::cout << "wF\n" << wB << "\n";
64 //std::cout << "wB\n" << wF << "\n";
65 if (wB > 0 && wF > 0) {
66 decimal mF = (sum1 - sumB) / wF;
67 decimal val = wB * wF * ((sumB / wB) - mF) * ((sumB / wB) - mF);
68 //std::cout << val << "\n";
69 if (val >= maximum) {
70 level = i;
71 maximum = val;
72 }
73 }
74 wB = wB + histogram[i];
75 sumB = sumB + i * histogram[i];
76 }
77 return level;
78}
79
80// a simple, but well tested thresholding algorithm that works well with star images
81int BasicThreshold(unsigned char *image, int imageWidth, int imageHeight) {
82 unsigned long totalMag = 0;
83 decimal std = 0;
85 for (long i = 0; i < totalPixels; i++) {
86 totalMag += image[i];
87 }
89 for (long i = 0; i < totalPixels; i++) {
90 std += DECIMAL_POW(image[i] - mean, 2);
91 }
93 return mean + (std * 5);
94}
95
96// basic thresholding, but do it faster (trade off of some accuracy?)
97int BasicThresholdOnePass(unsigned char *image, int imageWidth, int imageHeight) {
98 unsigned long totalMag = 0;
99 decimal std = 0;
102 for (long i = 0; i < totalPixels; i++) {
103 totalMag += image[i];
104 sq_totalMag += image[i] * image[i];
105 }
109 return mean + (std * 5);
110}
111
124
125//recursive helper here
126void CogHelper(CentroidParams *p, long i, unsigned char *image, int imageWidth, int imageHeight) {
127
128 if (i >= 0 && i < imageWidth * imageHeight && image[i] >= p->cutoff && p->checkedIndices.count(i) == 0) {
129 //check if pixel is on the edge of the image, if it is, we dont want to centroid this star
130 if (i % imageWidth == 0 || i % imageWidth == imageWidth - 1 || i / imageWidth == 0 || i / imageWidth == imageHeight - 1) {
131 p->isValid = false;
132 }
133 p->checkedIndices.insert(i);
134 if (i % imageWidth > p->xMax) {
135 p->xMax = i % imageWidth;
136 } else if (i % imageWidth < p->xMin) {
137 p->xMin = i % imageWidth;
138 }
139 if (i / imageWidth > p->yMax) {
140 p->yMax = i / imageWidth;
141 } else if (i / imageWidth < p->yMin) {
142 p->yMin = i / imageWidth;
143 }
144 p->magSum += image[i];
145 p->xCoordMagSum += ((i % imageWidth)) * image[i];
146 p->yCoordMagSum += ((i / imageWidth)) * image[i];
147 if (i % imageWidth != imageWidth - 1) {
148 CogHelper(p, i + 1, image, imageWidth, imageHeight);
149 }
150 if (i % imageWidth != 0) {
151 CogHelper(p, i - 1, image, imageWidth, imageHeight);
152 }
155 }
156}
157
158std::vector<Star> CenterOfGravityAlgorithm::Go(unsigned char *image, int imageWidth, int imageHeight) const {
160
161 std::vector<Star> result;
162
164 for (long i = 0; i < imageHeight * imageWidth; i++) {
165 if (image[i] >= p.cutoff && p.checkedIndices.count(i) == 0) {
166
167 //iterate over pixels that are part of the star
168 int xDiameter = 0; //radius of current star
169 int yDiameter = 0;
170 p.yCoordMagSum = 0; //y coordinate of current star
171 p.xCoordMagSum = 0; //x coordinate of current star
172 p.magSum = 0; //sum of magnitudes of current star
173
174 p.xMax = i % imageWidth;
175 p.xMin = i % imageWidth;
176 p.yMax = i / imageWidth;
177 p.yMin = i / imageWidth;
178 p.isValid = true;
179
180 int sizeBefore = p.checkedIndices.size();
181
182 CogHelper(&p, i, image, imageWidth, imageHeight);
183 xDiameter = (p.xMax - p.xMin) + 1;
184 yDiameter = (p.yMax - p.yMin) + 1;
185
186 //use the sums to finish CoG equation and add stars to the result
187 decimal xCoord = (p.xCoordMagSum / (p.magSum * DECIMAL(1.0)));
188 decimal yCoord = (p.yCoordMagSum / (p.magSum * DECIMAL(1.0)));
189
190 if (p.isValid) {
191 result.push_back(Star(xCoord + DECIMAL(0.5), yCoord + DECIMAL(0.5), (xDiameter)/DECIMAL(2.0), (yDiameter)/DECIMAL(2.0), p.checkedIndices.size() - sizeBefore));
192 }
193 }
194 }
195 return result;
196}
197
198//Determines how accurate and how much iteration is done by the IWCoG algorithm,
199//smaller means more accurate and more iterations.
201
203 int xMin;
204 int xMax;
205 int yMin;
206 int yMax;
209 int guess;
211 std::unordered_set<int> checkedIndices;
212};
213
214void IWCoGHelper(IWCoGParams *p, long i, unsigned char *image, int imageWidth, int imageHeight, std::vector<int> *starIndices) {
215 if (i >= 0 && i < imageWidth * imageHeight && image[i] >= p->cutoff && p->checkedIndices.count(i) == 0) {
216 //check if pixel is on the edge of the image, if it is, we dont want to centroid this star
217 if (i % imageWidth == 0 || i % imageWidth == imageWidth - 1 || i / imageWidth == 0 || i / imageWidth == imageHeight - 1) {
218 p->isValid = false;
219 }
220 p->checkedIndices.insert(i);
221 starIndices->push_back(i);
222 if (image[i] > p->maxIntensity) {
223 p->maxIntensity = image[i];
224 p->guess = i;
225 }
226 if (i % imageWidth > p->xMax) {
227 p->xMax = i % imageWidth;
228 } else if (i % imageWidth < p->xMin) {
229 p->xMin = i % imageWidth;
230 }
231 if (i / imageWidth > p->yMax) {
232 p->yMax = i / imageWidth;
233 } else if (i / imageWidth < p->yMin) {
234 p->yMin = i / imageWidth;
235 }
236 if (i % imageWidth != imageWidth - 1) {
238 }
239 if (i % imageWidth != 0) {
241 }
244 }
245}
246
249 std::vector<Star> result;
251 for (long i = 0; i < imageHeight * imageWidth; i++) {
252 //check if pixel is part of a "star" and has not been iterated over
253 if (image[i] >= p.cutoff && p.checkedIndices.count(i) == 0) {
254 // TODO: store longs --Mark
255 std::vector<int> starIndices; //indices of the current star
256 p.maxIntensity = 0;
257 int xDiameter = 0;
258 int yDiameter = 0;
262 decimal fwhm; //fwhm variable
264 decimal w; //weight value
265
266 p.xMax = i % imageWidth;
267 p.xMin = i % imageWidth;
268 p.yMax = i / imageWidth;
269 p.yMin = i / imageWidth;
270 p.isValid = true;
271
272
274
275 xDiameter = (p.xMax - p.xMin) + 1;
276 yDiameter = (p.yMax - p.yMin) + 1;
277
278 //calculate fwhm
279 decimal count = 0;
280 for (int j = 0; j < (int) starIndices.size(); j++) {
281 if (image[starIndices.at(j)] > p.maxIntensity / 2) {
282 count++;
283 }
284 }
288 // TODO: Why are these decimals? --Mark
289 decimal guessXCoord = (p.guess % imageWidth);
290 decimal guessYCoord = (p.guess / imageWidth);
291 //how much our new centroid estimate changes w each iteration
293 int stop = 0;
294 //while we see some large enough change in estimated, maybe make it a global variable
295 while (change > iWCoGMinChange && stop < 100000) {
296 //traverse through star indices, calculate W at each coordinate, add to final coordinate sums
299 weightedMagSum = 0;
300 stop++;
301 for (long j = 0; j < (long)starIndices.size(); j++) {
302 //calculate w
306
309 weightedMagSum += w * DECIMAL(image[starIndices.at(j)]);
310 }
313
315
318 }
319 if (p.isValid) {
320 result.push_back(Star(guessXCoord + DECIMAL(0.5), guessYCoord + DECIMAL(0.5), xDiameter/DECIMAL(2.0), yDiameter/DECIMAL(2.0), starIndices.size()));
321 }
322 }
323 }
324 return result;
325}
326
327}
Stars Go(unsigned char *image, int imageWidth, int imageHeight) const override
Actually perform the centroid detection.
Stars Go(unsigned char *image, int imageWidth, int imageHeight) const override
Actually perform the centroid detection.
Stars Go(unsigned char *image, int imageWidth, int imageHeight) const override
Actually perform the centroid detection.
A "centroid" detected in an image.
double decimal
Definition decimal.hpp:11
#define DECIMAL_LOG(x)
Definition decimal.hpp:41
#define DECIMAL(x)
Definition decimal.hpp:21
#define DECIMAL_POW(base, power)
Definition decimal.hpp:39
#define DECIMAL_SQRT(x)
Definition decimal.hpp:40
#define DECIMAL_EXP(x)
Definition decimal.hpp:42
LOST starting point.
int OtsusThreshold(unsigned char *image, int imageWidth, int imageHeight)
int BadThreshold(unsigned char *image, int imageWidth, int imageHeight)
std::vector< Star > Stars
void IWCoGHelper(IWCoGParams *p, long i, unsigned char *image, int imageWidth, int imageHeight, std::vector< int > *starIndices)
void SerializePrimitive(SerializeContext *ser, const T &val)
decimal iWCoGMinChange
void CogHelper(CentroidParams *p, long i, unsigned char *image, int imageWidth, int imageHeight)
int BasicThresholdOnePass(unsigned char *image, int imageWidth, int imageHeight)
int BasicThreshold(unsigned char *image, int imageWidth, int imageHeight)
std::unordered_set< int > checkedIndices
std::unordered_set< int > checkedIndices