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 <unordered_set>
10
11#include "decimal.hpp"
12
13namespace lost {
14
15// DUMMY
16
17std::vector<Star> DummyCentroidAlgorithm::Go(unsigned char *, int imageWidth, int imageHeight) const {
18 std::vector<Star> result;
19
20 unsigned int randomSeed = 123456;
21 for (int i = 0; i < numStars; i++) {
23 }
24
25 return result;
26}
27
28// a poorly designed thresholding algorithm
29int BadThreshold(unsigned char *image, int imageWidth, int imageHeight) {
30 //loop through entire array, find sum of magnitudes
31 long totalMag = 0;
32 for (long i = 0; i < imageHeight * imageWidth; i++) {
33 totalMag += image[i];
34 }
35 return (((totalMag/(imageHeight * imageWidth)) + 1) * 15) / 10;
36}
37
38// a more sophisticated thresholding algorithm, not tailored to star images
39int OtsusThreshold(unsigned char *image, int imageWidth, int imageHeight) {
40 // code here, duh
42 //decimal top = 255;
43 decimal sumB = 0;
44 decimal sum1 = 0;
45 decimal wB = 0;
46 decimal maximum = 0;
47 int level = 0;
48 // make the histogram (array length 256)
49 int histogram[256];
50
51 memset(histogram, 0, sizeof(int)*256);
52
53 for (long i = 0; i < total; i++) {
54 histogram[image[i]]++;
55 }
56 for (int i = 0; i < 256; i ++) {
57 sum1 += i * histogram[i];
58 }
59 for (int i = 0; i < 256; i ++) {
60 decimal wF = total - wB;
61 //std::cout << "wF\n" << wB << "\n";
62 //std::cout << "wB\n" << wF << "\n";
63 if (wB > 0 && wF > 0) {
64 decimal mF = (sum1 - sumB) / wF;
65 decimal val = wB * wF * ((sumB / wB) - mF) * ((sumB / wB) - mF);
66 //std::cout << val << "\n";
67 if (val >= maximum) {
68 level = i;
69 maximum = val;
70 }
71 }
72 wB = wB + histogram[i];
73 sumB = sumB + i * histogram[i];
74 }
75 return level;
76}
77
78// a simple, but well tested thresholding algorithm that works well with star images
79int BasicThreshold(unsigned char *image, int imageWidth, int imageHeight) {
80 unsigned long totalMag = 0;
81 decimal std = 0;
83 for (long i = 0; i < totalPixels; i++) {
84 totalMag += image[i];
85 }
87 for (long i = 0; i < totalPixels; i++) {
88 std += DECIMAL_POW(image[i] - mean, 2);
89 }
91 return mean + (std * 5);
92}
93
94// basic thresholding, but do it faster (trade off of some accuracy?)
95int BasicThresholdOnePass(unsigned char *image, int imageWidth, int imageHeight) {
96 unsigned long totalMag = 0;
97 decimal std = 0;
100 for (long i = 0; i < totalPixels; i++) {
101 totalMag += image[i];
102 sq_totalMag += image[i] * image[i];
103 }
107 return mean + (std * 5);
108}
109
113 long magSum = 0;
114 int xMin;
115 int xMax;
116 int yMin;
117 int yMax;
118
119 CentroidParams(int x, int y) : xMin(x), xMax(x), yMin(y), yMax(y) {}
120};
121
122std::vector<Star> CenterOfGravityAlgorithm::Go(unsigned char* image, int imageWidth, int imageHeight) const {
123 std::vector<Star> result;
124
125 int cutoff = BasicThreshold(image, imageWidth, imageHeight);
126 const int offsets[] = {1, -1, imageWidth, -imageWidth};
127 const long n = imageWidth * imageHeight;
128 std::vector<bool> visited(n, false);
129
130 for (long i = 0; i < n; i++) {
131 if (image[i] >= cutoff && !visited[i]) {
132 visited[i] = true;
133
134 // If any pixels are on the edge of the image then we don't centroid
135 // this star, in case part of the star is missing
136 bool isValid = true;
137 int centroidSize = 0;
138 std::vector<long> queue = {i};
140
141 while(!queue.empty()) {
142 long ind = queue.back();
143 queue.pop_back();
144 centroidSize++;
145 long x = ind % imageWidth, y = ind / imageWidth;
146 if (x == 0 || x == imageWidth - 1 || y == 0 || y == imageHeight - 1) {
147 isValid = false;
148 }
149
150 p.magSum += image[ind];
151 p.xCoordMagSum += x * image[ind];
152 p.yCoordMagSum += y * image[ind];
153
154 if (x > p.xMax) p.xMax = x;
155 if (x < p.xMin) p.xMin = x;
156 if (y > p.yMax) p.yMax = y;
157 if (y < p.yMin) p.yMin = y;
158
159 for(int offset : offsets) {
160 long ni = ind + offset;
161 if(ni >= 0 && ni < n && std::abs((ni % imageWidth)-x) <= 1 && image[ni] >= cutoff && !visited[ni]) {
162 queue.push_back(ni);
163 visited[ni] = true;
164 }
165 }
166 }
167
168 int xDiameter = (p.xMax - p.xMin) + 1;
169 int yDiameter = (p.yMax - p.yMin) + 1;
170
171 if (isValid && p.magSum > 0) {
172 decimal xCoord = p.xCoordMagSum / DECIMAL(p.magSum);
173 decimal yCoord = p.yCoordMagSum / DECIMAL(p.magSum);
174 result.push_back(Star(xCoord + DECIMAL(0.5), yCoord + DECIMAL(0.5), (xDiameter)/DECIMAL(2.0), (yDiameter)/DECIMAL(2.0), centroidSize));
175 }
176 }
177 }
178 return result;
179}
180
181//Determines how accurate and how much iteration is done by the IWCoG algorithm,
182//smaller means more accurate and more iterations.
184
186 int xMin;
187 int xMax;
188 int yMin;
189 int yMax;
192 int guess;
194 std::unordered_set<int> checkedIndices;
195};
196
197void IWCoGHelper(IWCoGParams *p, long i, unsigned char *image, int imageWidth, int imageHeight, std::vector<int> *starIndices) {
198 if (i >= 0 && i < imageWidth * imageHeight && image[i] >= p->cutoff && p->checkedIndices.count(i) == 0) {
199 //check if pixel is on the edge of the image, if it is, we dont want to centroid this star
200 if (i % imageWidth == 0 || i % imageWidth == imageWidth - 1 || i / imageWidth == 0 || i / imageWidth == imageHeight - 1) {
201 p->isValid = false;
202 }
203 p->checkedIndices.insert(i);
204 starIndices->push_back(i);
205 if (image[i] > p->maxIntensity) {
206 p->maxIntensity = image[i];
207 p->guess = i;
208 }
209 if (i % imageWidth > p->xMax) {
210 p->xMax = i % imageWidth;
211 } else if (i % imageWidth < p->xMin) {
212 p->xMin = i % imageWidth;
213 }
214 if (i / imageWidth > p->yMax) {
215 p->yMax = i / imageWidth;
216 } else if (i / imageWidth < p->yMin) {
217 p->yMin = i / imageWidth;
218 }
219 if (i % imageWidth != imageWidth - 1) {
221 }
222 if (i % imageWidth != 0) {
224 }
227 }
228}
229
232 std::vector<Star> result;
234 for (long i = 0; i < imageHeight * imageWidth; i++) {
235 //check if pixel is part of a "star" and has not been iterated over
236 if (image[i] >= p.cutoff && p.checkedIndices.count(i) == 0) {
237 // TODO: store longs --Mark
238 std::vector<int> starIndices; //indices of the current star
239 p.maxIntensity = 0;
240 int xDiameter = 0;
241 int yDiameter = 0;
245 decimal fwhm; //fwhm variable
247 decimal w; //weight value
248
249 p.xMax = i % imageWidth;
250 p.xMin = i % imageWidth;
251 p.yMax = i / imageWidth;
252 p.yMin = i / imageWidth;
253 p.isValid = true;
254
255
257
258 xDiameter = (p.xMax - p.xMin) + 1;
259 yDiameter = (p.yMax - p.yMin) + 1;
260
261 //calculate fwhm
262 decimal count = 0;
263 for (int j = 0; j < (int) starIndices.size(); j++) {
264 if (image[starIndices.at(j)] > p.maxIntensity / 2) {
265 count++;
266 }
267 }
271 // TODO: Why are these decimals? --Mark
272 decimal guessXCoord = (p.guess % imageWidth);
273 decimal guessYCoord = (p.guess / imageWidth);
274 //how much our new centroid estimate changes w each iteration
276 int stop = 0;
277 //while we see some large enough change in estimated, maybe make it a global variable
278 while (change > iWCoGMinChange && stop < 100000) {
279 //traverse through star indices, calculate W at each coordinate, add to final coordinate sums
282 weightedMagSum = 0;
283 stop++;
284 for (long j = 0; j < (long)starIndices.size(); j++) {
285 //calculate w
289
292 weightedMagSum += w * DECIMAL(image[starIndices.at(j)]);
293 }
296
298
301 }
302 if (p.isValid) {
303 result.push_back(Star(guessXCoord + DECIMAL(0.5), guessYCoord + DECIMAL(0.5), xDiameter/DECIMAL(2.0), yDiameter/DECIMAL(2.0), starIndices.size()));
304 }
305 }
306 }
307 return result;
308}
309
310}
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
int BasicThresholdOnePass(unsigned char *image, int imageWidth, int imageHeight)
int BasicThreshold(unsigned char *image, int imageWidth, int imageHeight)
CentroidParams(int x, int y)
std::unordered_set< int > checkedIndices