Source code for pyplate.image

import os
import glob
import numpy as np
import ConfigParser
from datetime import datetime
from astropy.io import fits
from .conf import read_conf
from ._version import __version__

try:
    from PIL import Image
except ImportError:
    import Image

gexiv_available = True

try:
    from gi.repository import GExiv2
except ImportError:
    gexiv_available = False

pytz_available = True

try:
    import pytz
except ImportError:
    pytz_available = False
    

[docs]class PlateConverter: """ TIFF-to-FITS converter class """ def __init__(self): self.tiff_dir = '' self.write_fits_dir = '' self.write_wedge_dir = '' self.wedge_height = None
[docs] def assign_conf(self, conf): """ Parse configuration and set class attributes. """ if isinstance(conf, str): conf = read_conf(conf) for attr in ['tiff_dir', 'write_fits_dir', 'write_wedge_dir']: try: setattr(self, attr, conf.get('Files', attr)) except ConfigParser.Error: pass
[docs] def batch_tiff2fits(self): """ Convert all TIFF images in the TIFF directory to FITS. """ for fn_tiff in sorted(glob.glob(os.path.join(self.tiff_dir, '*.tif'))): self.tiff2fits(os.path.basename(fn_tiff))
[docs] def tiff2fits(self, filename, wedge_height=None): """ Convert TIFF image to FITS. Parameters ---------- filename : str Filename of the TIFF image wedge_height : int Height of the wedge in pixels """ if wedge_height is None and self.wedge_height is not None: wedge_height = self.wedge_height fn_tiff = os.path.join(self.tiff_dir, filename) im_pil = Image.open(fn_tiff) exif_datetime = None if gexiv_available: exif = GExiv2.Metadata(fn_tiff) if 'Exif.Image.DateTime' in exif: exif_datetime = exif['Exif.Image.DateTime'] elif 'Exif.Photo.DateTimeDigitized' in exif: exif_datetime = exif['Exif.Photo.DateTimeDigitized'] else: try: exif_datetime = im_pil.tag[306] except Exception: pass if exif_datetime: if exif_datetime[4] == ':': exif_datetime = '{} {}'.format(exif_datetime[:10].replace(':', '-'), exif_datetime[11:]) if pytz_available: dt = datetime.strptime(exif_datetime, '%Y-%m-%d %H:%M:%S') # !!! Need to read timezone from configuration! dt_local = pytz.timezone('Europe/Berlin').localize(dt) exif_datetime = dt_local.astimezone(pytz.utc).strftime('%Y-%m-%dT%H:%M:%S') #print '{} Reading {}'.format(str(datetime.now()), fn_tiff) im = np.array(im_pil.getdata(), dtype=np.uint16).reshape(im_pil.size[1],-1) imwidth = im.shape[1] imheight = im.shape[0] imblack = im.min() imwhite = im.max() if wedge_height is not None: if wedge_height == 0: im_plates = im im_wedge = None else: ycut_wedge = imheight - wedge_height im_wedge = im[ycut_wedge:,:] im_plates = im[:ycut_wedge,:] else: yedge = [] yedge_plate = [] for x in np.arange(100, imwidth-100, 10): # Take column, reverse it and use pixels from the 101st to # 80% of the image height. colrev = im[::-1,x][100:int(0.8*imheight)] # Find nearly white pixels ind_white = np.where(colrev-imblack > 0.95*(imwhite-imblack))[0] # If the first near-white pixel is significantly lighter than # the first 500 pixels in colrev, then use it as an edge of the # wedge. if (ind_white.size > 0 and colrev[ind_white[0]]-imblack > 1.1*(np.median(colrev[:500])-imblack)): yedge.append(imheight - 100 - ind_white[0]) else: col = im[int(0.2*imheight):,x] ind_white = np.where(col-imblack > 0.95*(imwhite-imblack))[0] if (ind_white.size > 0 and col[ind_white[0]]-imblack > 1.1*(np.median(col[:500])-imblack)): yedge_plate.append(ind_white[0] + int(0.2*imheight)) if len(yedge) > 0.01*imwidth: ycut_wedge = int(np.median(yedge)) im_wedge = im[ycut_wedge:,:] im_plates = im[:ycut_wedge,:] else: try: ycut_wedge = int(np.percentile(yedge_plate, 80)) im_wedge = im[ycut_wedge:,:] im_plates = im[:ycut_wedge,:] except ValueError: print 'Cannot separate wedge in {}'.format(fn_tiff) im_wedge = None im_plates = im del im history_line = ('TIFF image converted to FITS with ' 'PyPlate v{} at {}' .format(__version__, datetime.utcnow() .strftime('%Y-%m-%dT%H:%M:%S'))) if im_wedge is not None: hdu_wedge = fits.PrimaryHDU(np.flipud(im_wedge)) if exif_datetime: hdu_wedge.header.set('DATESCAN', exif_datetime) hdu_wedge.header.add_history(history_line) # If filename contains dash, assume that two plates have been scanned # side by side. if '-' in os.path.basename(fn_tiff): xedge = [] for y in np.arange(100, im_plates.shape[0]-100, 10): row = im_plates[y,:] row_mid = row[int(0.25*row.size):int(0.75*row.size)] if row_mid.max() > 1.1*np.median(row_mid): xedge.append(np.argmax(row_mid)+int(0.25*row.size)) xcut = int(np.median(xedge)) im_left = im_plates[:,:xcut] im_right = im_plates[:,xcut:] del im_plates fn_two = os.path.splitext(os.path.basename(fn_tiff))[0] fn_parts = fn_two.split('-') fn_left = '{}{}.fits'.format(fn_parts[0][:7], fn_parts[1]) fn_right = '{}.fits'.format(fn_parts[0]) # Store left-side plate FITS hdu_left = fits.PrimaryHDU(np.flipud(im_left)) hdu_left.header.set('MINVAL', im_left.min()) hdu_left.header.set('MAXVAL', im_left.max()) if exif_datetime: hdu_left.header.set('DATESCAN', exif_datetime) hdu_left.header.add_history(history_line) hdu_left.writeto(os.path.join(self.write_fits_dir, fn_left), clobber=True) if im_wedge is not None: fn_wedge = os.path.splitext(fn_left)[0] + '_w.fits' hdu_wedge.writeto(os.path.join(self.write_wedge_dir, fn_wedge), clobber=True) # Store right-side plate FITS hdu_right = fits.PrimaryHDU(np.flipud(im_right)) hdu_right.header.set('MINVAL', im_right.min()) hdu_right.header.set('MAXVAL', im_right.max()) if exif_datetime: hdu_right.header.set('DATESCAN', exif_datetime) hdu_right.header.add_history(history_line) hdu_right.writeto(os.path.join(self.write_fits_dir, fn_right), clobber=True) fn_wedge = os.path.splitext(fn_right)[0] + '_w.fits' hdu_wedge.writeto(os.path.join(self.write_wedge_dir, fn_wedge), clobber=True) else: fn_plate = os.path.splitext(os.path.basename(fn_tiff))[0] + '.fits' hdu_plate = fits.PrimaryHDU(np.flipud(im_plates)) hdu_plate.header.set('MINVAL', im_plates.min()) hdu_plate.header.set('MAXVAL', im_plates.max()) if exif_datetime: hdu_plate.header.set('DATESCAN', exif_datetime) hdu_plate.header.add_history(history_line) hdu_plate.writeto(os.path.join(self.write_fits_dir, fn_plate), clobber=True) if im_wedge is not None: fn_wedge = os.path.splitext(fn_plate)[0] + '_w.fits' hdu_wedge.writeto(os.path.join(self.write_wedge_dir, fn_wedge), clobber=True)