Example #1
0
def create_mosaic(file_list,
                  inputimage,
                  outputDir,
                  outName,
                  config,
                  useweight=False,
                  verbose='NORMAL',
                  astrometry=False):
    """Create a mosaic of images"""

    np.savetxt('mosaic.list', file_list, fmt='%s')

    mosaic_name = outputDir + outName

    # Get pixel scale from input image header
    header = fits.getheader(inputimage)

    try:
        pixScale = abs(header['CDELT1'])
    except Exception:
        try:
            pixScale = abs(header['CD1_1'])
        except Exception:
            print(
                'Pixel scale could not be found in fits header.\n Expected keyword: CDELT1 or CD1_1'
            )
    pixScale = pixScale * 3600
    #print (inputimage, pixScale)
    crval1 = header['CRVAL1']
    crval2 = header['CRVAL2']
    #print (crval1, crval2)
    #print (header['CRPIX1'], header['CRPIX2'])
    imagesize = [header['NAXIS1'], header['NAXIS2']]

    # Force reference pixel to be in the center

    # File name to store the common header that will be shared by all
    # images in filelist
    point = 'registration'
    # Delete if already exists
    rm_p(point + '.head')
    # First run swarp to create a .head file containing the shared header
    subprocess.call(['swarp', '-HEADER_ONLY', 'Y', '-IMAGEOUT_NAME', \
                        point + '.head' , '-VERBOSE_TYPE', verbose] + [inputimage])
    # Some keywords manipulation using sed
    subprocess.call(['sed', '-i', \
                             's/MJD-OBS/COMMENT/; s/EXPTIME/COMMENT/; s/GAIN   /COMMENT/; s/SATURATE/COMMENT /', \
                     point + '.head'])

    imalists = ['@' + 'mosaic.list']
    # Remove mosaic if already exists
    rm_p(mosaic_name + '.fits')
    if 'mask' in mosaic_name:
        subBackground = 'N'
    else:
        subBackground = 'Y'

    # Copy the common header in the .head file
    # So that it is read by sawrp for each image
    shutil.copy(point + '.head', mosaic_name + '.head')

    if useweight:
        subprocess.call(['swarp',
                         '-IMAGEOUT_NAME', mosaic_name + '.fits', \
                         '-WEIGHTOUT_NAME', mosaic_name + '.weight.fits', \
                         '-VERBOSE_TYPE', verbose] + imalists)
    else:
        subprocess.call(['swarp',
                         '-IMAGEOUT_NAME', mosaic_name + '.fits',\
                         '-SUBTRACT_BACK', subBackground, \
                         '-COMBINE', 'Y', \
                         '-BACK_SIZE', '128', \
                         '-BACK_FILTERSIZE', '3',\
                         #'-CENTER_TYPE', 'MANUAL', \
                         #'-CENTER', '%s, %s' % (crval1,crval2), \
                         '-RESAMPLE', 'Y',\
                         '-RESAMPLING_TYPE', 'LANCZOS3',\
                         #'-RESAMPLING_TYPE', 'BILINEAR',\
                         '-PIXELSCALE_TYPE', 'MANUAL', \
                         '-PIXEL_SCALE', str(pixScale), \
                         #'-IMAGE_SIZE', '%s, %s' % (imagesize[0], imagesize[1]), \
                         '-OVERSAMPLING', '0',\
                         '-COMBINE_TYPE', 'MEDIAN', \
                         '-COPY_KEYWORDS', ' PIXEL_SCALE', \
                         '-VERBOSE_TYPE', verbose] + imalists)
    rm_p(mosaic_name + '.head')
    # Perform astrometric calibration of the mosaic with scamp
    if astrometry:
        scamp(mosaic_name + '.fits',
              config,
              useweight=False,
              CheckPlot=False,
              verbose=verbose)

    rm_p('mosaic.list')
    rm_p('swarp.xml')
    rm_p(point + '.head')

    return True
