Exemplo n.º 1
0
 def layer_sat_changed(self):
     if self.layer_stretched is not None:
         r = 3 * self.saturation * self.layer_stretched + self.lum
         r[r < 0] = 0
         r[r > 1] = 1
         Component.get('View').display_image(
             np.stack([r, self.lum, self.lum], axis=-1))
Exemplo n.º 2
0
    def on_save_object(self):
        ''' On saving we ensure that Name, OT and Con is saved as these 
            appear in the previous object table; other props don't need to
            be saved as they are looked up from the DSO database on each
            load.
        '''

        Component.get('Metadata').set({
            'Name': self.Name.strip(),
            'OT': self.OT,
            'Con': self.Con
        })

        # prepare props in canonical format
        props = {
            'Name': self.Name.strip(),
            'OT': self.OT.strip(),
            'Con': self.Con.strip(),
            'RA': RA.parse(self.RA),
            'Dec': Dec.parse(self.Dec),
            'Diam': str_to_arcmin(self.Diam),
            'Mag': str_to_float(self.Mag),
            'Other': self.Other
        }

        # get catalogue to check if anything has changed and update user objects if necc.
        Component.get('Catalogues').check_update(props)
Exemplo n.º 3
0
    def snap(self, return_image=False, *args):

        self.return_image = return_image

        view = Component.get('View')
        if not hasattr(view, 'last_image') or (view.last_image is None):
            return

        dso = Component.get('DSO')

        self.save_path = '{:} {:}.{:}'.format(
            os.path.join(self.app.get_path('snapshots'),
                         purify_name(dso.Name)),
            datetime.now().strftime('%d%b%y_%H_%M_%S'), self.save_format)

        if not return_image and self.save_format == 'fit':
            self.save_as_fits()

        elif self.style == 'eyepiece':
            im = self.eyepiece_view()

        elif self.style == 'landscape':
            im = self.landscape_view()

        if return_image:
            return im
Exemplo n.º 4
0
    def processing_details(self):

        block = []
        stacker = Component.get('Stacker')
        d = stacker.describe()
        if d is None:
            return []

        if 'total_exposure' in d:
            block += [s_to_minsec(d['total_exposure'])]
            if d['multiple_exposures']:
                block += ['varied exposures']
            else:
                block += [
                    '{:} x {:.0f}s'.format(d['nsubs'], d['sub_exposure'])
                ]

        if not d['filters'].endswith('L'):  # more interesting than just LUM
            block += [d['filters']]

        if d['nsubs'] > 1:
            block += ['{:} stack'.format(stacker.combine)]

        block += ['{:} stretch'.format(Component.get('Monochrome').stretch)]

        calib = ','.join([c for c in ['dark', 'flat', 'bias'] if d[c]])
        calib = calib if calib else 'no darks/flats'
        block += [calib]

        return block  # block[::-1]  # reverse!
Exemplo n.º 5
0
    def on_capturing(self, *args):
        # user (pressing camera button) or system changes capture state

        logger.debug('capturing state changed')

        if not self.capturing:
            self.stop_capture()
            return

        if not Component.get('Camera').connected():
            self.stop_capture(message='cannot connect to camera')
            return

        if not Component.get('FilterWheel').connected():
            self.stop_capture(message='cannot connect to filterwheel')
            return

        self.gui.disable(capture_controls)
        self.gui.disable({'load_previous', 'new_DSO'})
        self.gui.enable({'capturing'})
        logger.debug('camera connected, starting capture')

        try:
            self.capture()
        except Exception as e:
            self.stop_capture(message=e)
Exemplo n.º 6
0
 def create_RGB(self):
     ''' Combine L, A and B into RGB image. Called here when previous colour process
     has been applied (hue_changed), or when luminosity component has changed (below)
     '''
     if self.avail(['lum', 'A_hue']):
         self.RGB = lab2rgb(
             np.stack([100 * self.lum, self.A_hue, self.B_hue], axis=-1))
         Component.get('View').display_image(self.RGB)
Exemplo n.º 7
0
 def filter_selected(self, filt, but):
     # set exposure on GUI and on scripts panel
     if Component.get('CaptureScript').current_script == 'seq':
         logger.debug('toggled filter {:}'.format(filt))
     else:
         logger.debug('selected filter {:}'.format(filt))
         Component.get('CaptureScript').filter_changed([filt])
         self.hide()
