def fitsInfo(fitsname=None): """ Get fits info """ hdu = pyfits.open(fitsname) hdr = hdu[0].header ra = hdr['CRVAL1'] dra = abs(hdr['CDELT1']) raPix = hdr['CRPIX1'] dec = hdr['CRVAL2'] ddec = abs(hdr['CDELT2']) decPix = hdr['CRPIX2'] freq0 = 0 for i in range(1, hdr['NAXIS']+1): if hdr['CTYPE%d' % i].strip() == 'FREQ': freq0 = hdr['CRVAL%d' % i] break ndim = hdr["NAXIS"] imslice = np.zeros(ndim, dtype=int).tolist() imslice[-2:] = slice(None), slice(None) image = hdu[0].data[imslice] wcs = WCS(hdr, mode='pyfits') return {'image': image, 'wcs': wcs, 'ra': ra, 'dec': dec, 'dra': dra, 'ddec': ddec, 'raPix': raPix, 'decPix': decPix, 'freq0': freq0}
def loadFits(imagename): with pyfits.open(imagename) as hdu: data = hdu[0].data hdr = hdu[0].header wcs = WCS(hdr, mode="pyfits") return data, hdr, wcs
def reshape_data (image, prefix=None): """ Reshape FITS data to (stokes,freq,npix_ra,npix_dec). Returns reshaped data, wcs, the image header, and pixel size. image: Fits data """ with pyfits.open(image) as hdu: data = hdu[0].data hdr = hdu[0].header shape = list(data.shape) ndim = len(shape) wcs = WCS(hdr, mode="pyfits") log = logger(level=0, prefix=prefix) pixel_size = abs(hdr["CDELT1"]) if ndim < 2: log.error(" The FITS file needs at least two dimensions") # This is the shape I want the data in want = ( ["STOKES",0], ["FREQ",1], ["RA",2], ["DEC",3], ) # Assume RA,DEC is first (FITS) or last two (NUMPY) if ndim > 3: for ctype, ind in want[:2]: for axis in range(1, ndim+1): if hdr["CTYPE%d"%axis].startswith(ctype): want[ind].append(ndim-axis) if want[0][-1] == want[1][-2] and want[0][-2] == want[1][-1]: tmp = shape[0] shape[0] = shape[1] shape[1] = tmp data = numpy.reshape(data,shape) if ndim == 3: if not hdr["CTYPE3"].startswith("FREQ"): data = data[0,...] elif ndim > 4: log.error(" FITS file has more than 4 axes. Aborting") return data, wcs, hdr, pixel_size
def __init__ (self,header): """Constructor. Create from filename (treated as FITS file), or a FITS header object"""; # attach to FITS file or header if isinstance(header,str): header = pyfits.open(header)[0].header; else: self.wcs = WCS(header,mode="pyfits"); try: ra0,dec0 = self.wcs.getCentreWCSCoords(); self.xpix0,self.ypix0 = self.wcs.wcs2pix(*self.wcs.getCentreWCSCoords()); self.xscale = self.wcs.getXPixelSizeDeg()*DEG; self.yscale = self.wcs.getYPixelSizeDeg()*DEG; has_projection = True; except: print "No WCS in FITS file, falling back to pixel coordinates."; ra0 = dec0 = self.xpix0 = self.ypix0 = 0; self.xscale = self.yscale = DEG/3600; has_projection = False; _Projector.__init__(self,ra0*DEG,dec0*DEG,has_projection=has_projection);
def accept(self): """Tries to make a brick, and closes the dialog if successful.""" sources = [ src for src in self.model.sources if src.selected and src.typecode == 'pnt' ] filename = self.wfile.filename() if not self._fileSelected(filename): return # get PB expression pbfunc = None if self.wpb_apply.isChecked(): pbexp = str(self.wpb_exp.text()) try: pbfunc = eval("lambda r,fq:" + pbexp) except Exception as err: QMessageBox.warning( self, "Error parsing PB experssion", "Error parsing primary beam expression %s: %s" % (pbexp, str(err))) return # get frequency freq = str(self.wfreq.text()) freq = float(freq) * 1e+6 if freq else None # get pad factor pad = str(self.wpad.text()) pad = max(float(pad), 1) if pad else 1 # read fits file busy = BusyIndicator() try: input_hdu = pyfits.open(filename)[0] except Exception as err: busy = None QMessageBox.warning( self, "Error reading FITS", "Error reading FITS file %s: %s" % (filename, str(err))) return # reset data if asked to if self.woverwrite.isChecked(): input_hdu.data[...] = 0 # insert sources Imaging.restoreSources(input_hdu, sources, 0, primary_beam=pbfunc, freq=freq) # save fits file try: # pyfits seems to produce an exception: # TypeError: formatwarning() takes exactly 4 arguments (5 given) # when attempting to overwrite a file. As a workaround, remove the file first. if os.path.exists(filename): os.remove(filename) input_hdu.writeto(filename) except Exception as err: traceback.print_exc() busy = None QMessageBox.warning( self, "Error writing FITS", "Error writing FITS file %s: %s" % (filename, str(err))) return changed = False sources = self.model.sources # remove sources from model if asked to if self.wdel.isChecked(): sources = [ src for src in sources if not (src.selected and src.typecode == 'pnt') ] changed = True # add image to model if asked to if self.wadd.isChecked(): hdr = input_hdu.header # get image parameters max_flux = float(input_hdu.data.max()) wcs = WCS(hdr, mode='pyfits') # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1 for iaxis in range(hdr['NAXIS']): axs = str(iaxis + 1) name = hdr.get('CTYPE' + axs, axs).upper() if name.startswith("RA"): ra0 = hdr.get('CRPIX' + axs, 1) - 1 elif name.startswith("DEC"): dec0 = hdr.get('CRPIX' + axs, 1) - 1 # convert pixel to degrees ra0, dec0 = wcs.pix2wcs(ra0, dec0) ra0 *= DEG dec0 *= DEG sx, sy = wcs.getHalfSizeDeg() sx *= DEG sy *= DEG nx, ny = input_hdu.data.shape[-1:-3:-1] # check if this image is already contained in the model for src in sources: if isinstance(getattr(src, 'shape', None), ModelClasses.FITSImage) and os.path.samefile( src.shape.filename, filename): # update source parameters src.pos.ra, src.pos.dec = ra0, dec0 src.flux.I = max_flux src.shape.ex, src.shape.ey = sx, sy src.shape.nx, src.shape.ny = nx, ny src.shape.pad = pad break # not contained, make new source object else: pos = ModelClasses.Position(ra0, dec0) flux = ModelClasses.Flux(max_flux) shape = ModelClasses.FITSImage(sx, sy, 0, os.path.basename(filename), nx, ny, pad=pad) img_src = SkyModel.Source(os.path.splitext( os.path.basename(filename))[0], pos, flux, shape=shape) sources.append(img_src) changed = True if changed: self.model.setSources(sources) self.model.emitUpdate(SkyModel.SkyModel.UpdateAll, origin=self) self.parent().showMessage("Wrote %d sources to FITS file %s" % (len(sources), filename)) busy = None return QDialog.accept(self)
shape = None source = SkyModel.Source(name, pos, flux, shape=shape) # Adding source peak flux (error) as extra flux attributes for sources, # and to avoid null values for point sources I_peak = src["Total_flux"] if shape: source.setAttribute("I_peak", float(src["peak_flux"])) source.setAttribute("I_peak_err", float(src["err_peak_flux"])) else: source.setAttribute("I_peak", float(src["int_flux"])) source.setAttribute("I_peak_err", float(src["err_int_flux"])) return source data = Table.read('{0}_comp.{1}'.format( outfile.split('.')[0], outfile.split('.')[-1]), format=outfile.split('.')[-1]) for i, src in enumerate(data): model.sources.append(tigger_src(src, i)) wcs = WCS(image) centre = wcs.getCentreWCSCoords() model.ra0, model.dec0 = map(numpy.deg2rad, centre) model.save(tname_lsm) # Rename using CORPAT utils.xrun("tigger-convert", [tname_lsm, "--rename -f"])
class AddBrickDialog(QDialog): def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Add FITS brick") lo = QVBoxLayout(self) lo.setMargin(10) lo.setSpacing(5) # file selector self.wfile = FileSelector(self, label="FITS filename:", dialog_label="FITS file", default_suffix="fits", file_types="FITS files (*.fits *.FITS)", file_mode=QFileDialog.ExistingFile) lo.addWidget(self.wfile) # overwrite or add mode lo1 = QGridLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) lo1.addWidget(QLabel("Padding factor:", self), 0, 0) self.wpad = QLineEdit("2", self) self.wpad.setValidator(QDoubleValidator(self)) lo1.addWidget(self.wpad, 0, 1) lo1.addWidget(QLabel("Assign source name:", self), 1, 0) self.wname = QLineEdit(self) lo1.addWidget(self.wname, 1, 1) # OK/cancel buttons lo.addSpacing(10) lo2 = QHBoxLayout() lo.addLayout(lo2) lo2.setContentsMargins(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("filenameSelected"), self._fileSelected) # internal state self.qerrmsg = QErrorMessage(self) def setModel(self, model): self.model = model if model.filename(): self._model_dir = os.path.dirname(os.path.abspath( model.filename())) else: self._model_dir = os.path.abspath('.') self.wfile.setDirectory(self._model_dir) self._fileSelected(self.wfile.filename(), quiet=True) def _fileSelected(self, filename, quiet=False): self.wokbtn.setEnabled(False) if not filename: return None # check that filename matches model if not os.path.samefile(self._model_dir, os.path.dirname(filename)): self.wfile.setFilename('') if not quiet: QMessageBox.warning( self, "Directory mismatch", """<P>The FITS file must reside in the same directory as the current sky model.</P>""") self.wfile.setDirectory(self._model_dir) return None # if filename is not in model already, enable the "add to model" control for src in self.model.sources: if isinstance(getattr(src, 'shape', None), ModelClasses.FITSImage): if os.path.exists(src.shape.filename) and os.path.samefile( src.shape.filename, filename): if not quiet: QMessageBox.warning( self, "Already in model", "This FITS brick is already present in the model.") self.wfile.setFilename('') return None if not str(self.wname.text()): self.wname.setText( os.path.splitext(os.path.basename(str(filename)))[0]) self.wokbtn.setEnabled(True) return filename def accept(self): """Tries to add brick, and closes the dialog if successful.""" filename = self.wfile.filename() # read fits file busy = BusyIndicator() try: input_hdu = pyfits.open(filename)[0] except Exception, err: busy = None QMessageBox.warning( self, "Error reading FITS", "Error reading FITS file %s: %s" % (filename, str(err))) return # check name srcname = str(self.wname.text()) or os.path.splitext( os.path.basename(str(filename)))[0] if srcname in set([src.name for src in self.model.sources]): QMessageBox.warning( self, "Already in model", "<p>The model already contains a source named '%s'. Please select a different name.</p>" % srcname) return # get image parameters hdr = input_hdu.header max_flux = float(input_hdu.data.max()) wcs = WCS(hdr, mode='pyfits') # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1 for iaxis in range(hdr['NAXIS']): axs = str(iaxis + 1) name = hdr.get('CTYPE' + axs, axs).upper() if name.startswith("RA"): ra0 = hdr.get('CRPIX' + axs, 1) - 1 elif name.startswith("DEC"): dec0 = hdr.get('CRPIX' + axs, 1) - 1 # convert pixel to degrees # print ra0,dec0; ra0, dec0 = wcs.pix2wcs(ra0, dec0) ra0 *= DEG dec0 *= DEG # print ModelClasses.Position.ra_hms_static(ra0); # print ModelClasses.Position.dec_sdms_static(dec0); sx, sy = wcs.getHalfSizeDeg() sx *= DEG sy *= DEG nx, ny = input_hdu.data.shape[-1:-3:-1] pos = ModelClasses.Position(ra0, dec0) flux = ModelClasses.Flux(max_flux) shape = ModelClasses.FITSImage(sx, sy, 0, os.path.basename(filename), nx, ny, pad=float(str(self.wpad.text()) or "1")) img_src = SkyModel.Source(srcname, pos, flux, shape=shape) self.model.setSources(self.model.sources + [img_src]) self.model.emitUpdate(SkyModel.SkyModel.UpdateAll, origin=self) busy = None return QDialog.accept(self)
def __init__(self, imagename, psfname=None, sourcefinder_name='pybdsm', saveformat="gaul", makeplots=True, do_psf_corr=True, do_local_var=True, psf_corr_region=5, local_var_region=10, rel_excl_src=None, pos_smooth=2, neg_smooth=2, loglevel=0, thresh_pix=5, thresh_isl=3, neg_thresh_isl=3, neg_thresh_pix=5, reset_rel=None, prefix=None, do_nearsources=False, savefits=False, increase_beam_cluster=False, savemask_pos=False, savemask_neg=False, no_smooth=True, **kw): """ Takes in image and extracts sources and makes reliability estimations.. imagename: Fits image psfname: PSF fits image, optional. sourcefinder_name: str, optional. Default 'pybdsm'. Uses source finder specified. makeplots: bool, optional. Default is True. Make reliability plots. do_psf_corr : bool, optional. Default True. If True, PSF correlation will be added as an extra parameter for density estimations. NB: the PSF fits image must be provided. do_local_var : bool, optional. Default is True. If True, adds local variance as an extra parameter, for density estimations. do_nearsources: boolean. Default is False. If true it adds number of nearest neighnours as an extra parameter. It looks for sources around 5 beam sizes. psf_corr_region : int, optional. Default value is 5. Data size to correlate around a source, in beam sizes. local_var_region: int, optional. Default 10. Data size to compute the local variance in beam sizes. rel_excl_src : floats, optional. Default is None. Excludes sources in a specified region e.g ra, dec, radius in degrees. For 2 regions: ra1, dec1, radius1: ra2, dec2, radius2, etc. pos_smooth : float, optional. Default 2. Masking threshold for the positive image. For default value 2, data peaks < 2 * image noise are masked. neg_smooth : float, optional. Default 2. Similar to pos_smooth but applied to the negative image. thresh_isl : float, optional. Default is 3. Threshold for forming islands in the positive image thresh_pix : float, optional. Default is 5. Threshold for model fitting, in positive image. neg_thresh_isl : float, optional. Default is 3. Simialr to thresh_isl but for negative image. neg_thresh_pix : float, optional. Default is 5. Similar to thresh_pix but for negative image. savefits: boolean. Default is False. If True a negative image is saved. reset_rel: boolean. Default is False. If true then sources with correlation < 0.002 and rel >0.60 have their reliabilities set to 0. increase_beam_cluster: boolean, optional. If True, sources groupings will be increase by 20% the beam size. If False, the actual beam size will be used. Default is False. savemask_pos: boolean, optional. If true the mask applied on the positive side of an image after smoothing is saved. savemask_neg: Similar to savemask_pos but for the negative side of an image. loglevel : int, optional. Default is 0. Provides Pythonlogging options, 0, 1, 2 and 3 are for info, debug, error and critial respectively. kw : kward for source extractions. Should be a mapping e.g kw['thresh_isl'] = 2.0 or kw['do_polarization'] = True """ # self.smoothing = not no_smooth self.prefix = prefix # log level self.loglevel = loglevel self.log = utils.logger(self.loglevel, prefix=self.prefix) # image, psf image self.imagename = imagename self.psfname = psfname with pyfits.open(imagename) as hdu: self.header = hdu[0].header self.wcs = WCS(self.header, mode="pyfits") self.pixelsize = abs(self.header["cdelt1"]) self.bmaj = numpy.deg2rad(self.header["BMAJ"]) # boolean optionals self.makeplots = makeplots self.do_local_var = do_local_var self.nearsources = do_nearsources self.do_psf_corr = do_psf_corr self.savemaskpos = savemask_pos self.savemaskneg = savemask_neg self.savefits = savefits self.derel = reset_rel self.log.info("Catalogues will be saved as %s, where srl is source " " and gaul is Gaussians. " % saveformat) self.catalogue_format = "." + saveformat if not self.psfname: self.log.info(" No psf provided, do_psf_corr is set to False.") self.do_psf_corr = False # computing negative noise self.noise, self.mean = utils.negative_noise(self.imagename, self.prefix) self.log.info(" The negative noise is %e Jy/beam" % self.noise) if self.noise == 0: self.log.debug(" The negative noise is 0, check image") # source finder initialization self.sourcefinder_name = sourcefinder_name self.log.info(" Using %s source finder to extract the sources." % self.sourcefinder_name) self.negimage = self.prefix + "_negative.fits" utils.invert_image(self.imagename, self.negimage) # smoothing factors self.pos_smooth = pos_smooth self.neg_smooth = neg_smooth # region to evaluate self.corrstep = psf_corr_region self.localstep = local_var_region self.radiusrm = rel_excl_src self.do_beam = increase_beam_cluster beam_pix = int(round(numpy.rad2deg(self.bmaj) / self.pixelsize)) self.locstep = self.localstep * beam_pix self.cfstep = self.corrstep * beam_pix self.bmin, self.bpa = self.header["BMIN"], self.header["BPA"] self.opts_pos = {} if self.do_beam: bmaj = self.header["BMAJ"] self.opts_pos["beam"] = (1.2 * bmaj, 1.2 * self.bmin, self.bpa) # Pybdsm or source finder fitting thresholds self.thresh_isl = thresh_isl self.thresh_pix = thresh_pix self.opts_pos = dict(thresh_pix=self.thresh_pix, thresh_isl=self.thresh_isl) self.opts_pos.update(kw) self.opts_neg = {} self.opts_neg.update(kw) self.neg_thresh_isl = neg_thresh_isl self.neg_thresh_pix = neg_thresh_pix self.opts_neg["thresh_isl"] = self.neg_thresh_isl self.opts_neg["thresh_pix"] = self.neg_thresh_pix
def accept(self): """Tries to add brick, and closes the dialog if successful.""" filename = self.wfile.filename() # read fits file busy = BusyIndicator() try: input_hdu = pyfits.open(filename)[0] except Exception as err: busy.reset_cursor() QMessageBox.warning( self, "Error reading FITS", "Error reading FITS file %s: %s" % (filename, str(err))) return # check name srcname = str(self.wname.text()) or os.path.splitext( os.path.basename(str(filename)))[0] if srcname in set([src.name for src in self.model.sources]): QMessageBox.warning( self, "Already in model", "<p>The model already contains a source named '%s'. Please select a different name.</p>" % srcname) return # get image parameters hdr = input_hdu.header max_flux = float(input_hdu.data.max()) wcs = WCS(hdr, mode='pyfits') # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1 for iaxis in range(hdr['NAXIS']): axs = str(iaxis + 1) name = hdr.get('CTYPE' + axs, axs).upper() if name.startswith("RA"): ra0 = hdr.get('CRPIX' + axs, 1) - 1 elif name.startswith("DEC"): dec0 = hdr.get('CRPIX' + axs, 1) - 1 # convert pixel to degrees # print ra0,dec0 ra0, dec0 = wcs.pix2wcs(ra0, dec0) ra0 *= DEG dec0 *= DEG # print ModelClasses.Position.ra_hms_static(ra0) # print ModelClasses.Position.dec_sdms_static(dec0) sx, sy = wcs.getHalfSizeDeg() sx *= DEG sy *= DEG nx, ny = input_hdu.data.shape[-1:-3:-1] pos = ModelClasses.Position(ra0, dec0) flux = ModelClasses.Flux(max_flux) shape = ModelClasses.FITSImage(sx, sy, 0, os.path.basename(filename), nx, ny, pad=float(str(self.wpad.text()) or "1")) img_src = SkyModel.Source(srcname, pos, flux, shape=shape) self.model.setSources(self.model.sources + [img_src]) self.model.emitUpdate(SkyModel.SkyModel.UpdateAll, origin=self) busy.reset_cursor() return QDialog.accept(self)
def main(): # setup some standard command-line option parsing # from optparse import OptionParser parser = OptionParser(usage="""%prog: [options] <image names...>""") parser.add_option("-o", "--output", dest="output", type="string", help="name of output FITS file") parser.add_option( "-r", "--replace", action="store_true", help="replace (first) input file by output. Implies '--force'.") parser.add_option("-f", "--force", dest="force", action="store_true", help="overwrite output file even if it exists") parser.add_option( "-S", "--sanitize", type="float", metavar="VALUE", help="sanitize FITS files by replacing NANs and INFs with VALUE") parser.add_option("-N", "--nonneg", action="store_true", help="replace negative values by 0") parser.add_option("-m", "--mean", dest="mean", action="store_true", help="take mean of input images") parser.add_option("-d", "--diff", dest="diff", action="store_true", help="take difference of 2 input images") parser.add_option( "-t", "--transfer", action="store_true", help= "transfer data from image 2 into image 1, preserving the FITS header of image 1" ) parser.add_option("-z", "--zoom", dest="zoom", type="int", metavar="NPIX", help="zoom into central region of NPIX x NPIX size") parser.add_option("-R", "--rescale", dest="rescale", type="float", help="rescale image values") parser.add_option( "-E", "--edit-header", metavar="KEY=VALUE", type="string", action="append", help= "replace header KEY with VALUE. Use KEY=VALUE for floats and KEY='VALUE' for strings." ) parser.add_option("-D", "--delete-header", metavar="KEY", type="string", action="append", help="Remove KEY from header") parser.add_option( "--stack", metavar="outfile:axis", help= "Stack a list of FITS images along a given axis. This axis may given as an integer" "(as it appears in the NAXIS keyword), or as a string (as it appears in the CTYPE keyword)" ) parser.add_option("--reorder", help="Required order. List of comma seperated indeces") parser.add_option( "--add-axis", metavar="CTYPE:CRVAL:CRPIX:CDELT[:CUNIT:CROTA]", action="append", default=[], help= "Add axis to a FITS image. The AXIS will be described by CTYPE:CRVAL:CRPIX:CDELT[:CUNIT:CROTA]. " "The keywords in brackets are optinal, while those not in brackets are mendatory. " "This axis will be the last dimension. Maybe specified more than once." ) parser.add_option( "--unstack", metavar="prefix:axis:each_chunk", help= "Unstack a FITS image into smaller chunks each having [each_chunk] planes along a given axis. " "This axis may given as an integer (as it appears in the NAXIS keyword), or as a string " "(as it appears in the CTYPE keyword)") parser.add_option("-H", "--header", action="store_true", help="print header(s) of input image(s)") parser.add_option( "-s", "--stats", action="store_true", help="print stats on images and exit. No output images will be written." ) parser.set_defaults(output="", mean=False, zoom=0, rescale=1, edit_header=[], delete_header=[]) (options, imagenames) = parser.parse_args() if not imagenames: parser.error("No images specified. Use '-h' for help.") # print "%d input image(s): %s"%(len(imagenames),", ".join(imagenames)); images = [pyfits.open(img) for img in imagenames] updated = False # Stack FITS images if options.stack: if len(imagenames) < 1: parser.error("Need more than one image to stack") stack_args = options.stack.split(":") if len(stack_args) != 2: parser.error( "Two --stack options are required. See ./fitstool.py -h") outfile, axis = stack_args _string = True try: axis = int(axis) _string = False except ValueError: _string = True stack_planes(imagenames, ctype=axis if _string else None, keep_old=True, axis=None if _string else axis, outname=outfile, fits=True) # Unstack FITS image if options.unstack: image = imagenames[0] if len(imagenames) < 1: parser.error("Need more than one image to stack") unstack_args = options.unstack.split(":") if len(unstack_args) != 3: parser.error( "Two --unstack options are required. See ./fitstool.py -h") prefix, axis, each_chunk = unstack_args _string = True try: axis = int(axis) _string = False except ValueError: _string = True each_chunk = int(each_chunk) unstack_planes(image, each_chunk, ctype=axis if _string else None, axis=None if _string else axis, prefix=prefix, fits=True) sys.exit(0) if options.add_axis: for axis in options.add_axis: hdu = pyfits.open(imagenames[0]) hdr = hdu[0].header ndim = hdr["NAXIS"] hdu[0].data = hdu[0].data[numpy.newaxis, ...] _mendatory = "CTYPE CRVAL CDELT CRPIX".split() _optional = "CUNIT CROTA".split() L = len(_mendatory + _optional) values = axis.split(":") Lv = len(values) if len(_mendatory) > len(values): parser.error( "Something with the way specified --add-axis. See %prog -h for help" ) for i, value in enumerate(values): try: value = float(value) except ValueError: if isinstance(value, str): value = value.upper() hdu[0].header["%s%d" % ((_mendatory + _optional)[i], ndim + 1)] = value hdu.writeto(imagenames[0], clobber=True) print("Successfully added axis %s to %s" % (values[0], imagenames[0])) if options.reorder: for image in imagenames: order = map(int, options.reorder.split(",")) reorder(image, order=order, outfile=image) if options.header: for filename, img in zip(imagenames, images): img.verify('silentfix') if len(imagenames) > 1: print "======== FITS header for", filename for hdrline in img[0].header.cards: print hdrline if options.replace or len(imagenames) < 2: if options.output: parser.error("Cannot combine -r/--replace with -o/--output") outname = imagenames[0] options.force = True autoname = False else: outname = options.output autoname = not outname if autoname: outname = re.split('[_]', imagenames[0], 1)[-1] for keyval in options.edit_header: key, val = keyval.split("=") q = '' if val[0] == "'" and val[-1] == "'": images[0][0].header[key] = val[1:-1:] q = '"' elif val[-1] == 'd' or key.startswith('NAXIS'): images[0][0].header[key] = int(val[:-1] if val[-1] == 'd' else val) else: try: images[0][0].header[key] = float(val) except: images[0][0].header[key] = val q = '"' print "Setting header %s=%s%s%s" % (key, q, val, q) updated = True for key in options.delete_header: try: del images[0][0].header[key] except KeyError: raise "Key '%s' not found in FITS header" % key print "Deleting key '%s' header" % key updated = True if options.sanitize is not None: print "Sanitizing: replacing INF/NAN with", options.sanitize for img in images: d = img[0].data d[numpy.isnan(d) + numpy.isinf(d)] = options.sanitize # if using stats, do not generate output if not options.stats: updated = True if options.nonneg: print "Replacing negative value by 0" for img, name in zip(images, imagenames)[:1]: d = img[0].data wh = d < 0 d[wh] = 0 print "Image %s: replaced %d points" % (name, wh.sum()) updated = True if options.transfer: if len(images) != 2: parser.error( "The --transfer option requires exactly two input images.") if autoname: outname = "xfer_" + outname print "Transferring %s into coordinate system of %s" % (imagenames[1], imagenames[0]) images[0][0].data = images[1][0].data updated = True elif options.diff: if len(images) != 2: parser.error( "The --diff option requires exactly two input images.") if autoname: outname = "diff_" + outname print "Computing difference" data = images[0][0].data data -= images[1][0].data updated = True elif options.mean: if autoname: outname = "mean%d_" % len(images) + outname print "Computing mean" data = images[0][0].data for img in images[1:]: data += img[0].data data /= len(images) images = [images[0]] updated = True if options.zoom: z = options.zoom if autoname: outname = "zoom%d_" % z + outname if len(images) > 1: "Too many input images specified for this operation, at most 1 expected" sys.exit(2) data = images[0][0].data nx = data.shape[-2] ny = data.shape[-1] zdata = data[:, :, (nx - z) / 2:(nx + z) / 2, (ny - z) / 2:(ny + z) / 2] #update header hdr = images[0][0].header wcs = WCS(hdr, mode="pyfits") cr1, cr2 = wcs.pix2wcs(ny / 2, nx / 2) hdr["CRVAL1"] = cr1 hdr["CRVAL2"] = cr2 hdr["CRPIX1"] = zdata.shape[-1] / 2 hdr["CRPIX2"] = zdata.shape[-2] / 2 print "Making zoomed image of shape", "x".join(map(str, zdata.shape)) images = [pyfits.PrimaryHDU(zdata, hdr)] updated = True if options.rescale != 1: if autoname and not updated: outname = "rescale_" + outname if len(images) > 1: "Too many input images specified for this operation, at most 1 expected" sys.exit(2) print "Applying scaling factor of %f to image values" % options.rescale images[0][0].data *= options.rescale updated = True if updated: imagenames[0] = outname if options.stats: for ff, filename in zip(images, imagenames): data = ff[0].data min, max, dum1, dum2 = scipy.ndimage.measurements.extrema(data) sum = data.sum() mean = sum / data.size std = math.sqrt(((data - mean)**2).mean()) print "%s: min %g, max %g, sum %g, np %d, mean %g, std %g" % ( filename, min, max, sum, data.size, mean, std) sys.exit(0) if updated: print "Writing output image", outname if os.path.exists(outname) and not options.force: print "Output image exists, rerun with the -f switch to overwrite." sys.exit(1) images[0].writeto(outname, clobber=True) elif not (options.header or options.stack or options.add_axis or options.reorder): print "No operations specified. Use --help for help."
def correlation_factor(src, psf, img, pos_sky, step=None): image = pf.open(img) psf_image = pf.open(psf) hdr = image[0].header psf_hdr = psf_image[0].header ndim = len(image[0].shape) if ndim == 4: image_data = image[0].data[0, 0, :, :] psf_data_ = psf_image[0].data[0, 0, :, :] if ndim == 3: image_data = image[0].data[0, :, :] psf_data_ = psf_image[0].data[0, :, :] if ndim == 2: image_data = image[0].data[:, :] psf_data_ = psf_image[0].data[:, :] elif ndim < 2: raise ValueError('The FITS file needs at least two dimensions') elif ndim > 4: raise ValueError('FITS file has more than 4 axes. Aborting') # image padding n_pix = hdr['NAXIS1'] padding = np.zeros([n_pix + 2.0 * step, n_pix + 2.0 * step]) padding[step:-step, step:-step] = image_data hdr['CRPIX1'], hdr['CRPIX2'] = (n_pix + 2.0 * step) / 2.0, ( n_pix + 2.0 * step) / 2.0 # taking the positions wcs = WCS(hdr, mode='pyfits') pos_sky = [pos_sky] pos = [wcs.wcs2pix(*position) for position in pos_sky] step = [step, step] wcs_psf = WCS(psf_hdr, mode='pyfits') #pf.writeto('expore.fits', padding, header=hdr, clobber=True) center_psf_ra0, center_psf_dec0 = wcs_psf.wcs2pix(psf_hdr['CRVAL1'], psf_hdr['CRVAL2']) psf_region = psf_data_[center_psf_dec0 - step[0]:center_psf_dec0 + step[0], center_psf_ra0 - step[1]:center_psf_ra0 + step[1]] psf_data = psf_region.flatten() for (ra, dec) in pos: data = padding[dec - step[0]:dec + step[0], ra - step[1]:ra + step[1]] data_region = data.flatten() #if len(data_region) and len(psf_data) > 1: if data_region.shape == psf_data.shape: # computing th correlation matrix and cf is the correlation factor cmatrix = np.corrcoef((data_region, psf_data)) if len(cmatrix) > 0: cf = (np.diag((np.rot90(cmatrix))**2).sum())**0.5 / 2**0.5 else: cf = 0.0000001 src.setTag('cf', cf) return cf
def __init__(self, imagename, psfname, pmodel, nmodel, local_step=10, snr_thresh=40, high_corr_thresh=0.5, negdetec_region=10, negatives_thresh=5, phasecenter_excl_radius=None, prefix=None, loglevel=0): """ Determines sources that require direction-dependent (DD) calibration solutions. psfname: PSF fits data pmodel: Model of the positive image. nmodel: Model of the negative image header: The header of the input image snr_thresh: float, optional. Default is 40. Any source with 40 x the minimum SNR. high_corr_thresh: float, optional. Default is 0.5. Sources of high PSF correlation have correlation above 0.5. negdetec_region: float, optional. Default is 10. Region to lookup for negative detections around. In beam size. negative_thresh: float, optional. Default is 5. The number of nearby negative detections. Sources with number > 5 require direction dependent (DD) calibration solutions. phasecenter_excl_region: float (in degrees), optional. A radius from the phase center (in beam sizes) to exclude the sources from the evaluation. prefix: str, optional. Sets a prefix to the output directory. loglevel: int, optional. Default 0. Python logging. 0, 1, 2, 3 for info, debug, error and critical, respectively. """ self.loglevel = loglevel self.prefix = prefix self.log = utils.logger(self.loglevel, prefix=self.prefix) #image and psf image self.pmodel = pmodel self.nmodel = nmodel self.psfname = psfname self.log.info(" Loading image data") # tags self.dd_tag = "dE" # thresholds self.snr_factor = snr_thresh #self.localthresh = local_thresh self.corrthresh = high_corr_thresh self.negthresh = negatives_thresh with pyfits.open(imagename) as hdu: self.hdr = hdu[0].header self.data = utils.image_data(hdu[0].data) self.wcs = WCS(self.hdr, mode="pyfits") self.locstep = local_step #regions self.phaserad = phasecenter_excl_radius # radius from the phase center self.negregion = negdetec_region # region to look for negatives # conversion self.bmaj = self.hdr["BMAJ"] # in degrees self.ra0 = numpy.deg2rad(self.hdr["CRVAL1"]) self.dec0 = numpy.deg2rad(self.hdr["CRVAL2"])
traceback.print_exc(); busy = None; QMessageBox.warning(self,"Error writing FITS","Error writing FITS file %s: %s"%(filename,str(err))); return; changed = False; sources = self.model.sources; # remove sources from model if asked to if self.wdel.isChecked(): sources = [ src for src in sources if not (src.selected and src.typecode == 'pnt') ]; changed = True; # add image to model if asked to if self.wadd.isChecked(): hdr = input_hdu.header; # get image parameters max_flux = float(input_hdu.data.max()); wcs = WCS(hdr,mode='pyfits'); # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1; for iaxis in range(hdr['NAXIS']): axs = str(iaxis+1); name = hdr.get('CTYPE'+axs,axs).upper(); if name.startswith("RA"): ra0 = hdr.get('CRPIX'+axs,1)-1; elif name.startswith("DEC"): dec0 = hdr.get('CRPIX'+axs,1)-1; # convert pixel to degrees ra0,dec0 = wcs.pix2wcs(ra0,dec0); ra0 *= DEG; dec0 *= DEG;