Example #2
0
def registration(filelist,
                 config,
                 resultDir="",
                 reference=None,
                 useweight=False,
                 gain=1,
                 normalise_exp=True,
                 verbose="NORMAL"):
    """Register images"""
    # Initialise lists used for creating output astropy table
    inim_list = []
    refim_list = []
    mask_list = []
    XY_lim = []
    in_lo = []
    in_up = []
    ref_lo = []
    ref_up = []
    gain_in = []
    gain_ref = []

    for i in range(len(filelist)):
        inim = filelist[i][0]
        refim = filelist[i][1]
        refim_mask = filelist[i][2]

        # Create list of images to register
        files = [inim, refim]
        if refim_mask is not None:
            files = files + [refim_mask]
        # Save them in a file to give it as an argument to swarp
        np.savetxt("register.list", files, fmt="%s")

        # Get pixel scale from input image header
        header = fits.getheader(inim)
        pixScale = abs(float(header["CDELT1"])) * 3600

        imalists = ["@" + "register.list"]
        # File name to store the common header that will be shared by all
        # images in filelist
        point = "registration"
        # Delete if already exists
        rm_p(point + ".head")
        # First run swarp to create a .head file containing the shared header
        subprocess.call([
            "swarp",
            "-HEADER_ONLY",
            "Y",
            "-IMAGEOUT_NAME",
            point + ".head",
            "-GAIN_DEFAULT",
            str(gain),
            # '-VERBOSE_TYPE', verbose] + imalists)
            "-VERBOSE_TYPE",
            verbose,
        ]
                        # + [inim]
                        + [refim])
        # Some keywords manipulation using sed
        subprocess.call([
            "sed",
            "-i",
            "s/MJD-OBS/COMMENT/; s/EXPTIME/COMMENT/; s/GAIN   /COMMENT/; s/SATURATE/COMMENT /",
            point + ".head",
        ])
        outFiles = []
        # Run swarp to perform the registration on each image in filelist
        for j, ima in enumerate(files):

            path, filename_ext = os.path.split(ima)
            epoch = resultDir + os.path.splitext(filename_ext)[0] + \
                "_reg_%s" % i
            outFiles.append(epoch + ".fits")

            if "mask" in ima:
                subBackground = "N"
            else:
                subBackground = "Y"

            # use weight for PS1 image
            if reference == 'ps1' and 'rings_v3_skycell' in ima and \
                    'mask' not in ima:
                # weight_type = "MAP_WEIGHT"
                # weight_type = "MAP_VARIANCE"
                weight_type = "MAP_RMS"
                # weight_type = "NONE"

                weight_name = path + '/' + \
                    os.path.splitext(filename_ext)[0] + \
                    ".weight.fits"
            else:
                weight_type = "NONE"
                weight_name = path + '/' + \
                    os.path.splitext(filename_ext)[0] + \
                    ".weight.fits"

            # Copy the common header in the .head file
            # So that it is read by sawrp for each image
            shutil.copy(point + ".head", epoch + ".head")

            # Use bilinear to avoid artefact, but worst for
            # noise so would need to check in more details.
            subprocess.call([
                "swarp",
                "-IMAGEOUT_NAME",
                epoch + ".fits",
                "-WEIGHT_TYPE",
                weight_type,
                "-WEIGHT_IMAGE",
                weight_name,
                "-WEIGHTOUT_NAME",
                '.weight.fits',
                # Arbitrary threshold.
                # Pixels at the edsge after resampling are 0 so
                # it is enough here
                "-WEIGHT_THRESH",
                "0.1",
                "-RESCALE_WEIGHTS",
                "N",
                # '-GAIN_DEFAULT', str(gain),
                "-FSCALE_KEYWORD",
                "NONE",
                "-FSCALE_DEFAULT",
                "1, 1",
                "-SUBTRACT_BACK",
                subBackground,
                "-COMBINE",
                "Y",
                "-COMBINE_TYPE",
                "MEDIAN",
                "-BACK_SIZE",
                "128",
                "-BACK_FILTERSIZE",
                "3",
                "-RESAMPLE",
                "Y",
                "-RESAMPLE_DIR",
                resultDir,
                "-RESAMPLE_SUFFIX",
                '_test.fits',
                "-PIXELSCALE_TYPE",
                "MANUAL",
                "-PIXEL_SCALE",
                str(pixScale),
                # '-CENTER', '%s, %s' % (header['CRVAL1'],
                #                         header['CRVAL2']),
                # '-RESAMPLING_TYPE', 'LANCZOS3',
                "-RESAMPLING_TYPE",
                "BILINEAR",
                # '-RESAMPLING_TYPE', 'NEAREST',
                "-OVERSAMPLING",
                "0",
                "-VERBOSE_TYPE",
                verbose,
                "-COPY_KEYWORDS",
                "FILTER, DATE-OBS",
            ] + [ima])

            # replace borders with NaNs in ref image if there are
            # any that are == 0,
            # hdulist=fits.open(epoch + '.fits')
            # hdulist[0].data[hdulist[0].data==0]=np.nan
            # hdulist.writeto(epoch + '.fits',overwrite=True)

            rm_p(epoch + ".head")
        rm_p(point + ".head")
        rm_p("register.list")
        rm_p("coadd.weight.fits")
        rm_p('swarp.xml')

        inim_regist = outFiles[0]
        refim_regist = outFiles[1]
        maskim_regist = outFiles[2]

        print('Rescale and homogeneise mask maps for bad pixels.')
        # Rescale flux to 1s
        # In the future can try to rescale flux of ref image
        # to match input image.
        if normalise_exp:
            rescale_flux(inim_regist)
            rescale_flux(refim_regist)

        # Set masked pixels to same value
        mask_pix = flag_bad_pixels(inim_regist,
                                   mask_ref=maskim_regist,
                                   value=1e-30)
        # Update mask map
        _ = flag_bad_pixels(maskim_regist, value=1e8, mask_map=mask_pix)
        # Apply mask on ref data
        _ = flag_bad_pixels(refim_regist, mask_ref=maskim_regist, value=1e-30)

        print('Remove bad pixels on the edge.')
        # Take only part of image with data
        # This will decrease image size and speed up the substraction
        # Might also avoid probelm with masked values, depending on how
        # good they are deal with in hotpants.
        limits = keep_useful_area(inim_regist, image_ref=refim_regist)
        _ = keep_useful_area(maskim_regist, limits_force=limits)

        # Perform a second time, as the edge are not straight, we can still
        # remove some pixels after the first cut.
        limits = keep_useful_area(inim_regist, image_ref=refim_regist)
        _ = keep_useful_area(maskim_regist, limits_force=limits)

        # Get info to tune hotpants parameters
        filelist_regist = [inim_regist, refim_regist, maskim_regist]
        hotpants_info = get_hotpants_info(filelist_regist, config, verbose)

        inim_list.append(outFiles[0])
        refim_list.append(outFiles[1])
        mask_list.append(outFiles[2])
        XY_lim.append(hotpants_info[0])
        in_lo.append(hotpants_info[1][0])
        in_up.append(hotpants_info[1][1])
        ref_lo.append(hotpants_info[1][2])
        ref_up.append(hotpants_info[1][3])
        gain_in.append(hotpants_info[2][0])
        gain_ref.append(hotpants_info[2][1])

    info = Table(
        [
            inim_list,
            refim_list,
            mask_list,
            XY_lim,
            in_lo,
            in_up,
            ref_lo,
            ref_up,
            gain_in,
            gain_ref,
        ],
        names=[
            "inim",
            "refim",
            "mask",
            "XY_lim",
            "in_lo",
            "in_up",
            "ref_lo",
            "ref_up",
            "gain_in",
            "gain_ref",
        ],
    )
    return info
