def set_section(self, value): if type(value) != str: raise TypeError('Input type must be string. Got %s' % type(value)) self.sec = slice_from_string(value) self.serial_size = self.sec[1].stop - self.sec[1].start self.parallel_size = self.sec[0].stop - self.sec[0].start
def slices_config(config): """ From a string of the configuration file containing slices, returns a list with the slices to calculate, for example, the overscan, or trim image. :param config: string containing the slices :return: slices """ return [slice_from_string(match.group()) for match in inside_brackets.finditer(config)]
def _trim_oscan(ccd, biassec, trimsec, model=None): """Subtract the overscan region and trim image to desired size. The CCDPROC function subtract_overscan() expects the TRIMSEC of the image (the part you want to keep) to span the entirety of one dimension, with the BIASSEC (overscan section) being at the end of the other dimension. Both LMI and DeVeny have edge effects on all sides of their respective chips, and so the TRIMSEC and BIASSEC do not meet the expectations of subtract_overscan(). Therefore, this function is a wrapper to first remove the undesired ROWS from top and bottom, then perform the subtract_overscan() fitting and subtraction, followed by trimming off the now-spent overscan region. Args: ccd (:TYPE:`internal link or datatype`) Description. biassec (:TYPE:`str`) Description. trimsec (:TYPE:`str`) Description. model (:TYPE:internal link or datatype`) Description. Returns: ccd (:TYPE:`internal link or datatype`) Description. """ # Convert the FITS bias & trim sections into slice classes for use yb, xb = slice_from_string(biassec, fits_convention=True) yt, xt = slice_from_string(trimsec, fits_convention=True) # First trim off the top & bottom rows ccd = ccdp.trim_image(ccd[yt.start:yt.stop, :]) # Model & Subtract the overscan if model is None: model = models.Chebyshev1D(1) # Chebyshev 1st order function else: model = models.Chebyshev1D(1) # Figure out how to incorporate others ccd = ccdp.subtract_overscan(ccd, overscan=ccd[:, xb.start:xb.stop], median=True, model=model) # Trim the overscan & return return ccdp.trim_image(ccd[:, xt.start:xt.stop])
def slices_config(config): """ From a string of the configuration file containing slices, returns a list with the slices to calculate, for example, the overscan, or trim image. :param config: string containing the slices :return: slices """ return [ slice_from_string(match.group()) for match in inside_brackets.finditer(config) ]
def make_overscan_test_files(request, tmpdir): """ Creates two files, one with overscan, one without for Alta U9 Parameters test_dir: str Directory in which to create the overscan files. Returns info: list (working_dir, has_oscan, has_no_oscan) working_dir: str subdirectory of test_dir in which files are created has_oscan: str Name of FITS file that has overscan region has_no_oscan: str Name of FITS file that has no overscan region """ from .header_processing.feder import ApogeeAltaU9, MaximDL5 from os import path, mkdir import astropy.io.fits as fits import numpy as np test_dir = tmpdir oscan_names = ['yes_scan', 'no_scan'] oscan = {'yes_scan': True, 'no_scan': False} apogee = ApogeeAltaU9() working_dir = 'overscan_test' working_path = test_dir.mkdir(working_dir) add_instrument = lambda hdr: hdr.set('instrume', 'Apogee Alta') name_fits = lambda name: name + '.fit' for name in oscan_names: if oscan[name]: data = np.zeros([apogee.rows, apogee.columns]) has_oscan = name else: osc_slice = slice_from_string(apogee.trim_region) data = np.zeros([apogee.rows, osc_slice[0].stop]) no_oscan = name hdu = fits.PrimaryHDU(data) hdr = hdu.header add_instrument(hdu.header) mdl5 = MaximDL5() # all headers need a software name hdr[mdl5.fits_keyword] = mdl5.fits_name[0] hdr['imagetyp'] = 'LIGHT' hdu.writeto(path.join(working_path.strpath, name_fits(name))) return (working_path.strpath, name_fits(has_oscan), name_fits(no_oscan))
def has_overscan(self, image_dimensions): """ Determine whether an image taken by this instrument has overscan Parameters ---------- image_dimensions : list-like with two elements Shape of the image; can be any type as long as it has two elements. The order should be the FITS order, ``NAXIS1`` then ``NAXIS2``. Returns ------- bool Indicates whether or not image has overscan present. """ if self.trim_region is None: return False # Grab the trim region as a slice to make it easier to access end # points. Do *not* convert from FITS convention because input # dimensions follow FITS conventions. trim_dim = slice_from_string(self.trim_region) dim_end = lambda ax: (trim_dim[ax].stop + 1 if trim_dim[ax].stop is not None else image_dimensions[ax]) # print(trim_dim1, trim_dim2) # if trim_dim1.stop is not None: # dim1_end = trim_dim1.stop + 1 # else: # # None means use the whole thing.... # dim1_end = image_dimensions[0] # if trim_dim2.stop is not None: # dim2_end = trim_dim2.stop + 1 # else: # # None means use the whole thing.... # dim2_end = image_dimensions[1] if (dim_end(0) < image_dimensions[0] or dim_end(1) < image_dimensions[1]): return True else: return False
def cropImage(image, trim=None, zoom=None, center=None, pixels=None, width=None): if isinstance(image, str): image = fits2CCDData(image, single=True).data if trim is not None: return image[slice_from_string(trim)] if center is None: center = (image.shape[0] / 2, image.shape[1] / 2) dy, dx = image.shape if zoom is not None: if isinstance(zoom, (list, tuple)): xzoom, yzoom = zoom else: xzoom, yzoom = zoom, zoom if xzoom < 1.0 or yzoom < 1.0: print ('WARNING: Zoom needs to be >= 1.0 [%s, %s]! Nothing done!' % (xzoom, yzoom)) return image dy /= yzoom dx /= xzoom idy = slice(center[0] - int(dy / 2), center[0] + int(dy / 2), None) idx = slice(center[1] - int(dx / 2), center[1] + int(dx / 2), None) image = image[idy, idx] elif pixels is not None: if isinstance(pixels, (tuple, list, np.ndarray)): ypix, xpix = pixels else: ypix, xpix = pixels, pixels if ypix is not None: image = image[ypix : dy - ypix, ...] if xpix is not None: image = image[..., xpix: dx - xpix] elif width is not None: if isinstance(width, (tuple, list, np.ndarray)): ywidth, xwidth = width else: ywidth, xwidth = width, width if ywidth is not None: idy = slice(center[0] - int(ywidth / 2), center[0] + int(ywidth / 2), None) image = image[idy, ...] if xwidth is not None: idx = slice(center[1] - int(xwidth / 2), center[1] + int(xwidth / 2), None) image = image[..., idx] return image
def _calc_zsw(fun, arr, section=None): fun_simple = _nanfun2nonnan(fun) if section is not None: try: sl = slice_from_string(section, fits_convention=True) except (AttributeError, ValueError): # i.e., int-convertible sl = int(section) else: sl = [slice(None)]*(arr.ndim - 1) # TODO: There must be a better way to do this "redo" strategy... try: # If converted to numpy, this must work without error: if isinstance(sl, int): zsw = [fun_simple(arr[i].ravel()[::sl], axis=None) for i in range(arr.shape[0])] else: zsw = fun_simple(arr[(slice(None), *sl)], axis=tuple(np.arange(arr.ndim)[1:])) redo = ~np.all(np.isfinite(zsw)) except TypeError: # does not accept tuple axis redo = True if redo: zsw = [] if isinstance(sl, int): try: zsw = [(fun(arr[i].ravel()[::sl], axis=None)) for i in range(arr.shape[0])] except TypeError: # original fun has no `axis` parameter zsw = [(fun(arr[i].ravel()[::sl])) for i in range(arr.shape[0])] else: try: zsw = [(fun(arr[(i, *sl)], axis=None)) for i in range(arr.shape[0])] except TypeError: # original fun has no `axis` parameter zsw = [(fun(arr[(i, *sl)])) for i in range(arr.shape[0])] # raise ValueError() return np.atleast_1d(zsw)
def parse_scan(scan): # print scan # Try to parse it to integer try: reg_len = int(scan[1]) if scan[0] == 'serial_pre': log.debug('Serial pre-scan with %i length.' % reg_len) return self.section[0], slice(self.section[1].start-reg_len,self.section[1].start) elif scan[0] == 'serial_pos': log.debug('Serial pos-scan with %i length.' % reg_len) return self.section[0], slice(self.section[1].stop,self.section[1].stop+reg_len) elif scan[0] == 'parallel_pre': log.debug('Parallel pre-scan with %i length.' % reg_len) return slice(self.section[0].start-reg_len,self.section[0].start), self.section[1] elif scan[0] == 'parallel_pos': log.debug('Parallel pos-scan with %i length.' % reg_len) return slice(self.section[0].stop,self.section[0].stop+reg_len), self.section[1] else: raise KeyError('%s is not a valid key. Should be one of serial_pre, serial_pos, ' 'parallel_pre or parallel_pos' % (scan[0])) except ValueError, e: log.debug('Region is not convertible to int. Falling back to slice mode.') return slice_from_string(scan[1])