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)
688 reloadDarksFromDatabase();
694void DarkLibrary::clearRow(
int index)
699 QSqlRecord record = darkFramesModel->record(index);
708 reloadDarksFromDatabase();
714void DarkLibrary::openDarksFolder()
724void DarkLibrary::refreshDefectMastersList(
const QString &camera)
726 if (darkFramesModel->rowCount() == 0)
729 masterDarksCombo->blockSignals(
true);
730 masterDarksCombo->clear();
732 for (
int i = 0; i < darkFramesModel->rowCount(); ++i)
734 QSqlRecord record = darkFramesModel->record(i);
736 if (record.
value(
"ccd") != camera)
752 if (temperature > INVALID_VALUE)
760 masterDarksCombo->addItem(entry);
763 masterDarksCombo->blockSignals(
false);
771void DarkLibrary::reloadDarksFromDatabase()
773 if (!m_Camera)
return;
776 const QString camera = m_Camera->getDeviceName();
778 delete (darkFramesModel);
782 darkFramesModel->setTable(
"darkframe");
783 darkFramesModel->setFilter(
QString(
"ccd='%1'").arg(camera));
784 darkFramesModel->select();
787 sortFilter->setSourceModel(darkFramesModel);
788 sortFilter->sort (0);
789 darkTableView->setModel (sortFilter);
793 darkTableView->hideColumn(0);
795 darkTableView->hideColumn(2);
797 if (darkFramesModel->rowCount() == 0 && m_CurrentDarkFrame)
803 refreshDefectMastersList(camera);
804 loadCurrentMasterDark(camera);
810void DarkLibrary::loadCurrentMasterDark(
const QString &camera,
int masterIndex)
813 if (darkFramesModel->rowCount() == 0)
816 if (masterIndex == -1)
817 masterIndex = masterDarksCombo->currentIndex();
819 if (masterIndex < 0 || masterIndex >= darkFramesModel->rowCount())
822 QSqlRecord record = darkFramesModel->record(masterIndex);
823 if (record.
value(
"ccd") != camera)
826 m_MasterDarkFrameFilename = record.
value(
"filename").
toString();
828 if (m_MasterDarkFrameFilename.isEmpty() || !
QFileInfo::exists(m_MasterDarkFrameFilename))
835 if (m_CurrentDarkFrame->filename() != m_MasterDarkFrameFilename)
836 m_DarkFrameFutureWatcher.setFuture(m_CurrentDarkFrame->loadFromFile(m_MasterDarkFrameFilename));
839 loadCurrentMasterDefectMap();
845void DarkLibrary::loadCurrentMasterDefectMap()
848 if (m_CachedDefectMaps.contains(m_MasterDarkFrameFilename))
850 if (m_CurrentDefectMap != m_CachedDefectMaps.value(m_MasterDarkFrameFilename))
852 m_CurrentDefectMap = m_CachedDefectMaps.value(m_MasterDarkFrameFilename);
853 m_DarkView->setDefectMap(m_CurrentDefectMap);
854 m_CurrentDefectMap->setDarkData(m_CurrentDarkFrame);
860 m_CurrentDefectMap.reset(
new DefectMap());
861 connect(m_CurrentDefectMap.data(), &DefectMap::pixelsUpdated,
this, [
this](uint32_t hot, uint32_t cold)
863 hotPixelsCount->setValue(hot);
864 coldPixelsCount->setValue(cold);
865 aggresivenessHotSlider->setValue(m_CurrentDefectMap->property(
"HotPixelAggressiveness").toInt());
866 aggresivenessColdSlider->setValue(m_CurrentDefectMap->property(
"ColdPixelAggressiveness").toInt());
869 if (!m_DefectMapFilename.isEmpty())
870 cacheDefectMapFromFile(m_MasterDarkFrameFilename, m_DefectMapFilename);
872 m_DarkView->setDefectMap(m_CurrentDefectMap);
873 m_CurrentDefectMap->setDarkData(m_CurrentDarkFrame);
880void DarkLibrary::populateMasterMetedata()
882 if (m_CurrentDarkFrame.isNull())
887 if (m_CurrentDarkFrame->getRecordValue(
"DATE-OBS", value))
888 masterTime->setText(value.
toString());
890 if (m_CurrentDarkFrame->getRecordValue(
"CCD-TEMP", value) && value.
toDouble() < 100)
893 if (m_CurrentDarkFrame->getRecordValue(
"EXPTIME", value))
894 masterExposure->setText(value.
toString());
897 double median = m_CurrentDarkFrame->getAverageMedian();
903 double mean = m_CurrentDarkFrame->getAverageMean();
908 double stddev = m_CurrentDarkFrame->getAverageStdDev();
919void DarkLibrary::loadIndexInView(
int row)
921 QSqlRecord record = darkFramesModel->record(row);
924 if (m_DarkView->imageData().isNull() || m_DarkView->imageData()->filename() != filename)
925 m_DarkView->loadFile(filename);
933 if (m_Camera == device)
937 m_Camera->disconnect(
this);
943 darkTabsWidget->setEnabled(
true);
953 darkTabsWidget->setEnabled(
false);
963 if (m_Camera && m_Camera->getDeviceName() == device->getDeviceName())
965 m_Camera->disconnect(
this);
973void DarkLibrary::checkCamera()
978 auto device = m_Camera->getDeviceName();
980 m_TargetChip =
nullptr;
983 if (device.contains(
"Guider"))
985 m_UseGuideHead =
true;
986 m_TargetChip = m_Camera->getChip(ISD::CameraChip::GUIDE_CCD);
989 if (m_TargetChip ==
nullptr)
991 m_UseGuideHead =
false;
992 m_TargetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
997 if (!m_TargetChip || !m_TargetChip->getCCD() || m_TargetChip->isCapturing())
1000 if (m_Camera->hasCoolerControl())
1002 temperatureLabel->setEnabled(
true);
1003 temperatureStepLabel->setEnabled(
true);
1004 temperatureToLabel->setEnabled(
true);
1005 temperatureStepSpin->setEnabled(
true);
1006 minTemperatureSpin->setEnabled(
true);
1007 maxTemperatureSpin->setEnabled(
true);
1010 double temperature = 0;
1012 if (m_Camera->getTemperature(&temperature))
1014 minTemperatureSpin->setValue(temperature);
1015 maxTemperatureSpin->setValue(temperature);
1021 temperatureLabel->setEnabled(
false);
1022 temperatureStepLabel->setEnabled(
false);
1023 temperatureToLabel->setEnabled(
false);
1024 temperatureStepSpin->setEnabled(
false);
1025 minTemperatureSpin->setEnabled(
false);
1026 maxTemperatureSpin->setEnabled(
false);
1030 captureISOS->blockSignals(
true);
1031 captureISOS->
clear();
1036 captureISOS->setEnabled(
false);
1040 captureISOS->setEnabled(
true);
1041 captureISOS->addItems(isoList);
1042 captureISOS->setCurrentIndex(m_TargetChip->getISOIndex());
1044 captureISOS->blockSignals(
false);
1047 if (m_Camera->hasGain())
1049 double min, max, step, value, targetCustomGain;
1050 m_Camera->getGainMinMaxStep(&min, &max, &step);
1053 GainSpinSpecialValue = min - step;
1054 captureGainN->setRange(GainSpinSpecialValue, max);
1055 captureGainN->setSpecialValueText(
i18n(
"--"));
1056 captureGainN->setEnabled(
true);
1057 captureGainN->setSingleStep(step);
1058 m_Camera->getGain(&value);
1060 targetCustomGain = getGain();
1064 if (targetCustomGain > 0)
1065 captureGainN->setValue(targetCustomGain);
1067 captureGainN->setValue(GainSpinSpecialValue);
1069 captureGainN->setReadOnly(m_Camera->getGainPermission() == IP_RO);
1072 captureGainN->setEnabled(
false);
1074 countDarkTotalTime();
1081void DarkLibrary::countDarkTotalTime()
1083 double temperatureCount = 1;
1084 if (m_Camera && m_Camera->hasCoolerControl() && std::abs(maxTemperatureSpin->value() - minTemperatureSpin->value()) > 0)
1085 temperatureCount = (std::abs((maxTemperatureSpin->value() - minTemperatureSpin->value())) / temperatureStepSpin->value()) +
1088 if (bin1Check->isChecked())
1090 if (bin2Check->isChecked())
1092 if (bin4Check->isChecked())
1095 double darkTime = 0;
1096 int imagesCount = 0;
1097 for (
double startExposure = minExposureSpin->value(); startExposure <= maxExposureSpin->value();
1098 startExposure += exposureStepSin->value())
1100 darkTime += startExposure * temperatureCount * binnings * countSpin->value();
1101 imagesCount += temperatureCount * binnings * countSpin->value();
1106 darkProgress->setMaximum(imagesCount);
1113void DarkLibrary::generateDarkJobs()
1116 m_CaptureModule->clearSequenceQueue();
1118 if (m_JobsGenerated ==
false)
1120 m_JobsGenerated =
true;
1121 m_CaptureModuleSettings = m_CaptureModule->mainCamera()->getAllSettings();
1125 if (m_Camera->hasCoolerControl() && std::fabs(maxTemperatureSpin->value() - minTemperatureSpin->value()) >= 0)
1127 for (
double oneTemperature = minTemperatureSpin->value(); oneTemperature <= maxTemperatureSpin->value();
1128 oneTemperature += temperatureStepSpin->value())
1130 temperatures << oneTemperature;
1134 m_CaptureModule->mainCamera()->setForceTemperature(
true);
1139 m_CaptureModule->mainCamera()->setForceTemperature(
false);
1140 temperatures << INVALID_VALUE;
1144 if (bin1Check->isChecked())
1146 if (bin2Check->isChecked())
1148 if (bin4Check->isChecked())
1152 for (
double oneExposure = minExposureSpin->value(); oneExposure <= maxExposureSpin->value();
1153 oneExposure += exposureStepSin->value())
1155 exposures << oneExposure;
1163 for (
auto &oneTemperature : temperatures)
1165 for (
auto &oneExposure : exposures)
1167 for (
auto &oneBin : bins)
1170 QVariantMap settings;
1172 settings[
"opticalTrainCombo"] = opticalTrainCombo->currentText();
1173 settings[
"captureExposureN"] = oneExposure;
1174 settings[
"captureBinHN"] = oneBin;
1175 settings[
"captureBinVN"] = oneBin;
1176 settings[
"captureTypeS"] =
"Dark";
1177 settings[
"cameraTemperatureN"] = oneTemperature;
1178 if (captureGainN->isEnabled())
1179 settings[
"captureGainN"] = captureGainN->value();
1180 if (captureISOS->isEnabled())
1181 settings[
"captureISOS"] = captureISOS->currentText();
1183 settings[
"fileDirectoryT"] =
QString(prefix +
QString(
"sequence_%1").arg(sequence));
1184 settings[
"captureCountN"] = countSpin->value();
1186 m_CaptureModule->mainCamera()->setAllSettings(settings);
1187 m_CaptureModule->mainCamera()->createJob();
1196void DarkLibrary::execute()
1198 m_DarkImagesCounter = 0;
1199 darkProgress->setValue(0);
1200 darkProgress->setTextVisible(
true);
1205 Options::setUseFITSViewer(
false);
1206 Options::setUseSummaryPreview(
false);
1207 startB->setEnabled(
false);
1208 stopB->setEnabled(
true);
1209 m_DarkView->reset();
1210 m_StatusLabel->setText(
i18n(
"In progress..."));
1211 m_CaptureModule->start();
1218void DarkLibrary::stop()
1220 m_CaptureModule->abort();
1221 darkProgress->setValue(0);
1222 m_DarkView->reset();
1228void DarkLibrary::initView()
1230 m_DarkView.reset(
new DarkView(darkWidget));
1232 m_DarkView->setBaseSize(darkWidget->size());
1233 m_DarkView->createFloatingToolBar();
1236 darkWidget->setLayout(vlayout);
1237 connect(m_DarkView.get(), &DarkView::loaded,
this, [
this]()
1239 emit newImage(m_DarkView->imageData());
1248 switch (data->dataType())
1251 aggregateInternal<uint8_t>(data);
1255 aggregateInternal<int16_t>(data);
1259 aggregateInternal<uint16_t>(data);
1263 aggregateInternal<int32_t>(data);
1267 aggregateInternal<uint32_t>(data);
1271 aggregateInternal<float>(data);
1275 aggregateInternal<int64_t>(data);
1279 aggregateInternal<double>(data);
1290template <
typename T>
1293 T
const *darkBuffer =
reinterpret_cast<T const*
>(data->getImageBuffer());
1294 for (uint32_t i = 0; i < m_DarkMasterBuffer.size(); i++)
1295 m_DarkMasterBuffer[i] += darkBuffer[i];
1303 switch (data->dataType())
1306 generateMasterFrameInternal<uint8_t>(data, metadata);
1310 generateMasterFrameInternal<int16_t>(data, metadata);
1314 generateMasterFrameInternal<uint16_t>(data, metadata);
1318 generateMasterFrameInternal<int32_t>(data, metadata);
1322 generateMasterFrameInternal<uint32_t>(data, metadata);
1326 generateMasterFrameInternal<float>(data, metadata);
1330 generateMasterFrameInternal<int64_t>(data, metadata);
1334 generateMasterFrameInternal<double>(data, metadata);
1341 emit newImage(data);
1343 m_DarkMasterBuffer.assign(m_DarkMasterBuffer.size(), 0);
1353 T *writableBuffer =
reinterpret_cast<T *
>(data->getWritableImageBuffer());
1354 const uint32_t count = metadata[
"count"].toInt();
1356 for (uint32_t i = 0; i < m_DarkMasterBuffer.size(); i++)
1357 writableBuffer[i] = m_DarkMasterBuffer[i] / count;
1363 data->calculateStats(
true);
1364 if (!data->saveImage(path))
1366 m_FileLabel->setText(
i18n(
"Failed to save master frame: %1", data->getLastError()));
1370 auto memoryMB = KSUtils::getAvailableRAM() / 1e6;
1371 if (memoryMB > CACHE_MEMORY_LIMIT)
1372 cacheDarkFrameFromFile(data->filename());
1375 map[
"ccd"] = metadata[
"camera"].toString();
1376 map[
"chip"] = metadata[
"chip"].toInt();
1377 map[
"binX"] = metadata[
"binx"].toInt();
1378 map[
"binY"] = metadata[
"biny"].toInt();
1379 map[
"temperature"] = metadata[
"temperature"].toDouble(INVALID_VALUE);
1380 map[
"gain"] = metadata[
"gain"].toInt(-1);
1381 map[
"iso"] = metadata[
"iso"].toString();
1382 map[
"duration"] = metadata[
"duration"].toDouble();
1386 m_DarkFramesDatabaseList.
append(map);
1387 m_FileLabel->setText(
i18n(
"Master Dark saved to %1", path));
1394void DarkLibrary::setCaptureModule(Capture *instance)
1396 m_CaptureModule = instance;
1402void DarkLibrary::setCaptureState(CaptureState state)
1408 m_StatusLabel->setText(
i18n(
"Capture aborted."));
1412 m_StatusLabel->setText(
i18n(
"Capture completed."));
1422void DarkLibrary::saveDefectMap()
1424 if (!m_CurrentDarkFrame || !m_CurrentDefectMap)
1427 QString filename = m_CurrentDefectMap->filename();
1428 bool newFile =
false;
1437 if (m_CurrentDefectMap->save(filename, m_Camera->getDeviceName()))
1439 m_FileLabel->setText(
i18n(
"Defect map saved to %1", filename));
1443 auto currentMap = std::find_if(m_DarkFramesDatabaseList.begin(),
1444 m_DarkFramesDatabaseList.end(), [&](
const QVariantMap & oneMap)
1446 return oneMap[
"filename"].toString() == m_CurrentDarkFrame->filename();
1449 if (currentMap != m_DarkFramesDatabaseList.end())
1451 (*currentMap)[
"defectmap"] = filename;
1459 m_FileLabel->setText(
i18n(
"Failed to save defect map to %1", filename));
1466void DarkLibrary::start()
1475void DarkLibrary::setCameraPresets(
const QJsonObject &settings)
1477 const auto opticalTrain = settings[
"optical_train"].toString();
1478 const auto isDarkPrefer = settings[
"isDarkPrefer"].toBool(preferDarksRadio->isChecked());
1479 const auto isDefectPrefer = settings[
"isDefectPrefer"].toBool(preferDefectsRadio->isChecked());
1480 opticalTrainCombo->setCurrentText(opticalTrain);
1481 preferDarksRadio->setChecked(isDarkPrefer);
1482 preferDefectsRadio->setChecked(isDefectPrefer);
1484 reloadDarksFromDatabase();
1494 {
"optical_train", opticalTrainCombo->currentText()},
1495 {
"preferDarksRadio", preferDarksRadio->isChecked()},
1496 {
"preferDefectsRadio", preferDefectsRadio->isChecked()},
1497 {
"fileName", m_FileLabel->text()}
1499 return cameraSettings;
1509 for(
int i = 0; i < darkFramesModel->rowCount(); i++)
1511 QSqlRecord record = darkFramesModel->record(i);
1526 {
"temperature", temperature},
1527 {
"duaration", duration},
1532 filterRows[
"gain"] = gain;
1534 filterRows[
"iso"] = iso;
1536 array.
append(filterRows);
1544void DarkLibrary::setDefectPixels(
const QJsonObject &payload)
1546 const auto hotSpin = payload[
"hotSpin"].toInt();
1547 const auto coldSpin = payload[
"coldSpin"].toInt();
1548 const auto hotEnabled = payload[
"hotEnabled"].toBool(hotPixelsEnabled->isChecked());
1549 const auto coldEnabled = payload[
"coldEnabled"].toBool(coldPixelsEnabled->isChecked());
1551 hotPixelsEnabled->setChecked(hotEnabled);
1552 coldPixelsEnabled->setChecked(coldEnabled);
1554 aggresivenessHotSpin->setValue(hotSpin);
1555 aggresivenessColdSpin->setValue(coldSpin);
1557 m_DarkView->ZoomDefault();
1559 setDefectMapEnabled(
true);
1560 generateMapB->click();
1566void DarkLibrary::setDefectMapEnabled(
bool enabled)
1568 m_DarkView->setDefectMapEnabled(enabled);
1574double DarkLibrary::getGain()
1580 auto gain = m_Camera->getProperty(
"CCD_GAIN");
1582 return gain.getNumber()->at(0)->value;
1585 auto controls = m_Camera->getProperty(
"CCD_CONTROLS");
1588 auto oneGain = controls.getNumber()->findWidgetByName(
"Gain");
1590 return oneGain->value;
1599void DarkLibrary::setupOpticalTrainManager()
1601 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &DarkLibrary::refreshOpticalTrain);
1604 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
1608 ProfileSettings::Instance()->setOneSetting(ProfileSettings::DarkLibraryOpticalTrain,
1609 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
1610 refreshOpticalTrain();
1611 emit trainChanged();
1618void DarkLibrary::refreshOpticalTrain()
1620 opticalTrainCombo->blockSignals(
true);
1621 opticalTrainCombo->clear();
1622 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
1623 trainB->setEnabled(
true);
1625 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::DarkLibraryOpticalTrain);
1629 auto id = trainID.
toUInt();
1632 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
1634 emit newLog(
i18n(
"Optical train doesn't exist for id %1",
id));
1635 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
1638 auto name = OpticalTrainManager::Instance()->name(
id);
1640 opticalTrainCombo->setCurrentText(name);
1642 auto camera = OpticalTrainManager::Instance()->getCamera(name);
1645 auto scope = OpticalTrainManager::Instance()->getScope(name);
1646 opticalTrainCombo->setToolTip(
QString(
"%1 @ %2").arg(camera->getDeviceName(), scope[
"name"].toString()));
1651 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
1652 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::DarkLibrary);
1653 if (settings.isValid())
1656 if (map != m_Settings)
1659 setAllSettings(map);
1663 m_Settings = m_GlobalSettings;
1666 opticalTrainCombo->blockSignals(
false);
1672void DarkLibrary::loadGlobalSettings()
1677 QVariantMap settings;
1679 for (
auto &oneWidget : findChildren<QComboBox*>())
1681 if (oneWidget->objectName() ==
"opticalTrainCombo")
1684 key = oneWidget->objectName();
1685 value = Options::self()->property(key.
toLatin1());
1686 if (value.
isValid() && oneWidget->count() > 0)
1688 oneWidget->setCurrentText(value.
toString());
1689 settings[key] = value;
1694 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1696 key = oneWidget->objectName();
1697 value = Options::self()->property(key.
toLatin1());
1700 oneWidget->setValue(value.
toDouble());
1701 settings[key] = value;
1706 for (
auto &oneWidget : findChildren<QSpinBox*>())
1708 key = oneWidget->objectName();
1709 value = Options::self()->property(key.
toLatin1());
1712 oneWidget->setValue(value.
toInt());
1713 settings[key] = value;
1718 for (
auto &oneWidget : findChildren<QCheckBox*>())
1720 key = oneWidget->objectName();
1721 value = Options::self()->property(key.
toLatin1());
1724 oneWidget->setChecked(value.
toBool());
1725 settings[key] = value;
1729 m_GlobalSettings = m_Settings = settings;
1736void DarkLibrary::connectSettings()
1739 for (
auto &oneWidget : findChildren<QComboBox*>())
1743 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1747 for (
auto &oneWidget : findChildren<QSpinBox*>())
1751 for (
auto &oneWidget : findChildren<QCheckBox*>())
1755 for (
auto &oneWidget : findChildren<QRadioButton*>())
1759 disconnect(opticalTrainCombo, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::DarkLibrary::syncSettings);
1765void DarkLibrary::disconnectSettings()
1768 for (
auto &oneWidget : findChildren<QComboBox*>())
1769 disconnect(oneWidget, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::DarkLibrary::syncSettings);
1772 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1776 for (
auto &oneWidget : findChildren<QSpinBox*>())
1780 for (
auto &oneWidget : findChildren<QCheckBox*>())
1784 for (
auto &oneWidget : findChildren<QRadioButton*>())
1792QVariantMap DarkLibrary::getAllSettings()
const
1794 QVariantMap settings;
1797 for (
auto &oneWidget : findChildren<QComboBox*>())
1798 settings.insert(oneWidget->objectName(), oneWidget->currentText());
1801 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1802 settings.insert(oneWidget->objectName(), oneWidget->value());
1805 for (
auto &oneWidget : findChildren<QSpinBox*>())
1806 settings.insert(oneWidget->objectName(), oneWidget->value());
1809 for (
auto &oneWidget : findChildren<QCheckBox*>())
1810 settings.insert(oneWidget->objectName(), oneWidget->isChecked());
1818void DarkLibrary::setAllSettings(
const QVariantMap &settings)
1822 disconnectSettings();
1824 for (
auto &name : settings.keys())
1827 auto comboBox = findChild<QComboBox*>(name);
1830 syncControl(settings, name, comboBox);
1835 auto doubleSpinBox = findChild<QDoubleSpinBox*>(name);
1838 syncControl(settings, name, doubleSpinBox);
1843 auto spinBox = findChild<QSpinBox*>(name);
1846 syncControl(settings, name, spinBox);
1851 auto checkbox = findChild<QCheckBox*>(name);
1854 syncControl(settings, name, checkbox);
1859 auto radioButton = findChild<QRadioButton*>(name);
1862 syncControl(settings, name, radioButton);
1868 for (
auto &key : settings.keys())
1870 auto value = settings[key];
1872 Options::self()->setProperty(key.
toLatin1(), value);
1874 m_Settings[key] = value;
1875 m_GlobalSettings[key] = value;
1878 emit settingsUpdated(getAllSettings());
1881 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1882 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::DarkLibrary, m_Settings);
1891bool DarkLibrary::syncControl(
const QVariantMap &settings,
const QString &key,
QWidget * widget)
1900 if ((pSB = qobject_cast<QSpinBox *>(widget)))
1902 const int value = settings[key].toInt(&ok);
1909 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
1911 const double value = settings[key].toDouble(&ok);
1918 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
1920 const bool value = settings[key].toBool();
1926 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))
1928 const QString value = settings[key].toString();
1932 else if ((pRadioButton = qobject_cast<QRadioButton *>(widget)))
1934 const bool value = settings[key].toBool();
1936 pRadioButton->
click();
1946void DarkLibrary::syncSettings()
1957 if ( (dsb = qobject_cast<QDoubleSpinBox*>(sender())))
1960 value = dsb->
value();
1963 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
1966 value = sb->
value();
1968 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
1973 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
1978 else if ( (cradio = qobject_cast<QRadioButton*>(sender())))
1984 m_Settings.remove(key);
1991 Options::self()->setProperty(key.
toLatin1(), value);
1992 m_Settings[key] = value;
1993 m_GlobalSettings[key] = value;
1995 m_DebounceTimer.start();
2001void DarkLibrary::settleSettings()
2003 emit settingsUpdated(getAllSettings());
2004 Options::self()->save();
2006 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
2007 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::DarkLibrary, m_Settings);
2016 for (
int i = 0; i < masterDarksCombo->count(); i++)
2017 darkMasters << masterDarksCombo->itemText(i);
2021 {
"masterTime", masterTime->text()},
2022 {
"masterDarks", darkMasters.
join(
'|')},
2023 {
"masterExposure", masterExposure->text()},
2024 {
"masterTempreture", masterTemperature->text()},
2025 {
"masterMean", masterMean->text()},
2026 {
"masterMedian", masterMedian->text()},
2027 {
"masterDeviation", masterDeviation->text()},
2028 {
"hotPixelsEnabled", hotPixelsEnabled->isChecked()},
2029 {
"coldPixelsEnabled", coldPixelsEnabled->isChecked()},
2031 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 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)
QString name(StandardAction id)
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