setiastrosuitepro 1.6.7__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/Background_startup.jpg +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/acv_icon.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/first_quarter.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/full_moon.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/last_quarter.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/new_moon.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/rotatearbitrary.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/waning_crescent_1.png +0 -0
- setiastro/images/waning_crescent_2.png +0 -0
- setiastro/images/waning_crescent_3.png +0 -0
- setiastro/images/waning_crescent_4.png +0 -0
- setiastro/images/waning_crescent_5.png +0 -0
- setiastro/images/waning_gibbous_1.png +0 -0
- setiastro/images/waning_gibbous_2.png +0 -0
- setiastro/images/waning_gibbous_3.png +0 -0
- setiastro/images/waning_gibbous_4.png +0 -0
- setiastro/images/waning_gibbous_5.png +0 -0
- setiastro/images/waxing_crescent_1.png +0 -0
- setiastro/images/waxing_crescent_2.png +0 -0
- setiastro/images/waxing_crescent_3.png +0 -0
- setiastro/images/waxing_crescent_4.png +0 -0
- setiastro/images/waxing_crescent_5.png +0 -0
- setiastro/images/waxing_gibbous_1.png +0 -0
- setiastro/images/waxing_gibbous_2.png +0 -0
- setiastro/images/waxing_gibbous_3.png +0 -0
- setiastro/images/waxing_gibbous_4.png +0 -0
- setiastro/images/waxing_gibbous_5.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/qml/ResourceMonitor.qml +128 -0
- setiastro/saspro/__init__.py +20 -0
- setiastro/saspro/__main__.py +964 -0
- setiastro/saspro/_generated/__init__.py +7 -0
- setiastro/saspro/_generated/build_info.py +3 -0
- setiastro/saspro/abe.py +1379 -0
- setiastro/saspro/abe_preset.py +196 -0
- setiastro/saspro/aberration_ai.py +910 -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/acv_exporter.py +379 -0
- setiastro/saspro/add_stars.py +627 -0
- setiastro/saspro/astrobin_exporter.py +1010 -0
- setiastro/saspro/astrospike.py +153 -0
- setiastro/saspro/astrospike_python.py +1841 -0
- setiastro/saspro/autostretch.py +198 -0
- setiastro/saspro/backgroundneutral.py +639 -0
- setiastro/saspro/batch_convert.py +328 -0
- setiastro/saspro/batch_renamer.py +522 -0
- setiastro/saspro/blemish_blaster.py +494 -0
- setiastro/saspro/blink_comparator_pro.py +3149 -0
- setiastro/saspro/bundles.py +61 -0
- setiastro/saspro/bundles_dock.py +114 -0
- setiastro/saspro/cheat_sheet.py +213 -0
- setiastro/saspro/clahe.py +371 -0
- setiastro/saspro/comet_stacking.py +1442 -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 +1620 -0
- setiastro/saspro/convo.py +1403 -0
- setiastro/saspro/convo_preset.py +414 -0
- setiastro/saspro/copyastro.py +190 -0
- setiastro/saspro/cosmicclarity.py +1593 -0
- setiastro/saspro/cosmicclarity_preset.py +407 -0
- setiastro/saspro/crop_dialog_pro.py +1005 -0
- setiastro/saspro/crop_preset.py +189 -0
- setiastro/saspro/curve_editor_pro.py +2608 -0
- setiastro/saspro/curves_preset.py +375 -0
- setiastro/saspro/debayer.py +673 -0
- setiastro/saspro/debug_utils.py +29 -0
- setiastro/saspro/dnd_mime.py +35 -0
- setiastro/saspro/doc_manager.py +2727 -0
- setiastro/saspro/exoplanet_detector.py +2258 -0
- setiastro/saspro/file_utils.py +284 -0
- setiastro/saspro/fitsmodifier.py +748 -0
- setiastro/saspro/fix_bom.py +32 -0
- setiastro/saspro/free_torch_memory.py +48 -0
- setiastro/saspro/frequency_separation.py +1352 -0
- setiastro/saspro/function_bundle.py +1596 -0
- setiastro/saspro/generate_translations.py +3092 -0
- setiastro/saspro/ghs_dialog_pro.py +728 -0
- setiastro/saspro/ghs_preset.py +284 -0
- setiastro/saspro/graxpert.py +638 -0
- setiastro/saspro/graxpert_preset.py +287 -0
- setiastro/saspro/gui/__init__.py +0 -0
- setiastro/saspro/gui/main_window.py +8928 -0
- setiastro/saspro/gui/mixins/__init__.py +33 -0
- setiastro/saspro/gui/mixins/dock_mixin.py +375 -0
- setiastro/saspro/gui/mixins/file_mixin.py +450 -0
- setiastro/saspro/gui/mixins/geometry_mixin.py +503 -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 +391 -0
- setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
- setiastro/saspro/gui/mixins/toolbar_mixin.py +1824 -0
- setiastro/saspro/gui/mixins/update_mixin.py +323 -0
- setiastro/saspro/gui/mixins/view_mixin.py +477 -0
- setiastro/saspro/gui/statistics_dialog.py +47 -0
- setiastro/saspro/halobgon.py +492 -0
- setiastro/saspro/header_viewer.py +448 -0
- setiastro/saspro/headless_utils.py +88 -0
- setiastro/saspro/histogram.py +760 -0
- setiastro/saspro/history_explorer.py +941 -0
- setiastro/saspro/i18n.py +168 -0
- setiastro/saspro/image_combine.py +421 -0
- setiastro/saspro/image_peeker_pro.py +1608 -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 +236 -0
- setiastro/saspro/isophote.py +1186 -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 +2360 -0
- setiastro/saspro/legacy/numba_utils.py +3676 -0
- setiastro/saspro/legacy/xisf.py +1213 -0
- setiastro/saspro/linear_fit.py +537 -0
- setiastro/saspro/live_stacking.py +1854 -0
- setiastro/saspro/log_bus.py +5 -0
- setiastro/saspro/logging_config.py +460 -0
- setiastro/saspro/luminancerecombine.py +510 -0
- setiastro/saspro/main_helpers.py +201 -0
- setiastro/saspro/mask_creation.py +1090 -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 +3909 -0
- setiastro/saspro/mfdeconv_earlystop.py +71 -0
- setiastro/saspro/mfdeconvcudnn.py +3312 -0
- setiastro/saspro/mfdeconvsport.py +2459 -0
- setiastro/saspro/minorbodycatalog.py +567 -0
- setiastro/saspro/morphology.py +411 -0
- setiastro/saspro/multiscale_decomp.py +1751 -0
- setiastro/saspro/nbtorgb_stars.py +541 -0
- setiastro/saspro/numba_utils.py +3145 -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 +1105 -0
- setiastro/saspro/ops/scripts.py +1476 -0
- setiastro/saspro/ops/settings.py +637 -0
- setiastro/saspro/parallel_utils.py +554 -0
- setiastro/saspro/pedestal.py +121 -0
- setiastro/saspro/perfect_palette_picker.py +1105 -0
- setiastro/saspro/pipeline.py +110 -0
- setiastro/saspro/pixelmath.py +1604 -0
- setiastro/saspro/plate_solver.py +2480 -0
- setiastro/saspro/project_io.py +797 -0
- setiastro/saspro/psf_utils.py +136 -0
- setiastro/saspro/psf_viewer.py +631 -0
- setiastro/saspro/pyi_rthook_astroquery.py +95 -0
- setiastro/saspro/remove_green.py +331 -0
- setiastro/saspro/remove_stars.py +1599 -0
- setiastro/saspro/remove_stars_preset.py +446 -0
- setiastro/saspro/resources.py +570 -0
- setiastro/saspro/rgb_combination.py +208 -0
- setiastro/saspro/rgb_extract.py +19 -0
- setiastro/saspro/rgbalign.py +727 -0
- setiastro/saspro/runtime_imports.py +7 -0
- setiastro/saspro/runtime_torch.py +754 -0
- setiastro/saspro/save_options.py +73 -0
- setiastro/saspro/selective_color.py +1614 -0
- setiastro/saspro/sfcc.py +1530 -0
- setiastro/saspro/shortcuts.py +3125 -0
- setiastro/saspro/signature_insert.py +1106 -0
- setiastro/saspro/stacking_suite.py +19069 -0
- setiastro/saspro/star_alignment.py +7383 -0
- setiastro/saspro/star_alignment_preset.py +329 -0
- setiastro/saspro/star_metrics.py +49 -0
- setiastro/saspro/star_spikes.py +769 -0
- setiastro/saspro/star_stretch.py +542 -0
- setiastro/saspro/stat_stretch.py +554 -0
- setiastro/saspro/status_log_dock.py +78 -0
- setiastro/saspro/subwindow.py +3523 -0
- setiastro/saspro/supernovaasteroidhunter.py +1719 -0
- setiastro/saspro/swap_manager.py +134 -0
- setiastro/saspro/torch_backend.py +89 -0
- setiastro/saspro/torch_rejection.py +434 -0
- setiastro/saspro/translations/all_source_strings.json +4726 -0
- setiastro/saspro/translations/ar_translations.py +4096 -0
- setiastro/saspro/translations/de_translations.py +3728 -0
- setiastro/saspro/translations/es_translations.py +4169 -0
- setiastro/saspro/translations/fr_translations.py +4090 -0
- setiastro/saspro/translations/hi_translations.py +3803 -0
- setiastro/saspro/translations/integrate_translations.py +271 -0
- setiastro/saspro/translations/it_translations.py +4728 -0
- setiastro/saspro/translations/ja_translations.py +3834 -0
- setiastro/saspro/translations/pt_translations.py +3847 -0
- setiastro/saspro/translations/ru_translations.py +3082 -0
- setiastro/saspro/translations/saspro_ar.qm +0 -0
- setiastro/saspro/translations/saspro_ar.ts +16019 -0
- setiastro/saspro/translations/saspro_de.qm +0 -0
- setiastro/saspro/translations/saspro_de.ts +14548 -0
- setiastro/saspro/translations/saspro_es.qm +0 -0
- setiastro/saspro/translations/saspro_es.ts +16202 -0
- setiastro/saspro/translations/saspro_fr.qm +0 -0
- setiastro/saspro/translations/saspro_fr.ts +15870 -0
- setiastro/saspro/translations/saspro_hi.qm +0 -0
- setiastro/saspro/translations/saspro_hi.ts +14855 -0
- setiastro/saspro/translations/saspro_it.qm +0 -0
- setiastro/saspro/translations/saspro_it.ts +19046 -0
- setiastro/saspro/translations/saspro_ja.qm +0 -0
- setiastro/saspro/translations/saspro_ja.ts +14980 -0
- setiastro/saspro/translations/saspro_pt.qm +0 -0
- setiastro/saspro/translations/saspro_pt.ts +15024 -0
- setiastro/saspro/translations/saspro_ru.qm +0 -0
- setiastro/saspro/translations/saspro_ru.ts +11835 -0
- setiastro/saspro/translations/saspro_sw.qm +0 -0
- setiastro/saspro/translations/saspro_sw.ts +15237 -0
- setiastro/saspro/translations/saspro_uk.qm +0 -0
- setiastro/saspro/translations/saspro_uk.ts +15248 -0
- setiastro/saspro/translations/saspro_zh.qm +0 -0
- setiastro/saspro/translations/saspro_zh.ts +15289 -0
- setiastro/saspro/translations/sw_translations.py +3897 -0
- setiastro/saspro/translations/uk_translations.py +3929 -0
- setiastro/saspro/translations/zh_translations.py +3910 -0
- setiastro/saspro/versioning.py +77 -0
- setiastro/saspro/view_bundle.py +1558 -0
- setiastro/saspro/wavescale_hdr.py +648 -0
- setiastro/saspro/wavescale_hdr_preset.py +101 -0
- setiastro/saspro/wavescalede.py +683 -0
- setiastro/saspro/wavescalede_preset.py +230 -0
- setiastro/saspro/wcs_update.py +374 -0
- setiastro/saspro/whitebalance.py +540 -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/minigame/game.js +991 -0
- setiastro/saspro/widgets/minigame/index.html +53 -0
- setiastro/saspro/widgets/minigame/style.css +241 -0
- setiastro/saspro/widgets/preview_dialogs.py +280 -0
- setiastro/saspro/widgets/resource_monitor.py +313 -0
- setiastro/saspro/widgets/spinboxes.py +290 -0
- setiastro/saspro/widgets/themed_buttons.py +13 -0
- setiastro/saspro/widgets/wavelet_utils.py +331 -0
- setiastro/saspro/wimi.py +7367 -0
- setiastro/saspro/wims.py +588 -0
- setiastro/saspro/window_shelf.py +185 -0
- setiastro/saspro/xisf.py +1213 -0
- setiastrosuitepro-1.6.7.dist-info/METADATA +279 -0
- setiastrosuitepro-1.6.7.dist-info/RECORD +394 -0
- setiastrosuitepro-1.6.7.dist-info/WHEEL +4 -0
- setiastrosuitepro-1.6.7.dist-info/entry_points.txt +6 -0
- setiastrosuitepro-1.6.7.dist-info/licenses/LICENSE +674 -0
- setiastrosuitepro-1.6.7.dist-info/licenses/license.txt +2580 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Runtime hook for astroquery to prevent network downloads during import.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import tempfile
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
def setup_astroquery_offline():
|
|
11
|
+
"""Configure astroquery and astropy for offline operation."""
|
|
12
|
+
|
|
13
|
+
# Disable astropy data downloads
|
|
14
|
+
os.environ['ASTROPY_DOWNLOAD_CACHE_TIMEOUT'] = '0'
|
|
15
|
+
os.environ['ASTROPY_DOWNLOAD_BLOCK_SIZE'] = '0'
|
|
16
|
+
os.environ['ASTROQUERY_DOWNLOAD_CACHE_TIMEOUT'] = '0'
|
|
17
|
+
|
|
18
|
+
# Set up cache directories
|
|
19
|
+
if hasattr(sys, '_MEIPASS'):
|
|
20
|
+
# Running in PyInstaller bundle
|
|
21
|
+
cache_dir = os.path.join(tempfile.gettempdir(), 'astropy_cache')
|
|
22
|
+
os.makedirs(cache_dir, exist_ok=True)
|
|
23
|
+
os.environ['XDG_CACHE_HOME'] = cache_dir
|
|
24
|
+
|
|
25
|
+
# Create the missing query_criteria_fields.json file
|
|
26
|
+
try:
|
|
27
|
+
# Create minimal data that astroquery.simbad needs
|
|
28
|
+
query_criteria = {
|
|
29
|
+
"basic": [
|
|
30
|
+
"MAIN_ID", "RA", "DEC", "COO_ERR_MAJA", "COO_ERR_MINA",
|
|
31
|
+
"COO_ERR_ANGLE", "COO_QUAL", "COO_WAVELENGTH", "COO_BIBCODE"
|
|
32
|
+
],
|
|
33
|
+
"ids": ["ID"],
|
|
34
|
+
"biblio": ["BIBCODELIST"],
|
|
35
|
+
"measurements": ["FLUX", "FLUXDATA"],
|
|
36
|
+
"note": "Minimal data for offline PyInstaller bundle"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Create in multiple possible locations
|
|
40
|
+
locations = [
|
|
41
|
+
os.path.join(tempfile.gettempdir(), 'astropy_data'),
|
|
42
|
+
os.path.join(cache_dir, 'astropy', 'data'),
|
|
43
|
+
os.path.join(cache_dir, 'downloads'),
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
for loc in locations:
|
|
47
|
+
os.makedirs(loc, exist_ok=True)
|
|
48
|
+
query_file = os.path.join(loc, 'query_criteria_fields.json')
|
|
49
|
+
with open(query_file, 'w') as f:
|
|
50
|
+
json.dump(query_criteria, f, indent=2)
|
|
51
|
+
print(f"Created astroquery data file: {query_file}")
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
print(f"Warning: Could not create astroquery data files: {e}")
|
|
55
|
+
|
|
56
|
+
# Monkey patch astropy.utils.data.download_file BEFORE any imports
|
|
57
|
+
def patched_download_file(*args, **kwargs):
|
|
58
|
+
"""Patched download_file that returns a local fallback instead of downloading."""
|
|
59
|
+
|
|
60
|
+
# If it's asking for query_criteria_fields.json, return our local version
|
|
61
|
+
if len(args) > 0 and 'query_criteria_fields.json' in str(args[0]):
|
|
62
|
+
fallback_locations = [
|
|
63
|
+
os.path.join(tempfile.gettempdir(), 'astropy_data', 'query_criteria_fields.json'),
|
|
64
|
+
os.path.join(tempfile.gettempdir(), 'astropy_cache', 'astropy', 'data', 'query_criteria_fields.json'),
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
for fallback_file in fallback_locations:
|
|
68
|
+
if os.path.exists(fallback_file):
|
|
69
|
+
print(f"Using local astroquery data: {fallback_file}")
|
|
70
|
+
return fallback_file
|
|
71
|
+
|
|
72
|
+
# For other files, create a dummy file to prevent crashes
|
|
73
|
+
dummy_file = os.path.join(tempfile.gettempdir(), 'astropy_dummy.json')
|
|
74
|
+
if not os.path.exists(dummy_file):
|
|
75
|
+
with open(dummy_file, 'w') as f:
|
|
76
|
+
json.dump({"note": "Dummy file for offline operation"}, f)
|
|
77
|
+
|
|
78
|
+
return dummy_file
|
|
79
|
+
|
|
80
|
+
# Apply patches before any astropy/astroquery imports
|
|
81
|
+
try:
|
|
82
|
+
setup_astroquery_offline()
|
|
83
|
+
|
|
84
|
+
# Patch the download function early
|
|
85
|
+
import astropy.utils.data
|
|
86
|
+
if not hasattr(astropy.utils.data, '_original_download_file'):
|
|
87
|
+
astropy.utils.data._original_download_file = astropy.utils.data.download_file
|
|
88
|
+
astropy.utils.data.download_file = patched_download_file
|
|
89
|
+
print("✓ Patched astropy.utils.data.download_file for offline operation")
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"Warning: Could not fully patch astropy for offline operation: {e}")
|
|
93
|
+
# Continue anyway - the app might still work
|
|
94
|
+
|
|
95
|
+
print("✓ astroquery runtime hook applied")
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# pro/remove_green.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from PyQt6.QtCore import Qt
|
|
6
|
+
from PyQt6.QtWidgets import (
|
|
7
|
+
QDialog, QVBoxLayout, QLabel, QSlider, QHBoxLayout,
|
|
8
|
+
QPushButton, QMessageBox, QCheckBox, QComboBox
|
|
9
|
+
)
|
|
10
|
+
try:
|
|
11
|
+
import cv2
|
|
12
|
+
except Exception:
|
|
13
|
+
cv2 = None
|
|
14
|
+
|
|
15
|
+
# ---------- utils (now imported from shared location) ----------
|
|
16
|
+
from setiastro.saspro.widgets.image_utils import (
|
|
17
|
+
to_float01 as _to_float01,
|
|
18
|
+
extract_mask_from_document as _active_mask_array_from_doc
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def _ensure_rgb(arr: np.ndarray) -> np.ndarray | None:
|
|
22
|
+
"""Return float32 RGB [0..1] or None if impossible."""
|
|
23
|
+
a = _to_float01(arr)
|
|
24
|
+
if a.ndim == 2:
|
|
25
|
+
return None
|
|
26
|
+
if a.ndim == 3 and a.shape[2] == 1:
|
|
27
|
+
return None
|
|
28
|
+
if a.ndim == 3 and a.shape[2] >= 3:
|
|
29
|
+
return a[..., :3].astype(np.float32, copy=False)
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
# ---------- SCNR core (with modes + preserve lightness) ----------
|
|
33
|
+
_SCNR_MODE_LABELS = {
|
|
34
|
+
"avg": "Average(R,B)",
|
|
35
|
+
"max": "Max(R,B)",
|
|
36
|
+
"min": "Min(R,B)",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def _compute_neutral(r: np.ndarray, b: np.ndarray, mode: str) -> np.ndarray:
|
|
40
|
+
if mode == "max":
|
|
41
|
+
return np.maximum(r, b)
|
|
42
|
+
elif mode == "min":
|
|
43
|
+
return np.minimum(r, b)
|
|
44
|
+
# default "avg"
|
|
45
|
+
return (r + b) * 0.5
|
|
46
|
+
|
|
47
|
+
def _apply_scnr_rgb(rgb: np.ndarray, amount: float, mode: str = "avg", preserve_lightness: bool = True) -> np.ndarray:
|
|
48
|
+
"""
|
|
49
|
+
SCNR green suppression:
|
|
50
|
+
G' = G - amount * max(0, G - neutral)
|
|
51
|
+
where neutral is avg/max/min of (R,B) depending on mode.
|
|
52
|
+
|
|
53
|
+
If preserve_lightness=True:
|
|
54
|
+
compute per-pixel scale s = Y_before / Y_after (Rec.709 luma),
|
|
55
|
+
cap s so that no channel exceeds 1.0, and multiply ALL channels by s.
|
|
56
|
+
"""
|
|
57
|
+
rgb = np.clip(rgb.astype(np.float32, copy=False), 0.0, 1.0)
|
|
58
|
+
R, G, B = rgb[..., 0], rgb[..., 1], rgb[..., 2]
|
|
59
|
+
|
|
60
|
+
# choose neutral comparator (avg/max/min of R,B)
|
|
61
|
+
neutral = _compute_neutral(R, B, mode)
|
|
62
|
+
excess = np.maximum(0.0, G - neutral)
|
|
63
|
+
G_new = np.clip(G - float(np.clip(amount, 0.0, 1.0)) * excess, 0.0, 1.0)
|
|
64
|
+
|
|
65
|
+
out = np.stack([R, G_new, B], axis=-1)
|
|
66
|
+
|
|
67
|
+
if not preserve_lightness:
|
|
68
|
+
return out
|
|
69
|
+
|
|
70
|
+
# ---- preserve perceived lightness (scale ALL channels equally) ----
|
|
71
|
+
wR, wG, wB = 0.2126, 0.7152, 0.0722
|
|
72
|
+
Y_before = wR * R + wG * G + wB * B
|
|
73
|
+
Y_after = wR * out[..., 0] + wG * out[..., 1] + wB * out[..., 2]
|
|
74
|
+
|
|
75
|
+
eps = 1e-8
|
|
76
|
+
scale = Y_before / np.maximum(Y_after, eps)
|
|
77
|
+
|
|
78
|
+
# highlight safety: prevent any channel from exceeding 1.0 after scaling
|
|
79
|
+
maxc = np.max(out, axis=2) # current per-pixel max channel
|
|
80
|
+
cap = np.where(maxc > 0.0, 1.0 / np.maximum(maxc, eps), 1.0)
|
|
81
|
+
scale = np.minimum(scale, cap)
|
|
82
|
+
|
|
83
|
+
out = np.clip(out * scale[..., None], 0.0, 1.0)
|
|
84
|
+
return out
|
|
85
|
+
|
|
86
|
+
# ---------- headless core ----------
|
|
87
|
+
def remove_green_headless(
|
|
88
|
+
doc,
|
|
89
|
+
amount: float = 1.0,
|
|
90
|
+
mode: str = "avg", # "avg" | "max" | "min"
|
|
91
|
+
preserve_lightness: bool = True,
|
|
92
|
+
):
|
|
93
|
+
"""
|
|
94
|
+
Run SCNR on doc.image (RGB only), blend with active mask if present, push as undoable edit.
|
|
95
|
+
"""
|
|
96
|
+
if doc is None or getattr(doc, "image", None) is None:
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
src = np.asarray(doc.image)
|
|
100
|
+
rgb = _ensure_rgb(src)
|
|
101
|
+
if rgb is None:
|
|
102
|
+
try:
|
|
103
|
+
doc.apply_edit(src.astype(np.float32, copy=False),
|
|
104
|
+
metadata={"step_name": "Remove Green (no-op non-RGB)"},
|
|
105
|
+
step_name="Remove Green")
|
|
106
|
+
except Exception:
|
|
107
|
+
pass
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
amt = float(max(0.0, min(1.0, amount)))
|
|
111
|
+
mode = (mode or "avg").lower()
|
|
112
|
+
if mode not in ("avg", "max", "min"):
|
|
113
|
+
mode = "avg"
|
|
114
|
+
|
|
115
|
+
processed = _apply_scnr_rgb(rgb, amt, mode=mode, preserve_lightness=preserve_lightness)
|
|
116
|
+
|
|
117
|
+
# put processed back into original shape if source had >=3 channels
|
|
118
|
+
if src.ndim == 3 and src.shape[2] > 3:
|
|
119
|
+
out = src.astype(np.float32, copy=True)
|
|
120
|
+
out[..., :3] = processed
|
|
121
|
+
else:
|
|
122
|
+
out = processed
|
|
123
|
+
|
|
124
|
+
# mask-aware blend (mask from destination doc)
|
|
125
|
+
m = _active_mask_array_from_doc(doc)
|
|
126
|
+
if m is not None:
|
|
127
|
+
h, w = out.shape[:2]
|
|
128
|
+
if m.shape != (h, w):
|
|
129
|
+
if cv2 is not None:
|
|
130
|
+
m = cv2.resize(m, (w, h), interpolation=cv2.INTER_NEAREST)
|
|
131
|
+
else:
|
|
132
|
+
yi = (np.linspace(0, m.shape[0]-1, h)).astype(np.int32)
|
|
133
|
+
xi = (np.linspace(0, m.shape[1]-1, w)).astype(np.int32)
|
|
134
|
+
m = m[yi][:, xi]
|
|
135
|
+
if out.ndim == 3:
|
|
136
|
+
m = np.repeat(m[:, :, None], out.shape[2], axis=2)
|
|
137
|
+
src_f = _to_float01(src)
|
|
138
|
+
out = np.clip(src_f * (1.0 - m) + out * m, 0.0, 1.0)
|
|
139
|
+
|
|
140
|
+
meta = {
|
|
141
|
+
"step_name": "Remove Green",
|
|
142
|
+
"remove_green": {
|
|
143
|
+
"amount": amt,
|
|
144
|
+
"mode": mode,
|
|
145
|
+
"preserve_lightness": bool(preserve_lightness),
|
|
146
|
+
"mode_label": _SCNR_MODE_LABELS.get(mode, "Average(R,B)"),
|
|
147
|
+
},
|
|
148
|
+
"bit_depth": "32-bit floating point",
|
|
149
|
+
"is_mono": (out.ndim == 2),
|
|
150
|
+
}
|
|
151
|
+
doc.apply_edit(out.astype(np.float32, copy=False), metadata=meta, step_name="Remove Green")
|
|
152
|
+
|
|
153
|
+
# ---------- dialog ----------
|
|
154
|
+
class RemoveGreenDialog(QDialog):
|
|
155
|
+
def __init__(self, main, doc, parent=None):
|
|
156
|
+
super().__init__(parent)
|
|
157
|
+
self.main = main
|
|
158
|
+
self.doc = doc
|
|
159
|
+
self.setWindowTitle(self.tr("Remove Green (SCNR)"))
|
|
160
|
+
self.setWindowFlag(Qt.WindowType.Window, True)
|
|
161
|
+
self.setWindowModality(Qt.WindowModality.NonModal)
|
|
162
|
+
self.setModal(False)
|
|
163
|
+
self._build_ui()
|
|
164
|
+
|
|
165
|
+
def _build_ui(self):
|
|
166
|
+
lay = QVBoxLayout(self)
|
|
167
|
+
lay.addWidget(QLabel(self.tr("Select the amount to remove green noise:")))
|
|
168
|
+
|
|
169
|
+
# amount
|
|
170
|
+
self.slider = QSlider(Qt.Orientation.Horizontal)
|
|
171
|
+
self.slider.setRange(0, 100)
|
|
172
|
+
self.slider.setValue(100)
|
|
173
|
+
self.slider.setTickInterval(10)
|
|
174
|
+
self.slider.setTickPosition(QSlider.TickPosition.TicksBelow)
|
|
175
|
+
self.value_label = QLabel("Amount: 1.00")
|
|
176
|
+
self.slider.valueChanged.connect(lambda v: self.value_label.setText(f"Amount: {v/100.0:.2f}"))
|
|
177
|
+
lay.addWidget(self.slider)
|
|
178
|
+
lay.addWidget(self.value_label)
|
|
179
|
+
|
|
180
|
+
# mode dropdown
|
|
181
|
+
row_mode = QHBoxLayout()
|
|
182
|
+
row_mode.addWidget(QLabel(self.tr("Neutral mode:")))
|
|
183
|
+
self.mode_box = QComboBox()
|
|
184
|
+
# order: avg (default), max, min
|
|
185
|
+
self.mode_box.addItem(_SCNR_MODE_LABELS["avg"], userData="avg")
|
|
186
|
+
self.mode_box.addItem(_SCNR_MODE_LABELS["max"], userData="max")
|
|
187
|
+
self.mode_box.addItem(_SCNR_MODE_LABELS["min"], userData="min")
|
|
188
|
+
self.mode_box.setCurrentIndex(0)
|
|
189
|
+
row_mode.addWidget(self.mode_box)
|
|
190
|
+
row_mode.addStretch(1)
|
|
191
|
+
lay.addLayout(row_mode)
|
|
192
|
+
|
|
193
|
+
# preserve lightness
|
|
194
|
+
self.cb_preserve = QCheckBox(self.tr("Preserve lightness"))
|
|
195
|
+
self.cb_preserve.setChecked(True)
|
|
196
|
+
lay.addWidget(self.cb_preserve)
|
|
197
|
+
|
|
198
|
+
# buttons
|
|
199
|
+
row = QHBoxLayout()
|
|
200
|
+
btn_apply = QPushButton(self.tr("Apply")); btn_apply.clicked.connect(self._apply)
|
|
201
|
+
btn_cancel= QPushButton(self.tr("Cancel")); btn_cancel.clicked.connect(self.reject)
|
|
202
|
+
row.addStretch(1); row.addWidget(btn_apply); row.addWidget(btn_cancel)
|
|
203
|
+
lay.addLayout(row)
|
|
204
|
+
|
|
205
|
+
self.resize(460, 200)
|
|
206
|
+
|
|
207
|
+
def set_amount(self, amt: float):
|
|
208
|
+
try:
|
|
209
|
+
self.slider.setValue(int(round(max(0.0, min(1.0, float(amt))) * 100)))
|
|
210
|
+
except Exception:
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
def set_mode(self, mode: str | None):
|
|
214
|
+
m = (mode or "avg").lower()
|
|
215
|
+
idx = {"avg":0, "max":1, "min":2}.get(m, 0)
|
|
216
|
+
try:
|
|
217
|
+
self.mode_box.setCurrentIndex(idx)
|
|
218
|
+
except Exception:
|
|
219
|
+
pass
|
|
220
|
+
|
|
221
|
+
def set_preserve_lightness(self, preserve: bool | None):
|
|
222
|
+
try:
|
|
223
|
+
self.cb_preserve.setChecked(True if preserve is None else bool(preserve))
|
|
224
|
+
except Exception:
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
def _apply(self):
|
|
228
|
+
if self.doc is None or getattr(self.doc, "image", None) is None:
|
|
229
|
+
QMessageBox.warning(self, "Remove Green", "No image.")
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
amount = self.slider.value() / 100.0
|
|
233
|
+
mode = self.mode_box.currentData() or "avg"
|
|
234
|
+
preserve = self.cb_preserve.isChecked()
|
|
235
|
+
|
|
236
|
+
# Build a preset dict so headless + replay use the same schema
|
|
237
|
+
preset = {
|
|
238
|
+
"amount": float(amount),
|
|
239
|
+
"mode": str(mode),
|
|
240
|
+
"preserve_lightness": bool(preserve),
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
# Apply to this doc
|
|
244
|
+
remove_green_headless(self.doc, amount=amount, mode=mode, preserve_lightness=preserve)
|
|
245
|
+
|
|
246
|
+
# Log + record for Replay Last Action (if main supports it)
|
|
247
|
+
if hasattr(self.main, "_log"):
|
|
248
|
+
self.main._log(
|
|
249
|
+
f"Remove Green: amount={amount:.2f}, mode={mode}, "
|
|
250
|
+
f"preserve_lightness={preserve}"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
# stash last headless-style command
|
|
255
|
+
self.main._last_headless_command = {
|
|
256
|
+
"command_id": "remove_green",
|
|
257
|
+
"preset": dict(preset),
|
|
258
|
+
}
|
|
259
|
+
if hasattr(self.main, "_log"):
|
|
260
|
+
self.main._log(
|
|
261
|
+
f"[Replay] Recorded Remove Green preset "
|
|
262
|
+
f"(amount={amount:.2f}, mode={mode}, "
|
|
263
|
+
f"preserve_lightness={preserve})"
|
|
264
|
+
)
|
|
265
|
+
except Exception:
|
|
266
|
+
# Never let replay bookkeeping kill the dialog
|
|
267
|
+
pass
|
|
268
|
+
|
|
269
|
+
# Dialog stays open so user can apply to other images
|
|
270
|
+
# Refresh document reference for next operation
|
|
271
|
+
self._refresh_document_from_active()
|
|
272
|
+
|
|
273
|
+
def _refresh_document_from_active(self):
|
|
274
|
+
"""
|
|
275
|
+
Refresh the dialog's document reference to the currently active document.
|
|
276
|
+
This allows reusing the same dialog on different images.
|
|
277
|
+
"""
|
|
278
|
+
try:
|
|
279
|
+
if self.main and hasattr(self.main, "_active_doc"):
|
|
280
|
+
new_doc = self.main._active_doc()
|
|
281
|
+
if new_doc is not None and new_doc is not self.doc:
|
|
282
|
+
self.doc = new_doc
|
|
283
|
+
except Exception:
|
|
284
|
+
pass
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
# ---------- entry points used by main ----------
|
|
288
|
+
def open_remove_green_dialog(main, doc=None, preset: dict | None = None):
|
|
289
|
+
"""
|
|
290
|
+
Open the Remove Green dialog for a specific document.
|
|
291
|
+
|
|
292
|
+
If doc is None, we fall back to main._active_doc for legacy callers.
|
|
293
|
+
"""
|
|
294
|
+
from PyQt6.QtWidgets import QMessageBox
|
|
295
|
+
|
|
296
|
+
if doc is None:
|
|
297
|
+
doc = getattr(main, "_active_doc", None)
|
|
298
|
+
if callable(doc):
|
|
299
|
+
doc = doc()
|
|
300
|
+
|
|
301
|
+
if doc is None or getattr(doc, "image", None) is None:
|
|
302
|
+
QMessageBox.information(main, "Remove Green", "Open an image first.")
|
|
303
|
+
return
|
|
304
|
+
|
|
305
|
+
dlg = RemoveGreenDialog(main, doc, parent=main)
|
|
306
|
+
|
|
307
|
+
if preset:
|
|
308
|
+
amt = preset.get("amount", preset.get("strength", preset.get("value", None)))
|
|
309
|
+
if amt is not None:
|
|
310
|
+
dlg.set_amount(float(amt))
|
|
311
|
+
|
|
312
|
+
mode = preset.get("mode", preset.get("neutral_mode"))
|
|
313
|
+
if mode is not None:
|
|
314
|
+
dlg.set_mode(str(mode))
|
|
315
|
+
|
|
316
|
+
preserve = preset.get("preserve_lightness", preset.get("preserve", True))
|
|
317
|
+
dlg.set_preserve_lightness(bool(preserve))
|
|
318
|
+
|
|
319
|
+
dlg.show()
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def apply_remove_green_preset_to_doc(main, doc, preset: dict):
|
|
323
|
+
amt = float(preset.get("amount", preset.get("strength", preset.get("value", 1.0))))
|
|
324
|
+
mode = str(preset.get("mode", preset.get("neutral_mode", "avg"))).lower()
|
|
325
|
+
preserve = bool(preset.get("preserve_lightness", preset.get("preserve", True)))
|
|
326
|
+
remove_green_headless(doc, amount=amt, mode=mode, preserve_lightness=preserve)
|
|
327
|
+
if hasattr(main, "_log"):
|
|
328
|
+
name = doc.display_name() if hasattr(doc, "display_name") else "Image"
|
|
329
|
+
main._log(
|
|
330
|
+
f"Remove Green (headless) on '{name}'; amount={amt:.2f}, mode={mode}, preserve_lightness={preserve}"
|
|
331
|
+
)
|