13#include <QtConcurrent>
15#include "fitscentroiddetector.h"
16#include "fits_debug.h"
34bool FITSCentroidDetector::checkCollision(Edge * s1, Edge * s2)
const
38 int diff_x = s1->x - s2->x;
39 int diff_y = s1->y - s2->y;
41 dis = std::abs(sqrt(diff_x * diff_x + diff_y * diff_y));
55 FITSImage::Statistic
const &stats = m_ImageData->getStatistics();
56 switch (stats.dataType)
58#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
61 return QtConcurrent::run(&FITSCentroidDetector::findSources<uint8_t const>,
this, boundary);
64 return QtConcurrent::run(&FITSCentroidDetector::findSources<int16_t const>,
this, boundary);
67 return QtConcurrent::run(&FITSCentroidDetector::findSources<uint16_t const>,
this, boundary);
70 return QtConcurrent::run(&FITSCentroidDetector::findSources<int32_t const>,
this, boundary);
73 return QtConcurrent::run(&FITSCentroidDetector::findSources<uint32_t const>,
this, boundary);
76 return QtConcurrent::run(&FITSCentroidDetector::findSources<float const>,
this, boundary);
79 return QtConcurrent::run(&FITSCentroidDetector::findSources<int64_t const>,
this, boundary);
82 return QtConcurrent::run(&FITSCentroidDetector::findSources<double const>,
this, boundary);
86 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<uint8_t const>, boundary);
89 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<int16_t const>, boundary);
92 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<uint16_t const>, boundary);
95 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<int32_t const>, boundary);
98 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<uint32_t const>, boundary);
101 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<float const>, boundary);
104 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<int64_t const>, boundary);
107 return QtConcurrent::run(
this, &FITSCentroidDetector::findSources<double const>, boundary);
113bool FITSCentroidDetector::findSources(
const QRect &boundary)
115 FITSImage::Statistic
const &stats = m_ImageData->getStatistics();
116 FITSMode
const m_Mode =
static_cast<FITSMode
>(m_ImageData->
property(
"mode").toInt());
118 int MINIMUM_STDVAR = getValue(
"MINIMUM_STDVAR", 5).
toInt();
119 int minEdgeWidth = getValue(
"MINIMUM_PIXEL_RANGE", 5).
toInt();
120 double JMIndex = getValue(
"JMINDEX", 100.0).
toDouble();
122 int initStdDev = MINIMUM_STDVAR;
123 double threshold = 0, sum = 0, avg = 0, min = 0;
124 int starDiameter = 0;
126 int minimumEdgeCount = MINIMUM_EDGE_LIMIT;
128 auto * buffer =
reinterpret_cast<T
const *
>(m_ImageData->getImageBuffer());
130 float dispersion_ratio = 1.5;
134 if (JMIndex < DIFFUSE_THRESHOLD)
136 minEdgeWidth = JMIndex * 35 + 1;
137 minimumEdgeCount = minEdgeWidth - 1;
142 minimumEdgeCount = 4;
145 while (initStdDev >= 1)
150 minEdgeWidth = qMax(3, minEdgeWidth);
151 minimumEdgeCount = qMax(3, minimumEdgeCount);
153 if (JMIndex < DIFFUSE_THRESHOLD)
156 threshold = stats.max[0] - stats.mean[0] * ((MINIMUM_STDVAR - initStdDev) * 0.5 + 1);
159 if (threshold - min < 0)
161 threshold = stats.mean[0] * ((MINIMUM_STDVAR - initStdDev) * 0.5 + 1);
165 dispersion_ratio = 1.4 - (MINIMUM_STDVAR - initStdDev) * 0.08;
169 threshold = stats.mean[0] + stats.stddev[0] * initStdDev * (0.3 - (MINIMUM_STDVAR - initStdDev) * 0.05);
172 dispersion_ratio = 1.8 - (MINIMUM_STDVAR - initStdDev) * 0.2;
175 qCDebug(KSTARS_FITS) <<
"SNR: " << stats.SNR;
176 qCDebug(KSTARS_FITS) <<
"The threshold level is " << threshold <<
"(actual " << threshold - min
177 <<
") minimum edge width" << minEdgeWidth <<
" minimum edge limit " << minimumEdgeCount;
181 int subX, subY, subW, subH;
185 if (m_Mode == FITS_GUIDE || m_Mode == FITS_FOCUS)
188 subX = round(stats.width * 0.15);
189 subY = round(stats.height * 0.15);
190 subW = stats.width - subX;
191 subH = stats.height - subY;
206 subW = subX + boundary.
width();
207 subH = subY + boundary.
height();
211 for (
int i = subY; i < subH; i++)
215 for (
int j = subX; j < subW; j++)
217 pixVal = buffer[j + (i * stats.width)] - min;
220 if (pixVal >= threshold)
230 if (starDiameter >= minEdgeWidth)
232 float center = avg / sum + 0.5;
235 int i_center = std::floor(center);
238 if (((buffer[i_center + (i * stats.width)] - min) /
239 (buffer[i_center + (i * stats.width) - starDiameter / 2] - min) >=
241 ((buffer[i_center + (i * stats.width)] - min) /
242 (buffer[i_center + (i * stats.width) + starDiameter / 2] - min) >=
246 <<
"Edge center is " << buffer[i_center + (i * stats.width)] - min
247 <<
" Edge is " << buffer[i_center + (i * stats.width) - starDiameter / 2] - min
249 << ((buffer[i_center + (i * stats.width)] - min) /
250 (buffer[i_center + (i * stats.width) - starDiameter / 2] - min))
251 <<
" located at X: " << center <<
" Y: " << i + 0.5;
253 auto * newEdge =
new Edge();
256 newEdge->y = i + 0.5;
257 newEdge->scanned = 0;
258 newEdge->val = buffer[i_center + (i * stats.width)] - min;
259 newEdge->width = starDiameter;
269 avg = sum = starDiameter = 0;
274 qCDebug(KSTARS_FITS) <<
"Total number of edges found is: " << edges.
count();
277 if (edges.
count() == 1 && initStdDev > 1)
283 if (edges.
count() >= MAX_EDGE_LIMIT)
285 qCWarning(KSTARS_FITS) <<
"Too many edges, aborting... " << edges.
count();
290 if (edges.
count() >= minimumEdgeCount)
306 auto const greaterThan = [](Edge
const * a, Edge
const * b)
308 return a->sum > b->sum;
310 std::sort(edges.
begin(), edges.
end(), greaterThan);
314 for (
int i = 0; i < edges.
count(); i++)
316 qCDebug(KSTARS_FITS) <<
"# " << i <<
" Edge at (" << edges[i]->x <<
"," << edges[i]->y <<
") With a value of "
317 << edges[i]->val <<
" and width of " << edges[i]->width <<
" pixels. with sum " << edges[i]->sum;
320 if (edges[i]->scanned == 1)
322 qCDebug(KSTARS_FITS) <<
"Skipping check for center " << i <<
" because it was already counted";
326 qCDebug(KSTARS_FITS) <<
"Investigating edge # " << i <<
" now ...";
331 cen_v = edges[i]->sum;
332 cen_w = edges[i]->width;
341 for (
int j = 0; j < edges.
count(); j++)
343 if (edges[j]->scanned)
346 if (checkCollision(edges[j], edges[i]))
348 if (edges[j]->sum >= cen_v)
350 cen_v = edges[j]->sum;
351 cen_w = edges[j]->width;
354 edges[j]->scanned = 1;
357 avg_x += edges[j]->x * edges[j]->val;
358 avg_y += edges[j]->y * edges[j]->val;
359 sum += edges[j]->val;
365 int cen_limit = (MINIMUM_ROWS_PER_CENTER - (MINIMUM_STDVAR - initStdDev));
367 if (edges.
count() < LOW_EDGE_CUTOFF_1)
369 if (edges.
count() < LOW_EDGE_CUTOFF_2)
375 qCDebug(KSTARS_FITS) <<
"center_count: " << cen_count <<
" and initstdDev= " << initStdDev <<
" and limit is "
383 if (cen_count >= cen_limit)
386 auto * rCenter =
new Edge();
388 rCenter->x = avg_x / sum;
389 rCenter->y = avg_y / sum;
390 width_sum += rCenter->width;
391 rCenter->width = cen_w;
393 qCDebug(KSTARS_FITS) <<
"Found a real center with number with (" << rCenter->x <<
"," << rCenter->y <<
")";
400 cen_x = (int)std::floor(rCenter->x);
401 cen_y = (int)std::floor(rCenter->y);
403 if (cen_x < 0 || cen_x > stats.width || cen_y < 0 || cen_y > stats.height)
411 for (
int k = rCenter->width / 2; k >= -(rCenter->width / 2); k--)
413 FSum += buffer[cen_x - k + (cen_y * stats.width)] - min;
421 TF = buffer[cen_y * stats.width + cen_x] - min;
423 int pixelCounter = 1;
426 for (
int k = 1; k < rCenter->width / 2; k++)
430 qCDebug(KSTARS_FITS) <<
"Stopping at TF " << TF <<
" after #" << k <<
" pixels.";
434 TF += buffer[cen_y * stats.width + cen_x + k] - min;
435 TF += buffer[cen_y * stats.width + cen_x - k] - min;
441 rCenter->HFR = pixelCounter * (HF / TF);
445 qCDebug(KSTARS_FITS) <<
"HFR for this center is " << rCenter->HFR <<
" pixels and the total flux is " << FSum;
447 starCenters.
append(rCenter);
451 if (starCenters.
count() > 1 && m_Mode != FITS_FOCUS)
453 float width_avg = (float)width_sum / starCenters.
count();
454 float lsum = 0, sdev = 0;
456 for (
auto ¢er : starCenters)
457 lsum += (
center->width - width_avg) * (
center->width - width_avg);
459 sdev = (std::sqrt(lsum / (starCenters.count() - 1))) * 4;
462 foreach (Edge * center, starCenters)
464 starCenters.removeOne(center);
470 m_ImageData->setStarCenters(starCenters);
void append(QList< T > &&value)
qsizetype count() const const
QVariant property(const char *name) const const
bool isNull() const const
QTextStream & center(QTextStream &stream)
QFuture< T > run(Function function,...)
double toDouble(bool *ok) const const
int toInt(bool *ok) const const