Exemplo n.º 8
0
 def load_previous(self, path):
     # previous will have been saved by this point
     self.existing_object = True
     gui = self.app.gui
     gui.enable()
     gui.set('show_reticle', False, update_property=True)
     self.current_object_dir = path
     Component.initialise_previous_object()
Exemplo n.º 9
0
 def new_object(self, *args):
     if self.closing:
         return
     self.current_object_dir = None
     self.existing_object = False
     self.sub_type = None
     Component.initialise_new_object()
     self.app.gui.set('frame_script', True, update_property=True)
Exemplo n.º 10
0
 def connection_changed(self, device, connected):
     if device in self.connect_dots:
         self.connect_dots[device].text = jicon(
             'dot', color=('g' if connected else 'r'))
         Component.get(device).info('not connected')
     if device in self.connect_buttons:
         self.connect_buttons[
             device].text = 'disconnect...' if connected else 'connect...'
         Component.get(device).info('connected')
Exemplo n.º 11
0
 def send_to_display(self, *args):
     # send short subs directly to display
     self.fps = 1 / (time.time() - self.start_capture_time)
     try:
         Component.get('Monochrome').display_sub(
             Component.get('Camera').get_image())
         self.capture()
     except Exception as e:
         logger.exception('problem send to display {:}'.format(e))
Exemplo n.º 12
0
 def update_state(self):
     s = 'L-R, ' if self.flip_LR else ''
     s += 'U-D' if self.flip_UD else ''
     if s.endswith(', '):
         s = s[:-2]
     flipstr = ' | flip {:}'.format(s) if s else ''
     invstr = ' | inv' if self.invert else ''
     self.info('rot {:.0f}\u00b0 | {:4.1f}x{:}{:}'.format(
         self.orientation, self.lever_to_zoom(self.zoom), flipstr, invstr))
     Component.get('Annotator').update()
Exemplo n.º 13
0
 def reset(self):
     # Called when we have a new object and when user clears stack
     self.stack_cache = {}
     self.orig_rejects = set({})  # new
     self.subs.clear()
     self.selected_sub = -1
     self.update_stack_scroller()
     self.set_to_subs()
     Component.get(
         'View').reset()  # might not be needed as View also does a reset!
     self.info('')
Exemplo n.º 14
0
 def new_observation(self):
     OT = Component.get('Metadata').get('OT', '')
     Name = Component.get('Metadata').get('Name', None)
     logger.info('{:}/{:}'.format(Name, OT))
     #  update observed count if DSO is known
     if Name is not None:
         name = '{:}/{:}'.format(Name, OT)
         if name in self.objects:
             self.objects[name]['Obs'] += 1
         if hasattr(self, 'table'):
             self.table.update()
Exemplo n.º 15
0
    def on_save_object(self):

        logger.debug('saving properties to metadata')

        # save properties
        for p in self.props:
            Component.get('Metadata').set(p, getattr(self, p))

        # only update last session if live rather than previous
        if self.is_new_object:
            self.save_session()
Exemplo n.º 16
0
 def on_stop(self, exception=None):
     if exception is None:
         logger.info('normal close down')
     else:
         logger.exception('root exception: {:}'.format(exception))
     # save width and height
     Config.set('graphics', 'width', str(int(Window.width/ dp(1))))
     Config.set('graphics', 'height', str(int(Window.height/dp(1))))
     Config.write()
     Component.close()
     self.gui.on_close()
     logger.info('finished close down')
Exemplo n.º 17
0
 def recompute(self, widgy=None, realign=False):
     # initial load, recompute or realign
     Component.get('Aligner').reset()
     self.stack_cache = {}
     # shuffle-based realign
     if realign:
         np.random.shuffle(self.subs)
         # if we have a B or Ha, keep shuffling until we start with that
         if len([s for s in self.subs if s.filter in {'B', 'Ha'}]) > 0:
             while self.subs[0].filter not in {'B', 'Ha'}:
                 np.random.shuffle(self.subs)
     self.selected_sub = -1
     Clock.schedule_once(self._reprocess_sub, 0)
Exemplo n.º 18
0
    def adjust_lum(self, *args):
        ''' User has changed control position so generate luminance and either
            display it (if sub or in mono mode) or advise multispectral of the update
        '''

        lum = self.luminance()
        if self.stacker.sub_or_stack == "sub":
            self.view.display_image(lum)
        else:
            if self.stacker.spectral_mode == "mono":
                self.view.display_image(lum)
            else:
                Component.get("MultiSpectral").luminance_updated(lum)
