File indexing completed on 2024-04-21 14:45:47

0001 /*
0002     SPDX-FileCopyrightText: 2004 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006     Some code fragments were adapted from Peter Kirchgessner's FITS plugin
0007     SPDX-FileCopyrightText: Peter Kirchgessner <http://members.aol.com/pkirchg>
0008 */
0009 
0010 #pragma once
0011 
0012 #include "config-kstars.h"
0013 
0014 // From StellarSolver
0015 #ifdef HAVE_STELLARSOLVER
0016 #include <structuredefinitions.h>
0017 #else
0018 #include "structuredefinitions.h"
0019 #endif
0020 
0021 #include "kstarsdatetime.h"
0022 #include "bayer.h"
0023 #include "skybackground.h"
0024 #include "fitscommon.h"
0025 #include "fitsstardetector.h"
0026 #include "auxiliary/imagemask.h"
0027 
0028 #ifdef WIN32
0029 // This header must be included before fitsio.h to avoid compiler errors with Visual Studio
0030 #include <windows.h>
0031 #endif
0032 
0033 #include <fitsio.h>
0034 
0035 #include <QFuture>
0036 #include <QObject>
0037 #include <QRect>
0038 #include <QVariant>
0039 #include <QTemporaryFile>
0040 
0041 #ifndef KSTARS_LITE
0042 #include <kxmlguiwindow.h>
0043 #ifdef HAVE_WCSLIB
0044 #include <wcs.h>
0045 #endif
0046 #endif
0047 
0048 #include "fitsskyobject.h"
0049 
0050 class QProgressDialog;
0051 
0052 class SkyPoint;
0053 class FITSHistogramData;
0054 class Edge;
0055 
0056 class FITSData : public QObject
0057 {
0058         Q_OBJECT
0059 
0060         // Name of FITS file
0061         Q_PROPERTY(QString filename READ filename)
0062         // Extension
0063         Q_PROPERTY(QString extension READ extension)
0064         // Size of file in bytes
0065         Q_PROPERTY(qint64 size READ size)
0066         // Width in pixels
0067         Q_PROPERTY(quint16 width READ width)
0068         // Height in pixels
0069         Q_PROPERTY(quint16 height READ height)
0070         // FITS MODE --> Normal, Focus, Guide..etc
0071         Q_PROPERTY(FITSMode mode MEMBER m_Mode)
0072         // 1 channel (grayscale) or 3 channels (RGB)
0073         Q_PROPERTY(quint8 channels READ channels)
0074         // Bits per pixel
0075         Q_PROPERTY(quint8 bpp READ bpp)
0076         // Does FITS have WSC header?
0077         Q_PROPERTY(bool hasWCS READ hasWCS)
0078         // Does FITS have bayer data?
0079         Q_PROPERTY(bool hasDebayer READ hasDebayer)
0080 
0081     public:
0082         explicit FITSData(FITSMode fitsMode = FITS_NORMAL);
0083         explicit FITSData(const QSharedPointer<FITSData> &other);
0084         ~FITSData() override;
0085 
0086         /** Object to hold FITS Header records */
0087         struct Record
0088         {
0089             Record() = default;
0090             Record(QString k, QString v, QString c) : key(k), value(v), comment(c) {}
0091             QString key;      /** FITS Header Key */
0092             QVariant value;   /** FITS Header Value */
0093             QString comment;  /** FITS Header Comment, if any */
0094         };
0095 
0096         typedef enum
0097         {
0098             Idle,
0099             Busy,
0100             Success,
0101             Failure
0102         } WCSState;
0103 
0104         ////////////////////////////////////////////////////////////////////////////////////////
0105         ////////////////////////////////////////////////////////////////////////////////////////
0106         /// Read and Write file/buffer Functions.
0107         ////////////////////////////////////////////////////////////////////////////////////////
0108         ////////////////////////////////////////////////////////////////////////////////////////
0109         /**
0110          * @brief loadFITS Loading FITS file asynchronously.
0111          * @param inFilename Path to FITS file (or compressed fits.gz)
0112          * @return A QFuture that can be watched until the async operation is complete.
0113          */
0114         QFuture<bool> loadFromFile(const QString &inFilename);
0115 
0116         /**
0117          * @brief loadFITSFromMemory Loading FITS from memory buffer.
0118          * @param buffer The memory buffer containing the fits data.
0119          * @param extension file extension (e.g. "jpg", "fits", "cr2"...etc)
0120          * @param inFilename Set filename metadata, does not load from file.
0121          * @return bool indicating success or failure.
0122          */
0123         bool loadFromBuffer(const QByteArray &buffer, const QString &extension, const QString &inFilename = QString());
0124 
0125         /**
0126          * @brief parseSolution Parse the WCS solution information from the header into the given struct.
0127          * @param solution Solution structure to fill out.
0128          * @return True if parsing successful, false otherwise.
0129          */
0130         bool parseSolution(FITSImage::Solution &solution) const;
0131 
0132         /* Save FITS or JPG/PNG*/
0133         bool saveImage(const QString &newFilename);
0134 
0135         // Access functions
0136         void clearImageBuffers();
0137         void setImageBuffer(uint8_t *buffer);
0138         uint8_t const *getImageBuffer() const;
0139         uint8_t *getWritableImageBuffer();
0140 
0141         ////////////////////////////////////////////////////////////////////////////////////////
0142         ////////////////////////////////////////////////////////////////////////////////////////
0143         /// Statistics Functions.
0144         ////////////////////////////////////////////////////////////////////////////////////////
0145         ////////////////////////////////////////////////////////////////////////////////////////
0146         // Calculate stats
0147         void calculateStats(bool refresh = false, bool roi = false);
0148         void saveStatistics(FITSImage::Statistic &other);
0149         void restoreStatistics(FITSImage::Statistic &other);
0150         FITSImage::Statistic const &getStatistics() const
0151         {
0152             return m_Statistics;
0153         }
0154 
0155         uint16_t width(bool roi = false) const
0156         {
0157             return roi ?  m_ROIStatistics.width : m_Statistics.width;
0158         }
0159         uint16_t height(bool roi = false) const
0160         {
0161             return roi ?  m_ROIStatistics.height : m_Statistics.height;
0162         }
0163         int64_t size(bool roi = false) const
0164         {
0165             return roi ?  m_ROIStatistics.size : m_Statistics.size;
0166         }
0167         int channels() const
0168         {
0169             return m_Statistics.channels;
0170         }
0171         uint32_t samplesPerChannel(bool roi = false) const
0172         {
0173             return roi ?  m_ROIStatistics.samples_per_channel : m_Statistics.samples_per_channel;
0174         }
0175         uint32_t dataType() const
0176         {
0177             return m_Statistics.dataType;
0178         }
0179         double getMin(uint8_t channel = 0, bool roi = false) const
0180         {
0181             return roi ?  m_ROIStatistics.min[channel] : m_Statistics.min[channel];
0182         }
0183         double getMax(uint8_t channel = 0, bool roi = false) const
0184         {
0185             return roi ?  m_ROIStatistics.max[channel] : m_Statistics.max[channel];
0186 
0187         }
0188         void setMinMax(double newMin, double newMax, uint8_t channel = 0);
0189         void getMinMax(double *min, double *max, uint8_t channel = 0) const
0190         {
0191             *min = m_Statistics.min[channel];
0192             *max = m_Statistics.max[channel];
0193         }
0194         void setStdDev(double value, uint8_t channel = 0)
0195         {
0196             m_Statistics.stddev[channel] = value;
0197         }
0198         double getStdDev(uint8_t channel = 0, bool roi = false ) const
0199         {
0200             return roi ? m_ROIStatistics.stddev[channel] :  m_Statistics.stddev[channel];
0201         }
0202         double getAverageStdDev(bool roi = false) const;
0203         void setMean(double value, uint8_t channel = 0)
0204         {
0205             m_Statistics.mean[channel] = value;
0206         }
0207         double getMean(uint8_t channel = 0, bool roi = false) const
0208         {
0209             return roi ? m_ROIStatistics.mean[channel] :  m_Statistics.mean[channel];
0210         }
0211         // for single channel, just return the mean for channel zero
0212         // for color, return the average
0213         double getAverageMean(bool roi = false) const;
0214         void setMedian(double val, uint8_t channel = 0)
0215         {
0216             m_Statistics.median[channel] = val;
0217         }
0218         // for single channel, just return the median for channel zero
0219         // for color, return the average
0220         double getAverageMedian(bool roi = false) const;
0221         double getMedian(uint8_t channel = 0, bool roi = false) const
0222         {
0223             return roi ? m_ROIStatistics.median[channel] :  m_Statistics.median[channel];
0224         }
0225 
0226         int getBytesPerPixel() const
0227         {
0228             return m_Statistics.bytesPerPixel;
0229         }
0230         void setSNR(double val)
0231         {
0232             m_Statistics.SNR = val;
0233         }
0234         double getSNR() const
0235         {
0236             return m_Statistics.SNR;
0237         }
0238         uint32_t bpp() const
0239         {
0240             switch(m_Statistics.dataType)
0241             {
0242                 case TBYTE:
0243                     return 8;
0244                 case TSHORT:
0245                 case TUSHORT:
0246                     return 16;
0247                 case TLONG:
0248                 case TULONG:
0249                 case TFLOAT:
0250                     return 32;
0251                 case TLONGLONG:
0252                 case TDOUBLE:
0253                     return 64;
0254                 default:
0255                     return 8;
0256             }
0257         }
0258         double getADU() const;
0259 
0260         ////////////////////////////////////////////////////////////////////////////////////////
0261         ////////////////////////////////////////////////////////////////////////////////////////
0262         /// FITS Header Functions.
0263         ////////////////////////////////////////////////////////////////////////////////////////
0264         ////////////////////////////////////////////////////////////////////////////////////////
0265         // FITS Record
0266         bool getRecordValue(const QString &key, QVariant &value) const;
0267         const QList<Record> &getRecords() const
0268         {
0269             return m_HeaderRecords;
0270         }
0271 
0272         ////////////////////////////////////////////////////////////////////////////////////////
0273         ////////////////////////////////////////////////////////////////////////////////////////
0274         /// Star Search & HFR Functions.
0275         ////////////////////////////////////////////////////////////////////////////////////////
0276         ////////////////////////////////////////////////////////////////////////////////////////
0277         // Star Detection - Native KStars implementation
0278         void setStarAlgorithm(StarAlgorithm algorithm)
0279         {
0280             starAlgorithm = algorithm;
0281         }
0282         int getDetectedStars() const
0283         {
0284             return starCenters.count();
0285         }
0286         bool areStarsSearched() const
0287         {
0288             return starsSearched;
0289         }
0290         void appendStar(Edge *newCenter)
0291         {
0292             starCenters.append(newCenter);
0293         }
0294         const QList<Edge *> &getStarCenters() const
0295         {
0296             return starCenters;
0297         }
0298         QList<Edge *> getStarCentersInSubFrame(QRect subFrame) const;
0299 
0300         void setStarCenters(const QList<Edge*> &centers)
0301         {
0302             qDeleteAll(starCenters);
0303             starCenters = centers;
0304         }
0305         QFuture<bool> findStars(StarAlgorithm algorithm = ALGORITHM_CENTROID, const QRect &trackingBox = QRect());
0306 
0307         void setSkyBackground(const SkyBackground &bg)
0308         {
0309             m_SkyBackground = bg;
0310         }
0311         const SkyBackground &getSkyBackground() const
0312         {
0313             return m_SkyBackground;
0314         }
0315         const QVariantMap &getSourceExtractorSettings() const
0316         {
0317             return m_SourceExtractorSettings;
0318         }
0319         void setSourceExtractorSettings(const QVariantMap &settings)
0320         {
0321             m_SourceExtractorSettings = settings;
0322         }
0323         // Use SEP (Sextractor Library) to find stars
0324         template <typename T>
0325         void getFloatBuffer(float *buffer, int x, int y, int w, int h) const;
0326         //int findSEPStars(QList<Edge*> &, const int8_t &boundary = int8_t()) const;
0327 
0328         // filter all stars that are visible through the given mask
0329         int filterStars(QSharedPointer<ImageMask> mask);
0330 
0331         // Half Flux Radius
0332         const Edge &getSelectedHFRStar() const
0333         {
0334             return m_SelectedHFRStar;
0335         }
0336 
0337         // Calculates the median star eccentricity.
0338         double getEccentricity();
0339 
0340         double getHFR(HFRType type = HFR_AVERAGE);
0341         double getHFR(int x, int y, double scale = 1.0);
0342 
0343         ////////////////////////////////////////////////////////////////////////////////////////
0344         ////////////////////////////////////////////////////////////////////////////////////////
0345         /// Date & Time (WCS) Functions.
0346         ////////////////////////////////////////////////////////////////////////////////////////
0347         ////////////////////////////////////////////////////////////////////////////////////////
0348 
0349         const KStarsDateTime &getDateTime() const
0350         {
0351             return m_DateTime;
0352         }
0353 
0354         // Set the time, for testing (doesn't set header field)
0355         void setDateTime(const KStarsDateTime &t)
0356         {
0357             m_DateTime = t;
0358         }
0359 
0360         const QPoint getRoiCenter() const
0361         {
0362             return roiCenter;
0363         }
0364 
0365         void setRoiCenter(QPoint c)
0366         {
0367             roiCenter = c;
0368         }
0369 
0370         ////////////////////////////////////////////////////////////////////////////////////////
0371         ////////////////////////////////////////////////////////////////////////////////////////
0372         /// World Coordinate System (WCS) Functions.
0373         ////////////////////////////////////////////////////////////////////////////////////////
0374         ////////////////////////////////////////////////////////////////////////////////////////
0375         // Check if a particular point exists within the image
0376         bool contains(const QPointF &point) const;
0377         // Does image have valid WCS?
0378         bool hasWCS()
0379         {
0380             return HasWCS;
0381         }
0382         // Load WCS data
0383         bool loadWCS();
0384         // Get WCS State
0385         WCSState getWCSState() const
0386         {
0387             return m_WCSState;
0388         }
0389 
0390         /**
0391              * @brief wcsToPixel Given J2000 (RA0,DE0) coordinates. Find in the image the corresponding pixel coordinates.
0392              * @param wcsCoord Coordinates of target
0393              * @param wcsPixelPoint Return XY FITS coordinates
0394              * @param wcsImagePoint Return XY Image coordinates
0395              * @return True if conversion is successful, false otherwise.
0396              */
0397         bool wcsToPixel(const SkyPoint &wcsCoord, QPointF &wcsPixelPoint, QPointF &wcsImagePoint);
0398 
0399         /**
0400              * @brief pixelToWCS Convert Pixel coordinates to J2000 world coordinates
0401              * @param wcsPixelPoint Pixel coordinates in XY Image space.
0402              * @param wcsCoord Store back WCS world coordinate in wcsCoord
0403              * @return True if successful, false otherwise.
0404              */
0405         bool pixelToWCS(const QPointF &wcsPixelPoint, SkyPoint &wcsCoord);
0406 
0407         /**
0408              * @brief injectWCS Add WCS keywords
0409              * @param orientation Solver orientation, degrees E of N.
0410              * @param ra J2000 Right Ascension
0411              * @param dec J2000 Declination
0412              * @param pixscale Pixel scale in arcsecs per pixel
0413              * @param eastToTheRight if true, then when the image is rotated so that north is up, then east would be to the right on the image.
0414              */
0415         void injectWCS(double orientation, double ra, double dec, double pixscale, bool eastToTheRight);
0416 
0417         ////////////////////////////////////////////////////////////////////////////////////////
0418         ////////////////////////////////////////////////////////////////////////////////////////
0419         /// Debayering Functions
0420         ////////////////////////////////////////////////////////////////////////////////////////
0421         ////////////////////////////////////////////////////////////////////////////////////////
0422 
0423         // Debayer
0424         bool hasDebayer()
0425         {
0426             return HasDebayer;
0427         }
0428 
0429         /**
0430          * @brief debayer the 1-channel data to 3-channel RGB using the default debayer pattern detected in the FITS header.
0431          * @param reload If true, it will read the image again from disk before performing debayering. This is necessary to attempt
0432          * subsequent debayering processes on an already debayered image.
0433          */
0434         bool debayer(bool reload = false);
0435         bool debayer_8bit();
0436         bool debayer_16bit();
0437         void getBayerParams(BayerParams *param);
0438         void setBayerParams(BayerParams *param);
0439 
0440         ////////////////////////////////////////////////////////////////////////////////////////
0441         ////////////////////////////////////////////////////////////////////////////////////////
0442         /// Public Histogram Functions
0443         ////////////////////////////////////////////////////////////////////////////////////////
0444         ////////////////////////////////////////////////////////////////////////////////////////
0445 
0446         void resetHistogram()
0447         {
0448             m_HistogramConstructed = false;
0449         }
0450         double getHistogramBinWidth(int channel = 0)
0451         {
0452             return m_HistogramBinWidth[channel];
0453         }
0454 
0455         // Returns a vector with the counts (y-axis values) for the histogram.
0456         const QVector<uint32_t> &getCumulativeFrequency(uint8_t channel = 0) const
0457         {
0458             return m_CumulativeFrequency[channel];
0459         }
0460         // Returns a vector with the values (x-axis values) for the histogram.
0461         // The value returned is the low end of the histogram interval.
0462         // The high end is this intensity plus the value returned by getHistogramBinWidth().
0463         const QVector<double> &getHistogramIntensity(uint8_t channel = 0) const
0464         {
0465             return m_HistogramIntensity[channel];
0466         }
0467         const QVector<double> &getHistogramFrequency(uint8_t channel = 0) const
0468         {
0469             return m_HistogramFrequency[channel];
0470         }
0471         int getHistogramBinCount() const
0472         {
0473             return m_HistogramBinCount;
0474         }
0475 
0476         // Returns the histogram bin for the pixel at location x,y in the given channel.
0477         int32_t histogramBin(int x, int y, int channel) const;
0478 
0479         /**
0480          * @brief getJMIndex Overall contrast of the image used in find centeroid algorithm. i.e. is the image diffuse?
0481          * @return Value of JMIndex
0482          */
0483         double getJMIndex() const
0484         {
0485             return m_JMIndex;
0486         }
0487 
0488         bool isHistogramConstructed() const
0489         {
0490             return m_HistogramConstructed;
0491         }
0492         void constructHistogram();
0493 
0494         ////////////////////////////////////////////////////////////////////////////////////////
0495         ////////////////////////////////////////////////////////////////////////////////////////
0496         /// Filters and Rotations Functions.
0497         ////////////////////////////////////////////////////////////////////////////////////////
0498         ////////////////////////////////////////////////////////////////////////////////////////
0499         // Filter
0500         void applyFilter(FITSScale type, uint8_t *image = nullptr, QVector<double> *targetMin = nullptr,
0501                          QVector<double> *targetMax = nullptr);
0502 
0503         // Rotation counter. We keep count to rotate WCS keywords on save
0504         int getRotCounter() const;
0505         void setRotCounter(int value);
0506 
0507         // Filename
0508         const QString &filename() const
0509         {
0510             return m_Filename;
0511         }
0512         const QString &compressedFilename() const
0513         {
0514             return m_compressedFilename;
0515         }
0516         bool isCompressed() const
0517         {
0518             return m_isCompressed;
0519         }
0520         // Extension
0521         const QString &extension() const
0522         {
0523             return m_Extension;
0524         }
0525 
0526         // Horizontal flip counter. We keep count to rotate WCS keywords on save
0527         int getFlipHCounter() const;
0528         void setFlipHCounter(int value);
0529 
0530         // Horizontal flip counter. We keep count to rotate WCS keywords on save
0531         int getFlipVCounter() const;
0532         void setFlipVCounter(int value);
0533 
0534         ////////////////////////////////////////////////////////////////////////////////////////
0535         ////////////////////////////////////////////////////////////////////////////////////////
0536         /// Object Search Functions.
0537         ////////////////////////////////////////////////////////////////////////////////////////
0538         ////////////////////////////////////////////////////////////////////////////////////////
0539 #ifndef KSTARS_LITE
0540 #ifdef HAVE_WCSLIB
0541         bool searchObjects();
0542         bool findObjectsInImage(SkyPoint startPoint, SkyPoint endPoint);
0543         bool findWCSBounds(double &minRA, double &maxRA, double &minDec, double &maxDec);
0544 #endif
0545 #endif
0546         const QList<FITSSkyObject *> &getSkyObjects() const
0547         {
0548             return m_SkyObjects;
0549         }
0550 
0551         ////////////////////////////////////////////////////////////////////////////////////////
0552         ////////////////////////////////////////////////////////////////////////////////////////
0553         /// Image Conversion Functions.
0554         ////////////////////////////////////////////////////////////////////////////////////////
0555         ////////////////////////////////////////////////////////////////////////////////////////
0556         // Create autostretch image from FITS File
0557         static QImage FITSToImage(const QString &filename);
0558 
0559         /**
0560          * @brief ImageToFITS Convert an image file with supported format to a FITS file.
0561          * @param filename full path to filename without extension
0562          * @param format file extension. Supported formats are whatever supported by Qt (e.g. PNG, JPG,..etc)
0563          * @param output Output temporary file path. The created file is generated by the function and store in output.
0564          * @return True if conversion is successful, false otherwise.
0565          */
0566         static bool ImageToFITS(const QString &filename, const QString &format, QString &output);
0567 
0568         QString getLastError() const;
0569 
0570         static bool readableFilename(const QString &filename);
0571 
0572     signals:
0573         void converted(QImage);
0574 
0575         /**
0576          * @brief histogramReady Sends signal when histogram construction is complete.
0577          */
0578         void histogramReady();
0579 
0580         /**
0581          * @brief dataChanged Send signal when undelying raw data buffer data changed.
0582          */
0583         void dataChanged();
0584     public slots:
0585         void makeRoiBuffer(QRect roi);
0586 
0587     private:
0588         void loadCommon(const QString &inFilename);
0589         /**
0590          * @brief privateLoad Load an image (FITS, RAW, or images supported by Qt like jpeg, png).
0591          * @param Buffer pointer to image data. If buffer is emtpy, read from disk (m_Filename).
0592          * @return true if successfully loaded, false otherwise.
0593          */
0594         bool privateLoad(const QByteArray &buffer);
0595 
0596         // Load Qt-supported images.
0597         bool loadCanonicalImage(const QByteArray &buffer);
0598         // Load FITS images.
0599         bool loadFITSImage(const QByteArray &buffer, const bool isCompressed = false);
0600         // Load XISF images.
0601         bool loadXISFImage(const QByteArray &buffer);
0602         // Save XISF images.
0603         bool saveXISFImage(const QString &newFilename);
0604         // Load RAW images.
0605         bool loadRAWImage(const QByteArray &buffer);
0606 
0607         void rotWCSFITS(int angle, int mirror);
0608         void calculateMinMax(bool refresh = false, bool roi = false);
0609         void calculateMedian(bool refresh = false, bool roi = false);
0610         bool checkDebayer();
0611         void readWCSKeys();
0612 
0613         // Record last FITS error
0614         void recordLastError(int errorCode);
0615         void logOOMError(uint32_t requiredMemory = 0);
0616 
0617         // FITS Record
0618         bool parseHeader();
0619         //int getFITSRecord(QString &recordList, int &nkeys);
0620 
0621         // Templated functions
0622         template <typename T>
0623         bool debayer();
0624 
0625         template <typename T>
0626         bool rotFITS(int rotate, int mirror);
0627 
0628         // Apply Filter
0629         template <typename T>
0630         void applyFilter(FITSScale type, uint8_t *targetImage, QVector<double> * min = nullptr, QVector<double> * max = nullptr);
0631 
0632         template <typename T>
0633         void calculateMinMax(bool roi = false);
0634         template <typename T>
0635         void calculateMedian(bool roi = false);
0636 
0637         template <typename T>
0638         QPair<T, T> getParitionMinMax(uint32_t start, uint32_t stride, bool roi);
0639 
0640         /* Calculate the Gaussian blur matrix and apply it to the image using the convolution filter */
0641         QVector<double> createGaussianKernel(int size, double sigma);
0642         template <typename T>
0643         void convolutionFilter(const QVector<double> &kernel, int kernelSize);
0644         template <typename T>
0645         void gaussianBlur(int kernelSize, double sigma);
0646 
0647         /* Calculate running average & standard deviation */
0648         template <typename T>
0649         void calculateStdDev( bool roi = false );
0650 
0651         template <typename T>
0652         void convertToQImage(double dataMin, double dataMax, double scale, double zero, QImage &image);
0653 
0654         ////////////////////////////////////////////////////////////////////////////////////////
0655         ////////////////////////////////////////////////////////////////////////////////////////
0656         /// Private Histogram Functions.
0657         ////////////////////////////////////////////////////////////////////////////////////////
0658         ////////////////////////////////////////////////////////////////////////////////////////
0659         template <typename T>  void constructHistogramInternal();
0660         template <typename T> int32_t histogramBinInternal(T value, int channel) const;
0661         template <typename T> int32_t histogramBinInternal(int x, int y, int channel) const;
0662 
0663         /// Pointer to CFITSIO FITS file struct
0664         fitsfile *fptr { nullptr };
0665         /// Generic data image buffer
0666         uint8_t *m_ImageBuffer { nullptr };
0667         /// Above buffer size in bytes
0668         uint32_t m_ImageBufferSize { 0 };
0669         /// Image Buffer if Selection is to be done
0670         uint8_t *m_ImageRoiBuffer { nullptr };
0671         /// Above buffer size in bytes
0672         uint32_t m_ImageRoiBufferSize { 0 };
0673         /// Is this a temporary file or one loaded from disk?
0674         bool m_isTemporary { false };
0675         /// is this file compress (.fits.fz)?
0676         bool m_isCompressed { false };
0677         /// Did we search for stars yet?
0678         bool starsSearched { false };
0679         ///Star Selection Algorithm
0680         StarAlgorithm starAlgorithm { ALGORITHM_GRADIENT };
0681         /// Do we have WCS keywords in this FITS data?
0682         bool HasWCS { false };        /// Do we have WCS keywords in this FITS data?
0683         /// Is the image debayarable?
0684         bool HasDebayer { false };
0685         /// Buffer to hold fpack uncompressed data
0686         uint8_t *m_PackBuffer {nullptr};
0687 
0688         /// Our very own file name
0689         QString m_Filename, m_compressedFilename, m_Extension;
0690         /// FITS Mode (Normal, WCS, Guide, Focus..etc)
0691         FITSMode m_Mode;
0692         // FITS Observed UTC date time
0693         KStarsDateTime m_DateTime;
0694 
0695         /// How many times the image was rotated? Useful for WCS keywords rotation on save.
0696         int rotCounter { 0 };
0697         /// How many times the image was flipped horizontally?
0698         int flipHCounter { 0 };
0699         /// How many times the image was flipped vertically?
0700         int flipVCounter { 0 };
0701 
0702         /// WCS Struct
0703         struct wcsprm *m_WCSHandle
0704         {
0705             nullptr
0706         };
0707         /// Number of coordinate representations found.
0708         int m_nwcs {0};
0709         WCSState m_WCSState { Idle };
0710         /// All the stars we detected, if any.
0711         QList<Edge *> starCenters;
0712         QList<Edge *> localStarCenters;
0713         /// The biggest fattest star in the image.
0714         Edge m_SelectedHFRStar;
0715 
0716         /// Bayer parameters
0717         BayerParams debayerParams;
0718         QTemporaryFile m_TemporaryDataFile;
0719 
0720         /// Data type of fits pixel in the image. Used when saving FITS again.
0721         /// There is bit depth and also data type. They're not the same.
0722         /// 16bit can be either SHORT_IMG or USHORT_IMG, so m_FITSBITPIX specifies which is
0723         int m_FITSBITPIX {USHORT_IMG};
0724         FITSImage::Statistic m_Statistics;
0725         FITSImage::Statistic m_ROIStatistics;
0726 
0727         // A list of header records
0728         QList<Record> m_HeaderRecords;
0729 
0730         QList<FITSSkyObject *> m_SkyObjects;
0731         bool m_ObjectsSearched {false};
0732 
0733         QString m_LastError;
0734 
0735         ////////////////////////////////////////////////////////////////////////////////////////
0736         ////////////////////////////////////////////////////////////////////////////////////////
0737         /// Histogram Variables
0738         ////////////////////////////////////////////////////////////////////////////////////////
0739         ////////////////////////////////////////////////////////////////////////////////////////
0740         QVector<QVector<uint32_t>> m_CumulativeFrequency;
0741         QVector<QVector<double>> m_HistogramIntensity;
0742         QVector<QVector<double>> m_HistogramFrequency;
0743         QVector<double> m_HistogramBinWidth;
0744         uint16_t m_HistogramBinCount { 0 };
0745         double m_JMIndex { 1 };
0746         bool m_HistogramConstructed { false };
0747 
0748         ////////////////////////////////////////////////////////////////////////////////////////
0749         ////////////////////////////////////////////////////////////////////////////////////////
0750         /// Star Detector
0751         ////////////////////////////////////////////////////////////////////////////////////////
0752         ////////////////////////////////////////////////////////////////////////////////////////
0753         // Sky Background
0754         SkyBackground m_SkyBackground;
0755         // Detector Settings
0756         QVariantMap m_SourceExtractorSettings;
0757         QFuture<bool> m_StarFindFuture;
0758         QScopedPointer<FITSStarDetector, QScopedPointerDeleteLater> m_StarDetector;
0759 
0760         // Cached values for hfr and eccentricity computations
0761         double cacheHFR { -1 };
0762         HFRType cacheHFRType { HFR_AVERAGE };
0763         double cacheEccentricity { -1 };
0764         QPoint roiCenter;
0765 };