1 /* 2 SPDX-FileCopyrightText: 2021 Jasem Mutlaq <mutlaqja@ikarustech.com> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #pragma once 8 9 #include "indi/indiccd.h" 10 #include "indi/indicap.h" 11 #include "darkview.h" 12 #include "defectmap.h" 13 #include "ekos/ekos.h" 14 15 #include <QDialog> 16 #include <QPointer> 17 #include "ui_darklibrary.h" 18 19 class QSqlTableModel; 20 class QSortFilterProxyModel; 21 class FITSHistogramView; 22 23 namespace Ekos 24 { 25 26 class Capture; 27 class SequenceJob; 28 29 /** 30 * @class DarkLibrary 31 * @short Handles acquisition & loading of dark frames and defect map for cameras. If a suitable dark frame exists, 32 * it is loaded from disk, otherwise it gets captured and saved for later use. 33 * 34 * Dark Frames: 35 * 36 * The user can generate dark frames from an average combination of the camera dark frames. By default, 5 dark frames 37 * are captured to merged into a single master frame. Frame duration, binning, and temperature are all configurable. 38 * If the user select "Dark" in any of the Ekos module, Dark Library can be queried if a suitable dark frame exists given 39 * the current camera settings (binning, temperature..etc). If a suitable frame exists, it is loaded up and send to /class DarkProcessor 40 * class along with the light frame to perform subtraction or defect map corrections. 41 * 42 * Defect Maps: 43 * 44 * Some CMOS cameras exhibit hot pixels that are better treated with a defect map. A defect map is a collection of "bad" pixels that 45 * are above or below certain threshold controlled by the user. This should isolate the cold and hotpixels in frames so that they are 46 * removed from the light frames once the defect map is applied against it. This is done using 3x3 median filter over the bad pixels. 47 * 48 * @author Jasem Mutlaq 49 * @version 1.0 50 */ 51 class DarkLibrary : public QDialog, public Ui::DarkLibrary 52 { 53 Q_OBJECT 54 55 public: 56 static DarkLibrary *Instance(); 57 static void Release(); 58 59 /** 60 * @brief findDarkFrame Search for a dark frame that matches the passed paramters. 61 * @param targetChip Camera chip pointer to lookup for relevant information (binning, ROI..etc). 62 * @param duration Duration is second to match it against the database. 63 * @param darkData If a frame is found, load it from disk and store it in a shared FITSData pointer. 64 * @return True if a suitable frame was found the loaded successfully, false otherwise. 65 */ 66 bool findDarkFrame(ISD::CCDChip *targetChip, double duration, QSharedPointer<FITSData> &darkData); 67 68 /** 69 * @brief findDefectMap Search for a defect map that matches the passed paramters. 70 * @param targetChip Camera chip pointer to lookup for relevant information (binning, ROI..etc). 71 * @param duration Duration is second to match it against the database. 72 * @param defectMap If a frame is found, load it from disk and store it in a shared DefectMap pointer. 73 * @return True if a suitable frame was found the loaded successfully, false otherwise. 74 */ 75 bool findDefectMap(ISD::CCDChip *targetChip, double duration, QSharedPointer<DefectMap> &defectMap); 76 77 /** 78 * @brief cameraHasDefectMaps Check if camera has any defect maps available. 79 * @param name Camera name 80 * @return True if at least one defect maps exists for this camera, false otherwise. 81 */ cameraHasDefectMaps(const QString & name)82 bool cameraHasDefectMaps(const QString &name) const 83 { 84 return m_DefectCameras.contains(name); 85 } 86 87 void refreshFromDB(); 88 void addCamera(ISD::GDInterface * newCCD); 89 void removeCamera(ISD::GDInterface * newCCD); 90 void checkCamera(int ccdNum = -1); 91 //void reset(); 92 void setCaptureModule(Capture *instance); 93 94 protected: 95 virtual void closeEvent(QCloseEvent *ev) override; 96 97 signals: 98 void newLog(const QString &message); 99 100 public slots: 101 void processNewImage(SequenceJob *job, const QSharedPointer<FITSData> &data); 102 void processNewBLOB(IBLOB *bp); 103 104 private slots: 105 void clearAll(); 106 void clearRow(); 107 void clearExpired(); 108 void openDarksFolder(); 109 void saveDefectMap(); 110 void setCompleted(); 111 void loadDarkFITS(QModelIndex index); 112 113 private: 114 explicit DarkLibrary(QWidget *parent); 115 ~DarkLibrary() override; 116 117 static DarkLibrary *_DarkLibrary; 118 119 //////////////////////////////////////////////////////////////////////////////////////////////// 120 /// Dark Frames Functions 121 //////////////////////////////////////////////////////////////////////////////////////////////// 122 /** 123 * @brief countDarkTotalTime Given current settings, count how many minutes 124 * are required to complete all the darks. 125 */ 126 void countDarkTotalTime(); 127 128 /** 129 * @brief generateDarkJobs Check the user frame parameters in the Darks tab and generate the corresponding 130 * capture jobs. Populate capture module with the dark jobs. 131 */ 132 void generateDarkJobs(); 133 134 /** 135 * @brief executeDarkJobs Start executing the dark jobs in capture module. 136 */ 137 void executeDarkJobs(); 138 139 /** 140 * @brief stopDarkJobs Abort all dark job captures. 141 */ 142 void stopDarkJobs(); 143 144 /** 145 * @brief generateMasterFrameHelper Calls templated generateMasterFrame with the correct data type. 146 * @param data Passed dark frame data to generateMasterFrame 147 * @param metadata passed metadata to generateMasterFrame 148 */ 149 void generateMasterFrame(const QSharedPointer<FITSData> &data, const QJsonObject &metadata); 150 151 /** 152 * @brief generateMasterFrame After data aggregation is done, the selected stacking algorithm is applied and the master dark 153 * frame is saved to disk and user database along with the metadata. 154 * @param data last used data. This is not used for reading, but to simply apply the algorithm to the FITSData buffer 155 * and then save it to disk. 156 * @param metadata information on frame to help in the stacking process. 157 */ 158 template <typename T> void generateMasterFrameInternal(const QSharedPointer<FITSData> &data, const QJsonObject &metadata); 159 160 /** 161 * @brief aggregateHelper Calls tempelated aggregate function with the appropiate data type. 162 * @param data Dark frame data to pass on to aggregate function. 163 */ 164 void aggregate(const QSharedPointer<FITSData> &data); 165 166 /** 167 * @brief aggregate Aggregate the data as per the selected algorithm. Each time a new dark frame is received, this function 168 * adds the frame data to the dark buffer. 169 * @param data Dark frame data. 170 */ 171 template <typename T> void aggregateInternal(const QSharedPointer<FITSData> &data); 172 173 /** 174 * @brief cacheDarkFrameFromFile Load dark frame from disk and saves it in the local dark frames cache 175 * @param filename path of dark frame to load 176 * @return True if file is successfully loaded, false otherwise. 177 */ 178 bool cacheDarkFrameFromFile(const QString &filename); 179 180 181 //////////////////////////////////////////////////////////////////////////////////////////////// 182 /// Misc Functions 183 //////////////////////////////////////////////////////////////////////////////////////////////// 184 void initView(); 185 void setCaptureState(CaptureState state); 186 void reloadDarksFromDatabase(); 187 void loadCurrentMasterDefectMap(); 188 void clearBuffers(); 189 190 //////////////////////////////////////////////////////////////////////////////////////////////// 191 /// Defect Map Functions 192 //////////////////////////////////////////////////////////////////////////////////////////////// 193 void refreshDefectMastersList(const QString &camera); 194 void loadCurrentMasterDark(const QString &camera, int masterIndex = -1); 195 void populateMasterMetedata(); 196 /** 197 * @brief cacheDefectMapFromFile Load defect map from disk and saves it in the local defect maps cache 198 * @param key dark file name that is used as the key in the defect map cache 199 * @param filename path of dark frame to load 200 * @return True if file is successfully loaded, false otherwise. 201 */ 202 bool cacheDefectMapFromFile(const QString &key, const QString &filename); 203 204 //////////////////////////////////////////////////////////////////////////////////////////////// 205 /// Member Variables 206 //////////////////////////////////////////////////////////////////////////////////////////////// 207 208 QList<QVariantMap> m_DarkFramesDatabaseList; 209 QMap<QString, QSharedPointer<FITSData>> m_CachedDarkFrames; 210 QMap<QString, QSharedPointer<DefectMap>> m_CachedDefectMaps; 211 212 ISD::CCD *m_CurrentCamera {nullptr}; 213 ISD::CCDChip *m_TargetChip {nullptr}; 214 QList<ISD::CCD *> m_Cameras; 215 bool m_UseGuideHead {false}; 216 217 Capture *m_CaptureModule {nullptr}; 218 QSqlTableModel *darkFramesModel = nullptr; 219 QSortFilterProxyModel *sortFilter = nullptr; 220 221 std::vector<uint32_t> m_DarkMasterBuffer; 222 uint32_t m_DarkImagesCounter {0}; 223 bool m_RememberFITSViewer {true}; 224 bool m_RememberSummaryView {true}; 225 QString m_RememberFITSDirectory; 226 bool m_JobsGenerated {false}; 227 QJsonObject m_PresetSettings; 228 QString m_DefectMapFilename, m_MasterDarkFrameFilename; 229 QStringList m_DarkCameras, m_DefectCameras; 230 QPointer<DarkView> m_DarkView; 231 QPointer<QStatusBar> m_StatusBar; 232 QPointer<QLabel> m_StatusLabel, m_FileLabel; 233 QSharedPointer<DefectMap> m_CurrentDefectMap; 234 QSharedPointer<FITSData> m_CurrentDarkFrame; 235 QFutureWatcher<bool> m_DarkFrameFutureWatcher; 236 }; 237 } 238