File indexing completed on 2024-04-28 15:09:09
0001 /* 0002 SPDX-FileCopyrightText: 2021 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include "indi/indicamera.h" 0010 #include "indi/indidustcap.h" 0011 #include "darkview.h" 0012 #include "defectmap.h" 0013 #include "ekos/ekos.h" 0014 0015 #include <QDialog> 0016 #include <QPointer> 0017 #include "ui_darklibrary.h" 0018 0019 class QSqlTableModel; 0020 class QSortFilterProxyModel; 0021 class FITSHistogramView; 0022 0023 namespace Ekos 0024 { 0025 0026 class Capture; 0027 class SequenceJob; 0028 0029 /** 0030 * @class DarkLibrary 0031 * @short Handles acquisition & loading of dark frames and defect map for cameras. If a suitable dark frame exists, 0032 * it is loaded from disk, otherwise it gets captured and saved for later use. 0033 * 0034 * Dark Frames: 0035 * 0036 * The user can generate dark frames from an average combination of the camera dark frames. By default, 5 dark frames 0037 * are captured to merged into a single master frame. Frame duration, binning, and temperature are all configurable. 0038 * If the user select "Dark" in any of the Ekos module, Dark Library can be queried if a suitable dark frame exists given 0039 * the current camera settings (binning, temperature..etc). If a suitable frame exists, it is loaded up and send to /class DarkProcessor 0040 * class along with the light frame to perform subtraction or defect map corrections. 0041 * 0042 * Defect Maps: 0043 * 0044 * Some CMOS cameras exhibit hot pixels that are better treated with a defect map. A defect map is a collection of "bad" pixels that 0045 * are above or below certain threshold controlled by the user. This should isolate the cold and hotpixels in frames so that they are 0046 * removed from the light frames once the defect map is applied against it. This is done using 3x3 median filter over the bad pixels. 0047 * 0048 * @author Jasem Mutlaq 0049 * @version 1.0 0050 */ 0051 class DarkLibrary : public QDialog, public Ui::DarkLibrary 0052 { 0053 Q_OBJECT 0054 0055 public: 0056 static DarkLibrary *Instance(); 0057 static void Release(); 0058 0059 /** 0060 * @brief findDarkFrame Search for a dark frame that matches the passed paramters. 0061 * @param targetChip Camera chip pointer to lookup for relevant information (binning, ROI..etc). 0062 * @param duration Duration is second to match it against the database. 0063 * @param darkData If a frame is found, load it from disk and store it in a shared FITSData pointer. 0064 * @return True if a suitable frame was found the loaded successfully, false otherwise. 0065 */ 0066 bool findDarkFrame(ISD::CameraChip *targetChip, double duration, QSharedPointer<FITSData> &darkData); 0067 0068 /** 0069 * @brief findDefectMap Search for a defect map that matches the passed paramters. 0070 * @param targetChip Camera chip pointer to lookup for relevant information (binning, ROI..etc). 0071 * @param duration Duration is second to match it against the database. 0072 * @param defectMap If a frame is found, load it from disk and store it in a shared DefectMap pointer. 0073 * @return True if a suitable frame was found the loaded successfully, false otherwise. 0074 */ 0075 bool findDefectMap(ISD::CameraChip *targetChip, double duration, QSharedPointer<DefectMap> &defectMap); 0076 0077 void refreshFromDB(); 0078 bool setCamera(ISD::Camera *device); 0079 void removeDevice(const QSharedPointer<ISD::GenericDevice> &device); 0080 void checkCamera(); 0081 //void reset(); 0082 void setCaptureModule(Capture *instance); 0083 0084 void start(); 0085 void setCameraPresets(const QJsonObject &settings); 0086 QJsonObject getCameraPresets(); 0087 void setDefectPixels(const QJsonObject &payload); 0088 QJsonArray getViewMasters(); 0089 void getloadDarkViewMasterFITS(int index); 0090 0091 /** 0092 * @brief getDefectSettings Return Defect Map settings 0093 * @return JSON Object of defect map settings 0094 */ 0095 QJsonObject getDefectSettings(); 0096 0097 void setDefectMapEnabled(bool enabled); 0098 0099 // Settings 0100 QVariantMap getAllSettings() const; 0101 void setAllSettings(const QVariantMap &settings); 0102 0103 QString opticalTrain() const 0104 { 0105 return opticalTrainCombo->currentText(); 0106 } 0107 void setOpticalTrain(const QString &value) 0108 { 0109 opticalTrainCombo->setCurrentText(value); 0110 } 0111 0112 /** 0113 * @brief stop Abort all dark job captures. 0114 */ 0115 void stop(); 0116 protected: 0117 virtual void closeEvent(QCloseEvent *ev) override; 0118 0119 signals: 0120 void newLog(const QString &message); 0121 void newImage(const QSharedPointer<FITSData> &data); 0122 void newFrame(const QSharedPointer<FITSView> &view); 0123 // Settings 0124 void settingsUpdated(const QVariantMap &settings); 0125 void trainChanged(); 0126 0127 public slots: 0128 void processNewImage(SequenceJob *job, const QSharedPointer<FITSData> &data); 0129 void updateProperty(INDI::Property prop); 0130 void loadIndexInView(int row); 0131 void clearRow(int row = -1); 0132 0133 0134 private slots: 0135 void clearAll(); 0136 void clearExpired(); 0137 void openDarksFolder(); 0138 void saveDefectMap(); 0139 void setCompleted(); 0140 0141 0142 private: 0143 explicit DarkLibrary(QWidget *parent); 0144 ~DarkLibrary() override; 0145 0146 static DarkLibrary *_DarkLibrary; 0147 0148 //////////////////////////////////////////////////////////////////////////////////////////////// 0149 /// Dark Frames Functions 0150 //////////////////////////////////////////////////////////////////////////////////////////////// 0151 /** 0152 * @brief countDarkTotalTime Given current settings, count how many minutes 0153 * are required to complete all the darks. 0154 */ 0155 void countDarkTotalTime(); 0156 0157 /** 0158 * @brief generateDarkJobs Check the user frame parameters in the Darks tab and generate the corresponding 0159 * capture jobs. Populate capture module with the dark jobs. 0160 */ 0161 void generateDarkJobs(); 0162 0163 /** 0164 * @brief execute Start executing the dark jobs in capture module. 0165 */ 0166 void execute(); 0167 0168 /** 0169 * @brief generateMasterFrameHelper Calls templated generateMasterFrame with the correct data type. 0170 * @param data Passed dark frame data to generateMasterFrame 0171 * @param metadata passed metadata to generateMasterFrame 0172 */ 0173 void generateMasterFrame(const QSharedPointer<FITSData> &data, const QJsonObject &metadata); 0174 0175 /** 0176 * @brief generateMasterFrame After data aggregation is done, the selected stacking algorithm is applied and the master dark 0177 * frame is saved to disk and user database along with the metadata. 0178 * @param data last used data. This is not used for reading, but to simply apply the algorithm to the FITSData buffer 0179 * and then save it to disk. 0180 * @param metadata information on frame to help in the stacking process. 0181 */ 0182 template <typename T> void generateMasterFrameInternal(const QSharedPointer<FITSData> &data, const QJsonObject &metadata); 0183 0184 /** 0185 * @brief aggregateHelper Calls tempelated aggregate function with the appropiate data type. 0186 * @param data Dark frame data to pass on to aggregate function. 0187 */ 0188 void aggregate(const QSharedPointer<FITSData> &data); 0189 0190 /** 0191 * @brief aggregate Aggregate the data as per the selected algorithm. Each time a new dark frame is received, this function 0192 * adds the frame data to the dark buffer. 0193 * @param data Dark frame data. 0194 */ 0195 template <typename T> void aggregateInternal(const QSharedPointer<FITSData> &data); 0196 0197 /** 0198 * @brief cacheDarkFrameFromFile Load dark frame from disk and saves it in the local dark frames cache 0199 * @param filename path of dark frame to load 0200 * @return True if file is successfully loaded, false otherwise. 0201 */ 0202 bool cacheDarkFrameFromFile(const QString &filename); 0203 0204 0205 //////////////////////////////////////////////////////////////////////////////////////////////// 0206 /// Misc Functions 0207 //////////////////////////////////////////////////////////////////////////////////////////////// 0208 void initView(); 0209 void setCaptureState(CaptureState state); 0210 void reloadDarksFromDatabase(); 0211 void loadCurrentMasterDefectMap(); 0212 void clearBuffers(); 0213 0214 //////////////////////////////////////////////////////////////////////////////////////////////// 0215 /// Camera Functions 0216 //////////////////////////////////////////////////////////////////////////////////////////////// 0217 double getGain(); 0218 0219 //////////////////////////////////////////////////////////////////////////////////////////////// 0220 /// Optical Train 0221 //////////////////////////////////////////////////////////////////////////////////////////////// 0222 void setupOpticalTrainManager(); 0223 void refreshOpticalTrain(); 0224 0225 //////////////////////////////////////////////////////////////////////////////////////////////// 0226 /// Defect Map Functions 0227 //////////////////////////////////////////////////////////////////////////////////////////////// 0228 void refreshDefectMastersList(const QString &camera); 0229 void loadCurrentMasterDark(const QString &camera, int masterIndex = -1); 0230 void populateMasterMetedata(); 0231 /** 0232 * @brief cacheDefectMapFromFile Load defect map from disk and saves it in the local defect maps cache 0233 * @param key dark file name that is used as the key in the defect map cache 0234 * @param filename path of dark frame to load 0235 * @return True if file is successfully loaded, false otherwise. 0236 */ 0237 bool cacheDefectMapFromFile(const QString &key, const QString &filename); 0238 0239 //////////////////////////////////////////////////////////////////// 0240 /// Settings 0241 //////////////////////////////////////////////////////////////////// 0242 0243 /** 0244 * @brief Connect GUI elements to sync settings once updated. 0245 */ 0246 void connectSettings(); 0247 /** 0248 * @brief Stop updating settings when GUI elements are updated. 0249 */ 0250 void disconnectSettings(); 0251 /** 0252 * @brief loadSettings Load setting from Options and set them accordingly. 0253 */ 0254 void loadGlobalSettings(); 0255 0256 /** 0257 * @brief syncSettings When checkboxes, comboboxes, or spin boxes are updated, save their values in the 0258 * global and per-train settings. 0259 */ 0260 void syncSettings(); 0261 0262 /** 0263 * @brief syncControl Sync setting to widget. The value depends on the widget type. 0264 * @param settings Map of all settings 0265 * @param key name of widget to sync 0266 * @param widget pointer of widget to set 0267 * @return True if sync successful, false otherwise 0268 */ 0269 bool syncControl(const QVariantMap &settings, const QString &key, QWidget * widget); 0270 0271 //////////////////////////////////////////////////////////////////////////////////////////////// 0272 /// Member Variables 0273 //////////////////////////////////////////////////////////////////////////////////////////////// 0274 0275 QList<QVariantMap> m_DarkFramesDatabaseList; 0276 QMap<QString, QSharedPointer<FITSData>> m_CachedDarkFrames; 0277 QMap<QString, QSharedPointer<DefectMap>> m_CachedDefectMaps; 0278 0279 ISD::Camera *m_Camera {nullptr}; 0280 ISD::CameraChip *m_TargetChip {nullptr}; 0281 bool m_UseGuideHead {false}; 0282 double GainSpinSpecialValue { INVALID_VALUE }; 0283 0284 Capture *m_CaptureModule {nullptr}; 0285 QSqlTableModel *darkFramesModel = nullptr; 0286 QSortFilterProxyModel *sortFilter = nullptr; 0287 0288 std::vector<uint32_t> m_DarkMasterBuffer; 0289 uint32_t m_DarkImagesCounter {0}; 0290 bool m_RememberFITSViewer {true}; 0291 bool m_RememberSummaryView {true}; 0292 bool m_JobsGenerated {false}; 0293 QJsonObject m_PresetSettings, m_FileSettings; 0294 QString m_DefectMapFilename, m_MasterDarkFrameFilename; 0295 QSharedPointer<DarkView> m_DarkView; 0296 QPointer<QStatusBar> m_StatusBar; 0297 QPointer<QLabel> m_StatusLabel, m_FileLabel; 0298 QSharedPointer<DefectMap> m_CurrentDefectMap; 0299 QSharedPointer<FITSData> m_CurrentDarkFrame; 0300 QFutureWatcher<bool> m_DarkFrameFutureWatcher; 0301 0302 // Settings 0303 QVariantMap m_Settings; 0304 QVariantMap m_GlobalSettings; 0305 0306 // Do not add to cache if system memory falls below 250MB. 0307 static constexpr uint16_t CACHE_MEMORY_LIMIT {250}; 0308 }; 0309 }