graxpert 3.2.0a0.dev4__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.
- graxpert/AstroImageRepository.py +114 -0
- graxpert/__init__.py +1 -0
- graxpert/ai_model_handling.py +215 -0
- graxpert/app_state.py +10 -0
- graxpert/application/__init__.py +0 -0
- graxpert/application/app.py +741 -0
- graxpert/application/app_events.py +96 -0
- graxpert/application/eventbus.py +24 -0
- graxpert/astroimage.py +308 -0
- graxpert/background_extraction.py +290 -0
- graxpert/background_flood_selection.py +240 -0
- graxpert/background_grid_selection.py +64 -0
- graxpert/cmdline_tools.py +547 -0
- graxpert/commands.py +200 -0
- graxpert/deconvolution.py +176 -0
- graxpert/denoising.py +178 -0
- graxpert/grid_utils.py +38 -0
- graxpert/img/GraXpert_LOGO_Hauptvariante.png +0 -0
- graxpert/img/Icon.png +0 -0
- graxpert/img/LDN1235_original.jpg +0 -0
- graxpert/img/LDN1235_processed.jpg +0 -0
- graxpert/img/__init__.py +0 -0
- graxpert/img/gfx_numbers.png +0 -0
- graxpert/img/gfx_numbers.svg +737 -0
- graxpert/img/graXpert_Startbadge_Umbriel.png +0 -0
- graxpert/img/hourglass.png +0 -0
- graxpert/locales/__init__.py +0 -0
- graxpert/locales/de_DE/LC_MESSAGES/base.mo +0 -0
- graxpert/localization.py +39 -0
- graxpert/main.py +441 -0
- graxpert/mp_logging.py +97 -0
- graxpert/parallel_processing.py +3 -0
- graxpert/preferences.py +139 -0
- graxpert/radialbasisinterpolation.py +215 -0
- graxpert/resource_utils.py +35 -0
- graxpert/s3_secrets.py +16 -0
- graxpert/skyall.py +152 -0
- graxpert/stretch.py +151 -0
- graxpert/theme/__init__.py +0 -0
- graxpert/theme/graxpert-dark-blue.json +367 -0
- graxpert/ui/__init__.py +1 -0
- graxpert/ui/application_frame.py +115 -0
- graxpert/ui/canvas.py +558 -0
- graxpert/ui/left_menu.py +437 -0
- graxpert/ui/loadingframe.py +142 -0
- graxpert/ui/right_menu.py +315 -0
- graxpert/ui/statusbar.py +102 -0
- graxpert/ui/styling.py +23 -0
- graxpert/ui/tooltip.py +194 -0
- graxpert/ui/ui_events.py +19 -0
- graxpert/ui/widgets.py +297 -0
- graxpert/ui_scaling.py +13 -0
- graxpert/version.py +2 -0
- graxpert-3.2.0a0.dev4.dist-info/METADATA +219 -0
- graxpert-3.2.0a0.dev4.dist-info/RECORD +58 -0
- graxpert-3.2.0a0.dev4.dist-info/WHEEL +5 -0
- graxpert-3.2.0a0.dev4.dist-info/entry_points.txt +2 -0
- graxpert-3.2.0a0.dev4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from enum import Enum, auto
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AppEvents(Enum):
|
|
5
|
+
# image loading
|
|
6
|
+
OPEN_FILE_DIALOG_REQUEST = auto()
|
|
7
|
+
LOAD_IMAGE_REQUEST = auto()
|
|
8
|
+
LOAD_IMAGE_BEGIN = auto()
|
|
9
|
+
LOAD_IMAGE_END = auto()
|
|
10
|
+
LOAD_IMAGE_ERROR = auto()
|
|
11
|
+
# image stretching
|
|
12
|
+
STRETCH_IMAGE_BEGIN = auto()
|
|
13
|
+
STRETCH_IMAGE_END = auto()
|
|
14
|
+
STRETCH_IMAGE_ERROR = auto()
|
|
15
|
+
# image saturation
|
|
16
|
+
CHANGE_SATURATION_REQUEST = auto()
|
|
17
|
+
CHANGE_SATURATION_BEGIN = auto()
|
|
18
|
+
CHANGE_SATURATION_END = auto()
|
|
19
|
+
# image display
|
|
20
|
+
UPDATE_DISPLAY_TYPE_REEQUEST = auto()
|
|
21
|
+
DISPLAY_TYPE_CHANGED = auto()
|
|
22
|
+
REDRAW_POINTS_REQUEST = auto()
|
|
23
|
+
# stretch options
|
|
24
|
+
STRETCH_OPTION_CHANGED = auto()
|
|
25
|
+
CHANNELS_LINKED_CHANGED = auto()
|
|
26
|
+
# sample selection
|
|
27
|
+
DISPLAY_PTS_CHANGED = auto()
|
|
28
|
+
BG_FLOOD_SELECTION_CHANGED = auto()
|
|
29
|
+
BG_PTS_CHANGED = auto()
|
|
30
|
+
BG_TOL_CHANGED = auto()
|
|
31
|
+
CREATE_GRID_REQUEST = auto()
|
|
32
|
+
CREATE_GRID_BEGIN = auto()
|
|
33
|
+
CREATE_GRID_END = auto()
|
|
34
|
+
RESET_POITS_REQUEST = auto()
|
|
35
|
+
RESET_POITS_BEGIN = auto()
|
|
36
|
+
RESET_POITS_END = auto()
|
|
37
|
+
# calculation
|
|
38
|
+
INTERPOL_TYPE_CHANGED = auto()
|
|
39
|
+
SMOTTHING_CHANGED = auto()
|
|
40
|
+
CALCULATE_REQUEST = auto()
|
|
41
|
+
CALCULATE_BEGIN = auto()
|
|
42
|
+
CALCULATE_PROGRESS = auto()
|
|
43
|
+
CALCULATE_END = auto()
|
|
44
|
+
CALCULATE_SUCCESS = auto()
|
|
45
|
+
CALCULATE_ERROR = auto()
|
|
46
|
+
# deconvolution
|
|
47
|
+
DECONVOLUTION_TYPE_CHANGED = auto()
|
|
48
|
+
DECONVOLUTION_STRENGTH_CHANGED = auto()
|
|
49
|
+
DECONVOLUTION_PSFSIZE_CHANGED = auto()
|
|
50
|
+
DECONVOLUTION_OPERATION_CHANGED = auto()
|
|
51
|
+
DECONVOLUTION_REQUEST = auto()
|
|
52
|
+
DECONVOLUTION_BEGIN = auto()
|
|
53
|
+
DECONVOLUTION_PROGRESS = auto()
|
|
54
|
+
DECONVOLUTION_END = auto()
|
|
55
|
+
DECONVOLUTION_SUCCESS = auto()
|
|
56
|
+
DECONVOLUTION_ERROR = auto()
|
|
57
|
+
# denoising
|
|
58
|
+
DENOISE_STRENGTH_CHANGED = auto()
|
|
59
|
+
DENOISE_THRESHOLD_CHANGED = auto()
|
|
60
|
+
DENOISE_REQUEST = auto()
|
|
61
|
+
DENOISE_BEGIN = auto()
|
|
62
|
+
DENOISE_PROGRESS = auto()
|
|
63
|
+
DENOISE_END = auto()
|
|
64
|
+
DENOISE_SUCCESS = auto()
|
|
65
|
+
DENOISE_ERROR = auto()
|
|
66
|
+
# saving
|
|
67
|
+
SAVE_AS_CHANGED = auto()
|
|
68
|
+
SAVE_STRETCHED_CHANGED = auto()
|
|
69
|
+
SAVE_REQUEST = auto()
|
|
70
|
+
SAVE_BEGIN = auto()
|
|
71
|
+
SAVE_END = auto()
|
|
72
|
+
SAVE_ERROR = auto()
|
|
73
|
+
# ai model handling
|
|
74
|
+
AI_DOWNLOAD_BEGIN = auto()
|
|
75
|
+
AI_DOWNLOAD_PROGRESS = auto()
|
|
76
|
+
AI_DOWNLOAD_END = auto()
|
|
77
|
+
AI_DOWNLOAD_ERROR = auto()
|
|
78
|
+
# bge ai model handling
|
|
79
|
+
BGE_AI_VERSION_CHANGED = auto()
|
|
80
|
+
# denoise ai model handling
|
|
81
|
+
DECONVOLUTION_OBJECT_AI_VERSION_CHANGED = auto()
|
|
82
|
+
DECONVOLUTION_STARS_AI_VERSION_CHANGED = auto()
|
|
83
|
+
# denoise ai model handling
|
|
84
|
+
DENOISE_AI_VERSION_CHANGED = auto()
|
|
85
|
+
# advanced settings
|
|
86
|
+
SAMPLE_SIZE_CHANGED = auto()
|
|
87
|
+
SAMPLE_COLOR_CHANGED = auto()
|
|
88
|
+
RBF_KERNEL_CHANGED = auto()
|
|
89
|
+
SPLINE_ORDER_CHANGED = auto()
|
|
90
|
+
CORRECTION_TYPE_CHANGED = auto()
|
|
91
|
+
LANGUAGE_CHANGED = auto()
|
|
92
|
+
SCALING_CHANGED = auto()
|
|
93
|
+
AI_BATCH_SIZE_CHANGED = auto()
|
|
94
|
+
AI_GPU_ACCELERATION_CHANGED = auto()
|
|
95
|
+
# process control
|
|
96
|
+
CANCEL_PROCESSING = auto()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class EventBus:
|
|
2
|
+
def __init__(self):
|
|
3
|
+
self.listeners = {}
|
|
4
|
+
# self.loop = asyncio.get_event_loop()
|
|
5
|
+
|
|
6
|
+
def add_listener(self, event_name, listener):
|
|
7
|
+
if not self.listeners.get(event_name, None):
|
|
8
|
+
self.listeners[event_name] = [listener]
|
|
9
|
+
else:
|
|
10
|
+
if not listener in self.listeners[event_name]:
|
|
11
|
+
self.listeners[event_name].insert(0, listener)
|
|
12
|
+
|
|
13
|
+
def remove_listener(self, event_name, listener):
|
|
14
|
+
self.listeners[event_name].remove(listener)
|
|
15
|
+
if len(self.listeners[event_name]) == 0:
|
|
16
|
+
del self.listeners[event_name]
|
|
17
|
+
|
|
18
|
+
def emit(self, event_name, event=None):
|
|
19
|
+
listeners = self.listeners.get(event_name, [])
|
|
20
|
+
for listener in listeners:
|
|
21
|
+
listener(event)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
eventbus = EventBus()
|
graxpert/astroimage.py
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from astropy.io import fits
|
|
7
|
+
from PIL import Image, ImageEnhance
|
|
8
|
+
from skimage import exposure, img_as_float32, io
|
|
9
|
+
from skimage.util import img_as_uint
|
|
10
|
+
from xisf import XISF
|
|
11
|
+
|
|
12
|
+
from graxpert.app_state import AppState
|
|
13
|
+
from graxpert.preferences import Prefs, app_state_2_fitsheader
|
|
14
|
+
from graxpert.stretch import stretch, StretchParameters
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AstroImage:
|
|
18
|
+
def __init__(self, do_update_display=True):
|
|
19
|
+
self.img_array = None
|
|
20
|
+
self.img_display = None
|
|
21
|
+
self.img_display_saturated = None
|
|
22
|
+
self.img_format = None
|
|
23
|
+
self.fits_header = None
|
|
24
|
+
self.xisf_metadata = {}
|
|
25
|
+
self.image_metadata = {"FITSKeywords": {}}
|
|
26
|
+
self.do_update_display = do_update_display
|
|
27
|
+
self.width = 0
|
|
28
|
+
self.height = 0
|
|
29
|
+
self.roworder = "BOTTOM-UP"
|
|
30
|
+
|
|
31
|
+
def set_from_file(self, directory: str, stretch_params: StretchParameters, saturation: float):
|
|
32
|
+
self.img_format = os.path.splitext(directory)[1].lower()
|
|
33
|
+
|
|
34
|
+
img_array = None
|
|
35
|
+
if self.img_format == ".fits" or self.img_format == ".fit" or self.img_format == ".fts":
|
|
36
|
+
hdul = fits.open(directory)
|
|
37
|
+
img_array = np.copy(hdul[0].data)
|
|
38
|
+
self.fits_header = hdul[0].header
|
|
39
|
+
hdul.close()
|
|
40
|
+
|
|
41
|
+
if len(img_array.shape) == 3:
|
|
42
|
+
img_array = np.moveaxis(img_array, 0, -1)
|
|
43
|
+
|
|
44
|
+
if "ROWORDER" in self.fits_header:
|
|
45
|
+
self.roworder = self.fits_header["ROWORDER"]
|
|
46
|
+
|
|
47
|
+
elif self.img_format == ".xisf":
|
|
48
|
+
xisf = XISF(directory)
|
|
49
|
+
self.xisf_metadata = xisf.get_file_metadata()
|
|
50
|
+
self.image_metadata = xisf.get_images_metadata()[0]
|
|
51
|
+
self.fits_header = fits.Header()
|
|
52
|
+
self.xisf_imagedata_2_fitsheader()
|
|
53
|
+
img_array = np.copy(xisf.read_image(0))
|
|
54
|
+
|
|
55
|
+
entry = {"id": "GraXpert:ProcessingHistory", "type": "String", "value": "BackgroundExtraction"}
|
|
56
|
+
self.image_metadata["XISFProperties"]["GraXpert:ProcessingHistory"] = entry
|
|
57
|
+
|
|
58
|
+
else:
|
|
59
|
+
img_array = np.copy(io.imread(directory))
|
|
60
|
+
self.fits_header = fits.Header()
|
|
61
|
+
|
|
62
|
+
# Reshape greyscale picture to shape (y,x,1)
|
|
63
|
+
if len(img_array.shape) == 2:
|
|
64
|
+
img_array = np.array([img_array])
|
|
65
|
+
img_array = np.moveaxis(img_array, 0, -1)
|
|
66
|
+
|
|
67
|
+
# Use 32 bit float with range (0,1) for internal calculations
|
|
68
|
+
img_array = img_as_float32(img_array)
|
|
69
|
+
|
|
70
|
+
if np.min(img_array) < 0 or np.max(img_array > 1):
|
|
71
|
+
img_array = exposure.rescale_intensity(img_array, out_range=(0, 1))
|
|
72
|
+
|
|
73
|
+
self.img_array = img_array
|
|
74
|
+
self.width = self.img_array.shape[1]
|
|
75
|
+
self.height = self.img_array.shape[0]
|
|
76
|
+
|
|
77
|
+
if self.do_update_display:
|
|
78
|
+
self.update_display(stretch_params, saturation)
|
|
79
|
+
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
def set_from_array(self, array):
|
|
83
|
+
self.img_array = array
|
|
84
|
+
self.width = self.img_array.shape[1]
|
|
85
|
+
self.height = self.img_array.shape[0]
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
def update_display(self, stretch_params: StretchParameters, saturation: float):
|
|
89
|
+
img_display = self.stretch(stretch_params)
|
|
90
|
+
img_display = img_display * 255
|
|
91
|
+
|
|
92
|
+
# if self.roworder == "TOP-DOWN":
|
|
93
|
+
# img_display = np.flip(img_display, axis=0)
|
|
94
|
+
|
|
95
|
+
if img_display.shape[2] == 1:
|
|
96
|
+
self.img_display = Image.fromarray(img_display[:, :, 0].astype(np.uint8))
|
|
97
|
+
else:
|
|
98
|
+
self.img_display = Image.fromarray(img_display.astype(np.uint8))
|
|
99
|
+
|
|
100
|
+
self.update_saturation(saturation)
|
|
101
|
+
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
def update_display_from_array(self, img_display, saturation):
|
|
105
|
+
img_display = img_display * 255
|
|
106
|
+
|
|
107
|
+
# if self.roworder == "TOP-DOWN":
|
|
108
|
+
# img_display = np.flip(img_display, axis=0)
|
|
109
|
+
|
|
110
|
+
if img_display.shape[2] == 1:
|
|
111
|
+
self.img_display = Image.fromarray(img_display[:, :, 0].astype(np.uint8))
|
|
112
|
+
else:
|
|
113
|
+
self.img_display = Image.fromarray(img_display.astype(np.uint8))
|
|
114
|
+
|
|
115
|
+
self.update_saturation(saturation)
|
|
116
|
+
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
def stretch(self, stretch_params: StretchParameters):
|
|
120
|
+
if stretch_params.do_stretch:
|
|
121
|
+
return np.clip(stretch(self.img_array, stretch_params), 0.0, 1.0)
|
|
122
|
+
else:
|
|
123
|
+
return np.clip(self.img_array, 0.0, 1.0)
|
|
124
|
+
|
|
125
|
+
def crop(self, startx, endx, starty, endy):
|
|
126
|
+
self.img_array = self.img_array[starty:endy, startx:endx, :]
|
|
127
|
+
self.img_display = self.img_display.crop((startx, starty, endx, endy))
|
|
128
|
+
self.img_display_saturated = self.img_display_saturated.crop((startx, starty, endx, endy))
|
|
129
|
+
self.width = self.img_array.shape[1]
|
|
130
|
+
self.height = self.img_array.shape[0]
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
def update_fits_header(self, original_header, background_mean, prefs: Prefs, app_state: AppState):
|
|
134
|
+
if original_header is None:
|
|
135
|
+
self.fits_header = fits.Header()
|
|
136
|
+
else:
|
|
137
|
+
self.fits_header = original_header
|
|
138
|
+
|
|
139
|
+
self.fits_header["BG-EXTR"] = "GraXpert"
|
|
140
|
+
self.fits_header["CBG-1"] = background_mean
|
|
141
|
+
self.fits_header["CBG-2"] = background_mean
|
|
142
|
+
self.fits_header["CBG-3"] = background_mean
|
|
143
|
+
self.fits_header = app_state_2_fitsheader(prefs, app_state, self.fits_header)
|
|
144
|
+
|
|
145
|
+
if "ROWORDER" in self.fits_header:
|
|
146
|
+
self.roworder = self.fits_header["ROWORDER"]
|
|
147
|
+
|
|
148
|
+
def save(self, dir, saveas_type):
|
|
149
|
+
if self.img_array is None:
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
if saveas_type == "16 bit Tiff" or saveas_type == "16 bit Fits" or saveas_type == "16 bit XISF":
|
|
153
|
+
image_converted = img_as_uint(self.img_array)
|
|
154
|
+
else:
|
|
155
|
+
image_converted = self.img_array.astype(np.float32)
|
|
156
|
+
|
|
157
|
+
if saveas_type != "16 bit XISF" and saveas_type != "32 bit XISF":
|
|
158
|
+
if image_converted.shape[-1] == 3:
|
|
159
|
+
if saveas_type == "16 bit Fits" or saveas_type == "32 bit Fits":
|
|
160
|
+
image_converted = np.moveaxis(image_converted, -1, 0)
|
|
161
|
+
else:
|
|
162
|
+
image_converted = image_converted[:, :, 0]
|
|
163
|
+
|
|
164
|
+
if saveas_type == "16 bit Tiff" or saveas_type == "32 bit Tiff":
|
|
165
|
+
io.imsave(dir, image_converted)
|
|
166
|
+
|
|
167
|
+
elif saveas_type == "16 bit XISF" or saveas_type == "32 bit XISF":
|
|
168
|
+
self.update_xisf_imagedata()
|
|
169
|
+
XISF.write(dir, image_converted, creator_app="GraXpert", image_metadata=self.image_metadata, xisf_metadata=self.xisf_metadata)
|
|
170
|
+
else:
|
|
171
|
+
hdu = fits.PrimaryHDU(data=image_converted, header=self.fits_header)
|
|
172
|
+
hdul = fits.HDUList([hdu])
|
|
173
|
+
hdul.writeto(dir, output_verify="warn", overwrite=True)
|
|
174
|
+
hdul.close()
|
|
175
|
+
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
def save_stretched(self, dir, saveas_type, stretch_params):
|
|
179
|
+
if self.img_array is None:
|
|
180
|
+
return
|
|
181
|
+
|
|
182
|
+
if self.fits_header is not None:
|
|
183
|
+
self.fits_header["STRETCH"] = stretch_params.stretch_option
|
|
184
|
+
|
|
185
|
+
stretched_img = self.stretch(stretch_params)
|
|
186
|
+
|
|
187
|
+
if saveas_type == "16 bit Tiff" or saveas_type == "16 bit Fits" or saveas_type == "16 bit XISF":
|
|
188
|
+
image_converted = img_as_uint(stretched_img)
|
|
189
|
+
else:
|
|
190
|
+
image_converted = stretched_img.astype(np.float32)
|
|
191
|
+
|
|
192
|
+
if saveas_type != "16 bit XISF" and saveas_type != "32 bit XISF":
|
|
193
|
+
if image_converted.shape[-1] == 3:
|
|
194
|
+
if saveas_type == "16 bit Fits" or saveas_type == "32 bit Fits":
|
|
195
|
+
image_converted = np.moveaxis(image_converted, -1, 0)
|
|
196
|
+
else:
|
|
197
|
+
image_converted = image_converted[:, :, 0]
|
|
198
|
+
|
|
199
|
+
if saveas_type == "16 bit Tiff" or saveas_type == "32 bit Tiff":
|
|
200
|
+
io.imsave(dir, image_converted)
|
|
201
|
+
|
|
202
|
+
elif saveas_type == "16 bit XISF" or saveas_type == "32 bit XISF":
|
|
203
|
+
self.update_xisf_imagedata()
|
|
204
|
+
XISF.write(dir, image_converted, creator_app="GraXpert", image_metadata=self.image_metadata, xisf_metadata=self.xisf_metadata)
|
|
205
|
+
else:
|
|
206
|
+
hdu = fits.PrimaryHDU(data=image_converted, header=self.fits_header)
|
|
207
|
+
hdul = fits.HDUList([hdu])
|
|
208
|
+
hdul.writeto(dir, output_verify="warn", overwrite=True)
|
|
209
|
+
hdul.close()
|
|
210
|
+
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
def get_local_median(self, img_point):
|
|
214
|
+
sample_radius = 2
|
|
215
|
+
y1 = int(np.amax([img_point[1] - sample_radius, 0]))
|
|
216
|
+
y2 = int(np.amin([img_point[1] + sample_radius, self.height]))
|
|
217
|
+
x1 = int(np.amax([img_point[0] - sample_radius, 0]))
|
|
218
|
+
x2 = int(np.amin([img_point[0] + sample_radius, self.width]))
|
|
219
|
+
|
|
220
|
+
if self.img_array.shape[-1] == 3:
|
|
221
|
+
R = np.median(self.img_array[y1:y2, x1:x2, 0])
|
|
222
|
+
G = np.median(self.img_array[y1:y2, x1:x2, 1])
|
|
223
|
+
B = np.median(self.img_array[y1:y2, x1:x2, 2])
|
|
224
|
+
|
|
225
|
+
return [R, G, B]
|
|
226
|
+
|
|
227
|
+
if self.img_array.shape[-1] == 1:
|
|
228
|
+
L = np.median(self.img_array[x1:x2, y1:y2, 0])
|
|
229
|
+
|
|
230
|
+
return L
|
|
231
|
+
|
|
232
|
+
def copy_metadata(self, source_img):
|
|
233
|
+
self.xisf_metadata = source_img.xisf_metadata
|
|
234
|
+
self.image_metadata = source_img.image_metadata
|
|
235
|
+
|
|
236
|
+
def update_saturation(self, saturation):
|
|
237
|
+
self.img_display_saturated = self.img_display
|
|
238
|
+
|
|
239
|
+
if self.img_array.shape[-1] == 3:
|
|
240
|
+
self.img_display_saturated = ImageEnhance.Color(self.img_display)
|
|
241
|
+
self.img_display_saturated = self.img_display_saturated.enhance(saturation)
|
|
242
|
+
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
def update_xisf_imagedata(self):
|
|
246
|
+
unique_keys = list(dict.fromkeys(self.fits_header.keys()))
|
|
247
|
+
|
|
248
|
+
for key in unique_keys:
|
|
249
|
+
if key == "BG-PTS":
|
|
250
|
+
try:
|
|
251
|
+
bg_pts = json.loads(self.fits_header["BG-PTS"])
|
|
252
|
+
|
|
253
|
+
for i in range(len(bg_pts)):
|
|
254
|
+
self.image_metadata["FITSKeywords"]["BG-PTS" + str(i)] = [{"value": bg_pts[i], "comment": ""}]
|
|
255
|
+
except:
|
|
256
|
+
logging.warning("Could not transfer background points from fits header to xisf image metadata", stack_info=True)
|
|
257
|
+
else:
|
|
258
|
+
value = str(self.fits_header[key]).splitlines()
|
|
259
|
+
comment = str(self.fits_header.comments[key]).splitlines()
|
|
260
|
+
|
|
261
|
+
entry = []
|
|
262
|
+
|
|
263
|
+
for i in range(max(len(comment), len(value))):
|
|
264
|
+
value_i = ""
|
|
265
|
+
comment_i = ""
|
|
266
|
+
|
|
267
|
+
if i < len(comment):
|
|
268
|
+
comment_i = comment[i]
|
|
269
|
+
if i < len(value):
|
|
270
|
+
value_i = value[i]
|
|
271
|
+
|
|
272
|
+
entry.append({"value": value_i, "comment": comment_i})
|
|
273
|
+
|
|
274
|
+
if len(entry) == 0:
|
|
275
|
+
entry = [{"value": "", "comment": ""}]
|
|
276
|
+
|
|
277
|
+
self.image_metadata["FITSKeywords"][key] = entry
|
|
278
|
+
|
|
279
|
+
def xisf_imagedata_2_fitsheader(self):
|
|
280
|
+
commentary_keys = ["HISTORY", "COMMENT", ""]
|
|
281
|
+
|
|
282
|
+
bg_pts = []
|
|
283
|
+
for key in self.image_metadata["FITSKeywords"].keys():
|
|
284
|
+
if key.startswith("BG-PTS"):
|
|
285
|
+
try:
|
|
286
|
+
bg_pts.append(json.loads(self.image_metadata["FITSKeywords"][key][0]["value"]))
|
|
287
|
+
except:
|
|
288
|
+
logging.warning(f"Could not load background points from xisf image metadata. Affected entry: {self.image_metadata['FITSKeywords'][key]}", stack_info=True)
|
|
289
|
+
|
|
290
|
+
else:
|
|
291
|
+
for i in range(len(self.image_metadata["FITSKeywords"][key])):
|
|
292
|
+
value = self.image_metadata["FITSKeywords"][key][i]["value"]
|
|
293
|
+
comment = self.image_metadata["FITSKeywords"][key][i]["comment"]
|
|
294
|
+
|
|
295
|
+
# Commentary cards have to comments in Fits standard
|
|
296
|
+
if key in commentary_keys:
|
|
297
|
+
if value == "":
|
|
298
|
+
value = comment
|
|
299
|
+
|
|
300
|
+
if value.isdigit():
|
|
301
|
+
value = int(value)
|
|
302
|
+
elif value.isdecimal():
|
|
303
|
+
value = float(value)
|
|
304
|
+
|
|
305
|
+
self.fits_header[key] = (value, comment)
|
|
306
|
+
|
|
307
|
+
if len(bg_pts) > 0:
|
|
308
|
+
self.fits_header["BG-PTS"] = str(bg_pts)
|