Example #3
0
def create_ps1_mosaic(file_list,
                      inputimage,
                      outputDir,
                      config,
                      band,
                      useweight=False,
                      verbose="NORMAL"):
    """Create a single mosaic of PS1 image using swarp"""
    _, filenameInput = os.path.split(inputimage)

    #  Create list of mask fits
    ima_list = [ima for ima in file_list if "_mask" not in ima]
    mask_list = [ima for ima in file_list if "_mask" in ima]
    np.savetxt("mosaic.list", ima_list, fmt="%s")
    np.savetxt("mask.list", mask_list, fmt="%s")

    imagefiles = [
        outputDir + os.path.splitext(filenameInput)[0] + "_ps1_mosaic",
        outputDir + os.path.splitext(filenameInput)[0] + "_ps1_mosaic_mask",
    ]

    # Get pixel scale from input image header
    header = fits.getheader(inputimage)

    try:
        pixScale = abs(header["CDELT1"])
    except Exception:
        try:
            pixScale = abs(header["CD1_1"])
        except Exception:
            print("Pixel scale could not be found in fits header.\n"
                  "Expected keyword: CDELT1 or CD1_1")
    pixScale = pixScale * 3600
    # print (inputimage, pixScale)
    crval1 = header["CRVAL1"]
    crval2 = header["CRVAL2"]
    # print (crval1, crval2)
    # print (header['CRPIX1'], header['CRPIX2'])
    imagesize = [header["NAXIS1"], header["NAXIS2"]]

    #  Force reference pixel to be in the center

    # File name to store the common header that will be shared by all
    # images in filelist
    point = "registration"
    # Delete if already exists
    rm_p(point + ".head")
    # First run swarp to create a .head file containing the shared header
    subprocess.call([
        "swarp",
        "-HEADER_ONLY",
        "Y",
        "-IMAGEOUT_NAME",
        point + ".head",
        "-VERBOSE_TYPE",
        verbose,
    ] + [inputimage])
    # Some keywords manipulation using sed
    subprocess.call([
        "sed",
        "-i",
        "s/MJD-OBS/COMMENT/; s/EXPTIME/COMMENT/; s/GAIN   /COMMENT/; s/SATURATE/COMMENT /",
        point + ".head",
    ])

    imalists = [["@" + "mosaic.list"], ["@" + "mask.list"]]
    for i, imagefile in enumerate(imagefiles):
        #  Remove mosaic if already exists
        rm_p(imagefile + ".fits")
        if "mask" in imagefile:
            subBackground = "N"
        else:
            subBackground = "Y"

        # Copy the common header in the .head file
        # So that it is read by sawrp for each image
        shutil.copy(point + ".head", imagefile + ".head")

        if useweight:
            subprocess.call([
                "swarp",
                "-IMAGEOUT_NAME",
                imagefile + ".fits",
                "-WEIGHTOUT_NAME",
                imagefile + ".weight.fits",
                "-VERBOSE_TYPE",
                verbose,
            ] + imalists[i])
        else:
            subprocess.call([
                "swarp",
                "-IMAGEOUT_NAME",
                imagefile + ".fits",
                "-SUBTRACT_BACK",
                subBackground,
                "-COMBINE",
                "Y",
                "-BACK_SIZE",
                "128",
                "-BACK_FILTERSIZE",
                "3",
                # '-CENTER_TYPE', 'MANUAL',
                # '-CENTER', '%s, %s' % (crval1,crval2),
                "-RESAMPLE",
                "Y",
                #"-RESAMPLING_TYPE", "LANCZOS3",
                '-RESAMPLING_TYPE',
                'BILINEAR',
                "-PIXELSCALE_TYPE",
                "MANUAL",
                "-PIXEL_SCALE",
                str(pixScale),
                # '-IMAGE_SIZE', '%s, %s' % (imagesize[0], imagesize[1]),
                "-OVERSAMPLING",
                "0",
                "-COMBINE_TYPE",
                "MEDIAN",
                "-COPY_KEYWORDS",
                " PIXEL_SCALE",
                "-VERBOSE_TYPE",
                verbose,
            ] + imalists[i])
        rm_p(imagefile + ".head")
    #  Perform astrometric calibration of the mosaic with scamp
    scamp(
        imagefiles[0] + ".fits",
        config,
        useweight=False,
        CheckPlot=False,
        verbose=verbose,
    )
    # replace pixels == 0 with NaNs. Mostly the border, saturated pixels
    hdulist = fits.open(imagefiles[0] + ".fits")
    hdulist[0].data[hdulist[0].data == 0] = np.nan
    """
    # Add header
    hdulist[0].header['FILTER'] = band
    hdulist[0].header['PHOT_C'] = 25
    hdulist[0].header['PHOT_K'] = 0
    hdulist[0].header['PHOTFLAG'] = 'T'
    hdulist[0].header['EXPTIME'] = 1
    """
    hdulist[0].header["GAIN"] = 1
    hdulist[0].header["EXPTIME"] = 1
    hdulist[0].header.remove("SATURATE")

    hdulist.writeto(imagefiles[0] + ".fits", overwrite=True)

    #  Create a mask to propagate the nan pixels
    hdulist = fits.open(imagefiles[1] + ".fits")
    hdulist[0].data[hdulist[0].data > 0] = 1
    hdulist[0].data[np.isnan(hdulist[0].data)] = 1
    hdulist.writeto(imagefiles[1] + ".fits", overwrite=True)

    # for ima in file_list:
    #    rm_p(ima)
    # for ima in mask_list:
    #    rm_p(ima)
    rm_p("mosaic.list")
    rm_p("mask.list")
    rm_p("swarp.xml")
    rm_p(point + ".head")
    # rm_p('coadd.weight.fits')

    #  Add extension to files
    imagefiles = [i + ".fits" for i in imagefiles]

    return imagefiles
