def img_data(file_name): """Load common image files into a Glue data object""" result = Data() data = img_loader(file_name) data = np.flipud(data) shp = data.shape comps = [] labels = [] # split 3 color images into each color plane if len(shp) == 3 and shp[2] in [3, 4]: comps.extend([data[:, :, 0], data[:, :, 1], data[:, :, 2]]) labels.extend(['red', 'green', 'blue']) if shp[2] == 4: comps.append(data[:, :, 3]) labels.append('alpha') else: comps = [data] labels = ['PRIMARY'] # look for AVM coordinate metadata try: from pyavm import AVM avm = AVM(str(file_name)) # avoid unicode wcs = avm.to_wcs() except: pass else: result.coords = coordinates_from_wcs(wcs) for c, l in zip(comps, labels): result.add_component(c, l) return result
def make_rgb_image(data, output, indices=(0, 1, 2), \ vmin_r=None, vmax_r=None, pmin_r=0.25, pmax_r=99.75, \ stretch_r='linear', vmid_r=None, exponent_r=2, \ vmin_g=None, vmax_g=None, pmin_g=0.25, pmax_g=99.75, \ stretch_g='linear', vmid_g=None, exponent_g=2, \ vmin_b=None, vmax_b=None, pmin_b=0.25, pmax_b=99.75, \ stretch_b='linear', vmid_b=None, exponent_b=2, \ embed_avm_tags=False): ''' Make an RGB image from a FITS RGB cube or from three FITS files Required arguments: *data*: [ string | tuple | list ] If a string, this is the filename of an RGB FITS cube. If a tuple or list, this should give the filename of three files to use for the red, green, and blue channel. *output*: [ string ] The output filename. The image type (e.g. PNG, JPEG, TIFF, ...) will be determined from the extension. Any image type supported by the Python Imaging Library can be used. Optional keyword arguments: *indices*: [ tuple ] If data is the filename of a FITS cube, these indices are the positions in the third dimension to use for red, green, and blue respectively. The default is to use the first three indices. *vmin_r*: [ None | float ] *vmin_g*: [ None | float ] *vmin_b*: [ None | float ] Minimum pixel value to use for the red, green, and blue channels. If set to None for a given channel, the minimum pixel value for that channel is determined using the corresponding pmin_x argument (default). *vmax_r*: [ None | float ] *vmax_g*: [ None | float ] *vmax_b*: [ None | float ] Maximum pixel value to use for the red, green, and blue channels. If set to None for a given channel, the maximum pixel value for that channel is determined using the corresponding pmax_x argument (default). *pmin_r*: [ float ] *pmin_g*: [ float ] *pmin_b*: [ float ] Percentile values used to determine for a given channel the minimum pixel value to use for that channel if the corresponding vmin_x is set to None. The default is 0.25% for all channels. *pmax_r*: [ float ] *pmax_g*: [ float ] *pmax_b*: [ float ] Percentile values used to determine for a given channel the maximum pixel value to use for that channel if the corresponding vmax_x is set to None. The default is 99.75% for all channels. *stretch_r*: [ 'linear' | 'log' | 'sqrt' | 'arcsinh' | 'power' ] *stretch_g*: [ 'linear' | 'log' | 'sqrt' | 'arcsinh' | 'power' ] *stretch_b*: [ 'linear' | 'log' | 'sqrt' | 'arcsinh' | 'power' ] The stretch function to use for the different channels. *vmid_r*: [ None | float ] *vmid_g*: [ None | float ] *vmid_b*: [ None | float ] Baseline values used for the log and arcsinh stretches. If set to None, this is set to zero for log stretches and to vmin - (vmax - vmin) / 30. for arcsinh stretches *exponent_r*: [ float ] *exponent_g*: [ float ] *exponent_b*: [ float ] If stretch_x is set to 'power', this is the exponent to use. ''' if not installed_pil: raise Exception( "The Python Imaging Library (PIL) is not installed but is required for this function" ) if isinstance(data, basestring): image = pyfits.getdata(data) image_r = image[indices[0], :, :] image_g = image[indices[1], :, :] image_b = image[indices[2], :, :] # Read in header header = pyfits.getheader(data) # Remove information about third dimension header['NAXIS'] = 2 for key in [ 'NAXIS', 'CTYPE', 'CRPIX', 'CRVAL', 'CUNIT', 'CDELT', 'CROTA' ]: for coord in range(3, 6): name = key + str(coord) if name in header: header.__delitem__(name) elif (type(data) == list or type(data) == tuple) and len(data) == 3: filename_r, filename_g, filename_b = data image_r = pyfits.getdata(filename_r) image_g = pyfits.getdata(filename_g) image_b = pyfits.getdata(filename_b) # Read in header header = pyfits.getheader(filename_r) else: raise Exception( "data should either be the filename of a FITS cube or a list/tuple of three images" ) logger.info("Red:") image_r = Image.fromarray(_data_stretch(image_r, \ vmin=vmin_r, vmax=vmax_r, \ pmin=pmin_r, pmax=pmax_r, \ stretch=stretch_r, \ vmid=vmid_r, \ exponent=exponent_r)) logger.info("\nGreen:") image_g = Image.fromarray(_data_stretch(image_g, \ vmin=vmin_g, vmax=vmax_g, \ pmin=pmin_g, pmax=pmax_g, \ stretch=stretch_g, \ vmid=vmid_g, \ exponent=exponent_g)) logger.info("\nBlue:") image_b = Image.fromarray(_data_stretch(image_b, \ vmin=vmin_b, vmax=vmax_b, \ pmin=pmin_b, pmax=pmax_b, \ stretch=stretch_b, \ vmid=vmid_b, \ exponent=exponent_b)) img = Image.merge("RGB", (image_r, image_g, image_b)) img = img.transpose(Image.FLIP_TOP_BOTTOM) img.save(output) if embed_avm_tags: if not avm_installed: raise Exception( "PyAVM needs to be installed in order to be able to embed AVM tags into the RGB image" ) else: avm = AVM(header) avm.embed(output, output) return
def overlay( image, bdf, # basic inputs l1=0.0, l2=1.0, # levels shift=[0.0, 0.0], # target shift from reference value radec=[0.0, 0.0], # target coords, if not ref value (d/s) nod=[0, 0], # shift from default ctr (in asec) showGrid=False, # show coordinate grid? stretch='linear', # 'log', 'linear', etc. invert=False, # invert a grayscale image? hdu=0, # HDU, if not 0. gray=True, readAVM=False): # plot colour, AVM read """ Overlay a SAMI bundle onto a fits image Adapted to astropy input. Inputs ------- image: fits image used for overlay; bdf: a 'bundle definition file', generate with the 'bundle_definition' function in this module. """ import aplpy import astropy.wcs as pywcs # is the input image a fits file? isfits = (image[len(image) - 5:] == '.fits') or (image[len(image) - 4:] == '.fit') # Use APLPy to read in the FITS file. fig = aplpy.FITSFigure(image, north=True, hdu=hdu) if (gray == True): fig.show_grayscale(vmin=l1, vmax=l2, stretch=stretch, invert=invert) else: fig.show_rgb() if showGrid == True: fig.show_grid() # Read the AVM of a jpg or tiff image: if readAVM == True: from pyavm import AVM avm = AVM(image) # read BDF tab = tab.read(bdf) # Get field centre coordinates -- quite messy, clean up. ctr = [0., 0.] # just initiate the field centre (list ok) # Input type: image loaded with Astro Visualisation Metadata -- if (np.mean(radec) == 0.0) and (readAVM != True) and (isfits != True): ctr = [0.0, 0.0] # if cannot find AVM, ctr=0,0 print("Warning: did not find a valid field centre definition") if (np.mean(radec) != 0.0) and (isfits != True): # respec' user input radec = np.array(radec) if radec.size > 2: # if input in sex, not dec from SAMI_sdss import ten ctr[0] = ten(radec[0], radec[1], radec[2], RA=True) ctr[1] = ten(radec[3], radec[4], radec[5]) else: ctr = radec if readAVM == True and (np.mean(radec) == 0.0): ctr = avm.Spatial.ReferenceValue # read AVM field centre # Input type: fits file -- if isfits: data = pf.open(image) wcs = pywcs.WCS(data[0].header) ctr = wcs.wcs.crval # apply 'nod' (fine positioning shift) if (nod[0] != 0) and (nod[1] != 0): nod[0] = nod[0] * 15 nod = np.array(nod) / 3600. ctr = np.array(ctr) - nod from SAMI_sdss import sixty stringer1 = 'Recentering to: ' + str(ctr[0]) + ' ' + str(ctr[1]) stringer2 = ' ie: ' + str(sixty(ctr[0],RA=True)) + \ ' ' + str(sixty(ctr[1])) print('') print(stringer1) print(stringer2) # shift SAMI bundle into place ra = tab['RA'] / np.cos(np.radians(ctr[1])) + ctr[0] dec = tab['DEC'] + ctr[1] # SAMI bundle (individual fibres) fig.show_circles(ra, dec, 0.8 / 3600., edgecolor='cyan', facecolor='cyan', alpha=0.5) # Exclusion radius fig.show_circles(ctr[0], ctr[1], 165. / 3600., edgecolor='green', facecolor='none', linewidth=3.)