E: Ejercicio resuelto: Generacion de una funcion para reducir datos


Ejercicio E.1:

Basándonos en el código de los anteriores notebooks crear una función a la que pasándole el directorio donde están nuestras imágenes, bias, darks y flats reduzca la imagen automáticamente.

[1]:
import matplotlib.pyplot as plt

import numpy as np
import glob
from astropy.io import fits
import os
import astroscrappy
[2]:
import astroalign
from astropy.io import fits as ft


def imprimir_info(p, ii):
    # Esta función imprime por pantalla la info de la transformación que se aplicará.
    # Aunque es innecesaria, sirve para que el usuario sepa que la máquina está haciendo algo.
    print("\nAlineando imagen {:}".format(ii))
    print("Rotación: {:.2f} grados".format(p.rotation * 180.0 / np.pi))
    print("Factor de escala: {:.2f}".format(p.scale))
    print("Traslación: (x, y) = ({:.2f}, {:.2f})".format(*p.translation))


def registra_lista(lista, infoAlineado = False):
    '''
    Función para la alineacion de imagenes a traves de astroalign

    lista: tenemos que pasar una lista de la ruta donde se encuentran nuestras imagenes. List of string.

    Return: Lista de numpy array con los datos de las imagenes alineadas. List of numpy array.
    '''


    cantidad=len(lista)

    # La primera imagen de la lista será la toma de referencia.

    print("\nComenzando la alineación.")
    print("\nLa toma de referencia es {:}".format(lista[0]))
    blanco=ft.open(lista[0])
    img_blanco=blanco[0].data
    hdr_blanco=blanco[0].header
    blanco.close()

    del(lista[0]) # Quito la imagen de referencia del listado
    imagenes_alineadas = [img_blanco, ]
    for ii in lista:
        ff=ft.open(ii)
        img_torcida=ff[0].data
        hdr_torcida=ff[0].header
        ff.close()
        p, (pos_img, pos_img_rot) = astroalign.find_transform(img_torcida, img_blanco)
        img_aligned = astroalign.register(img_torcida, img_blanco)
        hdr_torcida.add_comment("Registrado con Astroalign y PyReduc")
        imagenes_alineadas.append(img_aligned[0])
        if infoAlineado:
            imprimir_info(p, ii)

    print("\nAlineado realizado con éxito")
    return imagenes_alineadas

Creamos nuestra funcion reducir en donde las entradas de la función serán los directorios donde tenemos guardados los archivos FITS.