Example #4
0
def psfex(filename,
          config,
          useweight=False,
          verbose="NORMAL",
          outLevel=0,
          outDir=''):
    """Compute PSF in astronomical images"""

    FWHM_list = []

    # imagelist=glob.glob(path+'/*.fits')
    imagelist = np.atleast_1d(filename)
    for ima in imagelist:
        print("\nRunning psfex to estimate FWHM in %s" % ima)
        root = os.path.splitext(ima)[0]
        if useweight:
            weight = root + ".weight.fits"
            subprocess.call([
                "sex",
                ima,
                "-c",
                config["psfex"]["sextractor"],
                "-WEIGHT_IMAGE",
                weight,
                "-VERBOSE_TYPE",
                verbose,
                "-PARAMETERS_NAME",
                config["psfex"]["param"],
                "-FILTER_NAME",
                config['sextractor']['convFilter'],
            ])
        else:
            subprocess.call([
                "sex",
                ima,
                "-c",
                config["psfex"]["sextractor"],
                "-VERBOSE_TYPE",
                verbose,
                "-PARAMETERS_NAME",
                config["psfex"]["param"],
                "-FILTER_NAME",
                config['sextractor']['convFilter'],
            ])
        cat = "preppsfex.cat"
        subprocess.call([
            "psfex", cat, "-c", config["psfex"]["conf"], "-VERBOSE_TYPE",
            verbose
        ])
        rm_p(cat)

        #  Delete files depending on the required level of output files
        mv_p("snap_preppsfex.fits", root + "_psf.fits")

        # Get the mean PSF FWHM in pixels
        with open("psfex.xml") as fd:
            doc = xmltodict.parse(fd.read())
            FWHM_stats = doc["VOTABLE"]["RESOURCE"]["RESOURCE"]["TABLE"][0][
                "DATA"]["TABLEDATA"]["TR"]["TD"][20:23]
            FHWM_min = float(FWHM_stats[0])
            FHWM_mean = float(FWHM_stats[1])
            FHWM_max = float(FWHM_stats[2])

            print("\nFWHM min: %.2f pixels" % FHWM_min)
            print("FWHM mean: %.2f pixels" % FHWM_mean)
            print("FWHM max: %.2f pixels\n" % FHWM_max)

        #  Get number of psf snapshot per axis
        psf_snaps = os.popen("sed -n '/PSFVAR_NSNAP/p' %s" %
                             config["psfex"]["conf"]).read()
        nb_snaps = psf_snaps.split()[1]
        # Add info to the header
        hdulist = fits.open(root + "_psf.fits")
        hdr = hdulist[0].header
        hdr["FWHMMIN"] = str(FHWM_min)
        hdr["FWHMMEA"] = str(FHWM_mean)
        hdr["FWHMMAX"] = str(FHWM_max)
        hdr["PSF_NB"] = str(nb_snaps)
        hdulist.writeto(root + "_psf.fits", overwrite=True)

        FWHM_list.append(FHWM_mean)

        mv_p("preppsfex.psf", root + ".psf")
        rm_p("preppsfex.psf")
        rm_p("psfex.xml")
    return FWHM_list
