def transform(self, image: Image): if not self.requirements_check(image): raise ValueError( "Missing required transformations on image. Need:" + str(self.REQUIRES)) if "dark" in image.processing_parameters: raise AttributeError("dark correction already applied") img = fits.open(image.fixed_parameters["path"]) values = img[0].data - image.get_exposure() / self.image.get_exposure( ) * self.dark header = img[0].header # path and filename old_path = image.fixed_parameters["path"] new_path = old_path.parent new_file_name = old_path.stem + "d.fits" new_path = new_path / new_file_name image.fixed_parameters["path"] = new_path # overrwriting old one if os.path.exists(new_path) and CONFIG["OVERWRITE"]: os.remove(new_path) # writing image to fits and creating image object fits.writeto(image.fixed_parameters["path"], values, header) image.processing_parameters["dark"] = True return image
def get_list(self): # data type and corrections if self.type in ["flat", "dark", "data"]: processing_pars = {} elif self.type in ["cdata", "dfdata"]: processing_pars = {"flat": True, "dark": True} self.type = "data" else: processing_pars = {"dark": True} self.type = "data" p = self.path paths = list(p.glob(self.selector)) image_list = [] for im_path in paths: image = fits.open(im_path) exposure = image[0].header["EXPOSURE"] time_jd = image[0].header["JD"] fixed_pars = { "time_jd": time_jd, "path": im_path, "type": self.type, "exposure": exposure, "id": im_path.stem } image_list.append( Image(fixed_parameters=fixed_pars, processing_parameters=processing_pars)) image_list.sort(key=lambda x: x.get_time_jd()) # TODO: logging debug - images # TODO: logging info - len images return image_list
def get_list(self): if self.type in ["cdata", "dfdata"]: processing_parameters = {"flat": True, "dark": True} elif self.type is "ddata": processing_parameters = {"dark": True} else: processing_parameters = {} image_list = [] for path in self.pathlist: image = fits.open(path) exposure = image[0].header["EXPOSURE"] time_jd = image[0].header["JD"] fixed_pars = { "time_jd": time_jd, "path": path, "type": self.type, "exposure": exposure, "id": path.stem } image_list.append( Image(fixed_parameters=fixed_pars, processing_parameters=processing_parameters)) image_list.sort(key=lambda x: x.get_time_jd()) # TODO: logging debug - images # TODO: logging info - len images return image_list
def create_master_flat(images: [Image], save_path: str = CONFIG["FLAT_PATH"]): """ Static method to create master flat from given flat images. Save path specified in Config.FLAT_PATH Overwrites flat image in Config.FLAT_PATH ! :param images: Flat images list :param save_path: Optional save path :return: master flat as Image type object """ flat_filename = "master_flat" + datetime.now().strftime( "_%H-%M-%Y-%d-%m") + ".fits" save_path = Path(save_path) / flat_filename counter = 0 values = [] for image in images: values.append(fits.open(image.fixed_parameters["path"])[0].data) counter += 1 flat_data = np.median(values, axis=0) flat_data = flat_data / np.mean(flat_data) hdu = fits.PrimaryHDU(flat_data) if os.path.exists(save_path) and CONFIG["OVERWRITE"]: os.remove(save_path) hdu.writeto(save_path) return Image( { "time_jd": 0, "exposure": 0, "type": "flat", "path": save_path, "id": "mflat" }, {})
def transform(self, image: Image): if not self.requirements_check(image): raise ValueError( "Missing required transformations on image. Need:" + str(self.REQUIRES)) # INIT from pyraf import iraf iraf.noao.digiphot(_doprint=0) iraf.noao.digiphot.daophot(_doprint=0) capable.OF_GRAPHICS = False # File handling temp_final_out = CONFIG["FILE_DUMP"] + 'TempPhotOut.dat' if os.path.exists(temp_final_out): os.remove(temp_final_out) base = image.fixed_parameters["path"].split('/')[-1] dao_phot_out = CONFIG["FILE_DUMP"] + base + ".mag.dat" phot_txt_out = CONFIG["FILE_DUMP"] + base + "PhoTxOut.dat" # Setting pyraf phot parameters photpars = iraf.photpars.getParList() iraf.photpars.setParam('apertures', CONFIG["APERTURE"]) iraf.phot.setParam('image', image.fixed_parameters["path"]) iraf.phot.setParam('coords', self._get_coordinates_file(image)) iraf.phot.setParam('verify', 'no') iraf.phot.setParam('output', dao_phot_out) iraf.phot.setParam('interactive', 'no') if os.path.exists(dao_phot_out): os.remove(dao_phot_out) # Running IRAF task dump = iraf.phot(mode='h', Stdout=1) if os.path.exists(phot_txt_out): os.remove(phot_txt_out) # Getting better formatted file with magnitudes iraf.txdump(dao_phot_out, 'XCENTER,YCENTER,MAG,MERR', 'yes', Stdout=phot_txt_out) # Getting results from output file with open(phot_txt_out) as output_file: results = {} i = 0 for lines in output_file: parts = lines.split() results[self.objects[i].fixed_parameters["id"]] = ( float(parts[2]) if parts[2] != "INDEF" else None, float(parts[3]) if parts[3] != "INDEF" else None) i += 1 image.processing_parameters["photometry"] = results return image
def transform(self, image: Image): if not self.requirements_check(image): raise ValueError( "Missing required transformations on image. Need:" + str(self.REQUIRES)) shifts = {} for id, value in image.get_photometry().items(): star = self.find_star_with_id(id) if star is None: continue cat_mag = star.get_catalog_magnitude() shifts[id] = (cat_mag[0] - value[0], np.sqrt(cat_mag[1]**2 + value[1]**2)) image.processing_parameters["shifts"] = shifts image.processing_parameters["shift"] = ShiftTransform.calculate_shift( image) return image
def transform(self, image: Image): img = fits.getdata(image.get_path()) xpos, ypos = self._get_coordinates_arrays(image) mag, magerr, flux, fluxerr, sky, skyerr, badflag, outstr = \ aper.aper(img, xpos, ypos, phpadu=1, apr=self.aperture, zeropoint=25, skyrad=[40, 50], badpix=[-12000, 1060000], exact=True) results = {} i = 0 for o in self.objects: results[o.get_id()] = ( float(mag[i]) if mag[i] is not "nan" else None, float(magerr[i]) if magerr[i] is not "nan" else None) i += 1 image.processing_parameters["photometry"] = results # workaround for single object photometry try: image.processing_parameters["src_flux"] = (float(flux[0]), float(fluxerr[0])) image.processing_parameters["sky"] = (float(sky[0]), float(skyerr[0])) except IndexError: image.processing_parameters["src_flux"] = (float(flux), float(fluxerr)) image.processing_parameters["sky"] = (float(sky), float(skyerr)) return image
def _load_images(self): image_list = [] db_image_list = self.session.query(db.Frame).all() # TODO: logging debug - list query # TODO: logging info - len of loaded images for db_image in db_image_list: image_list.append( Image(fixed_parameters={ "time_jd": db_image.time_jd, "exposure": db_image.exposure, "id": db_image.id, "type": db_image.type, "path": Path(db_image.path) }, processing_parameters=eval(db_image.additional))) return self._string_ids(image_list)
def _get_coordinates_arrays(self, image: Image): """ Creates coordinates arrays for photometry using wcs coordinates in FITS header. :return: filename """ header = fits.getheader(image.get_path()) w = WCS(header) pixel_coordinates_ra = [] pixel_coordinates_dec = [] for o in self.objects: x, y = w.wcs_world2pix(o.fixed_parameters['ra'], o.fixed_parameters['dec'], 1) pixel_coordinates_ra.append(float(x)) pixel_coordinates_dec.append(float(y)) return np.array(pixel_coordinates_ra), np.array(pixel_coordinates_dec)
def _get_coordinates_file(self, image: Image): """ Creates coordinates file for photometry using wcs coordinates in FITS header. :return: filename """ filename = CONFIG["FILE_DUMP"] + "xy_coords_file.txt" header = fits.getheader(image.get_path()) w = WCS(header) pixel_coordinates = [] for o in self.objects: x, y = w.wcs_world2pix(o.fixed_parameters['ra'], o.fixed_parameters['dec'], 1) pixel_coordinates.append([float(x), float(y)]) np.savetxt(filename, pixel_coordinates) return filename
def create_master_dark(images: [Image], exposure=20, save_path=CONFIG["DARK_PATH"]): """ Static method to create master flat from given flat images. Save path specified in Config.DARK_PATH :param images: Dark images list :param save_path: Optional save path :param exposure: exposure of input dark images to be selected and combined :return: master flat as Image type object """ dark_filename = "master_dark" + datetime.now().strftime( "_%H-%M-%Y-%d-%m") + ".fits" save_path = Path(save_path) / dark_filename counter = 0 values = [] for image in images: if image.get_exposure() == exposure: values.append( fits.open(image.fixed_parameters["path"])[0].data) counter += 1 if counter == 0: raise RuntimeError("No darks with given exposure") dark_data = np.median(values, axis=0) hdu = fits.PrimaryHDU(dark_data) if os.path.exists(save_path) and CONFIG["OVERWRITE"]: os.remove(save_path) hdu.writeto(save_path) return Image( { "time_jd": 0, "exposure": 20, "type": "dark", "path": save_path, "id": "mdark" }, {})
def stacking_procedure(images: [Image]): """stacks images in list into single one and writes file header will be from middle image in the list. Time will be between start of first and end of last exposure with exposure length of this difference. :param images list of Image list objects to stack """ # go through images and collect info names = [] i = 0 half = len(images) // 2 tfirst = images[0].get_time_jd() tlast = images[-1].get_time_jd() + images[-1].get_exposure() / 86000 timejd_mid = (tfirst + tlast) / 2 timecoverage = (tlast - tfirst) * 86000 # s for image in images: # get stack names if "stack" in image.processing_parameters: for name in image.get_stack(): names.append(name) else: names.append(str(image.get_path())) i += 1 if i == half: header = fits.getheader(image.get_path()) midpoint_WCS = WCS(header) reprojected = [] # reproject all images onto the middle one for image in images: data = fits.getdata(image.get_path()) header_wcs = fits.getheader(image.get_path()) ccddata = ccdproc.CCDData(data, wcs=WCS(header_wcs), unit="adu") reprojected.append(wcs_project(ccddata, midpoint_WCS)) combiner = ccdproc.Combiner(reprojected) final_image_data = combiner.average_combine() final_image_data.wcs = WCS(header) header["EXPTIME"] = timecoverage header["EXPOSURE"] = timecoverage header["JD"] = tfirst filename = "stack-" + str(timejd_mid) + "-e" + "{:.0f}".format( timecoverage) + ".fits" path = Path("/tmp") path = path / filename if os.path.exists(path): os.remove(path) fits.writeto(path, final_image_data, header) stacked_image = Image(fixed_parameters={ "path": path, "exposure": timecoverage, "time_jd": tfirst, "type": "data", "id": filename }, processing_parameters={ "flat": True, "dark": True, "stack": names }) return stacked_image