diff --git a/kstars/CMakeLists.txt b/kstars/CMakeLists.txt --- a/kstars/CMakeLists.txt +++ b/kstars/CMakeLists.txt @@ -266,6 +266,7 @@ fitsviewer/fitsgradientdetector.cpp fitsviewer/fitscentroiddetector.cpp fitsviewer/fitssepdetector.cpp + fitsviewer/fitsskyobject.cpp ) set (fitsui_SRCS fitsviewer/fitsheaderdialog.ui diff --git a/kstars/fitsviewer/fitscentroiddetector.h b/kstars/fitsviewer/fitscentroiddetector.h --- a/kstars/fitsviewer/fitscentroiddetector.h +++ b/kstars/fitsviewer/fitscentroiddetector.h @@ -38,23 +38,31 @@ /** @brief Configure the detection method. * @see FITSStarDetector::configure(). - * @note Parameter "initStdDev" defaults to MINIMUM_STDVAR. - * @note Parameter "minEdgeWidth" defaults to MINIMUM_PIXEL_RANGE. - * @todo Provide all constants of this class as parameters, and explain their use. + * @see Detection parameters. */ FITSStarDetector & configure(const QString &setting, const QVariant &value) override; -public: - /** @group Detection internals +protected: + /** @group Detection parameters. Use the names as strings for FITSStarDetector::configure(). * @{ */ - static constexpr int MINIMUM_STDVAR { 5 }; - static constexpr int MINIMUM_PIXEL_RANGE { 5 }; - static constexpr int MINIMUM_EDGE_LIMIT { 2 }; - static constexpr int MAX_EDGE_LIMIT { 10000 }; - static constexpr double DIFFUSE_THRESHOLD { 0.15 }; - static constexpr int MINIMUM_ROWS_PER_CENTER { 3 }; - static constexpr int LOW_EDGE_CUTOFF_1 { 50 }; - static constexpr int LOW_EDGE_CUTOFF_2 { 10 }; + /** @brief Initial variation, decreasing as search progresses. Configurable. */ + int MINIMUM_STDVAR { 5 }; + /** @brief Initial source width, decreasing as search progresses. Configurable. */ + int MINIMUM_PIXEL_RANGE { 5 }; + /** @brief Custom image contrast index from the frame histogram. Configurable. */ + double JMINDEX { 100 }; + /** @brief Initial source count over which search stops. */ + int MINIMUM_EDGE_LIMIT { 2 }; + /** @brief Maximum source count over which search aborts. */ + int MAX_EDGE_LIMIT { 10000 }; + /** @brief Minimum value of JMINDEX under which the custom image contrast index from the histogram is used to redefine edge width and count. */ + double DIFFUSE_THRESHOLD { 0.15 }; + /** @brief */ + int MINIMUM_ROWS_PER_CENTER { 3 }; + /** @brief */ + int LOW_EDGE_CUTOFF_1 { 50 }; + /** @brief */ + int LOW_EDGE_CUTOFF_2 { 10 }; /** @} */ protected: @@ -69,10 +77,6 @@ * @return true if the sources collide, else false. */ bool checkCollision(Edge * s1, Edge * s2) const; - -protected: - int m_initStdDev { MINIMUM_STDVAR }; - int m_minEdgeWidth { MINIMUM_PIXEL_RANGE }; }; #endif // FITSCENTROIDDETECTOR_H diff --git a/kstars/fitsviewer/fitscentroiddetector.cpp b/kstars/fitsviewer/fitscentroiddetector.cpp --- a/kstars/fitsviewer/fitscentroiddetector.cpp +++ b/kstars/fitsviewer/fitscentroiddetector.cpp @@ -24,20 +24,17 @@ FITSStarDetector& FITSCentroidDetector::configure(const QString &setting, const QVariant &value) { - if (!setting.compare("initStdDev", Qt::CaseInsensitive)) - { - bool ok = false; - double const result = value.toDouble(&ok); - if (ok) - m_initStdDev = result; - } - if (!setting.compare("minEdgeWidth", Qt::CaseInsensitive)) - { - bool ok = false; - int const result = value.toInt(&ok); - if (ok) - m_initStdDev = result; - } + if (!setting.compare("MINIMUM_STDVAR", Qt::CaseInsensitive)) + if (value.canConvert ()) + MINIMUM_STDVAR = value.value (); + + if (!setting.compare("MINIMUM_PIXEL_RANGE", Qt::CaseInsensitive)) + if (value.canConvert ()) + MINIMUM_PIXEL_RANGE = value.value (); + + if (!setting.compare("JMINDEX", Qt::CaseInsensitive)) + if (value.canConvert ()) + JMINDEX = value.value (); return *this; } @@ -105,72 +102,66 @@ FITSData::Statistic const &stats = image_data->getStatistics(); FITSMode const m_Mode = static_cast (parent()->property("mode").toInt()); + int initStdDev = MINIMUM_STDVAR; + int minEdgeWidth = MINIMUM_PIXEL_RANGE; + double threshold = 0, sum = 0, avg = 0, min = 0; int starDiameter = 0; int pixVal = 0; int minimumEdgeCount = MINIMUM_EDGE_LIMIT; auto * buffer = reinterpret_cast(image_data->getImageBuffer()); - double JMIndex = 100; - -#if 0//ndef KSTARS_LITE - if (histogram) - { - if (!histogram->isConstructed()) - histogram->constructHistogram(); - JMIndex = histogram->getJMIndex(); - } -#endif + double JMIndex = JMINDEX; float dispersion_ratio = 1.5; QList edges; if (JMIndex < DIFFUSE_THRESHOLD) { - m_minEdgeWidth = JMIndex * 35 + 1; - minimumEdgeCount = m_minEdgeWidth - 1; + minEdgeWidth = JMIndex * 35 + 1; + minimumEdgeCount = minEdgeWidth - 1; } else { - m_minEdgeWidth = 6; + minEdgeWidth = 6; minimumEdgeCount = 4; } - while (m_initStdDev >= 1) + while (initStdDev >= 1) { - m_minEdgeWidth--; + minEdgeWidth--; minimumEdgeCount--; - m_minEdgeWidth = qMax(3, m_minEdgeWidth); + minEdgeWidth = qMax(3, minEdgeWidth); minimumEdgeCount = qMax(3, minimumEdgeCount); if (JMIndex < DIFFUSE_THRESHOLD) { // Taking the average out seems to have better result for noisy images - threshold = stats.max[0] - stats.mean[0] * ((MINIMUM_STDVAR - m_initStdDev) * 0.5 + 1); + threshold = stats.max[0] - stats.mean[0] * ((MINIMUM_STDVAR - initStdDev) * 0.5 + 1); min = stats.min[0]; if (threshold - min < 0) { - threshold = stats.mean[0] * ((MINIMUM_STDVAR - m_initStdDev) * 0.5 + 1); + threshold = stats.mean[0] * ((MINIMUM_STDVAR - initStdDev) * 0.5 + 1); min = 0; } - dispersion_ratio = 1.4 - (MINIMUM_STDVAR - m_initStdDev) * 0.08; + dispersion_ratio = 1.4 - (MINIMUM_STDVAR - initStdDev) * 0.08; } else { - threshold = stats.mean[0] + stats.stddev[0] * m_initStdDev * (0.3 - (MINIMUM_STDVAR - m_initStdDev) * 0.05); + threshold = stats.mean[0] + stats.stddev[0] * initStdDev * (0.3 - (MINIMUM_STDVAR - initStdDev) * 0.05); min = stats.min[0]; // Ratio between centeroid center and edge - dispersion_ratio = 1.8 - (MINIMUM_STDVAR - m_initStdDev) * 0.2; + dispersion_ratio = 1.8 - (MINIMUM_STDVAR - initStdDev) * 0.2; } qCDebug(KSTARS_FITS) << "SNR: " << stats.SNR; qCDebug(KSTARS_FITS) << "The threshold level is " << threshold << "(actual " << threshold - min - << ") minimum edge width" << m_minEdgeWidth << " minimum edge limit " << minimumEdgeCount; + << ") minimum edge width" << minEdgeWidth << " minimum edge limit " << minimumEdgeCount; threshold -= min; @@ -223,7 +214,7 @@ else if (sum > 0) { // We found a potential centroid edge - if (starDiameter >= m_minEdgeWidth) + if (starDiameter >= minEdgeWidth) { float center = avg / sum + 0.5; if (center > 0) @@ -270,9 +261,9 @@ qCDebug(KSTARS_FITS) << "Total number of edges found is: " << edges.count(); // In case of hot pixels - if (edges.count() == 1 && m_initStdDev > 1) + if (edges.count() == 1 && initStdDev > 1) { - m_initStdDev--; + initStdDev--; continue; } @@ -288,7 +279,7 @@ qDeleteAll(edges); edges.clear(); - m_initStdDev--; + initStdDev--; } int cen_count = 0; @@ -354,7 +345,7 @@ } } - int cen_limit = (MINIMUM_ROWS_PER_CENTER - (MINIMUM_STDVAR - m_initStdDev)); + int cen_limit = (MINIMUM_ROWS_PER_CENTER - (MINIMUM_STDVAR - initStdDev)); if (edges.count() < LOW_EDGE_CUTOFF_1) { @@ -364,7 +355,7 @@ cen_limit = 2; } - qCDebug(KSTARS_FITS) << "center_count: " << cen_count << " and initstdDev= " << m_initStdDev << " and limit is " + qCDebug(KSTARS_FITS) << "center_count: " << cen_count << " and initstdDev= " << initStdDev << " and limit is " << cen_limit; if (cen_limit < 1) diff --git a/kstars/fitsviewer/fitsdata.h b/kstars/fitsviewer/fitsdata.h --- a/kstars/fitsviewer/fitsdata.h +++ b/kstars/fitsviewer/fitsdata.h @@ -44,9 +44,10 @@ #endif #endif +#include "fitsskyobject.h" + class QProgressDialog; -class SkyObject; class SkyPoint; class FITSHistogram; @@ -58,23 +59,6 @@ class Edge; -class FITSSkyObject : public QObject -{ - Q_OBJECT - public: - explicit FITSSkyObject(SkyObject *object, int xPos, int yPos); - SkyObject *skyObject(); - int x(); - int y(); - void setX(int xPos); - void setY(int yPos); - - private: - SkyObject *skyObjectStored; - int xLoc; - int yLoc; -}; - class FITSData : public QObject { Q_OBJECT diff --git a/kstars/fitsviewer/fitsdata.cpp b/kstars/fitsviewer/fitsdata.cpp --- a/kstars/fitsviewer/fitsdata.cpp +++ b/kstars/fitsviewer/fitsdata.cpp @@ -895,13 +895,23 @@ break; case ALGORITHM_CENTROID: +#ifndef KSTARS_LITE + if (histogram) + if (!histogram->isConstructed()) + histogram->constructHistogram(); + + count = FITSCentroidDetector(this) + .configure("JMINDEX", histogram? histogram->getJMIndex() : 100) + .findSources(starCenters, trackingBox); +#else count = FITSCentroidDetector(this) .findSources(starCenters, trackingBox); +#endif break; case ALGORITHM_THRESHOLD: count = FITSThresholdDetector(this) - .configure("Threshold", Options::focusThreshold()) + .configure("THRESHOLD_PERCENTAGE", Options::focusThreshold()) .findSources(starCenters, trackingBox); break; } @@ -1772,38 +1782,6 @@ return objList; } -FITSSkyObject::FITSSkyObject(SkyObject * object, int xPos, int yPos) : QObject() -{ - skyObjectStored = object; - xLoc = xPos; - yLoc = yPos; -} - -SkyObject * FITSSkyObject::skyObject() -{ - return skyObjectStored; -} - -int FITSSkyObject::x() -{ - return xLoc; -} - -int FITSSkyObject::y() -{ - return yLoc; -} - -void FITSSkyObject::setX(int xPos) -{ - xLoc = xPos; -} - -void FITSSkyObject::setY(int yPos) -{ - yLoc = yPos; -} - int FITSData::getFlipVCounter() const { return flipVCounter; diff --git a/kstars/fitsviewer/fitsskyobject.h b/kstars/fitsviewer/fitsskyobject.h new file mode 100644 --- /dev/null +++ b/kstars/fitsviewer/fitsskyobject.h @@ -0,0 +1,63 @@ +/*************************************************************************** + fitsskyobject.cpp - FITS Image + ------------------- + begin : Tue Apr 07 2020 + copyright : (C) 2004 by Jasem Mutlaq, (C) 2020 by Eric Dejouhanet + email : mutlaqja@ikarustech.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * Some code fragments were adapted from Peter Kirchgessner's FITS plugin* + * See http://members.aol.com/pkirchg for more details. * + ***************************************************************************/ + +#ifndef FITSSKYOBJECT_H +#define FITSSKYOBJECT_H + +#include + +class SkyObject; + +class FITSSkyObject : public QObject +{ + Q_OBJECT + +public: + /** @brief Locate a SkyObject at a pixel position. + * @param object is the SkyObject to locate in the frame. + * @param xPos and yPos are the pixel position of the SkyObject in the frame. + */ + explicit FITSSkyObject(SkyObject /*const*/ *object, int xPos, int yPos); + +public: + /** @brief Getting the SkyObject this instance locates. + */ + SkyObject /*const*/ *skyObject(); + +public: + /** @brief Getting the pixel position of the SkyObject this instance locates. */ + /** @{ */ + int x() const; + int y() const; + /** @} */ + +public: + /** @brief Setting the pixel position of the SkyObject this instance locates. */ + /** @{ */ + void setX(int xPos); + void setY(int yPos); + /** @} */ + +protected: + SkyObject /*const*/ *skyObjectStored { nullptr }; + int xLoc { 0 }; + int yLoc { 0 }; +}; + +#endif // FITSSKYOBJECT_H diff --git a/kstars/fitsviewer/fitsskyobject.cpp b/kstars/fitsviewer/fitsskyobject.cpp new file mode 100644 --- /dev/null +++ b/kstars/fitsviewer/fitsskyobject.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + fitsskyobject.cpp - FITS Image + ------------------- + begin : Tue Apr 07 2020 + copyright : (C) 2004 by Jasem Mutlaq, (C) 2020 by Eric Dejouhanet + email : mutlaqja@ikarustech.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * Some code fragments were adapted from Peter Kirchgessner's FITS plugin* + * See http://members.aol.com/pkirchg for more details. * + ***************************************************************************/ + +#include "fitsskyobject.h" + +FITSSkyObject::FITSSkyObject(SkyObject /*const*/ * object, int xPos, int yPos) : QObject() +{ + skyObjectStored = object; + xLoc = xPos; + yLoc = yPos; +} + +SkyObject /*const*/ * FITSSkyObject::skyObject() +{ + return skyObjectStored; +} + +int FITSSkyObject::x() const +{ + return xLoc; +} + +int FITSSkyObject::y() const +{ + return yLoc; +} + +void FITSSkyObject::setX(int xPos) +{ + xLoc = xPos; +} + +void FITSSkyObject::setY(int yPos) +{ + yLoc = yPos; +} diff --git a/kstars/fitsviewer/fitsthresholddetector.h b/kstars/fitsviewer/fitsthresholddetector.h --- a/kstars/fitsviewer/fitsthresholddetector.h +++ b/kstars/fitsviewer/fitsthresholddetector.h @@ -43,20 +43,17 @@ FITSStarDetector & configure(const QString &setting, const QVariant &value) override; public: - /** @group Detection internals + /** @group Detection parameters. * @{ */ - static constexpr int THRESHOLD_PERCENTAGE { 120 }; + int THRESHOLD_PERCENTAGE { 120 }; /** @} */ protected: /** @internal Find sources in the parent FITS data file, dependent of the pixel depth. * @see FITSGradientDetector::findSources. */ template int findOneStar(QList &starCenters, const QRect &boundary) const; - -protected: - double focusThreshold { THRESHOLD_PERCENTAGE }; }; #endif // FITSTHRESHOLDDETECTOR_H diff --git a/kstars/fitsviewer/fitsthresholddetector.cpp b/kstars/fitsviewer/fitsthresholddetector.cpp --- a/kstars/fitsviewer/fitsthresholddetector.cpp +++ b/kstars/fitsviewer/fitsthresholddetector.cpp @@ -24,14 +24,9 @@ FITSStarDetector& FITSThresholdDetector::configure(const QString &setting, const QVariant &value) { - bool ok = false; - - if (!setting.compare("threshold", Qt::CaseInsensitive)) - { - double const _focusThreshold = value.toDouble(&ok); - if (ok) - focusThreshold = _focusThreshold; - } + if (!setting.compare("THRESHOLD_PERCENTAGE", Qt::CaseInsensitive)) + if (value.canConvert ()) + THRESHOLD_PERCENTAGE = value.value (); return *this; } @@ -94,7 +89,7 @@ auto * buffer = reinterpret_cast(image_data->getImageBuffer()); // TODO replace magic number with something more useful to understand - double threshold = stats.mean[0] * focusThreshold / 100.0; + double threshold = stats.mean[0] * THRESHOLD_PERCENTAGE / 100.0; for (int y = subY; y < subH; y++) { diff --git a/kstars/fitsviewer/starprofileviewer.cpp b/kstars/fitsviewer/starprofileviewer.cpp --- a/kstars/fitsviewer/starprofileviewer.cpp +++ b/kstars/fitsviewer/starprofileviewer.cpp @@ -417,7 +417,7 @@ QStringList rowLabels; QStringList columnLabels; - auto *buffer = reinterpret_cast(imageData->getImageBuffer()); + auto *buffer = reinterpret_cast(imageData->getImageBuffer()); int width = imageData->width(); for (int j = subFrame.y(); j < subFrame.y() + subFrame.height(); j++) @@ -778,7 +778,7 @@ template void StarProfileViewer::getSubFrameMinMax(float *subFrameMin, float *subFrameMax) { - T *buffer = reinterpret_cast(imageData->getImageBuffer()); + auto *buffer = reinterpret_cast(imageData->getImageBuffer()); T min = std::numeric_limits::max(); T max = std::numeric_limits::min(); int width = imageData->width(); @@ -803,8 +803,7 @@ { if(!imageData) return 0; - uint8_t *image_buffer = imageData->getImageBuffer(); - T *buffer = reinterpret_cast(image_buffer); + auto *buffer = reinterpret_cast(imageData->getImageBuffer()); return (float) buffer[y * imageData->width() + x]; }