Example #5
0
def resample_ps1(filename,
                 inputDir,
                 config,
                 useweight=False,
                 verbose="NORMAL"):
    """Resample PS1 image to the telescope resolution"""
    pixScale = config['pixScale'][0]

    basename = os.path.splitext(filename)[0]
    if useweight:
        subprocess.call(
            [
             "swarp",
             inputDir+filename,
             "-IMAGEOUT_NAME", inputDIr + basename + \
                         '_%s' % config['telescope'] + ".fits",
             "-WEIGHTOUT_NAME", inputDIr + epoch + \
                         '_%s' % config['telescope'] + ".weight.fits",
             "-VERBOSE_TYPE", verbose,
            ]
        )
    else:
        # Use bilinear to avoid artefact, but worst for
        # noise so would need to check in more details.
        subprocess.call(
           [
            "swarp",
            inputDir+filename,
            "-IMAGEOUT_NAME", inputDir + basename + \
                       '_%s' % config['telescope'] + ".fits",
            # '-GAIN_DEFAULT', str(gain),
            "-FSCALE_KEYWORD", "NONE",
            "-FSCALE_DEFAULT", "1, 1",
            "-SUBTRACT_BACK", "N",
            "-COMBINE", "N",
            "-BACK_SIZE", "128",
            "-BACK_FILTERSIZE", "3",
            "-RESAMPLE", "Y",
            "-RESAMPLE_DIR", inputDir,
            "-RESAMPLE_SUFFIX", '_%s.fits' % config['telescope'],
            "-PIXELSCALE_TYPE", "MANUAL",
            "-PIXEL_SCALE", str(pixScale),
            # '-CENTER', '%s, %s' % (header['CRVAL1'],
            #                         header['CRVAL2']),
            # '-RESAMPLING_TYPE', 'LANCZOS3',
            "-RESAMPLING_TYPE", "BILINEAR",
            # '-RESAMPLING_TYPE', 'NEAREST',
            "-OVERSAMPLING", "0",
            "-COMBINE_TYPE", "MEDIAN",
            "-VERBOSE_TYPE", verbose,
            "-COPY_KEYWORDS", "FILTER, EXPTIME, SATURATE",
           ]
        )
    rm_p('swarp.xml')
    rm_p("coadd.weight.fits")
    rm_p(inputDir + filename)

    if 'mask' in basename:
        # Add the new pixels created on the edge after resampling to
        # the mask
        hdulist1 = fits.open(inputDir + basename + \
                '_%s' % config['telescope'] + ".weight.fits")
        zero_pix = hdulist1[0].data == 0
        hdulist1.close()

        outName = inputDir + basename + \
                '_%s' % config['telescope'] + ".fits"
        hdulist2 = fits.open(outName)
        # Put high value
        hdulist2[0].data[zero_pix] = 1e8
        hdulist2.writeto(outName, overwrite=True)

    return True