Exemplo n.º 19
0
 def update_panel(self):
     filters = Component.get('CaptureScript').get_filters()
     for f, but in self.buts.items():
         but.state = 'down' if f in filters else 'normal'
     nsubs = Component.get('CaptureScript').get_nsubs()
     if nsubs > 1:
         self.nsubs_slider.value = nsubs
         self.nsubs_label.text = '{:} subs/filter'.format(nsubs)
         self.nsubs = nsubs
         self.title.text = 'Select filters'
         self.nsubs_box.disabled = False
     else:
         self.title.text = 'Select a filter'
         self.nsubs_box.disabled = True
Exemplo n.º 20
0
 def on_current_script(self, *args):
     ''' carry out any special actions when certain scripts are selected
     '''
     logger.debug('Changed script to {:}'.format(self.current_script))
     self.app.gui.set('script_button', self.current_script)
     self.update()
     if self.current_script == 'align':
         Component.get('View').fit_to_window(zero_orientation=False)
     self.app.gui.set('show_reticle',
                      self.current_script == 'align',
                      update_property=True)
     self.app.gui.set('80' if self.current_script == 'flat' else 'mean',
                      True,
                      update_property=True)
Exemplo n.º 21
0
    def stack_changed(self):
        ''' Called whenever we might need to update the stack e.g. sub added/selected
        deselected/change in stack view/change in mode
        '''

        if self.is_empty():
            return
        if self.sub_or_stack == 'sub':
            return

        # see if we can satisfy user's non-mono preferences and if not, drop thru to mono
        # filters = self.get_filters()

        if self.spectral_mode == 'LRGB':
            Component.get('MultiSpectral').LRGB_changed(L=self.get_stack('L'),
                                                        R=self.get_stack('R'),
                                                        G=self.get_stack('G'),
                                                        B=self.get_stack('B'))

        elif self.spectral_mode == 'L+':
            Component.get('MultiSpectral').L_plus_changed(
                L=self.get_stack('L'), layer=self.get_stack(self.L_plus_other))

        else:
            Component.get('Monochrome').L_changed(self.get_stack(filt='all'))
            Component.get('MultiSpectral').reset()

        self.update_status()
Exemplo n.º 22
0
 def stop_capture(self, message=None):
     # stops capture normally or abnormally
     logger.debug('stopping capture')
     Component.get('Camera').stop_capture()
     self.gui.set('capturing', False, update_property=True)
     self.gui.enable(capture_controls)
     self.gui.enable({'new_DSO'})
     if Component.get('Stacker').is_empty():
         self.gui.enable({'load_previous'})
     if message is not None:
         Component.get('CaptureScript').reset_generator()
         logger.error('problem capturing ({:})'.format(message))
         toast('Capture problem: {:}'.format(message))
     self.info('')
Exemplo n.º 23
0
    def luminance_updated(self, lum):
        # called from monochrome if user updates luminance control e.g. white

        self.lum = lum
        # we are in LRGB mode
        if self.LAB is not None:
            self.create_RGB()

        # we are in L+ mode
        elif self.layer is not None:
            self.layer_sat_changed()

        # display as mono
        else:
            Component.get('View').display_image(lum)
Exemplo n.º 24
0
    def new_sub(self,
                data=None,
                name=None,
                exposure=None,
                filt=None,
                temperature=None,
                sub_type=None):
        ''' Called by Capture or WatchedCamera
        '''

        if data is None or name is None:
            return

        logger.debug(
            'New sub | type {:} name {:} expo {:} filt {:} temp {:}'.format(
                sub_type, name, exposure, filt, temperature))

        stacker = Component.get('Stacker')

        if self.current_object_dir is None:
            # new object, so check if calibration or light
            if sub_type in {'dark', 'flat', 'bias'}:
                self.current_object_dir = os.path.join(
                    self.session_dir,
                    generate_observation_name(self.session_dir,
                                              prefix=sub_type))
                stacker.sub_type = sub_type  # is this needed any more?
                Component.get('DSO').Name = sub_type
            else:
                self.current_object_dir = os.path.join(
                    self.session_dir,
                    generate_observation_name(
                        self.session_dir, prefix=Component.get('DSO').Name))
                self.app.gui.disable(['load_previous'])
            add_if_not_exists(self.current_object_dir)

        path = os.path.join(self.current_object_dir, name)

        try:
            save_image(data=data,
                       path=path,
                       exposure=exposure,
                       filt=filt,
                       temperature=temperature,
                       sub_type=sub_type)
            stacker.add_sub(Image(path))
        except Exception as e:
            logger.exception('cannot add sub to stack ({:})'.format(e))
