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>
31 DarkLibrary *DarkLibrary::_DarkLibrary =
nullptr;
33 DarkLibrary *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");
65 loadIndexInView(index.
row());
76 if (m_DarkFrameFutureWatcher.result())
78 m_DarkView->loadData(m_CurrentDarkFrame);
79 loadCurrentMasterDefectMap();
80 populateMasterMetedata();
83 m_FileLabel->setText(
i18n(
"Failed to load %1: %2", m_MasterDarkFrameFilename, m_CurrentDarkFrame->getLastError()));
90 DarkLibrary::loadCurrentMasterDark(m_Camera->getDeviceName(), index);
99 maxTemperatureSpin->setMinimum(minTemperatureSpin->value());
100 countDarkTotalTime();
104 minTemperatureSpin->setMaximum(maxTemperatureSpin->value());
105 countDarkTotalTime();
109 maxTemperatureSpin->setMinimum(minTemperatureSpin->value());
110 minTemperatureSpin->setMaximum(maxTemperatureSpin->value());
111 countDarkTotalTime();
115 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
117 this, [
this](
int,
bool)
120 this, [
this](
int,
bool)
123 countDarkTotalTime();
129 KStarsData::Instance()->
userdb()->GetAllDarkFrames(m_DarkFramesDatabaseList);
135 m_DarkView->setDefectMapEnabled(index == 1 && m_CurrentDefectMap);
141 if (m_CurrentDefectMap)
142 m_CurrentDefectMap->setProperty(
"HotEnabled", toggled);
146 if (m_CurrentDefectMap)
147 m_CurrentDefectMap->setProperty(
"ColdEnabled", toggled);
151 if (m_CurrentDefectMap)
153 m_CurrentDefectMap->setProperty(
"HotPixelAggressiveness", aggresivenessHotSpin->value());
154 m_CurrentDefectMap->setProperty(
"ColdPixelAggressiveness", aggresivenessColdSpin->value());
155 m_CurrentDefectMap->filterPixels();
156 emit newFrame(m_DarkView);
161 if (m_CurrentDefectMap)
163 aggresivenessHotSlider->setValue(75);
164 aggresivenessColdSlider->setValue(75);
165 m_CurrentDefectMap->setProperty(
"HotPixelAggressiveness", 75);
166 m_CurrentDefectMap->setProperty(
"ColdPixelAggressiveness", 75);
167 m_CurrentDefectMap->filterPixels();
174 m_RememberFITSViewer = Options::useFITSViewer();
175 m_RememberSummaryView = Options::useSummaryPreview();
178 loadGlobalSettings();
182 setupOpticalTrainManager();
185 DarkLibrary::~DarkLibrary()
192 void DarkLibrary::refreshFromDB()
194 KStarsData::Instance()->
userdb()->GetAllDarkFrames(m_DarkFramesDatabaseList);
202 QVariantMap bestCandidate;
203 for (
auto &map : m_DarkFramesDatabaseList)
206 if (map[
"ccd"].toString() == m_TargetChip->getCCD()->getDeviceName() &&
207 map[
"chip"].toInt() ==
static_cast<int>(m_TargetChip->getType()))
210 int gain = getGain();
211 if (gain >= 0 && map[
"gain"].toInt() != gain)
216 if (m_TargetChip->getISOValue(isoValue) && map[
"iso"].toString() != isoValue)
220 int binX = 1, binY = 1;
221 m_TargetChip->getBinning(&binX, &binY);
224 if (map[
"binX"].toInt() != binX || map[
"binY"].toInt() != binY)
228 if (m_TargetChip->getCCD()->hasCoolerControl())
230 double temperature = 0;
231 m_TargetChip->getCCD()->getTemperature(&temperature);
232 double darkTemperature = map[
"temperature"].toDouble();
234 if (darkTemperature != INVALID_VALUE && fabs(darkTemperature - temperature) > maxDarkTemperatureDiff->value())
238 if (bestCandidate.isEmpty())
247 uint32_t thisMapScore = 0;
248 uint32_t bestCandidateScore = 0;
251 if (m_TargetChip->getCCD()->hasCooler())
253 double temperature = 0;
254 m_TargetChip->getCCD()->getTemperature(&temperature);
255 double diffMap = std::fabs(temperature - map[
"temperature"].toDouble());
256 double diffBest = std::fabs(temperature - bestCandidate[
"temperature"].toDouble());
258 if (diffMap < diffBest)
260 else if (diffBest < diffMap)
261 bestCandidateScore++;
266 double diffMap = std::fabs(map[
"duration"].toDouble() - duration);
267 double diffBest = std::fabs(bestCandidate[
"duration"].toDouble() - duration);
268 if (diffMap < diffBest)
270 else if (diffBest < diffMap)
271 bestCandidateScore += 5;
277 int64_t diffMap = map[
"timestamp"].toDateTime().secsTo(now);
278 int64_t diffBest = bestCandidate[
"timestamp"].toDateTime().secsTo(now);
279 if (diffMap < diffBest)
281 else if (diffBest < diffMap)
282 bestCandidateScore++;
286 if (thisMapScore > bestCandidateScore)
291 if (bestCandidate.isEmpty())
294 if (fabs(bestCandidate[
"duration"].toDouble() - duration) > 3)
295 emit
i18n(
"Using available dark frame with %1 seconds exposure. Please take a dark frame with %1 seconds exposure for more accurate results.",
299 QString filename = bestCandidate[
"filename"].toString();
302 QDateTime frameTime = bestCandidate[
"timestamp"].toDateTime();
305 emit
i18n(
"Dark frame %s is expired. Please create new master dark.", filename);
309 if (m_CachedDarkFrames.contains(filename))
311 darkData = m_CachedDarkFrames[filename];
316 auto memoryMB = KSUtils::getAvailableRAM() / 1e6;
317 if (memoryMB < CACHE_MEMORY_LIMIT)
318 m_CachedDarkFrames.
clear();
321 if (cacheDarkFrameFromFile(filename))
323 darkData = m_CachedDarkFrames[filename];
328 emit newLog(
i18n(
"Removing bad dark frame file %1", filename));
329 m_CachedDarkFrames.remove(filename);
341 QVariantMap bestCandidate;
342 for (
auto &map : m_DarkFramesDatabaseList)
344 if (map[
"defectmap"].toString().isEmpty())
348 if (map[
"ccd"].toString() == m_TargetChip->getCCD()->getDeviceName() &&
349 map[
"chip"].toInt() ==
static_cast<int>(m_TargetChip->getType()))
352 m_TargetChip->getBinning(&binX, &binY);
355 if (map[
"binX"].toInt() == binX && map[
"binY"].toInt() == binY)
357 if (bestCandidate.isEmpty())
366 uint32_t thisMapScore = 0;
367 uint32_t bestCandidateScore = 0;
370 if (m_TargetChip->getCCD()->hasCooler())
372 double temperature = 0;
373 m_TargetChip->getCCD()->getTemperature(&temperature);
374 double diffMap = std::fabs(temperature - map[
"temperature"].toDouble());
375 double diffBest = std::fabs(temperature - bestCandidate[
"temperature"].toDouble());
377 if (diffMap < diffBest)
379 else if (diffBest < diffMap)
380 bestCandidateScore++;
384 double diffMap = std::fabs(map[
"duration"].toDouble() - duration);
385 double diffBest = std::fabs(bestCandidate[
"duration"].toDouble() - duration);
386 if (diffMap < diffBest)
388 else if (diffBest < diffMap)
389 bestCandidateScore += 2;
392 if (thisMapScore > bestCandidateScore)
399 if (bestCandidate.isEmpty())
403 QString darkFilename = bestCandidate[
"filename"].toString();
404 QString defectFilename = bestCandidate[
"defectmap"].toString();
409 if (m_CachedDefectMaps.contains(darkFilename))
411 defectMap = m_CachedDefectMaps[darkFilename];
416 if (cacheDefectMapFromFile(darkFilename, defectFilename))
418 defectMap = m_CachedDefectMaps[darkFilename];
424 emit newLog(
i18n(
"Failed to load defect map %1", defectFilename));
432 bool DarkLibrary::cacheDefectMapFromFile(
const QString &key,
const QString &filename)
435 oneMap.
reset(
new DefectMap());
437 if (oneMap->load(filename))
439 oneMap->filterPixels();
440 m_CachedDefectMaps[key] = oneMap;
444 emit newLog(
i18n(
"Failed to load defect map file %1", filename));
451 bool DarkLibrary::cacheDarkFrameFromFile(
const QString &filename)
460 m_CachedDarkFrames[filename] = data;
464 emit newLog(
i18n(
"Failed to load dark frame file %1", filename));
476 if (job->getStatus() == JOB_IDLE)
479 if (job->getCompleted() == job->getCoreProperty(SequenceJob::SJ_Count).toInt())
483 {
"camera", m_Camera->getDeviceName()},
484 {
"chip", m_TargetChip->getType()},
485 {
"binx", job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().x()},
486 {
"biny", job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().y()},
487 {
"duration", job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble()}
492 bool success = m_Camera->getTemperature(&value);
494 metadata[
"temperature"] = value;
496 success = m_Camera->hasGain() && m_Camera->getGain(&value);
498 metadata[
"gain"] = value;
501 success = m_TargetChip->getISOValue(isoValue);
503 metadata[
"iso"] = isoValue;
505 metadata[
"count"] = job->getCoreProperty(SequenceJob::SJ_Count).toInt();
506 generateMasterFrame(m_CurrentDarkFrame, metadata);
507 reloadDarksFromDatabase();
508 populateMasterMetedata();
515 void DarkLibrary::updateProperty(INDI::Property prop)
517 if (prop.getType() != INDI_BLOB)
520 auto bp = prop.getBLOB()->at(0);
522 if (!m_CurrentDarkFrame->loadFromBuffer(buffer, bp->getFormat()))
524 m_FileLabel->setText(
i18n(
"Failed to process dark data."));
528 if (!m_DarkView->loadData(m_CurrentDarkFrame))
530 m_FileLabel->setText(
i18n(
"Failed to load dark data."));
534 uint32_t totalElements = m_CurrentDarkFrame->channels() * m_CurrentDarkFrame->samplesPerChannel();
535 if (totalElements != m_DarkMasterBuffer.size())
536 m_DarkMasterBuffer.assign(totalElements, 0);
538 aggregate(m_CurrentDarkFrame);
539 darkProgress->setValue(darkProgress->value() + 1);
540 m_StatusLabel->setText(
i18n(
"Received %1/%2 images.", darkProgress->value(), darkProgress->maximum()));
546 void DarkLibrary::Release()
548 delete (_DarkLibrary);
549 _DarkLibrary =
nullptr;
562 Options::setUseFITSViewer(m_RememberFITSViewer);
563 Options::setUseSummaryPreview(m_RememberSummaryView);
566 m_JobsGenerated =
false;
567 m_CaptureModule->clearSequenceQueue();
568 m_CaptureModule->setPresetSettings(m_PresetSettings);
569 m_CaptureModule->setFileSettings(m_FileSettings);
576 void DarkLibrary::setCompleted()
578 startB->setEnabled(
true);
579 stopB->setEnabled(
false);
581 Options::setUseFITSViewer(m_RememberFITSViewer);
582 Options::setUseSummaryPreview(m_RememberSummaryView);
585 m_JobsGenerated =
false;
586 m_CaptureModule->clearSequenceQueue();
587 m_CaptureModule->setPresetSettings(m_PresetSettings);
588 m_CaptureModule->setFileSettings(m_FileSettings);
591 m_Camera->disconnect(
this);
592 m_CaptureModule->disconnect(
this);
598 void DarkLibrary::clearExpired()
600 if (darkFramesModel->rowCount() == 0)
609 darkframe.setTable(
"darkframe");
611 darkframe.setFilter(
"ccd LIKE \'" + m_Camera->getDeviceName() +
"\' AND timestamp < \'" + expiredDate.
toString(
617 for (
int i = 0; i < darkframe.rowCount(); ++i)
619 QString oneFile = darkframe.record(i).value(
"filename").toString();
621 QString defectMap = darkframe.record(i).value(
"defectmap").toString();
622 if (defectMap.
isEmpty() ==
false)
628 darkframe.removeRows(0, darkframe.rowCount());
629 darkframe.submitAll();
631 Ekos::DarkLibrary::Instance()->refreshFromDB();
633 reloadDarksFromDatabase();
639 void DarkLibrary::clearBuffers()
641 m_CurrentDarkFrame.clear();
644 m_DarkView->clearData();
645 m_CurrentDefectMap.clear();
651 void DarkLibrary::clearAll()
653 if (darkFramesModel->rowCount() == 0)
657 i18n(
"Are you sure you want to delete all dark frames images and data?")) ==
664 darkframe.setTable(
"darkframe");
665 darkframe.setFilter(
"ccd LIKE \'" + m_Camera->getDeviceName() +
"\'");
666 darkFramesModel->select();
669 for (
int i = 0; i < darkframe.rowCount(); ++i)
671 QString oneFile = darkframe.record(i).value(
"filename").toString();
673 QString defectMap = darkframe.record(i).value(
"defectmap").toString();
674 if (defectMap.
isEmpty() ==
false)
679 darkFramesModel->removeRows(0, darkFramesModel->rowCount());
680 darkFramesModel->submitAll();
682 Ekos::DarkLibrary::Instance()->refreshFromDB();
685 reloadDarksFromDatabase();
691 void DarkLibrary::clearRow(
int index)
695 index = darkTableView->currentIndex().row();
697 QSqlRecord record = darkFramesModel->record(index);
704 darkFramesModel->removeRow(index);
705 darkFramesModel->submitAll();
711 reloadDarksFromDatabase();
717 void DarkLibrary::openDarksFolder()
727 void DarkLibrary::refreshDefectMastersList(
const QString &camera)
729 if (darkFramesModel->rowCount() == 0)
732 masterDarksCombo->blockSignals(
true);
733 masterDarksCombo->clear();
735 for (
int i = 0; i < darkFramesModel->rowCount(); ++i)
737 QSqlRecord record = darkFramesModel->record(i);
739 if (record.
value(
"ccd") != camera)
755 if (temperature > INVALID_VALUE)
763 masterDarksCombo->addItem(entry);
766 masterDarksCombo->blockSignals(
false);
774 void DarkLibrary::reloadDarksFromDatabase()
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);
812 void 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())
837 if (m_CurrentDarkFrame->filename() != m_MasterDarkFrameFilename)
838 m_DarkFrameFutureWatcher.setFuture(m_CurrentDarkFrame->loadFromFile(m_MasterDarkFrameFilename));
841 loadCurrentMasterDefectMap();
847 void 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);
882 void 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();
921 void 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);
947 reloadDarksFromDatabase();
952 darkTabsWidget->setEnabled(
false);
962 if (m_Camera && m_Camera->getDeviceName() == device->getDeviceName())
964 m_Camera->disconnect(
this);
972 void DarkLibrary::checkCamera()
977 auto device = m_Camera->getDeviceName();
979 m_TargetChip =
nullptr;
982 if (device.contains(
"Guider"))
984 m_UseGuideHead =
true;
985 m_TargetChip = m_Camera->getChip(ISD::CameraChip::GUIDE_CCD);
988 if (m_TargetChip ==
nullptr)
990 m_UseGuideHead =
false;
991 m_TargetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
996 if (!m_TargetChip || !m_TargetChip->getCCD() || m_TargetChip->isCapturing())
999 if (m_Camera->hasCoolerControl())
1001 temperatureLabel->setEnabled(
true);
1002 temperatureStepLabel->setEnabled(
true);
1003 temperatureToLabel->setEnabled(
true);
1004 temperatureStepSpin->setEnabled(
true);
1005 minTemperatureSpin->setEnabled(
true);
1006 maxTemperatureSpin->setEnabled(
true);
1009 double temperature = 0;
1011 if (m_Camera->getTemperature(&temperature))
1013 minTemperatureSpin->setValue(temperature);
1014 maxTemperatureSpin->setValue(temperature);
1020 temperatureLabel->setEnabled(
false);
1021 temperatureStepLabel->setEnabled(
false);
1022 temperatureToLabel->setEnabled(
false);
1023 temperatureStepSpin->setEnabled(
false);
1024 minTemperatureSpin->setEnabled(
false);
1025 maxTemperatureSpin->setEnabled(
false);
1029 captureISOS->blockSignals(
true);
1030 captureISOS->
clear();
1035 captureISOS->setEnabled(
false);
1039 captureISOS->setEnabled(
true);
1040 captureISOS->addItems(isoList);
1041 captureISOS->setCurrentIndex(m_TargetChip->getISOIndex());
1043 captureISOS->blockSignals(
false);
1046 if (m_Camera->hasGain())
1048 double min, max, step, value, targetCustomGain;
1049 m_Camera->getGainMinMaxStep(&min, &max, &step);
1052 GainSpinSpecialValue = min - step;
1053 captureGainN->setRange(GainSpinSpecialValue, max);
1054 captureGainN->setSpecialValueText(
i18n(
"--"));
1055 captureGainN->setEnabled(
true);
1056 captureGainN->setSingleStep(step);
1057 m_Camera->getGain(&value);
1059 targetCustomGain = getGain();
1063 if (targetCustomGain > 0)
1064 captureGainN->setValue(targetCustomGain);
1066 captureGainN->setValue(GainSpinSpecialValue);
1068 captureGainN->setReadOnly(m_Camera->getGainPermission() == IP_RO);
1071 captureGainN->setEnabled(
false);
1073 countDarkTotalTime();
1080 void DarkLibrary::countDarkTotalTime()
1082 double temperatureCount = 1;
1083 if (m_Camera && m_Camera->hasCoolerControl() && std::abs(maxTemperatureSpin->value() - minTemperatureSpin->value()) > 0)
1084 temperatureCount = (std::abs((maxTemperatureSpin->value() - minTemperatureSpin->value())) / temperatureStepSpin->value()) +
1087 if (bin1Check->isChecked())
1089 if (bin2Check->isChecked())
1091 if (bin4Check->isChecked())
1094 double darkTime = 0;
1095 int imagesCount = 0;
1096 for (
double startExposure = minExposureSpin->value(); startExposure <= maxExposureSpin->value();
1097 startExposure += exposureStepSin->value())
1099 darkTime += startExposure * temperatureCount * binnings * countSpin->value();
1100 imagesCount += temperatureCount * binnings * countSpin->value();
1105 darkProgress->setMaximum(imagesCount);
1112 void DarkLibrary::generateDarkJobs()
1115 m_CaptureModule->clearSequenceQueue();
1117 if (m_JobsGenerated ==
false)
1119 m_JobsGenerated =
true;
1120 m_PresetSettings = m_CaptureModule->getPresetSettings();
1121 m_FileSettings = m_CaptureModule->getFileSettings();
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->setForceTemperature(
true);
1139 m_CaptureModule->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)
1173 settings[
"optical_train"] = opticalTrainCombo->currentText();
1174 settings[
"exp"] = oneExposure;
1175 settings[
"bin"] = oneBin;
1176 settings[
"frameType"] = FRAME_DARK;
1177 settings[
"temperature"] = oneTemperature;
1178 if (captureGainN->isEnabled())
1179 settings[
"gain"] = captureGainN->
value();
1180 if (captureISOS->isEnabled())
1181 settings[
"iso"] = captureISOS->currentIndex();
1186 fileSettings[
"directory"] = directory;
1187 m_CaptureModule->setPresetSettings(settings);
1188 m_CaptureModule->setFileSettings(fileSettings);
1189 m_CaptureModule->setCount(countSpin->value());
1190 m_CaptureModule->addJob();
1199 void DarkLibrary::execute()
1201 m_DarkImagesCounter = 0;
1202 darkProgress->setValue(0);
1203 darkProgress->setTextVisible(
true);
1204 connect(m_CaptureModule, &Capture::newImage,
this, &DarkLibrary::processNewImage,
Qt::UniqueConnection);
1205 connect(m_CaptureModule, &Capture::newStatus,
this, &DarkLibrary::setCaptureState,
Qt::UniqueConnection);
1206 connect(m_Camera, &ISD::Camera::propertyUpdated,
this, &DarkLibrary::updateProperty,
Qt::UniqueConnection);
1208 Options::setUseFITSViewer(
false);
1209 Options::setUseSummaryPreview(
false);
1210 startB->setEnabled(
false);
1211 stopB->setEnabled(
true);
1212 m_DarkView->reset();
1213 m_StatusLabel->setText(
i18n(
"In progress..."));
1214 m_CaptureModule->start();
1221 void DarkLibrary::stop()
1223 m_CaptureModule->abort();
1224 darkProgress->setValue(0);
1225 m_DarkView->reset();
1231 void DarkLibrary::initView()
1233 m_DarkView.reset(
new DarkView(darkWidget));
1235 m_DarkView->setBaseSize(darkWidget->size());
1236 m_DarkView->createFloatingToolBar();
1239 darkWidget->setLayout(vlayout);
1240 connect(m_DarkView.get(), &DarkView::loaded,
this, [
this]()
1242 emit newImage(m_DarkView->imageData());
1251 switch (data->dataType())
1254 aggregateInternal<uint8_t>(data);
1258 aggregateInternal<int16_t>(data);
1262 aggregateInternal<uint16_t>(data);
1266 aggregateInternal<int32_t>(data);
1270 aggregateInternal<uint32_t>(data);
1274 aggregateInternal<float>(data);
1278 aggregateInternal<int64_t>(data);
1282 aggregateInternal<double>(data);
1293 template <
typename T>
1296 T
const *darkBuffer =
reinterpret_cast<T const*
>(data->getImageBuffer());
1297 for (uint32_t i = 0; i < m_DarkMasterBuffer.size(); i++)
1298 m_DarkMasterBuffer[i] += darkBuffer[i];
1306 switch (data->dataType())
1309 generateMasterFrameInternal<uint8_t>(data, metadata);
1313 generateMasterFrameInternal<int16_t>(data, metadata);
1317 generateMasterFrameInternal<uint16_t>(data, metadata);
1321 generateMasterFrameInternal<int32_t>(data, metadata);
1325 generateMasterFrameInternal<uint32_t>(data, metadata);
1329 generateMasterFrameInternal<float>(data, metadata);
1333 generateMasterFrameInternal<int64_t>(data, metadata);
1337 generateMasterFrameInternal<double>(data, metadata);
1344 emit newImage(data);
1346 m_DarkMasterBuffer.assign(m_DarkMasterBuffer.size(), 0);
1356 T *writableBuffer =
reinterpret_cast<T *
>(data->getWritableImageBuffer());
1357 const uint32_t count = metadata[
"count"].toInt();
1359 for (uint32_t i = 0; i < m_DarkMasterBuffer.size(); i++)
1360 writableBuffer[i] = m_DarkMasterBuffer[i] / count;
1366 data->calculateStats(
true);
1367 if (!data->saveImage(path))
1369 m_FileLabel->setText(
i18n(
"Failed to save master frame: %1", data->getLastError()));
1373 auto memoryMB = KSUtils::getAvailableRAM() / 1e6;
1374 if (memoryMB > CACHE_MEMORY_LIMIT)
1375 cacheDarkFrameFromFile(data->filename());
1378 map[
"ccd"] = metadata[
"camera"].toString();
1379 map[
"chip"] = metadata[
"chip"].toInt();
1380 map[
"binX"] = metadata[
"binx"].toInt();
1381 map[
"binY"] = metadata[
"biny"].toInt();
1382 map[
"temperature"] = metadata[
"temperature"].toDouble(INVALID_VALUE);
1383 map[
"gain"] = metadata[
"gain"].toInt(-1);
1384 map[
"iso"] = metadata[
"iso"].toString();
1385 map[
"duration"] = metadata[
"duration"].toDouble();
1389 m_DarkFramesDatabaseList.
append(map);
1390 m_FileLabel->setText(
i18n(
"Master Dark saved to %1", path));
1397 void DarkLibrary::setCaptureModule(Capture *instance)
1399 m_CaptureModule = instance;
1405 void DarkLibrary::setCaptureState(CaptureState state)
1411 m_StatusLabel->setText(
i18n(
"Capture aborted."));
1415 m_StatusLabel->setText(
i18n(
"Capture completed."));
1425 void DarkLibrary::saveDefectMap()
1427 if (!m_CurrentDarkFrame)
1430 QString filename = m_CurrentDefectMap->filename();
1431 bool newFile =
false;
1440 if (m_CurrentDefectMap->save(filename, m_Camera->getDeviceName()))
1442 m_FileLabel->setText(
i18n(
"Defect map saved to %1", filename));
1446 auto currentMap = std::find_if(m_DarkFramesDatabaseList.begin(),
1447 m_DarkFramesDatabaseList.end(), [&](
const QVariantMap & oneMap)
1449 return oneMap[
"filename"].toString() == m_CurrentDarkFrame->filename();
1452 if (currentMap != m_DarkFramesDatabaseList.end())
1454 (*currentMap)[
"defectmap"] = filename;
1462 m_FileLabel->setText(
i18n(
"Failed to save defect map to %1", filename));
1469 void DarkLibrary::start()
1478 void DarkLibrary::setCameraPresets(
const QJsonObject &settings)
1480 const auto opticalTrain = settings[
"optical_train"].toString();
1481 const auto isDarkPrefer = settings[
"isDarkPrefer"].toBool(preferDarksRadio->isChecked());
1482 const auto isDefectPrefer = settings[
"isDefectPrefer"].toBool(preferDefectsRadio->isChecked());
1483 opticalTrainCombo->setCurrentText(opticalTrain);
1484 preferDarksRadio->setChecked(isDarkPrefer);
1485 preferDefectsRadio->setChecked(isDefectPrefer);
1487 reloadDarksFromDatabase();
1497 {
"optical_train", opticalTrainCombo->currentText()},
1498 {
"preferDarksRadio", preferDarksRadio->isChecked()},
1499 {
"preferDefectsRadio", preferDefectsRadio->isChecked()},
1500 {
"fileName", m_FileLabel->text()}
1502 return cameraSettings;
1512 for(
int i = 0; i < darkFramesModel->rowCount(); i++)
1514 QSqlRecord record = darkFramesModel->record(i);
1529 {
"temperature", temperature},
1530 {
"duaration", duration},
1535 filterRows[
"gain"] = gain;
1537 filterRows[
"iso"] = iso;
1539 array.
append(filterRows);
1547 void DarkLibrary::setDefectPixels(
const QJsonObject &payload)
1549 const auto hotSpin = payload[
"hotSpin"].toInt();
1550 const auto coldSpin = payload[
"coldSpin"].toInt();
1551 const auto hotEnabled = payload[
"hotEnabled"].toBool(hotPixelsEnabled->isChecked());
1552 const auto coldEnabled = payload[
"coldEnabled"].toBool(coldPixelsEnabled->isChecked());
1554 hotPixelsEnabled->setChecked(hotEnabled);
1555 coldPixelsEnabled->setChecked(coldEnabled);
1557 aggresivenessHotSpin->setValue(hotSpin);
1558 aggresivenessColdSpin->setValue(coldSpin);
1560 m_DarkView->ZoomDefault();
1562 setDefectMapEnabled(
true);
1563 generateMapB->click();
1569 void DarkLibrary::setDefectMapEnabled(
bool enabled)
1571 m_DarkView->setDefectMapEnabled(enabled);
1577 double DarkLibrary::getGain()
1583 auto gain = m_Camera->getProperty(
"CCD_GAIN");
1585 return gain.getNumber()->at(0)->value;
1588 auto controls = m_Camera->getProperty(
"CCD_CONTROLS");
1591 auto oneGain = controls.getNumber()->findWidgetByName(
"Gain");
1593 return oneGain->value;
1602 void DarkLibrary::setupOpticalTrainManager()
1604 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &DarkLibrary::refreshOpticalTrain);
1607 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
1611 ProfileSettings::Instance()->setOneSetting(ProfileSettings::DarkLibraryOpticalTrain,
1612 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
1613 refreshOpticalTrain();
1614 emit trainChanged();
1621 void DarkLibrary::refreshOpticalTrain()
1623 opticalTrainCombo->blockSignals(
true);
1624 opticalTrainCombo->clear();
1625 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
1626 trainB->setEnabled(
true);
1628 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::DarkLibraryOpticalTrain);
1632 auto id = trainID.
toUInt();
1635 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
1637 emit newLog(
i18n(
"Optical train doesn't exist for id %1",
id));
1638 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
1641 auto name = OpticalTrainManager::Instance()->name(
id);
1643 opticalTrainCombo->setCurrentText(name);
1645 auto camera = OpticalTrainManager::Instance()->getCamera(name);
1648 auto scope = OpticalTrainManager::Instance()->getScope(name);
1649 opticalTrainCombo->setToolTip(
QString(
"%1 @ %2").arg(camera->getDeviceName(), scope[
"name"].toString()));
1654 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
1655 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::DarkLibrary);
1656 if (settings.isValid())
1657 setAllSettings(settings.toJsonObject().
toVariantMap());
1659 m_Settings = m_GlobalSettings;
1662 opticalTrainCombo->blockSignals(
false);
1668 void DarkLibrary::loadGlobalSettings()
1673 QVariantMap settings;
1675 for (
auto &oneWidget : findChildren<QComboBox*>())
1677 if (oneWidget->objectName() ==
"opticalTrainCombo")
1680 key = oneWidget->objectName();
1681 value = Options::self()->property(key.
toLatin1());
1684 oneWidget->setCurrentText(value.
toString());
1685 settings[key] = value;
1690 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1692 key = oneWidget->objectName();
1693 value = Options::self()->property(key.
toLatin1());
1697 settings[key] = value;
1702 for (
auto &oneWidget : findChildren<QSpinBox*>())
1704 key = oneWidget->objectName();
1705 value = Options::self()->property(key.
toLatin1());
1709 settings[key] = value;
1714 for (
auto &oneWidget : findChildren<QCheckBox*>())
1716 key = oneWidget->objectName();
1717 value = Options::self()->property(key.
toLatin1());
1720 oneWidget->setChecked(value.
toBool());
1721 settings[key] = value;
1725 m_GlobalSettings = m_Settings = settings;
1732 void DarkLibrary::connectSettings()
1735 for (
auto &oneWidget : findChildren<QComboBox*>())
1736 connect(oneWidget, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::DarkLibrary::syncSettings);
1739 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1743 for (
auto &oneWidget : findChildren<QSpinBox*>())
1747 for (
auto &oneWidget : findChildren<QCheckBox*>())
1751 for (
auto &oneWidget : findChildren<QRadioButton*>())
1755 disconnect(opticalTrainCombo, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::DarkLibrary::syncSettings);
1761 void DarkLibrary::disconnectSettings()
1764 for (
auto &oneWidget : findChildren<QComboBox*>())
1765 disconnect(oneWidget, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::DarkLibrary::syncSettings);
1768 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1772 for (
auto &oneWidget : findChildren<QSpinBox*>())
1776 for (
auto &oneWidget : findChildren<QCheckBox*>())
1780 for (
auto &oneWidget : findChildren<QRadioButton*>())
1788 QVariantMap DarkLibrary::getAllSettings()
const
1790 QVariantMap settings;
1793 for (
auto &oneWidget : findChildren<QComboBox*>())
1794 settings.insert(oneWidget->objectName(), oneWidget->currentText());
1797 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
1798 settings.insert(oneWidget->objectName(), oneWidget->value());
1801 for (
auto &oneWidget : findChildren<QSpinBox*>())
1802 settings.insert(oneWidget->objectName(), oneWidget->value());
1805 for (
auto &oneWidget : findChildren<QCheckBox*>())
1806 settings.insert(oneWidget->objectName(), oneWidget->isChecked());
1814 void DarkLibrary::setAllSettings(
const QVariantMap &settings)
1818 disconnectSettings();
1820 for (
auto &name : settings.keys())
1823 auto comboBox = findChild<QComboBox*>(name);
1826 syncControl(settings, name, comboBox);
1831 auto doubleSpinBox = findChild<QDoubleSpinBox*>(name);
1834 syncControl(settings, name, doubleSpinBox);
1839 auto spinBox = findChild<QSpinBox*>(name);
1842 syncControl(settings, name, spinBox);
1847 auto checkbox = findChild<QCheckBox*>(name);
1850 syncControl(settings, name, checkbox);
1855 auto radioButton = findChild<QRadioButton*>(name);
1858 syncControl(settings, name, radioButton);
1864 for (
auto &key : settings.keys())
1866 auto value = settings[key];
1868 Options::self()->setProperty(key.
toLatin1(), value);
1869 Options::self()->save();
1871 m_Settings[key] = value;
1872 m_GlobalSettings[key] = value;
1875 emit settingsUpdated(getAllSettings());
1878 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1879 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::DarkLibrary, m_Settings);
1888 bool DarkLibrary::syncControl(
const QVariantMap &settings,
const QString &key,
QWidget * widget)
1897 if ((pSB = qobject_cast<QSpinBox *>(widget)))
1899 const int value = settings[key].
toInt(&ok);
1906 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
1908 const double value = settings[key].toDouble(&ok);
1915 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
1917 const bool value = settings[key].toBool();
1922 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))
1924 const QString value = settings[key].toString();
1928 else if ((pRadioButton = qobject_cast<QRadioButton *>(widget)))
1930 const bool value = settings[key].toBool();
1941 void DarkLibrary::syncSettings()
1952 if ( (dsb = qobject_cast<QDoubleSpinBox*>(sender())))
1955 value = dsb->
value();
1958 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
1961 value = sb->
value();
1963 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
1968 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
1973 else if ( (cradio = qobject_cast<QRadioButton*>(sender())))
1982 if (m_Settings.contains(key))
1984 m_Settings.remove(key);
1985 emit settingsUpdated(getAllSettings());
1986 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1987 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::DarkLibrary, m_Settings);
1996 Options::self()->setProperty(key.
toLatin1(), value);
1997 Options::self()->save();
1999 m_Settings[key] = value;
2000 m_GlobalSettings[key] = value;
2002 emit settingsUpdated(getAllSettings());
2005 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
2006 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::DarkLibrary, m_Settings);
2015 for (
int i = 0; i < masterDarksCombo->count(); i++)
2016 darkMasters << masterDarksCombo->itemText(i);
2020 {
"masterTime", masterTime->text()},
2021 {
"masterDarks", darkMasters.
join(
'|')},
2022 {
"masterExposure", masterExposure->text()},
2023 {
"masterTempreture", masterTemperature->text()},
2024 {
"masterMean", masterMean->text()},
2025 {
"masterMedian", masterMedian->text()},
2026 {
"masterDeviation", masterDeviation->text()},
2027 {
"hotPixelsEnabled", hotPixelsEnabled->isChecked()},
2028 {
"coldPixelsEnabled", coldPixelsEnabled->isChecked()},
2030 return createDefectMaps;