[3]:
def reducir(dirBias, dirDarks, dirFlats, dirLights, dirSalida, imaInter = False, infoCosmicray = False):
    '''
    Función para reducir datos en formato fit. En los directorios solo deben
    estar los ficheros particulares de cada caso.

    dirBias: directorio donde se encuentran los bias. String.
    dirDarks: directorio donde se encuentran los darks. String.
    dirFlats: directorio donde se encuentran los bias. String.
    dirLights: directorio donde se encuentran los bias. String.
    dirSalida: directorio donde irán las imagenes calibradas en formato fit. String.
    imaInter: Si queremos guardar las imagenes intermedias pondremos True. Booleano.
    infoCosmicray: Si queremos informacion de los rayos cosmicos que ha detectado el algoritmo astroscrappy. Booleano.

    Return: Imagen calibrada en forma de matriz. numpy array.
    '''

    try:
        os.mkdir(dirSalida)
    except:
        print(f"El directorio {dirSalida} ya existe")

    bias_list = sorted(glob.glob(f"{dirBias}*"))
    darks_list = sorted(glob.glob(f"{dirDarks}*"))
    flats_list = sorted(glob.glob(f"{dirFlats}*"))
    lights_list = sorted(glob.glob(f"{dirLights}*"))

    # Bias

    print("Procesando BIAS")

    bias_data = []
    bias_header = []
    for bias in bias_list:
        hdul_bias = fits.open(bias)
        bias_data.append(hdul_bias[0].data)
        bias_header.append(hdul_bias[0].header)
        hdul_bias.close()
    for r in range(len(bias_list)):
        if np.nanstd(bias_data[r]) > np.median(np.nanstd(bias_data))*1.2:
            print("Eliminando BIAS: " + bias_list[r])
            bias_list.remove(bias_list[r])
    superBias = np.nanmedian(bias_data, axis=0)
    bias_header[0]['history'] = f"Esta imagen es un stacking de {len(bias_list)} imagenes"

    # Darks

    print("Procesando DARKs")

    darks_data = []
    darks_header = []
    darks_current = []
    for dark in darks_list:
        hdul_darks = fits.open(dark)
        darks_data.append(hdul_darks[0].data)
        darks_header.append(hdul_darks[0].header)
        hdul_darks.close()
    for dark in range(len(darks_list)):
        darks_current.append(darks_data[dark] - superBias)
    for i in range(len(darks_list)):
        darks_current[i][darks_current[i] < 0] = 0
    superDark = np.nanmedian(darks_data, axis=0)
    darkCurrent = np.median(darks_current, axis=0)

    #Flats

    print(f"Procesando FLATs")

    flats_data = []
    flats_header = []
    flat_data_b = []
    for flat in flats_list:
        hdul_flats = fits.open(flat)
        flats_data.append(hdul_flats[0].data)
        flats_header.append(hdul_flats[0].header)
        hdul_flats.close()
    for r in range(len(flats_list)):
        if np.nanstd(flats_data[r]) > np.median(np.nanstd(flats_data))*1.1:
            print(bias_list[r])
            bias_list.remove(bias_list[r])
    y_len, x_len = np.shape(flats_data[0])
    x_center, y_center = x_len//2, y_len//2
    for flat in range(len(flats_list)):
        flat_superBias =  flats_data[flat] - superBias
        flat_norm = flat_superBias / np.median(flat_superBias[y_center-250:y_center+250,x_center-250:x_center+250])
        flat_data_b.append(flat_norm)
    superFlat = np.nanmedian(flat_data_b, axis=0)

    #lights

    print(f"Procesando LIGHTs de {flats_header[0]['FILTER']}")

    lights_header = []
    lights_data = []
    FWHM = []
    for f in lights_list:
        hdul = fits.open(f)
        lights_header.append(hdul[0].header)
        lights_data.append(hdul[0].data)
        FWHM.append(hdul[0].header['FWHM'])
        hdul.close()
#    print(f"Lights de {lights_header[0]['FILTER']}")
    for r in range(len(lights_list)):
        if lights_header[r]['FWHM'] > np.median(FWHM)*1.5:
            lights_data.remove(lights_data[r])
            lights_header.reomve(lights_header[r])
            lights_list.remove(lights_list[r])
            print(f"Se ha eliminado la imagen {lights_list[r]}")

    lights_correction = []
    for light in range(len(lights_list)):
        light_b =lights_data[light].astype(np.float32) - superBias.astype(np.float32)
        light_bd = light_b - darkCurrent.astype(np.float32)
        light_bdf = light_bd / superFlat.astype(np.float32)
        lights_correction.append(light_bdf)

    for hot in range(len(lights_list)):
        hot_pixeles = np.where(lights_correction[hot] < 0) # hotpixel será un array con la posicion del los hot pixeles
        for i in range(len(hot_pixeles[0])): #
            lights_correction[hot][hot_pixeles[0][i]][hot_pixeles[1][i]] = np.median([lights_correction[hot][hot_pixeles[0][i]-1, hot_pixeles[1][0]], lights_correction[hot][hot_pixeles[1][i]+1, hot_pixeles[1][0]]])
    lights_correction_cosmicray = []
    mask_cosmicray = []
    for image in range(len(lights_list)):
        mask, cosmicray = astroscrappy.detect_cosmics(lights_correction[image], sigclip=6, sigfrac=15, objlim=5.0, gain=1.0, readnoise=6.5, satlevel=65536.0, niter=4, verbose=infoCosmicray)
        lights_correction_cosmicray.append(cosmicray)
        mask_cosmicray.append(mask)
    imagenes_alineadas = registra_lista(lights_list)
    imagenFinal = np.nanmedian(imagenes_alineadas, axis=0)
    # Guardamos
    if imaInter:
        hdu_Bias = fits.PrimaryHDU(data=superBias.astype(np.float32), header=bias_header[0])
        hdu_Bias.writeto(dirSalida + "superBias.fit", overwrite=True)

        super_dark = fits.PrimaryHDU(data=superDark.astype(np.float32), header=darks_header[0])
        super_dark.writeto(dirSalida + "superDark.fit", overwrite=True)
        hdu_Dark_current = fits.PrimaryHDU(data=darkCurrent.astype(np.float32))
        hdu_Dark_current.writeto(dirSalida + "darkCurrent.fit", overwrite=True)

        hdu_FlatH = fits.PrimaryHDU(data=superFlat.astype(np.float32), header=flats_header[0])
        hdu_FlatH.writeto(dirSalida + "superFlat.fit",overwrite=True)

    hdu_imagenFinal = fits.PrimaryHDU(data=imagenFinal.astype(np.float32), header=lights_header[0])
    hdu_imagenFinal.writeto(dirSalida + f"imagenFinal_{lights_header[0]['FILTER']}.fit",overwrite=True)
    return imagenFinal