Exemplo n.º 25
0
    def update_stack_scroller(self, *args):
        # sub_labels is array representing the stack
        # these are sub positions on the screen

        self.update_status()
        gui = self.app.gui.gui
        labs = [
            gui[n]['widget']
            for n in ['sub_m2', 'sub_m1', 'sub_0', 'sub_p1', 'sub_p2']
        ]

        # set background to transparent and text to blank to start with
        for l in labs:
            l.text = ''
            l.background_color[-1] = 0

        # we have some subs
        fw = Component.get('FilterChooser')
        for i, l in enumerate(labs, start=self.selected_sub - 2):
            # if position is occupied by a sub
            if (i >= 0) and (i < len(self.subs)):
                l.text = str(i + 1)
                l.color = self.sub_colors[self.subs[i].status]
                l.background_color = fw.filter_properties[
                    self.subs[i].filter]['bg_color']
Exemplo n.º 26
0
    def on_selected_sub(self, *args):
        # This is the key method that dictates whether the display has changed
        # on new sub, change of sub selection etc and hence stack updates

        s = self.selected_sub
        if (s < 0) or (s >= len(self.subs)):
            return

        if self.sub_or_stack == 'sub':
            ss = self.subs[s]
            Component.get('Monochrome').display_sub(
                ss.get_image(), do_gradient=ss.sub_type == 'light')
        else:
            self.stack_changed()

        self.update_stack_scroller()
Exemplo n.º 27
0
    def get_dark(self, sub):
        # Find suitable dark for this sub given its parameters

        if sub.exposure is None:
            return None

        # choose darks that are the right shape with exposure within tolerance
        darks = {
            k: v
            for k, v in self.masters.items()
            if v.shape == sub.shape and v.sub_type == 'dark' and v.exposure
            is not None and abs(v.exposure - sub.exposure) < self.exposure_tol
        }

        temperature = Component.get('Session').temperature

        if temperature is not None:
            # we know temperature, select those with temperatures and within tolerance
            darks = [
                k for k, v in darks.items() if v.temperature is not None
                and abs(v.temperature - temperature) < self.temperature_tol
            ]
        else:
            # find those within date tolerance (set to 1 to get darks in current session)
            darks = [k for k, v in darks.items() if v.age < self.dark_days_tol]

        # if we have darks, return name of first one
        return darks[0] if len(darks) > 0 else None
Exemplo n.º 28
0
    def on_action(self, name, *args):
        ''' Intercept any GUI event in order to load component, before
			passing action on to component via a property change
		'''

        spec = self.gui[name]
        comp = spec['component']
        c = Component.get(comp)  # loads if needed

        if name in self.disabled_controls:
            return

        # if action is specified, simply call that method on component
        if 'action' in spec:
            getattr(c, spec['action'])()
            return

        # otherwise it involves a value change
        control = spec['control_type']

        # handle button groups
        if control == 'JToggleButton':
            if 'group' in spec:
                setattr(c, spec['group'], spec['widget'].text)
                return

        if hasattr(c, name):
            if control == 'JToggleButton':
                setattr(c, name, spec['widget'].state == 'down')
            elif control == 'JLever':
                setattr(c, name, spec['widget'].value)
            elif control == 'JMulti':
                setattr(c, name, spec['widget'].text)
Exemplo n.º 29
0
 def compute_ADU(self, expo):
     ''' Estimate ADU in central part of image given exposure
     '''
     im = Component.get('Camera').capture_sub(exposure=expo,
                                              return_image=True,
                                              on_failure=self.stop_capture)
     return image_stats(im)['central 75%']
Exemplo n.º 30
0
 def __init__(self, **kwargs):
     super().__init__(**kwargs)
     self.app = App.get_running_app()
     otypes = Component.get('Catalogues').get_object_types()
     self.otypes = {k: v['name'] for k, v in otypes.items()}
     self.dso_panel = DSO_panel(self)
     self.app.gui.add_widget(self.dso_panel)
     self.initial_values = {}