setiastrosuitepro 1.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of setiastrosuitepro might be problematic. Click here for more details.
- setiastro/__init__.py +2 -0
- setiastro/data/SASP_data.fits +0 -0
- setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
- setiastro/data/catalogs/astrobin_filters.csv +890 -0
- setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
- setiastro/data/catalogs/cali2.csv +63 -0
- setiastro/data/catalogs/cali2color.csv +65 -0
- setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
- setiastro/data/catalogs/celestial_catalog.csv +24031 -0
- setiastro/data/catalogs/detected_stars.csv +24784 -0
- setiastro/data/catalogs/fits_header_data.csv +46 -0
- setiastro/data/catalogs/test.csv +8 -0
- setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
- setiastro/images/Astro_Spikes.png +0 -0
- setiastro/images/HRDiagram.png +0 -0
- setiastro/images/LExtract.png +0 -0
- setiastro/images/LInsert.png +0 -0
- setiastro/images/Oxygenation-atm-2.svg.png +0 -0
- setiastro/images/RGB080604.png +0 -0
- setiastro/images/abeicon.png +0 -0
- setiastro/images/aberration.png +0 -0
- setiastro/images/andromedatry.png +0 -0
- setiastro/images/andromedatry_satellited.png +0 -0
- setiastro/images/annotated.png +0 -0
- setiastro/images/aperture.png +0 -0
- setiastro/images/astrosuite.ico +0 -0
- setiastro/images/astrosuite.png +0 -0
- setiastro/images/astrosuitepro.icns +0 -0
- setiastro/images/astrosuitepro.ico +0 -0
- setiastro/images/astrosuitepro.png +0 -0
- setiastro/images/background.png +0 -0
- setiastro/images/background2.png +0 -0
- setiastro/images/benchmark.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
- setiastro/images/blaster.png +0 -0
- setiastro/images/blink.png +0 -0
- setiastro/images/clahe.png +0 -0
- setiastro/images/collage.png +0 -0
- setiastro/images/colorwheel.png +0 -0
- setiastro/images/contsub.png +0 -0
- setiastro/images/convo.png +0 -0
- setiastro/images/copyslot.png +0 -0
- setiastro/images/cosmic.png +0 -0
- setiastro/images/cosmicsat.png +0 -0
- setiastro/images/crop1.png +0 -0
- setiastro/images/cropicon.png +0 -0
- setiastro/images/curves.png +0 -0
- setiastro/images/cvs.png +0 -0
- setiastro/images/debayer.png +0 -0
- setiastro/images/denoise_cnn_custom.png +0 -0
- setiastro/images/denoise_cnn_graph.png +0 -0
- setiastro/images/disk.png +0 -0
- setiastro/images/dse.png +0 -0
- setiastro/images/exoicon.png +0 -0
- setiastro/images/eye.png +0 -0
- setiastro/images/fliphorizontal.png +0 -0
- setiastro/images/flipvertical.png +0 -0
- setiastro/images/font.png +0 -0
- setiastro/images/freqsep.png +0 -0
- setiastro/images/functionbundle.png +0 -0
- setiastro/images/graxpert.png +0 -0
- setiastro/images/green.png +0 -0
- setiastro/images/gridicon.png +0 -0
- setiastro/images/halo.png +0 -0
- setiastro/images/hdr.png +0 -0
- setiastro/images/histogram.png +0 -0
- setiastro/images/hubble.png +0 -0
- setiastro/images/imagecombine.png +0 -0
- setiastro/images/invert.png +0 -0
- setiastro/images/isophote.png +0 -0
- setiastro/images/isophote_demo_figure.png +0 -0
- setiastro/images/isophote_demo_image.png +0 -0
- setiastro/images/isophote_demo_model.png +0 -0
- setiastro/images/isophote_demo_residual.png +0 -0
- setiastro/images/jwstpupil.png +0 -0
- setiastro/images/linearfit.png +0 -0
- setiastro/images/livestacking.png +0 -0
- setiastro/images/mask.png +0 -0
- setiastro/images/maskapply.png +0 -0
- setiastro/images/maskcreate.png +0 -0
- setiastro/images/maskremove.png +0 -0
- setiastro/images/morpho.png +0 -0
- setiastro/images/mosaic.png +0 -0
- setiastro/images/multiscale_decomp.png +0 -0
- setiastro/images/nbtorgb.png +0 -0
- setiastro/images/neutral.png +0 -0
- setiastro/images/nuke.png +0 -0
- setiastro/images/openfile.png +0 -0
- setiastro/images/pedestal.png +0 -0
- setiastro/images/pen.png +0 -0
- setiastro/images/pixelmath.png +0 -0
- setiastro/images/platesolve.png +0 -0
- setiastro/images/ppp.png +0 -0
- setiastro/images/pro.png +0 -0
- setiastro/images/project.png +0 -0
- setiastro/images/psf.png +0 -0
- setiastro/images/redo.png +0 -0
- setiastro/images/redoicon.png +0 -0
- setiastro/images/rescale.png +0 -0
- setiastro/images/rgbalign.png +0 -0
- setiastro/images/rgbcombo.png +0 -0
- setiastro/images/rgbextract.png +0 -0
- setiastro/images/rotate180.png +0 -0
- setiastro/images/rotateclockwise.png +0 -0
- setiastro/images/rotatecounterclockwise.png +0 -0
- setiastro/images/satellite.png +0 -0
- setiastro/images/script.png +0 -0
- setiastro/images/selectivecolor.png +0 -0
- setiastro/images/simbad.png +0 -0
- setiastro/images/slot0.png +0 -0
- setiastro/images/slot1.png +0 -0
- setiastro/images/slot2.png +0 -0
- setiastro/images/slot3.png +0 -0
- setiastro/images/slot4.png +0 -0
- setiastro/images/slot5.png +0 -0
- setiastro/images/slot6.png +0 -0
- setiastro/images/slot7.png +0 -0
- setiastro/images/slot8.png +0 -0
- setiastro/images/slot9.png +0 -0
- setiastro/images/spcc.png +0 -0
- setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
- setiastro/images/spinner.gif +0 -0
- setiastro/images/stacking.png +0 -0
- setiastro/images/staradd.png +0 -0
- setiastro/images/staralign.png +0 -0
- setiastro/images/starnet.png +0 -0
- setiastro/images/starregistration.png +0 -0
- setiastro/images/starspike.png +0 -0
- setiastro/images/starstretch.png +0 -0
- setiastro/images/statstretch.png +0 -0
- setiastro/images/supernova.png +0 -0
- setiastro/images/uhs.png +0 -0
- setiastro/images/undoicon.png +0 -0
- setiastro/images/upscale.png +0 -0
- setiastro/images/viewbundle.png +0 -0
- setiastro/images/whitebalance.png +0 -0
- setiastro/images/wimi_icon_256x256.png +0 -0
- setiastro/images/wimilogo.png +0 -0
- setiastro/images/wims.png +0 -0
- setiastro/images/wrench_icon.png +0 -0
- setiastro/images/xisfliberator.png +0 -0
- setiastro/saspro/__init__.py +20 -0
- setiastro/saspro/__main__.py +809 -0
- setiastro/saspro/_generated/__init__.py +7 -0
- setiastro/saspro/_generated/build_info.py +2 -0
- setiastro/saspro/abe.py +1295 -0
- setiastro/saspro/abe_preset.py +196 -0
- setiastro/saspro/aberration_ai.py +694 -0
- setiastro/saspro/aberration_ai_preset.py +224 -0
- setiastro/saspro/accel_installer.py +218 -0
- setiastro/saspro/accel_workers.py +30 -0
- setiastro/saspro/add_stars.py +621 -0
- setiastro/saspro/astrobin_exporter.py +1007 -0
- setiastro/saspro/astrospike.py +153 -0
- setiastro/saspro/astrospike_python.py +1839 -0
- setiastro/saspro/autostretch.py +196 -0
- setiastro/saspro/backgroundneutral.py +560 -0
- setiastro/saspro/batch_convert.py +325 -0
- setiastro/saspro/batch_renamer.py +519 -0
- setiastro/saspro/blemish_blaster.py +488 -0
- setiastro/saspro/blink_comparator_pro.py +2926 -0
- setiastro/saspro/bundles.py +61 -0
- setiastro/saspro/bundles_dock.py +114 -0
- setiastro/saspro/cheat_sheet.py +178 -0
- setiastro/saspro/clahe.py +342 -0
- setiastro/saspro/comet_stacking.py +1377 -0
- setiastro/saspro/common_tr.py +107 -0
- setiastro/saspro/config.py +38 -0
- setiastro/saspro/config_bootstrap.py +40 -0
- setiastro/saspro/config_manager.py +316 -0
- setiastro/saspro/continuum_subtract.py +1617 -0
- setiastro/saspro/convo.py +1397 -0
- setiastro/saspro/convo_preset.py +414 -0
- setiastro/saspro/copyastro.py +187 -0
- setiastro/saspro/cosmicclarity.py +1564 -0
- setiastro/saspro/cosmicclarity_preset.py +407 -0
- setiastro/saspro/crop_dialog_pro.py +956 -0
- setiastro/saspro/crop_preset.py +189 -0
- setiastro/saspro/curve_editor_pro.py +2544 -0
- setiastro/saspro/curves_preset.py +375 -0
- setiastro/saspro/debayer.py +670 -0
- setiastro/saspro/debug_utils.py +29 -0
- setiastro/saspro/dnd_mime.py +35 -0
- setiastro/saspro/doc_manager.py +2641 -0
- setiastro/saspro/exoplanet_detector.py +2166 -0
- setiastro/saspro/file_utils.py +284 -0
- setiastro/saspro/fitsmodifier.py +745 -0
- setiastro/saspro/fix_bom.py +32 -0
- setiastro/saspro/free_torch_memory.py +48 -0
- setiastro/saspro/frequency_separation.py +1343 -0
- setiastro/saspro/function_bundle.py +1594 -0
- setiastro/saspro/generate_translations.py +2378 -0
- setiastro/saspro/ghs_dialog_pro.py +660 -0
- setiastro/saspro/ghs_preset.py +284 -0
- setiastro/saspro/graxpert.py +634 -0
- setiastro/saspro/graxpert_preset.py +287 -0
- setiastro/saspro/gui/__init__.py +0 -0
- setiastro/saspro/gui/main_window.py +8567 -0
- setiastro/saspro/gui/mixins/__init__.py +33 -0
- setiastro/saspro/gui/mixins/dock_mixin.py +263 -0
- setiastro/saspro/gui/mixins/file_mixin.py +443 -0
- setiastro/saspro/gui/mixins/geometry_mixin.py +403 -0
- setiastro/saspro/gui/mixins/header_mixin.py +441 -0
- setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
- setiastro/saspro/gui/mixins/menu_mixin.py +361 -0
- setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
- setiastro/saspro/gui/mixins/toolbar_mixin.py +1457 -0
- setiastro/saspro/gui/mixins/update_mixin.py +309 -0
- setiastro/saspro/gui/mixins/view_mixin.py +435 -0
- setiastro/saspro/halobgon.py +462 -0
- setiastro/saspro/header_viewer.py +448 -0
- setiastro/saspro/headless_utils.py +88 -0
- setiastro/saspro/histogram.py +753 -0
- setiastro/saspro/history_explorer.py +939 -0
- setiastro/saspro/i18n.py +156 -0
- setiastro/saspro/image_combine.py +414 -0
- setiastro/saspro/image_peeker_pro.py +1601 -0
- setiastro/saspro/imageops/__init__.py +37 -0
- setiastro/saspro/imageops/mdi_snap.py +292 -0
- setiastro/saspro/imageops/scnr.py +36 -0
- setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
- setiastro/saspro/imageops/stretch.py +244 -0
- setiastro/saspro/isophote.py +1179 -0
- setiastro/saspro/layers.py +208 -0
- setiastro/saspro/layers_dock.py +714 -0
- setiastro/saspro/lazy_imports.py +193 -0
- setiastro/saspro/legacy/__init__.py +2 -0
- setiastro/saspro/legacy/image_manager.py +2226 -0
- setiastro/saspro/legacy/numba_utils.py +3659 -0
- setiastro/saspro/legacy/xisf.py +1071 -0
- setiastro/saspro/linear_fit.py +534 -0
- setiastro/saspro/live_stacking.py +1830 -0
- setiastro/saspro/log_bus.py +5 -0
- setiastro/saspro/logging_config.py +460 -0
- setiastro/saspro/luminancerecombine.py +309 -0
- setiastro/saspro/main_helpers.py +201 -0
- setiastro/saspro/mask_creation.py +928 -0
- setiastro/saspro/masks_core.py +56 -0
- setiastro/saspro/mdi_widgets.py +353 -0
- setiastro/saspro/memory_utils.py +666 -0
- setiastro/saspro/metadata_patcher.py +75 -0
- setiastro/saspro/mfdeconv.py +3826 -0
- setiastro/saspro/mfdeconv_earlystop.py +71 -0
- setiastro/saspro/mfdeconvcudnn.py +3263 -0
- setiastro/saspro/mfdeconvsport.py +2382 -0
- setiastro/saspro/minorbodycatalog.py +567 -0
- setiastro/saspro/morphology.py +382 -0
- setiastro/saspro/multiscale_decomp.py +1290 -0
- setiastro/saspro/nbtorgb_stars.py +531 -0
- setiastro/saspro/numba_utils.py +3044 -0
- setiastro/saspro/numba_warmup.py +141 -0
- setiastro/saspro/ops/__init__.py +9 -0
- setiastro/saspro/ops/command_help_dialog.py +623 -0
- setiastro/saspro/ops/command_runner.py +217 -0
- setiastro/saspro/ops/commands.py +1594 -0
- setiastro/saspro/ops/script_editor.py +1102 -0
- setiastro/saspro/ops/scripts.py +1413 -0
- setiastro/saspro/ops/settings.py +679 -0
- setiastro/saspro/parallel_utils.py +554 -0
- setiastro/saspro/pedestal.py +121 -0
- setiastro/saspro/perfect_palette_picker.py +1070 -0
- setiastro/saspro/pipeline.py +110 -0
- setiastro/saspro/pixelmath.py +1600 -0
- setiastro/saspro/plate_solver.py +2444 -0
- setiastro/saspro/project_io.py +797 -0
- setiastro/saspro/psf_utils.py +136 -0
- setiastro/saspro/psf_viewer.py +549 -0
- setiastro/saspro/pyi_rthook_astroquery.py +95 -0
- setiastro/saspro/remove_green.py +314 -0
- setiastro/saspro/remove_stars.py +1625 -0
- setiastro/saspro/remove_stars_preset.py +404 -0
- setiastro/saspro/resources.py +477 -0
- setiastro/saspro/rgb_combination.py +207 -0
- setiastro/saspro/rgb_extract.py +19 -0
- setiastro/saspro/rgbalign.py +723 -0
- setiastro/saspro/runtime_imports.py +7 -0
- setiastro/saspro/runtime_torch.py +754 -0
- setiastro/saspro/save_options.py +72 -0
- setiastro/saspro/selective_color.py +1552 -0
- setiastro/saspro/sfcc.py +1430 -0
- setiastro/saspro/shortcuts.py +3043 -0
- setiastro/saspro/signature_insert.py +1099 -0
- setiastro/saspro/stacking_suite.py +18181 -0
- setiastro/saspro/star_alignment.py +7420 -0
- setiastro/saspro/star_alignment_preset.py +329 -0
- setiastro/saspro/star_metrics.py +49 -0
- setiastro/saspro/star_spikes.py +681 -0
- setiastro/saspro/star_stretch.py +470 -0
- setiastro/saspro/stat_stretch.py +506 -0
- setiastro/saspro/status_log_dock.py +78 -0
- setiastro/saspro/subwindow.py +3267 -0
- setiastro/saspro/supernovaasteroidhunter.py +1716 -0
- setiastro/saspro/swap_manager.py +99 -0
- setiastro/saspro/torch_backend.py +89 -0
- setiastro/saspro/torch_rejection.py +434 -0
- setiastro/saspro/translations/de_translations.py +3733 -0
- setiastro/saspro/translations/es_translations.py +3923 -0
- setiastro/saspro/translations/fr_translations.py +3842 -0
- setiastro/saspro/translations/integrate_translations.py +234 -0
- setiastro/saspro/translations/it_translations.py +3662 -0
- setiastro/saspro/translations/ja_translations.py +3585 -0
- setiastro/saspro/translations/pt_translations.py +3853 -0
- setiastro/saspro/translations/saspro_de.qm +0 -0
- setiastro/saspro/translations/saspro_de.ts +253 -0
- setiastro/saspro/translations/saspro_es.qm +0 -0
- setiastro/saspro/translations/saspro_es.ts +12520 -0
- setiastro/saspro/translations/saspro_fr.qm +0 -0
- setiastro/saspro/translations/saspro_fr.ts +12514 -0
- setiastro/saspro/translations/saspro_it.qm +0 -0
- setiastro/saspro/translations/saspro_it.ts +12520 -0
- setiastro/saspro/translations/saspro_ja.qm +0 -0
- setiastro/saspro/translations/saspro_ja.ts +257 -0
- setiastro/saspro/translations/saspro_pt.qm +0 -0
- setiastro/saspro/translations/saspro_pt.ts +257 -0
- setiastro/saspro/translations/saspro_zh.qm +0 -0
- setiastro/saspro/translations/saspro_zh.ts +12520 -0
- setiastro/saspro/translations/zh_translations.py +3659 -0
- setiastro/saspro/versioning.py +71 -0
- setiastro/saspro/view_bundle.py +1555 -0
- setiastro/saspro/wavescale_hdr.py +624 -0
- setiastro/saspro/wavescale_hdr_preset.py +101 -0
- setiastro/saspro/wavescalede.py +658 -0
- setiastro/saspro/wavescalede_preset.py +230 -0
- setiastro/saspro/wcs_update.py +374 -0
- setiastro/saspro/whitebalance.py +456 -0
- setiastro/saspro/widgets/__init__.py +48 -0
- setiastro/saspro/widgets/common_utilities.py +306 -0
- setiastro/saspro/widgets/graphics_views.py +122 -0
- setiastro/saspro/widgets/image_utils.py +518 -0
- setiastro/saspro/widgets/preview_dialogs.py +280 -0
- setiastro/saspro/widgets/spinboxes.py +275 -0
- setiastro/saspro/widgets/themed_buttons.py +13 -0
- setiastro/saspro/widgets/wavelet_utils.py +299 -0
- setiastro/saspro/window_shelf.py +185 -0
- setiastro/saspro/xisf.py +1123 -0
- setiastrosuitepro-1.6.1.dist-info/METADATA +267 -0
- setiastrosuitepro-1.6.1.dist-info/RECORD +342 -0
- setiastrosuitepro-1.6.1.dist-info/WHEEL +4 -0
- setiastrosuitepro-1.6.1.dist-info/entry_points.txt +6 -0
- setiastrosuitepro-1.6.1.dist-info/licenses/LICENSE +674 -0
- setiastrosuitepro-1.6.1.dist-info/licenses/license.txt +2580 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
# pro/remove_stars_preset.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import shutil
|
|
6
|
+
import numpy as np
|
|
7
|
+
from PyQt6.QtCore import QTimer
|
|
8
|
+
from PyQt6.QtWidgets import QMessageBox, QDialog, QFormLayout, QDialogButtonBox, QComboBox, QCheckBox, QSpinBox, QLabel
|
|
9
|
+
|
|
10
|
+
from setiastro.saspro.legacy.image_manager import save_image, load_image
|
|
11
|
+
|
|
12
|
+
# Reuse helpers & plumbing from the interactive module
|
|
13
|
+
from .remove_stars import (
|
|
14
|
+
_ProcThread, _ProcDialog,
|
|
15
|
+
_stat_stretch_rgb, _stat_unstretch_rgb,
|
|
16
|
+
_active_mask3_from_doc, _mask_blend_with_doc_mask, _push_as_new_doc,
|
|
17
|
+
_ensure_exec_bit,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# ---------- Headless public entry ----------
|
|
21
|
+
def run_remove_stars_via_preset(main, doc_or_preset=None, preset: dict | None = None, target_doc=None):
|
|
22
|
+
"""
|
|
23
|
+
Headless star removal from a shortcut preset.
|
|
24
|
+
|
|
25
|
+
Supports BOTH call shapes:
|
|
26
|
+
1) New CommandRunner shape:
|
|
27
|
+
run_remove_stars_via_preset(main, target_doc, preset)
|
|
28
|
+
2) Legacy shape:
|
|
29
|
+
run_remove_stars_via_preset(main, preset_dict, target_doc=doc)
|
|
30
|
+
run_remove_stars_via_preset(main, preset_dict)
|
|
31
|
+
"""
|
|
32
|
+
from PyQt6.QtWidgets import QMessageBox
|
|
33
|
+
from PyQt6.QtCore import QTimer
|
|
34
|
+
import os
|
|
35
|
+
import platform
|
|
36
|
+
|
|
37
|
+
# ---- Interpret arguments for backward compat / new executor ----
|
|
38
|
+
if preset is None and isinstance(doc_or_preset, dict):
|
|
39
|
+
# Legacy: (main, preset_dict, target_doc=?)
|
|
40
|
+
p = dict(doc_or_preset or {})
|
|
41
|
+
doc = target_doc
|
|
42
|
+
else:
|
|
43
|
+
# New executor: (main, doc, preset_dict)
|
|
44
|
+
p = dict(preset or {})
|
|
45
|
+
doc = target_doc if target_doc is not None else doc_or_preset
|
|
46
|
+
|
|
47
|
+
# Resolve active doc if still None
|
|
48
|
+
if doc is None:
|
|
49
|
+
d = getattr(main, "_active_doc", None)
|
|
50
|
+
doc = d() if callable(d) else d
|
|
51
|
+
|
|
52
|
+
if doc is None or getattr(doc, "image", None) is None:
|
|
53
|
+
QMessageBox.warning(main, "Remove Stars", "Load an image first.")
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
tool = str(p.get("tool", "starnet")).lower()
|
|
57
|
+
|
|
58
|
+
# mark headless + short cool-down to block the interactive path
|
|
59
|
+
setattr(main, "_remove_stars_headless_running", True)
|
|
60
|
+
setattr(main, "_remove_stars_guard", True)
|
|
61
|
+
|
|
62
|
+
def _clear_flags():
|
|
63
|
+
for name in ("_remove_stars_headless_running", "_remove_stars_guard"):
|
|
64
|
+
try:
|
|
65
|
+
delattr(main, name)
|
|
66
|
+
except Exception:
|
|
67
|
+
setattr(main, name, False)
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
if tool in ("starnet", "star_net", "sn"):
|
|
71
|
+
_run_starnet_headless(main, doc, p)
|
|
72
|
+
elif tool in ("darkstar", "cosmicclarity", "cosmic_clarity"):
|
|
73
|
+
_run_darkstar_headless(main, doc, p)
|
|
74
|
+
else:
|
|
75
|
+
QMessageBox.critical(main, "Remove Stars", f"Unknown tool '{tool}'.")
|
|
76
|
+
finally:
|
|
77
|
+
QTimer.singleShot(1200, _clear_flags)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def apply_remove_stars_to_doc(parent, target_doc, preset: dict | None):
|
|
81
|
+
"""
|
|
82
|
+
Replay helper: apply Remove Stars to a specific doc (base/ROI).
|
|
83
|
+
"""
|
|
84
|
+
if parent is None:
|
|
85
|
+
return
|
|
86
|
+
main = parent
|
|
87
|
+
# walk up to main window if needed
|
|
88
|
+
while main is not None and not hasattr(main, "doc_manager"):
|
|
89
|
+
main = main.parent() if hasattr(main, "parent") else None
|
|
90
|
+
if main is None:
|
|
91
|
+
main = parent
|
|
92
|
+
|
|
93
|
+
run_remove_stars_via_preset(main, preset, target_doc=target_doc)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# ---------- StarNet headless ----------
|
|
97
|
+
def _resolve_starnet_exe_headless(main, override: str | None) -> str | None:
|
|
98
|
+
if override and os.path.exists(override):
|
|
99
|
+
if platform.system() in ("Darwin", "Linux"): _ensure_exec_bit(override)
|
|
100
|
+
return override
|
|
101
|
+
s = getattr(main, "settings", None)
|
|
102
|
+
exe = None
|
|
103
|
+
if s:
|
|
104
|
+
for key in ("starnet/exe_path", "paths/starnet"):
|
|
105
|
+
try:
|
|
106
|
+
val = s.value(key, "", type=str)
|
|
107
|
+
except Exception:
|
|
108
|
+
val = s.value(key, "")
|
|
109
|
+
if isinstance(val, str) and val.strip() and os.path.exists(val):
|
|
110
|
+
exe = val.strip(); break
|
|
111
|
+
if exe and platform.system() in ("Darwin", "Linux"): _ensure_exec_bit(exe)
|
|
112
|
+
return exe
|
|
113
|
+
|
|
114
|
+
def _run_starnet_headless(main, doc, p):
|
|
115
|
+
exe = _resolve_starnet_exe_headless(main, p.get("starnet_exe") or p.get("exe"))
|
|
116
|
+
if not exe:
|
|
117
|
+
QMessageBox.warning(main, "StarNet", "StarNet path not set. Open the interactive tool once to set it.")
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
# RGB float32 [0..1]
|
|
121
|
+
src = np.asarray(doc.image)
|
|
122
|
+
if src.ndim == 2: processing_image = np.stack([src]*3, axis=-1)
|
|
123
|
+
elif src.ndim == 3 and src.shape[2] == 1: processing_image = np.repeat(src, 3, axis=2)
|
|
124
|
+
else: processing_image = src
|
|
125
|
+
processing_image = processing_image.astype(np.float32, copy=False)
|
|
126
|
+
|
|
127
|
+
is_linear = bool(p.get("linear", True))
|
|
128
|
+
did_stretch = False
|
|
129
|
+
stretch_params = None
|
|
130
|
+
if is_linear:
|
|
131
|
+
processing_image, stretch_params = _stat_stretch_rgb(processing_image)
|
|
132
|
+
did_stretch = True
|
|
133
|
+
setattr(main, "_starnet_last_stretch_params", stretch_params)
|
|
134
|
+
else:
|
|
135
|
+
if hasattr(main, "_starnet_last_stretch_params"):
|
|
136
|
+
delattr(main, "_starnet_last_stretch_params")
|
|
137
|
+
|
|
138
|
+
starnet_dir = os.path.dirname(exe) or os.getcwd()
|
|
139
|
+
in_path = os.path.join(starnet_dir, "imagetoremovestars.tif")
|
|
140
|
+
out_path = os.path.join(starnet_dir, "starless.tif")
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
save_image(processing_image, in_path, original_format="tif",
|
|
144
|
+
bit_depth="16-bit", original_header=None, is_mono=False,
|
|
145
|
+
image_meta=None, file_meta=None)
|
|
146
|
+
except Exception as e:
|
|
147
|
+
QMessageBox.critical(main, "StarNet", f"Failed to write input TIFF:\n{e}")
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
exe_name = os.path.basename(exe).lower()
|
|
151
|
+
sysname = platform.system()
|
|
152
|
+
if sysname in ("Windows", "Linux"):
|
|
153
|
+
command = [exe, in_path, out_path, "256"]
|
|
154
|
+
else:
|
|
155
|
+
if "starnet2" in exe_name:
|
|
156
|
+
command = [exe, "--input", in_path, "--output", out_path]
|
|
157
|
+
else:
|
|
158
|
+
command = [exe, in_path, out_path]
|
|
159
|
+
|
|
160
|
+
dlg = _ProcDialog(main, title="StarNet Progress")
|
|
161
|
+
thr = _ProcThread(command, cwd=starnet_dir)
|
|
162
|
+
thr.output_signal.connect(dlg.append_text)
|
|
163
|
+
thr.finished_signal.connect(lambda rc: _finish_starnet(main, doc, rc, dlg, in_path, out_path, did_stretch))
|
|
164
|
+
dlg.cancel_button.clicked.connect(thr.terminate)
|
|
165
|
+
dlg.show(); thr.start(); dlg.exec()
|
|
166
|
+
|
|
167
|
+
def _finish_starnet(main, doc, rc, dlg, in_path, out_path, did_stretch):
|
|
168
|
+
if rc != 0 or not os.path.exists(out_path):
|
|
169
|
+
QMessageBox.critical(main, "StarNet", "StarNet failed or no output image produced.")
|
|
170
|
+
_safe_rm(in_path); _safe_rm(out_path); dlg.close(); return
|
|
171
|
+
|
|
172
|
+
starless_rgb, _, _, _ = load_image(out_path)
|
|
173
|
+
if starless_rgb is None:
|
|
174
|
+
QMessageBox.critical(main, "StarNet", "Failed to load starless image.")
|
|
175
|
+
_safe_rm(in_path); _safe_rm(out_path); dlg.close(); return
|
|
176
|
+
|
|
177
|
+
if starless_rgb.ndim == 2 or (starless_rgb.ndim == 3 and starless_rgb.shape[2] == 1):
|
|
178
|
+
starless_rgb = np.stack([starless_rgb]*3, axis=-1)
|
|
179
|
+
starless_rgb = starless_rgb.astype(np.float32, copy=False)
|
|
180
|
+
|
|
181
|
+
if did_stretch:
|
|
182
|
+
try:
|
|
183
|
+
params = getattr(main, "_starnet_last_stretch_params", None)
|
|
184
|
+
if params: starless_rgb = _stat_unstretch_rgb(starless_rgb, params)
|
|
185
|
+
except Exception:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
# original as RGB
|
|
189
|
+
orig = np.asarray(doc.image)
|
|
190
|
+
if orig.ndim == 2: original_rgb = np.stack([orig]*3, axis=-1)
|
|
191
|
+
elif orig.ndim == 3 and orig.shape[2] == 1: original_rgb = np.repeat(orig, 3, axis=2)
|
|
192
|
+
else: original_rgb = orig
|
|
193
|
+
original_rgb = original_rgb.astype(np.float32, copy=False)
|
|
194
|
+
|
|
195
|
+
# Stars-Only (same as interactive)
|
|
196
|
+
with np.errstate(divide='ignore', invalid='ignore'):
|
|
197
|
+
stars_only = (original_rgb - starless_rgb) / np.clip(1.0 - starless_rgb, 1e-6, None)
|
|
198
|
+
stars_only = np.nan_to_num(stars_only, nan=0.0, posinf=0.0, neginf=0.0)
|
|
199
|
+
stars_only = np.clip(stars_only, 0.0, 1.0)
|
|
200
|
+
m3 = _active_mask3_from_doc(doc, stars_only.shape[1], stars_only.shape[0])
|
|
201
|
+
if m3 is not None: stars_only *= m3
|
|
202
|
+
_push_as_new_doc(main, doc, stars_only, title_suffix="_stars", source="Stars-Only (StarNet)")
|
|
203
|
+
|
|
204
|
+
# mask-blend starless, then commit
|
|
205
|
+
final_starless = _mask_blend_with_doc_mask(doc, starless_rgb, original_rgb)
|
|
206
|
+
try:
|
|
207
|
+
meta = {"step_name": "Stars Removed", "bit_depth": "32-bit floating point", "is_mono": False}
|
|
208
|
+
doc.apply_edit(final_starless.astype(np.float32, copy=False), metadata=meta, step_name="Stars Removed")
|
|
209
|
+
if hasattr(main, "_log"): main._log("Stars Removed (StarNet, headless)")
|
|
210
|
+
except Exception as e:
|
|
211
|
+
QMessageBox.critical(main, "StarNet", f"Failed to apply starless result:\n{e}")
|
|
212
|
+
|
|
213
|
+
_safe_rm(in_path); _safe_rm(out_path); dlg.close()
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# ---------- DarkStar headless ----------
|
|
217
|
+
def _resolve_darkstar_exe_headless(main, override: str | None) -> tuple[str | None, str | None]:
|
|
218
|
+
if override and os.path.exists(override):
|
|
219
|
+
base = os.path.dirname(override)
|
|
220
|
+
if platform.system() in ("Darwin","Linux"): _ensure_exec_bit(override)
|
|
221
|
+
return override, base
|
|
222
|
+
s = getattr(main, "settings", None)
|
|
223
|
+
base = None
|
|
224
|
+
if s:
|
|
225
|
+
for key in ("paths/cosmic_clarity", "cosmic_clarity_folder"):
|
|
226
|
+
try:
|
|
227
|
+
v = s.value(key, "", type=str)
|
|
228
|
+
except Exception:
|
|
229
|
+
v = s.value(key, "")
|
|
230
|
+
if isinstance(v, str) and v.strip() and os.path.isdir(v):
|
|
231
|
+
base = v.strip(); break
|
|
232
|
+
if not base: return None, None
|
|
233
|
+
exe = os.path.join(base, "setiastrocosmicclarity_darkstar.exe" if platform.system()=="Windows"
|
|
234
|
+
else "setiastrocosmicclarity_darkstar")
|
|
235
|
+
if not os.path.exists(exe): return None, None
|
|
236
|
+
if platform.system() in ("Darwin","Linux"): _ensure_exec_bit(exe)
|
|
237
|
+
return exe, base
|
|
238
|
+
|
|
239
|
+
def _run_darkstar_headless(main, doc, p):
|
|
240
|
+
exe, base = _resolve_darkstar_exe_headless(main, p.get("darkstar_exe") or p.get("exe"))
|
|
241
|
+
if not exe or not base:
|
|
242
|
+
QMessageBox.warning(main, "CosmicClarity DarkStar", "DarkStar path not set. Open the interactive tool once to set it.")
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
input_dir = os.path.join(base, "input")
|
|
246
|
+
output_dir = os.path.join(base, "output")
|
|
247
|
+
os.makedirs(input_dir, exist_ok=True)
|
|
248
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
249
|
+
|
|
250
|
+
in_path = os.path.join(input_dir, "imagetoremovestars.tif")
|
|
251
|
+
try:
|
|
252
|
+
save_image(doc.image, in_path, original_format="tif",
|
|
253
|
+
bit_depth="32-bit floating point",
|
|
254
|
+
original_header=None, is_mono=False, image_meta=None, file_meta=None)
|
|
255
|
+
except Exception as e:
|
|
256
|
+
QMessageBox.critical(main, "CosmicClarity DarkStar", f"Failed to write input TIFF:\n{e}")
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
disable_gpu = bool(p.get("disable_gpu", False))
|
|
260
|
+
mode = str(p.get("mode", "unscreen"))
|
|
261
|
+
show = bool(p.get("show_extracted_stars", True))
|
|
262
|
+
stride = int(p.get("stride", 512))
|
|
263
|
+
|
|
264
|
+
args = []
|
|
265
|
+
if disable_gpu: args.append("--disable_gpu")
|
|
266
|
+
args += ["--star_removal_mode", mode]
|
|
267
|
+
if show: args.append("--show_extracted_stars")
|
|
268
|
+
args += ["--chunk_size", str(stride)]
|
|
269
|
+
|
|
270
|
+
command = [exe] + args
|
|
271
|
+
|
|
272
|
+
dlg = _ProcDialog(main, title="CosmicClarityDarkStar Progress")
|
|
273
|
+
thr = _ProcThread(command, cwd=base)
|
|
274
|
+
thr.output_signal.connect(dlg.append_text)
|
|
275
|
+
thr.finished_signal.connect(lambda rc: _finish_darkstar(main, doc, rc, dlg, in_path, output_dir))
|
|
276
|
+
dlg.cancel_button.clicked.connect(thr.terminate)
|
|
277
|
+
dlg.show(); thr.start(); dlg.exec()
|
|
278
|
+
|
|
279
|
+
def _finish_darkstar(main, doc, rc, dlg, in_path, output_dir):
|
|
280
|
+
if rc != 0:
|
|
281
|
+
QMessageBox.critical(main, "CosmicClarity DarkStar", "Process failed.")
|
|
282
|
+
_safe_rm(in_path); dlg.close(); return
|
|
283
|
+
|
|
284
|
+
starless_path = os.path.join(output_dir, "imagetoremovestars_starless.tif")
|
|
285
|
+
if not os.path.exists(starless_path):
|
|
286
|
+
QMessageBox.critical(main, "CosmicClarity DarkStar", "Starless image not found.")
|
|
287
|
+
_safe_rm(in_path); dlg.close(); return
|
|
288
|
+
|
|
289
|
+
starless, _, _, _ = load_image(starless_path)
|
|
290
|
+
if starless is None:
|
|
291
|
+
QMessageBox.critical(main, "CosmicClarity DarkStar", "Failed to load starless image.")
|
|
292
|
+
_safe_rm(in_path); dlg.close(); return
|
|
293
|
+
|
|
294
|
+
if starless.ndim == 2 or (starless.ndim == 3 and starless.shape[2] == 1):
|
|
295
|
+
starless_rgb = np.stack([starless]*3, axis=-1)
|
|
296
|
+
else:
|
|
297
|
+
starless_rgb = starless
|
|
298
|
+
starless_rgb = starless_rgb.astype(np.float32, copy=False)
|
|
299
|
+
|
|
300
|
+
src = np.asarray(doc.image)
|
|
301
|
+
if src.ndim == 2: original_rgb = np.stack([src]*3, axis=-1)
|
|
302
|
+
elif src.ndim == 3 and src.shape[2] == 1: original_rgb = np.repeat(src, 3, axis=2)
|
|
303
|
+
else: original_rgb = src
|
|
304
|
+
original_rgb = original_rgb.astype(np.float32, copy=False)
|
|
305
|
+
|
|
306
|
+
# stars-only (if DarkStar produced it)
|
|
307
|
+
stars_path = os.path.join(output_dir, "imagetoremovestars_stars_only.tif")
|
|
308
|
+
if os.path.exists(stars_path):
|
|
309
|
+
stars_only, _, _, _ = load_image(stars_path)
|
|
310
|
+
if stars_only is not None:
|
|
311
|
+
if stars_only.ndim == 2 or (stars_only.ndim == 3 and stars_only.shape[2] == 1):
|
|
312
|
+
stars_only = np.stack([stars_only]*3, axis=-1)
|
|
313
|
+
stars_only = stars_only.astype(np.float32, copy=False)
|
|
314
|
+
m3 = _active_mask3_from_doc(doc, stars_only.shape[1], stars_only.shape[0])
|
|
315
|
+
if m3 is not None: stars_only *= m3
|
|
316
|
+
_push_as_new_doc(main, doc, stars_only, title_suffix="_stars", source="Stars-Only (DarkStar)")
|
|
317
|
+
|
|
318
|
+
final_starless = _mask_blend_with_doc_mask(doc, starless_rgb, original_rgb)
|
|
319
|
+
try:
|
|
320
|
+
meta = {"step_name": "Stars Removed", "bit_depth": "32-bit floating point", "is_mono": False}
|
|
321
|
+
doc.apply_edit(final_starless.astype(np.float32, copy=False), metadata=meta, step_name="Stars Removed")
|
|
322
|
+
if hasattr(main, "_log"): main._log("Stars Removed (DarkStar, headless)")
|
|
323
|
+
except Exception as e:
|
|
324
|
+
QMessageBox.critical(main, "CosmicClarity DarkStar", f"Failed to apply starless result:\n{e}")
|
|
325
|
+
|
|
326
|
+
# cleanup
|
|
327
|
+
try:
|
|
328
|
+
_safe_rm(in_path)
|
|
329
|
+
for fn in ("imagetoremovestars_starless.tif","imagetoremovestars_stars_only.tif"):
|
|
330
|
+
p = os.path.join(output_dir, fn)
|
|
331
|
+
if os.path.exists(p): _safe_rm(p)
|
|
332
|
+
except Exception:
|
|
333
|
+
pass
|
|
334
|
+
dlg.close()
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
# ---------- Simple preset editor (for the shortcut button) ----------
|
|
338
|
+
class RemoveStarsPresetDialog(QDialog):
|
|
339
|
+
def __init__(self, parent=None, initial: dict | None = None):
|
|
340
|
+
super().__init__(parent)
|
|
341
|
+
self.setWindowTitle("Remove Stars — Preset")
|
|
342
|
+
p = dict(initial or {})
|
|
343
|
+
|
|
344
|
+
self.cmb_tool = QComboBox()
|
|
345
|
+
self.cmb_tool.addItems(["StarNet", "CosmicClarity DarkStar"])
|
|
346
|
+
self.cmb_tool.setCurrentIndex(0 if str(p.get("tool","starnet")).lower().startswith("star") else 1)
|
|
347
|
+
|
|
348
|
+
# StarNet options
|
|
349
|
+
self.chk_linear = QCheckBox("Image is linear (apply temporary stretch)")
|
|
350
|
+
self.chk_linear.setChecked(bool(p.get("linear", True)))
|
|
351
|
+
|
|
352
|
+
# DarkStar options
|
|
353
|
+
self.chk_disable_gpu = QCheckBox("Disable GPU")
|
|
354
|
+
self.chk_disable_gpu.setChecked(bool(p.get("disable_gpu", False)))
|
|
355
|
+
self.cmb_mode = QComboBox(); self.cmb_mode.addItems(["unscreen","additive"])
|
|
356
|
+
self.cmb_mode.setCurrentText(str(p.get("mode","unscreen")))
|
|
357
|
+
self.chk_show = QCheckBox("Show extracted stars")
|
|
358
|
+
self.chk_show.setChecked(bool(p.get("show_extracted_stars", True)))
|
|
359
|
+
self.cmb_stride = QComboBox()
|
|
360
|
+
for v in (64,128,256,512,1024): self.cmb_stride.addItem(str(v), v)
|
|
361
|
+
self.cmb_stride.setCurrentText(str(int(p.get("stride", 512))))
|
|
362
|
+
|
|
363
|
+
form = QFormLayout(self)
|
|
364
|
+
form.addRow("Tool:", self.cmb_tool)
|
|
365
|
+
form.addRow(QLabel("— StarNet —"))
|
|
366
|
+
form.addRow("", self.chk_linear)
|
|
367
|
+
form.addRow(QLabel("— DarkStar —"))
|
|
368
|
+
form.addRow("Mode:", self.cmb_mode)
|
|
369
|
+
form.addRow("Stride:", self.cmb_stride)
|
|
370
|
+
form.addRow("", self.chk_disable_gpu)
|
|
371
|
+
form.addRow("", self.chk_show)
|
|
372
|
+
|
|
373
|
+
btns = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, parent=self)
|
|
374
|
+
btns.accepted.connect(self.accept); btns.rejected.connect(self.reject)
|
|
375
|
+
form.addRow(btns)
|
|
376
|
+
|
|
377
|
+
# show/hide sections depending on tool
|
|
378
|
+
def _toggle():
|
|
379
|
+
star = self.cmb_tool.currentIndex() == 0
|
|
380
|
+
self.chk_linear.setEnabled(star)
|
|
381
|
+
for w in (self.cmb_mode, self.cmb_stride, self.chk_disable_gpu, self.chk_show):
|
|
382
|
+
w.setEnabled(not star)
|
|
383
|
+
self.cmb_tool.currentIndexChanged.connect(lambda _: _toggle())
|
|
384
|
+
_toggle()
|
|
385
|
+
|
|
386
|
+
def result_dict(self) -> dict:
|
|
387
|
+
if self.cmb_tool.currentIndex() == 0:
|
|
388
|
+
return {"tool": "starnet", "linear": bool(self.chk_linear.isChecked())}
|
|
389
|
+
return {
|
|
390
|
+
"tool": "darkstar",
|
|
391
|
+
"disable_gpu": bool(self.chk_disable_gpu.isChecked()),
|
|
392
|
+
"mode": self.cmb_mode.currentText(),
|
|
393
|
+
"show_extracted_stars": bool(self.chk_show.isChecked()),
|
|
394
|
+
"stride": int(self.cmb_stride.currentData()),
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
# ---------- local util ----------
|
|
399
|
+
def _safe_rm(p):
|
|
400
|
+
try:
|
|
401
|
+
if p and os.path.exists(p): os.remove(p)
|
|
402
|
+
except Exception as e:
|
|
403
|
+
import logging
|
|
404
|
+
logging.debug(f"Exception suppressed: {type(e).__name__}: {e}")
|