Generamos los directorios y llamamos a la funcion reducir.

[4]:
import os

baseDir = "imagenes/calibracionImagenes/"

dirBias = baseDir + 'bias/'
dirDarks = baseDir + 'darks/'

dirFlatsHa = baseDir + 'flats/ha/'
dirFlatsO3 = baseDir + 'flats/O3/'
dirFlatsS2 = baseDir + 'flats/S2/'

dirLightsHa = baseDir + 'ha/'
dirLightsO3 = baseDir + 'O3/'
dirLightsS2 = baseDir + 'S2/'

dirSalida = 'salidas/salidaCalibracion/sho/'

try:
    os.mkdir(dirSalida)
except:
    print("Probablemente el directorio ya existe")

ha = reducir(dirBias, dirDarks, dirFlatsHa, dirLightsHa, dirSalida, imaInter = False)
O3 = reducir(dirBias, dirDarks, dirFlatsO3, dirLightsO3, dirSalida, imaInter = False)
S2 = reducir(dirBias, dirDarks, dirFlatsS2, dirLightsS2, dirSalida, imaInter = False)
Probablemente el directorio ya existe
El directorio salidas/salidaCalibracion/sho/ ya existe
Procesando BIAS
Eliminando BIAS: imagenes/calibracionImagenes/bias/Telescope3_BIAS_1x1_0s_-30degC_20200120_0547_000001089.fit
Procesando DARKs
Procesando FLATs
Procesando LIGHTs de H-alpha

Comenzando la alineación.

La toma de referencia es imagenes/calibracionImagenes/ha/NGC2070-20200208@030339-300S-H-alpha.fit

Alineado realizado con éxito
El directorio salidas/salidaCalibracion/sho/ ya existe
Procesando BIAS
Eliminando BIAS: imagenes/calibracionImagenes/bias/Telescope3_BIAS_1x1_0s_-30degC_20200120_0547_000001089.fit
Procesando DARKs
Procesando FLATs
Procesando LIGHTs de Oiii

Comenzando la alineación.

La toma de referencia es imagenes/calibracionImagenes/O3/NGC2070-20200208@035232-300S-Oiii.fit

Alineado realizado con éxito
El directorio salidas/salidaCalibracion/sho/ ya existe
Procesando BIAS
Eliminando BIAS: imagenes/calibracionImagenes/bias/Telescope3_BIAS_1x1_0s_-30degC_20200120_0547_000001089.fit
Procesando DARKs
Procesando FLATs
Procesando LIGHTs de Sii

Comenzando la alineación.

La toma de referencia es imagenes/calibracionImagenes/S2/NGC2070-20200209@020725-600S-Sii.fit

Alineado realizado con éxito