7#include "darklibrary.h"
10#include "ekos/manager.h"
11#include "ekos/capture/capture.h"
12#include "ekos/capture/sequencejob.h"
13#include "ekos/auxiliary/opticaltrainmanager.h"
14#include "ekos/auxiliary/profilesettings.h"
15#include "ekos/auxiliary/opticaltrainsettings.h"
18#include "kstarsdata.h"
19#include "fitsviewer/fitsdata.h"
20#include "fitsviewer/fitsview.h"
22#include <QDesktopServices>
24#include <QSqlTableModel>
31DarkLibrary *DarkLibrary::_DarkLibrary =
nullptr;
33DarkLibrary *DarkLibrary::Instance()
35 if (_DarkLibrary ==
nullptr)
36 _DarkLibrary =
new DarkLibrary(Manager::Instance());
46 m_StatusLabel =
new QLabel(
i18n(
"Idle"),
this);
47 m_FileLabel =
new QLabel(
this);
50 m_StatusBar->insertPermanentWidget(0, m_StatusLabel);
51 m_StatusBar->insertPermanentWidget(1, m_FileLabel, 1);
52 mainLayout->addWidget(m_StatusBar);
55 writableDir.mkpath(
"darks");
56 writableDir.mkpath(
"defectmaps");
59 m_DebounceTimer.setInterval(500);
60 m_DebounceTimer.setSingleShot(
true);
70 loadIndexInView(index.
row());
76 auto selectionModel = darkTableView->selectionModel();
77 if (selectionModel->hasSelection())
79 auto index = selectionModel->currentIndex().
row();
90 if (m_DarkFrameFutureWatcher.result())
92 m_DarkView->loadData(m_CurrentDarkFrame);
93 loadCurrentMasterDefectMap();
94 populateMasterMetedata();
97 m_FileLabel->setText(
i18n(
"Failed to load %1: %2", m_MasterDarkFrameFilename, m_CurrentDarkFrame->getLastError()));
104 DarkLibrary::loadCurrentMasterDark(m_Camera->getDeviceName(), index);
113 maxTemperatureSpin->setMinimum(minTemperatureSpin->value());
114 countDarkTotalTime();
118 minTemperatureSpin->setMaximum(maxTemperatureSpin->value());
119 countDarkTotalTime();
123 maxTemperatureSpin->setMinimum(minTemperatureSpin->value());
124 minTemperatureSpin->setMaximum(maxTemperatureSpin->value());
125 countDarkTotalTime();
129#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
131 this, [
this](
int,
bool)
134 this, [
this](
int,
bool)
137 countDarkTotalTime();
143 KStarsData::Instance()->
userdb()->GetAllDarkFrames(m_DarkFramesDatabaseList);
149 m_DarkView->setDefectMapEnabled(index == 1 && m_CurrentDefectMap);
155 if (m_CurrentDefectMap)
156 m_CurrentDefectMap->setProperty(
"HotEnabled", toggled);
160 if (m_CurrentDefectMap)
161 m_CurrentDefectMap->setProperty(
"ColdEnabled", toggled);
165 if (m_CurrentDefectMap)
167 m_CurrentDefectMap->setProperty(
"HotPixelAggressiveness", aggresivenessHotSpin->value());
168 m_CurrentDefectMap->setProperty(
"ColdPixelAggressiveness", aggresivenessColdSpin->value());
169 m_CurrentDefectMap->filterPixels();
170 emit newFrame(m_DarkView);
175 if (m_CurrentDefectMap)
177 aggresivenessHotSlider->setValue(75);
178 aggresivenessColdSlider->setValue(75);
179 m_CurrentDefectMap->setProperty(
"HotPixelAggressiveness", 75);
180 m_CurrentDefectMap->setProperty(
"ColdPixelAggressiveness", 75);
181 m_CurrentDefectMap->filterPixels();
188 m_RememberFITSViewer = Options::useFITSViewer();
189 m_RememberSummaryView = Options::useSummaryPreview();
192 loadGlobalSettings();
196 setupOpticalTrainManager();
199DarkLibrary::~DarkLibrary()
206void DarkLibrary::refreshFromDB()
208 KStarsData::Instance()->
userdb()->GetAllDarkFrames(m_DarkFramesDatabaseList);
216 QVariantMap bestCandidate;
217 for (
auto &map : m_DarkFramesDatabaseList)
220 if (map[
"ccd"].toString() == m_TargetChip->getCCD()->getDeviceName() &&
221 map[
"chip"].toInt() ==
static_cast<int>(m_TargetChip->getType()))
224 int gain = getGain();
225 if (gain >= 0 && map[
"gain"].toInt() != gain)
230 if (m_TargetChip->getISOValue(isoValue) && map[
"iso"].toString() != isoValue)
234 int binX = 1, binY = 1;
235 m_TargetChip->getBinning(&binX, &binY);
238 if (map[
"binX"].toInt() != binX || map[
"binY"].toInt() != binY)
242 if (m_TargetChip->getCCD()->hasCoolerControl())
244 double temperature = 0;
245 m_TargetChip->getCCD()->getTemperature(&temperature);
246 double darkTemperature = map[
"temperature"].toDouble();
248 if (darkTemperature != INVALID_VALUE && fabs(darkTemperature - temperature) > maxDarkTemperatureDiff->value())
252 if (bestCandidate.isEmpty())
261 uint32_t thisMapScore = 0;
262 uint32_t bestCandidateScore = 0;
265 if (m_TargetChip->getCCD()->hasCooler())
267 double temperature = 0;
268 m_TargetChip->getCCD()->getTemperature(&temperature);
269 double diffMap = std::fabs(temperature - map[
"temperature"].toDouble());
270 double diffBest = std::fabs(temperature - bestCandidate[
"temperature"].toDouble());
272 if (diffMap < diffBest)
274 else if (diffBest < diffMap)
275 bestCandidateScore++;
280 double diffMap = std::fabs(map[
"duration"].toDouble() - duration);
281 double diffBest = std::fabs(bestCandidate[
"duration"].toDouble() - duration);
282 if (diffMap < diffBest)
284 else if (diffBest < diffMap)
285 bestCandidateScore += 5;
291 int64_t diffMap = map[
"timestamp"].toDateTime().secsTo(now);
292 int64_t diffBest = bestCandidate[
"timestamp"].toDateTime().secsTo(now);
293 if (diffMap < diffBest)
295 else if (diffBest < diffMap)
296 bestCandidateScore++;
300 if (thisMapScore > bestCandidateScore)
305 if (bestCandidate.isEmpty())
308 if (fabs(bestCandidate[
"duration"].toDouble() - duration) > 3)
309 emit
i18n(
"Using available dark frame with %1 seconds exposure. Please take a dark frame with %1 seconds exposure for more accurate results.",
313 QString filename = bestCandidate[
"filename"].toString();
316 QDateTime frameTime = bestCandidate[
"timestamp"].toDateTime();
319 emit
i18n(
"Dark frame %s is expired. Please create new master dark.", filename);
323 if (m_CachedDarkFrames.contains(filename))
325 darkData = m_CachedDarkFrames[filename];
330 auto memoryMB = KSUtils::getAvailableRAM() / 1e6;
331 if (memoryMB < CACHE_MEMORY_LIMIT)
332 m_CachedDarkFrames.clear();
335 if (cacheDarkFrameFromFile(filename))
337 darkData = m_CachedDarkFrames[filename];
342 emit newLog(
i18n(
"Removing bad dark frame file %1", filename));
343 m_CachedDarkFrames.remove(filename);
355 QVariantMap bestCandidate;
356 for (
auto &map : m_DarkFramesDatabaseList)
358 if (map[
"defectmap"].toString().isEmpty())
362 if (map[
"ccd"].toString() == m_TargetChip->getCCD()->getDeviceName() &&
363 map[
"chip"].toInt() ==
static_cast<int>(m_TargetChip->getType()))
366 m_TargetChip->getBinning(&binX, &binY);
369 if (map[
"binX"].toInt() == binX && map[
"binY"].toInt() == binY)
371 if (bestCandidate.isEmpty())
380 uint32_t thisMapScore = 0;
381 uint32_t bestCandidateScore = 0;
384 if (m_TargetChip->getCCD()->hasCooler())
386 double temperature = 0;
387 m_TargetChip->getCCD()->getTemperature(&temperature);
388 double diffMap = std::fabs(temperature - map[
"temperature"].toDouble());
389 double diffBest = std::fabs(temperature - bestCandidate[
"temperature"].toDouble());
391 if (diffMap < diffBest)
393 else if (diffBest < diffMap)
394 bestCandidateScore++;
398 double diffMap = std::fabs(map[
"duration"].toDouble() - duration);
399 double diffBest = std::fabs(bestCandidate[
"duration"].toDouble() - duration);
400 if (diffMap < diffBest)
402 else if (diffBest < diffMap)
403 bestCandidateScore += 2;
406 if (thisMapScore > bestCandidateScore)
413 if (bestCandidate.isEmpty())
417 QString darkFilename = bestCandidate[
"filename"].toString();
418 QString defectFilename = bestCandidate[
"defectmap"].toString();
423 if (m_CachedDefectMaps.contains(darkFilename))
425 defectMap = m_CachedDefectMaps[darkFilename];
430 if (cacheDefectMapFromFile(darkFilename, defectFilename))
432 defectMap = m_CachedDefectMaps[darkFilename];
438 emit newLog(
i18n(
"Failed to load defect map %1", defectFilename));
446bool DarkLibrary::cacheDefectMapFromFile(
const QString &key,
const QString &filename)
449 oneMap.
reset(
new DefectMap());
451 if (oneMap->load(filename))
453 oneMap->filterPixels();
454 m_CachedDefectMaps[key] = oneMap;
458 emit newLog(
i18n(
"Failed to load defect map file %1", filename));
465bool DarkLibrary::cacheDarkFrameFromFile(
const QString &filename)
474 m_CachedDarkFrames[filename] = data;
478 emit newLog(
i18n(
"Failed to load dark frame file %1", filename));
490 if (job->getStatus() == JOB_IDLE)
493 if (job->getCompleted() == job->getCoreProperty(SequenceJob::SJ_Count).toInt())
497 {
"camera", m_Camera->getDeviceName()},
498 {
"chip", m_TargetChip->getType()},
499 {
"binx", job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().x()},
500 {
"biny", job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().y()},
501 {
"duration", job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble()}
506 bool success = m_Camera->getTemperature(&value);
508 metadata[
"temperature"] = value;
510 success = m_Camera->hasGain() && m_Camera->getGain(&value);
512 metadata[
"gain"] = value;
515 success = m_TargetChip->getISOValue(isoValue);
517 metadata[
"iso"] = isoValue;
519 metadata[
"count"] = job->getCoreProperty(SequenceJob::SJ_Count).toInt();
520 generateMasterFrame(m_CurrentDarkFrame, metadata);
521 reloadDarksFromDatabase();
522 populateMasterMetedata();
529void DarkLibrary::updateProperty(INDI::Property prop)
531 if (prop.getType() != INDI_BLOB)
534 auto bp = prop.getBLOB()->at(0);
535 m_CurrentDarkFrame->setExtension(
QString(bp->getFormat()));
537 if (!m_CurrentDarkFrame->loadFromBuffer(buffer))
539 m_FileLabel->setText(
i18n(
"Failed to process dark data."));
543 if (!m_DarkView->loadData(m_CurrentDarkFrame))
545 m_FileLabel->setText(
i18n(
"Failed to load dark data."));
549 uint32_t totalElements = m_CurrentDarkFrame->channels() * m_CurrentDarkFrame->samplesPerChannel();
550 if (totalElements != m_DarkMasterBuffer.size())
551 m_DarkMasterBuffer.assign(totalElements, 0);
553 aggregate(m_CurrentDarkFrame);
554 darkProgress->setValue(darkProgress->value() + 1);
555 m_StatusLabel->setText(
i18n(
"Received %1/%2 images.", darkProgress->value(), darkProgress->maximum()));
561void DarkLibrary::Release()
563 delete (_DarkLibrary);
564 _DarkLibrary =
nullptr;
577 Options::setUseFITSViewer(m_RememberFITSViewer);
578 Options::setUseSummaryPreview(m_RememberSummaryView);
581 m_JobsGenerated =
false;
582 m_CaptureModule->clearSequenceQueue();
583 m_CaptureModule->mainCamera()->setAllSettings(m_CaptureModuleSettings);
590void DarkLibrary::setCompleted()
592 startB->setEnabled(
true);
593 stopB->setEnabled(
false);
595 Options::setUseFITSViewer(m_RememberFITSViewer);
596 Options::setUseSummaryPreview(m_RememberSummaryView);
599 m_JobsGenerated =
false;
600 m_CaptureModule->clearSequenceQueue();
601 m_CaptureModule->mainCamera()->setAllSettings(m_CaptureModuleSettings);
604 m_Camera->disconnect(
this);
605 m_CaptureModule->disconnect(
this);
611void DarkLibrary::clearExpired()
613 if (darkFramesModel->rowCount() == 0)
622 darkframe.setTable(
"darkframe");
624 darkframe.setFilter(
"ccd LIKE \'" + m_Camera->getDeviceName() +
"\' AND timestamp < \'" + expiredDate.
toString(
630 for (
int i = 0; i < darkframe.rowCount(); ++i)
632 QString oneFile = darkframe.record(i).value(
"filename").toString();
634 QString defectMap = darkframe.record(i).value(
"defectmap").toString();
635 if (defectMap.
isEmpty() ==
false)
641 darkframe.removeRows(0, darkframe.rowCount());
642 darkframe.submitAll();
644 Ekos::DarkLibrary::Instance()->refreshFromDB();
646 reloadDarksFromDatabase();
652void DarkLibrary::clearBuffers()
654 m_CurrentDarkFrame.clear();
657 m_DarkView->clearData();
658 m_CurrentDefectMap.clear();
664void DarkLibrary::clearAll()
666 if (darkFramesModel->rowCount() == 0)
670 i18n(
"Are you sure you want to delete all dark frames images and data?")) ==
675 for (
int i = 0; i < darkFramesModel->rowCount(); ++i)
677 QString oneFile = darkFramesModel->record(i).value(
"filename").toString();
679 QString defectMap = darkFramesModel->record(i).value(
"defectmap").toString();
680 if (defectMap.
isEmpty() ==
false)
682 darkFramesModel->removeRow(i);
686 darkFramesModel->submitAll();
690 reloadDarksFromDatabase();
696void DarkLibrary::clearRow(
int index)
701 QSqlRecord record = darkFramesModel->record(index);
710 reloadDarksFromDatabase();
716void DarkLibrary::openDarksFolder()
726void DarkLibrary::refreshDefectMastersList(
const QString &camera)
728 if (darkFramesModel->rowCount() == 0)
731 masterDarksCombo->blockSignals(
true);
732 masterDarksCombo->clear();
734 for (
int i = 0; i < darkFramesModel->rowCount(); ++i)
736 QSqlRecord record = darkFramesModel->record(i);
738 if (record.
value(
"ccd") != camera)
754 if (temperature > INVALID_VALUE)
762 masterDarksCombo->addItem(entry);
765 masterDarksCombo->blockSignals(
false);
773void DarkLibrary::reloadDarksFromDatabase()
775 if (!m_Camera)
return;
778 const QString camera = m_Camera->getDeviceName();
780 delete (darkFramesModel);
784 darkFramesModel->setTable(
"darkframe");
785 darkFramesModel->setFilter(
QString(
"ccd='%1'").arg(camera));
786 darkFramesModel->select();
789 sortFilter->setSourceModel(darkFramesModel);
790 sortFilter->sort (0);
791 darkTableView->setModel (sortFilter);
795 darkTableView->hideColumn(0);
797 darkTableView->hideColumn(2);
799 if (darkFramesModel->rowCount() == 0 && m_CurrentDarkFrame)
805 refreshDefectMastersList(camera);
806 loadCurrentMasterDark(camera);
812void DarkLibrary::loadCurrentMasterDark(
const QString &camera,
int masterIndex)
815 if (darkFramesModel->rowCount() == 0)
818 if (masterIndex == -1)
819 masterIndex = masterDarksCombo->currentIndex();
821 if (masterIndex < 0 || masterIndex >= darkFramesModel->rowCount())
824 QSqlRecord record = darkFramesModel->record(masterIndex);
825 if (record.
value(
"ccd") != camera)
828 m_MasterDarkFrameFilename = record.
value(
"filename").
toString();
830 if (m_MasterDarkFrameFilename.isEmpty() || !
QFileInfo::exists(m_MasterDarkFrameFilename))
837 if (m_CurrentDarkFrame->filename() != m_MasterDarkFrameFilename)
838 m_DarkFrameFutureWatcher.setFuture(m_CurrentDarkFrame->loadFromFile(m_MasterDarkFrameFilename));
841 loadCurrentMasterDefectMap();
847void DarkLibrary::loadCurrentMasterDefectMap()
850 if (m_CachedDefectMaps.contains(m_MasterDarkFrameFilename))
852 if (m_CurrentDefectMap != m_CachedDefectMaps.value(m_MasterDarkFrameFilename))
854 m_CurrentDefectMap = m_CachedDefectMaps.value(m_MasterDarkFrameFilename);
855 m_DarkView->setDefectMap(m_CurrentDefectMap);
856 m_CurrentDefectMap->setDarkData(m_CurrentDarkFrame);
862 m_CurrentDefectMap.reset(
new DefectMap());
863 connect(m_CurrentDefectMap.data(), &DefectMap::pixelsUpdated,
this, [
this](uint32_t hot, uint32_t cold)
865 hotPixelsCount->setValue(hot);
866 coldPixelsCount->setValue(cold);
867 aggresivenessHotSlider->setValue(m_CurrentDefectMap->property(
"HotPixelAggressiveness").toInt());
868 aggresivenessColdSlider->setValue(m_CurrentDefectMap->property(
"ColdPixelAggressiveness").toInt());
871 if (!m_DefectMapFilename.isEmpty())
872 cacheDefectMapFromFile(m_MasterDarkFrameFilename, m_DefectMapFilename);
874 m_DarkView->setDefectMap(m_CurrentDefectMap);
875 m_CurrentDefectMap->setDarkData(m_CurrentDarkFrame);
882void DarkLibrary::populateMasterMetedata()
884 if (m_CurrentDarkFrame.isNull())
889 if (m_CurrentDarkFrame->getRecordValue(
"DATE-OBS", value))
890 masterTime->setText(value.
toString());
892 if (m_CurrentDarkFrame->getRecordValue(
"CCD-TEMP", value) && value.
toDouble() < 100)
895 if (m_CurrentDarkFrame->getRecordValue(
"EXPTIME", value))
896 masterExposure->setText(value.
toString());
899 double median = m_CurrentDarkFrame->getAverageMedian();
905 double mean = m_CurrentDarkFrame->getAverageMean();
910 double stddev = m_CurrentDarkFrame->getAverageStdDev();
921void DarkLibrary::loadIndexInView(
int row)
923 QSqlRecord record = darkFramesModel->record(row);
926 if (m_DarkView->imageData().isNull() || m_DarkView->imageData()->filename() != filename)
927 m_DarkView->loadFile(filename);
935 if (m_Camera == device)
939 m_Camera->disconnect(
this);
945 darkTabsWidget->setEnabled(
true);
955 darkTabsWidget->setEnabled(
false);
965 if (m_Camera && m_Camera->getDeviceName() == device->getDeviceName())
967 m_Camera->disconnect(
this);
975void DarkLibrary::checkCamera()
980 auto device = m_Camera->getDeviceName();
982 m_TargetChip =
nullptr;
985 if (device.contains(
"Guider"))
987 m_UseGuideHead =
true;
988 m_TargetChip = m_Camera->getChip(ISD::CameraChip::GUIDE_CCD);
991 if (m_TargetChip ==
nullptr)
993 m_UseGuideHead =
false;
994 m_TargetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
999 if (!m_TargetChip || !m_TargetChip->getCCD() || m_TargetChip->isCapturing())
1002 if (m_Camera->hasCoolerControl())
1004 temperatureLabel->setEnabled(
true);
1005 temperatureStepLabel->setEnabled(
true);
1006 temperatureToLabel->setEnabled(
true);
1007 temperatureStepSpin->setEnabled(
true);
1008 minTemperatureSpin->setEnabled(
true);
1009 maxTemperatureSpin->setEnabled(
true);
1012 double temperature = 0;
1014 if (m_Camera->getTemperature(&temperature))
1016 minTemperatureSpin->setValue(temperature);
1017 maxTemperatureSpin->setValue(temperature);
1023 temperatureLabel->setEnabled(
false);
1024 temperatureStepLabel->setEnabled(
false);
1025 temperatureToLabel->setEnabled(
false);
1026 temperatureStepSpin->setEnabled(
false);
1027 minTemperatureSpin->setEnabled(
false);
1028 maxTemperatureSpin->setEnabled(
false);
1032 captureISOS->blockSignals(
true);
1033 captureISOS->
clear();
1038 captureISOS->setEnabled(
false);
1042 captureISOS->setEnabled(
true);
1043 captureISOS->addItems(isoList);
1044 captureISOS->setCurrentIndex(m_TargetChip->getISOIndex());
1046 captureISOS->blockSignals(
false);
1049 if (m_Camera->hasGain())
1051 double min, max, step, value, targetCustomGain;
1052 m_Camera->getGainMinMaxStep(&min, &max, &step);
1055 GainSpinSpecialValue = min - step;
1056 captureGainN->setRange(GainSpinSpecialValue, max);
1057 captureGainN->setSpecialValueText(
i18n(
"--"));
1058 captureGainN->setEnabled(
true);
1059 captureGainN->setSingleStep(step);
1060 m_Camera->getGain(&value);
1062 targetCustomGain = getGain();
1066 if (targetCustomGain > 0)
1067 captureGainN->setValue(targetCustomGain);
1069 captureGainN->setValue(GainSpinSpecialValue);
1071 captureGainN->setReadOnly(m_Camera->getGainPermission() == IP_RO);
1074 captureGainN->setEnabled(
false);
1076 countDarkTotalTime();
1083void DarkLibrary::countDarkTotalTime()
1085 double temperatureCount = 1;
1086 if (m_Camera && m_Camera->hasCoolerControl() && std::abs(maxTemperatureSpin->value() - minTemperatureSpin->value()) > 0)
1087 temperatureCount = (std::abs((maxTemperatureSpin->value() - minTemperatureSpin->value())) / temperatureStepSpin->value()) +
1090 if (bin1Check->isChecked())
1092 if (bin2Check->isChecked())
1094 if (bin4Check->isChecked())
1097 double darkTime = 0;
1098 int imagesCount = 0;
1099 for (
double startExposure = minExposureSpin->value(); startExposure <= maxExposureSpin->value();
1100 startExposure += exposureStepSin->value())
1102 darkTime += startExposure * temperatureCount * binnings * countSpin->value();
1103 imagesCount += temperatureCount * binnings * countSpin->value();
1108 darkProgress->setMaximum(imagesCount);
1115void DarkLibrary::generateDarkJobs()
1118 m_CaptureModule->clearSequenceQueue();
1120 if (m_JobsGenerated ==
false)
1122 m_JobsGenerated =
true;
1123 m_CaptureModuleSettings = m_CaptureModule->mainCamera()->getAllSettings();
1127 if (m_Camera->hasCoolerControl() && std::fabs(maxTemperatureSpin->value() - minTemperatureSpin->value()) >= 0)
1129 for (
double oneTemperature = minTemperatureSpin->value(); oneTemperature <= maxTemperatureSpin->value();
1130 oneTemperature += temperatureStepSpin->value())
1132 temperatures << oneTemperature;
1136 m_CaptureModule->mainCamera()->setForceTemperature(
true);
1141 m_CaptureModule->mainCamera()->setForceTemperature(
false);
1142 temperatures << INVALID_VALUE;
1146 if (bin1Check->isChecked())
1148 if (bin2Check->isChecked())
1150 if (bin4Check->isChecked())
1154 for (
double oneExposure = minExposureSpin->value(); oneExposure <= maxExposureSpin->value();
1155 oneExposure += exposureStepSin->value())
1157 exposures << oneExposure;
1165 for (
auto &oneTemperature : temperatures)
1167 for (
auto &oneExposure : exposures)
1169 for (
auto &oneBin : bins)
1172 QVariantMap settings;
1174 settings[
"opticalTrainCombo"] = opticalTrainCombo->currentText();
1175 settings[
"captureExposureN"] = oneExposure;
1176 settings[
"captureBinHN"] = oneBin;
1177 settings[
"captureBinVN"] = oneBin;
1178 settings[
"captureTypeS"] =
"Dark";
1179 settings[
"cameraTemperatureN"] = oneTemperature;
1180 if (captureGainN->isEnabled())
1181 settings[
"captureGainN"] = captureGainN->value();
1182 if (captureISOS->isEnabled())
1183 settings[
"captureISOS"] = captureISOS->currentText();
1185 settings[
"fileDirectoryT"] =
QString(prefix +
QString(
"sequence_%1").arg(sequence));
1186 settings[
"captureCountN"] = countSpin->value();
1188 m_CaptureModule->mainCamera()->setAllSettings(settings);
1189 m_CaptureModule->mainCamera()->createJob();
1198void DarkLibrary::execute()
1200 m_DarkImagesCounter = 0;
1201 darkProgress->setValue(0);
1202 darkProgress->setTextVisible(
true);
1207 Options::setUseFITSViewer(
false);
1208 Options::setUseSummaryPreview(
false);
1209 startB->setEnabled(
false);
1210 stopB->setEnabled(
true);
1211 m_DarkView->reset();
1212 m_StatusLabel->setText(
i18n(
"In progress..."));
1213 m_CaptureModule->start();
1220void DarkLibrary::stop()
1222 m_CaptureModule->abort();
1223 darkProgress->setValue(0);
1224 m_DarkView->reset();
1230void DarkLibrary::initView()
1232 m_DarkView.reset(
new DarkView(darkWidget));
1234 m_DarkView->setBaseSize(darkWidget->size());
1235 m_DarkView->createFloatingToolBar();
1238 darkWidget->setLayout(vlayout);
1239 connect(m_DarkView.get(), &DarkView::loaded,
this, [
this]()
1241 emit newImage(m_DarkView->imageData());
1250 switch (data->dataType())
1253 aggregateInternal<uint8_t>(data);
1257 aggregateInternal<int16_t>(data);
1261 aggregateInternal<uint16_t>(data);
1265 aggregateInternal<int32_t>(data);
1269 aggregateInternal<uint32_t>(data);
1273 aggregateInternal<float>(data);
1277 aggregateInternal<int64_t>(data);
1281 aggregateInternal<double>(data);
1292template <
typename T>
1295 T
const *darkBuffer =
reinterpret_cast<T const*
>(data->getImageBuffer());
1296 for (uint32_t i = 0; i < m_DarkMasterBuffer.size(); i++)
1297 m_DarkMasterBuffer[i] += darkBuffer[i];
1305 switch (data->dataType())
1308 generateMasterFrameInternal<uint8_t>(data, metadata);
1312 generateMasterFrameInternal<int16_t>(data, metadata);
1316 generateMasterFrameInternal<uint16_t>(data, metadata);
1320 generateMasterFrameInternal<int32_t>(data, metadata);
1324 generateMasterFrameInternal<uint32_t>(data, metadata);
1328 generateMasterFrameInternal<float>(data, metadata);
1332 generateMasterFrameInternal<int64_t>(data, metadata);
1336 generateMasterFrameInternal<double>(data, metadata);
1343 emit newImage(data);
1345 m_DarkMasterBuffer.assign(m_DarkMasterBuffer.size(), 0);
1355 T *writableBuffer =
reinterpret_cast<T *
>(data->getWritableImageBuffer());
1356 const uint32_t count = metadata[
"count"].toInt();
1358 for (uint32_t i = 0; i < m_DarkMasterBuffer.size(); i++)
1359 writableBuffer[i] = m_DarkMasterBuffer[i] / count;
1365 data->calculateStats(
true);
1366 if (!data->saveImage(path))
1368 m_FileLabel->setText(
i18n(
"Failed to save master frame: %1", data->getLastError()));
1372 auto memoryMB = KSUtils::getAvailableRAM() / 1e6;
1373 if (memoryMB > CACHE_MEMORY_LIMIT)
1374 cacheDarkFrameFromFile(data->filename());
1377 map[
"ccd"] = metadata[
"camera"].toString();
1378 map[
"chip"] = metadata[
"chip"].toInt();
1379 map[
"binX"] = metadata[
"binx"].toInt();
1380 map[
"binY"] = metadata[
"biny"].toInt();
1381 map[
"temperature"] = metadata[
"temperature"].toDouble(INVALID_VALUE);
1382 map[
"gain"] = metadata[
"gain"].toInt(-1);
1383 map[
"iso"] = metadata[
"iso"].toString();
1384 map[
"duration"] = metadata[
"duration"].toDouble();
1388 m_DarkFramesDatabaseList.
append(map);
1389 m_FileLabel->setText(
i18n(
"Master Dark saved to %1", path));
1396void DarkLibrary::setCaptureModule(Capture *instance)
1398 m_CaptureModule = instance;
1404void DarkLibrary::setCaptureState(CaptureState state)
1410 m_StatusLabel->setText(
i18n(
"Capture aborted."));
1414 m_StatusLabel->setText(
i18n(
"Capture completed."));
1424void DarkLibrary::saveDefectMap()
1426 if (!m_CurrentDarkFrame || !m_CurrentDefectMap)
1429 QString filename = m_CurrentDefectMap->filename();
1430 bool newFile =
false;
1439 if (m_CurrentDefectMap->save(filename, m_Camera->getDeviceName()))
1441 m_FileLabel->setText(
i18n(
"Defect map saved to %1", filename));
1445 auto currentMap = std::find_if(m_DarkFramesDatabaseList.begin(),
1446 m_DarkFramesDatabaseList.end(), [&](
const QVariantMap & oneMap)
1448 return oneMap[
"filename"].toString() == m_CurrentDarkFrame->filename();
1451 if (currentMap != m_DarkFramesDatabaseList.end())
1453 (*currentMap)[
"defectmap"] = filename;
1461 m_FileLabel->setText(
i18n(
"Failed to save defect map to %1", filename));
1468void DarkLibrary::start()
1477void DarkLibrary::setCameraPresets(
const QJsonObject &settings)
1479 const auto opticalTrain = settings[
"optical_train"].toString();
1480 const auto isDarkPrefer = settings[
"isDarkPrefer"].toBool(preferDarksRadio->isChecked());
1481 const auto isDefectPrefer = settings[
"isDefectPrefer"].toBool(preferDefectsRadio->isChecked());
1482 opticalTrainCombo->setCurrentText(opticalTrain);
1483 preferDarksRadio->setChecked(isDarkPrefer);
1484 preferDefectsRadio->setChecked(isDefectPrefer);
1486 reloadDarksFromDatabase();
1496 {
"optical_train", opticalTrainCombo->currentText()},
1497 {
"preferDarksRadio", preferDarksRadio->isChecked()},
1498 {
"preferDefectsRadio", preferDefectsRadio->isChecked()},
1499 {
"fileName", m_FileLabel->text()}
1501 return cameraSettings;
1511 for(
int i = 0; i < darkFramesModel->rowCount(); i++)
1513 QSqlRecord record = darkFramesModel->record(i);
1528 {
"temperature", temperature},
1529 {
"duaration", duration},
1534 filterRows[
"gain"] = gain;
1536 filterRows[
"iso"] = iso;
1538 array.
append(filterRows);
1546void DarkLibrary::setDefectPixels(
const QJsonObject &payload)
1548 const auto hotSpin = payload[
"hotSpin"].toInt();
1549 const auto coldSpin = payload[
"coldSpin"].toInt();
1550 const auto hotEnabled = payload[
"hotEnabled"].toBool(hotPixelsEnabled->isChecked());
1551 const auto coldEnabled = payload[
"coldEnabled"].toBool(coldPixelsEnabled->isChecked());
1553 hotPixelsEnabled->setChecked(hotEnabled);
1554 coldPixelsEnabled->setChecked(coldEnabled);
1556 aggresivenessHotSpin->setValue(hotSpin);
1557 aggresivenessColdSpin->setValue(coldSpin);
1559 m_DarkView->ZoomDefault();
1561 setDefectMapEnabled(
true);
1562 generateMapB->click();
1568void DarkLibrary::setDefectMapEnabled(
bool enabled)
1570 m_DarkView->setDefectMapEnabled(enabled);
1576double DarkLibrary::getGain()
1582 auto gain = m_Camera->getProperty(
"CCD_GAIN");
1584 return gain.getNumber()->at(0)->value;
1587 auto controls = m_Camera->getProperty(
"CCD_CONTROLS");
1590 auto oneGain = controls.getNumber()->findWidgetByName(
"Gain");
1592 return oneGain->value;
1601void DarkLibrary::setupOpticalTrainManager()
1603 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &DarkLibrary::refreshOpticalTrain);
1606 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
1610 ProfileSettings::Instance()->setOneSetting(ProfileSettings::DarkLibraryOpticalTrain,
1611 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
1612 refreshOpticalTrain();
1613 emit trainChanged();
1620void DarkLibrary::refreshOpticalTrain()
1622 opticalTrainCombo->blockSignals(
true);
1623 opticalTrainCombo->clear();
1624 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
1625 trainB->setEnabled(
true);
1627 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::DarkLibraryOpticalTrain);
1631 auto id = trainID.
toUInt();
1634 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
1636 emit newLog(
i18n(
"Optical train doesn't exist for id %1",
id));
1637 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
1640 auto name = OpticalTrainManager::Instance()->name(
id);
1642 opticalTrainCombo->setCurrentText(name);
1644 auto camera = OpticalTrainManager::Instance()->getCamera(name);
1647 auto scope = OpticalTrainManager::Instance()->getScope(name);
1648 opticalTrainCombo->setToolTip(
QString(
"%1 @ %2").arg(camera->getDeviceName(), scope[
"name"].toString()));
1653 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
1654 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::DarkLibrary);
1655 if (settings.isValid())
1658 if (map != m_Settings)
1661 setAllSettings(map);
1665 m_Settings = m_GlobalSettings;
1668 opticalTrainCombo->blockSignals(
false);
1674void DarkLibrary::loadGlobalSettings()
1679 QVariantMap settings;
1681 for (
auto &oneWidget : findChildren<QComboBox*>())
1683 if (oneWidget->objectName() ==
"opticalTrainCombo")
1686 key = oneWidget->objectName();
1687 value = Options::self()->property(key.
toLatin1());
1688 if (value.
isValid() && oneWidget->count() > 0)
1690 oneWidget->setCurrentText(value.
toString());
1691 settings[key] = value;
1696 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1698 key = oneWidget->objectName();
1699 value = Options::self()->property(key.
toLatin1());
1702 oneWidget->setValue(value.
toDouble());
1703 settings[key] = value;
1708 for (
auto &oneWidget : findChildren<QSpinBox*>())
1710 key = oneWidget->objectName();
1711 value = Options::self()->property(key.
toLatin1());
1714 oneWidget->setValue(value.
toInt());
1715 settings[key] = value;
1720 for (
auto &oneWidget : findChildren<QCheckBox*>())
1722 key = oneWidget->objectName();
1723 value = Options::self()->property(key.
toLatin1());
1726 oneWidget->setChecked(value.
toBool());
1727 settings[key] = value;
1731 m_GlobalSettings = m_Settings = settings;
1738void DarkLibrary::connectSettings()
1741 for (
auto &oneWidget : findChildren<QComboBox*>())
1745 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1749 for (
auto &oneWidget : findChildren<QSpinBox*>())
1753 for (
auto &oneWidget : findChildren<QCheckBox*>())
1757 for (
auto &oneWidget : findChildren<QRadioButton*>())
1761 disconnect(opticalTrainCombo, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::DarkLibrary::syncSettings);
1767void DarkLibrary::disconnectSettings()
1770 for (
auto &oneWidget : findChildren<QComboBox*>())
1771 disconnect(oneWidget, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::DarkLibrary::syncSettings);
1774 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1778 for (
auto &oneWidget : findChildren<QSpinBox*>())
1782 for (
auto &oneWidget : findChildren<QCheckBox*>())
1786 for (
auto &oneWidget : findChildren<QRadioButton*>())
1794QVariantMap DarkLibrary::getAllSettings()
const
1796 QVariantMap settings;
1799 for (
auto &oneWidget : findChildren<QComboBox*>())
1800 settings.insert(oneWidget->objectName(), oneWidget->currentText());
1803 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1804 settings.insert(oneWidget->objectName(), oneWidget->value());
1807 for (
auto &oneWidget : findChildren<QSpinBox*>())
1808 settings.insert(oneWidget->objectName(), oneWidget->value());
1811 for (
auto &oneWidget : findChildren<QCheckBox*>())
1812 settings.insert(oneWidget->objectName(), oneWidget->isChecked());
1820void DarkLibrary::setAllSettings(
const QVariantMap &settings)
1824 disconnectSettings();
1826 for (
auto &name : settings.keys())
1829 auto comboBox = findChild<QComboBox*>(name);
1832 syncControl(settings, name, comboBox);
1837 auto doubleSpinBox = findChild<QDoubleSpinBox*>(name);
1840 syncControl(settings, name, doubleSpinBox);
1845 auto spinBox = findChild<QSpinBox*>(name);
1848 syncControl(settings, name, spinBox);
1853 auto checkbox = findChild<QCheckBox*>(name);
1856 syncControl(settings, name, checkbox);
1861 auto radioButton = findChild<QRadioButton*>(name);
1864 syncControl(settings, name, radioButton);
1870 for (
auto &key : settings.keys())
1872 auto value = settings[key];
1874 Options::self()->setProperty(key.
toLatin1(), value);
1876 m_Settings[key] = value;
1877 m_GlobalSettings[key] = value;
1880 emit settingsUpdated(getAllSettings());
1883 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1884 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::DarkLibrary, m_Settings);
1893bool DarkLibrary::syncControl(
const QVariantMap &settings,
const QString &key,
QWidget * widget)
1902 if ((pSB = qobject_cast<QSpinBox *>(widget)))
1904 const int value = settings[key].toInt(&ok);
1911 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
1913 const double value = settings[key].toDouble(&ok);
1920 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
1922 const bool value = settings[key].toBool();
1928 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))
1930 const QString value = settings[key].toString();
1934 else if ((pRadioButton = qobject_cast<QRadioButton *>(widget)))
1936 const bool value = settings[key].toBool();
1938 pRadioButton->
click();
1948void DarkLibrary::syncSettings()
1959 if ( (dsb = qobject_cast<QDoubleSpinBox*>(sender())))
1962 value = dsb->
value();
1965 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
1968 value = sb->
value();
1970 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
1975 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
1980 else if ( (cradio = qobject_cast<QRadioButton*>(sender())))
1986 m_Settings.remove(key);
1993 Options::self()->setProperty(key.
toLatin1(), value);
1994 m_Settings[key] = value;
1995 m_GlobalSettings[key] = value;
1997 m_DebounceTimer.start();
2003void DarkLibrary::settleSettings()
2005 emit settingsUpdated(getAllSettings());
2006 Options::self()->save();
2008 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
2009 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::DarkLibrary, m_Settings);
2018 for (
int i = 0; i < masterDarksCombo->count(); i++)
2019 darkMasters << masterDarksCombo->itemText(i);
2023 {
"masterTime", masterTime->text()},
2024 {
"masterDarks", darkMasters.
join(
'|')},
2025 {
"masterExposure", masterExposure->text()},
2026 {
"masterTempreture", masterTemperature->text()},
2027 {
"masterMean", masterMean->text()},
2028 {
"masterMedian", masterMedian->text()},
2029 {
"masterDeviation", masterDeviation->text()},
2030 {
"hotPixelsEnabled", hotPixelsEnabled->isChecked()},
2031 {
"coldPixelsEnabled", coldPixelsEnabled->isChecked()},
2033 return createDefectMaps;
CameraChip class controls a particular chip in camera.
Camera class controls an INDI Camera device.
bool DeleteDarkFrame(const QString &filename)
KSUserDB::DeleteDarkFrame Delete from database a dark frame record that matches the filename field.
bool AddDarkFrame(const QVariantMap &oneFrame)
KSUserDB::AddDarkFrame Saves a new dark frame data to the database.
bool UpdateDarkFrame(const QVariantMap &oneFrame)
KSUserDB::UpdateDarkFrame Updates an existing dark frame record in the data, replace all values match...
static KStars * Instance()
Sequence Job is a container for the details required to capture a series of images.
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
QString name(GameStandardAction id)
QString path(const QString &relativePath)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
void doubleClicked(const QModelIndex &index)
void valueChanged(int value)
QByteArray fromRawData(const char *data, qsizetype size)
void activated(int index)
void currentIndexChanged(int index)
void setCurrentText(const QString &text)
QDateTime addDays(qint64 ndays) const const
QDateTime currentDateTime()
qint64 currentSecsSinceEpoch()
qint64 daysTo(const QDateTime &other) const const
QString toString(QStringView format, QCalendar cal) const const
bool openUrl(const QUrl &url)
QString filePath(const QString &fileName) const const
void setValue(double val)
bool exists() const const
void append(const QJsonValue &value)
QVariantMap toVariantMap() const const
bool isEmpty() const const
QSqlDatabase database(const QString &connectionName, bool open)
QVariant value(const QString &name) const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QByteArray toLatin1() const const
QString join(QChar separator) const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
bool isValid() const const
bool toBool() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
QString toString() const const
uint toUInt(bool *ok) const const