E: Corrigiendo la cabecera de un fichero FITS
¶
Nos hemos encontrado un fichero imagenes/fitsHeaderIncorrecto.fit
, generado por MaxIm DL que produce un error al intentar abrirlo con AstroPy
. El error concretamente es que la cabecera del fichero BZERO
tiene un valor igual a 0.00000000000000000 0
, cuando debería ser 0.00000000000000000
.
[1]:
import os
import os.path
import shutil
from astropy.io import fits
import matplotlib.pyplot as plt
import numpy as np
ficheroConflictivo = "imagenes/fitsHeaderIncorrecto.fit"
im = fits.open(ficheroConflictivo) # Fallará, porque el fichero tiene una cabecera incorrecta:
# BZERO = 0.00000000000000000 0
WARNING: VerifyWarning: Error validating header for HDU #0 (note: Astropy uses zero-based indexing).
Unparsable card (BZERO), fix it first with .verify('fix').
There may be extra bytes after the last HDU or the file is corrupted. [astropy.io.fits.hdu.hdulist]
---------------------------------------------------------------------------
OSError Traceback (most recent call last)
Cell In[1], line 10
6 import numpy as np
8 ficheroConflictivo = "imagenes/fitsHeaderIncorrecto.fit"
---> 10 im = fits.open(ficheroConflictivo) # Fallará, porque el fichero tiene una cabecera incorrecta:
11 # BZERO = 0.00000000000000000 0
File ~/anaconda3/envs/cursoAstronomia2/lib/python3.8/site-packages/astropy/io/fits/hdu/hdulist.py:214, in fitsopen(name, mode, memmap, save_backup, cache, lazy_load_hdus, ignore_missing_simple, use_fsspec, fsspec_kwargs, **kwargs)
211 if not name:
212 raise ValueError(f"Empty filename: {name!r}")
--> 214 return HDUList.fromfile(
215 name,
216 mode,
217 memmap,
218 save_backup,
219 cache,
220 lazy_load_hdus,
221 ignore_missing_simple,
222 use_fsspec=use_fsspec,
223 fsspec_kwargs=fsspec_kwargs,
224 **kwargs,
225 )
File ~/anaconda3/envs/cursoAstronomia2/lib/python3.8/site-packages/astropy/io/fits/hdu/hdulist.py:482, in HDUList.fromfile(cls, fileobj, mode, memmap, save_backup, cache, lazy_load_hdus, ignore_missing_simple, **kwargs)
462 @classmethod
463 def fromfile(
464 cls,
(...)
472 **kwargs,
473 ):
474 """
475 Creates an `HDUList` instance from a file-like object.
476
(...)
479 documentation for details of the parameters accepted by this method).
480 """
--> 482 return cls._readfrom(
483 fileobj=fileobj,
484 mode=mode,
485 memmap=memmap,
486 save_backup=save_backup,
487 cache=cache,
488 ignore_missing_simple=ignore_missing_simple,
489 lazy_load_hdus=lazy_load_hdus,
490 **kwargs,
491 )
File ~/anaconda3/envs/cursoAstronomia2/lib/python3.8/site-packages/astropy/io/fits/hdu/hdulist.py:1248, in HDUList._readfrom(cls, fileobj, data, mode, memmap, cache, lazy_load_hdus, ignore_missing_simple, use_fsspec, fsspec_kwargs, **kwargs)
1245 if hdulist._file.close_on_error:
1246 hdulist._file.close()
-> 1248 raise OSError("Empty or corrupt FITS file")
1250 if not lazy_load_hdus or kwargs.get("checksum") is True:
1251 # Go ahead and load all HDUs
1252 while hdulist._read_next_hdu():
OSError: Empty or corrupt FITS file
Vamos a corregir reemplazando dicha cabecera de manera artesanal (no podemos usar los mecanismos habituales de AstroPy
porque la misma biblioteca no es capaz de cargar dicho fichero.
Primero copiamos el fichero para evitar el riesgo de estropear el fichero:
[2]:
ficheroCorregido = "salidas/fitsHeaderIncorrecto_corregido.fit"
shutil.copyfile(ficheroConflictivo, ficheroCorregido)
[2]:
'salidas/fitsHeaderIncorrecto_corregido.fit'
[3]:
def corrigeHeaderFits(nombreArchivo):
f = open(nombreArchivo, "r+b") # Abrimos el fichero como lectura y escritura binaria
readed = b""
while not readed.startswith(b"END"): # La última línea de la cabecera debe empezar por END
readed = f.read(80) # Las cabeceras FITS son de 80 caracteres ASCII (80 bytes)
print(readed)
if readed.startswith(b"BZERO"): # Si la línea de la cabecera comienza por BZERO
if b"0.00000000000000000 0" in readed: # Y encontramos la cadena errónea dentro
print("Hemos encontrado un BZERO incorrecto. Sustituyendo")
f.seek(-80, os.SEEK_CUR) # Retrocedemos 80 caracteres el puntero de lectura del fichero
# Y escribimos la cabecera bien
f.write(b'BZERO = 0.00000000000000000 ') # Ojo! no quitar ni un espacio en blanco de la cadena
f.close()
corrigeHeaderFits(ficheroCorregido)
b'SIMPLE = T / conforms to FITS standard '
b'BITPIX = -32 / array data type '
b'NAXIS = 2 / number of array dimensions '
b'NAXIS1 = 200 '
b'NAXIS2 = 200 '
b'BZERO = 0.00000000000000000 0 '
Hemos encontrado un BZERO incorrecto. Sustituyendo
b'DATAMIN = 0.000000 '
b'DATAMAX = 65535.000000 '
b"INSTRUME= 'ATIK-460ex: fw rev 3.34' "
b"TELESCOP= 'Mewlon210' "
b"OBSERVER= 'Pedro Benedicto' "
b"FILTER = 'Position 0'osition 0' "
b'EXPTIME = 10.000000000000000 '
b"DATE-OBS= '2022-04-02T22:50:02'T22:50:02' "
b'XPIXSZ = 4.540 '
b'YPIXSZ = 4.540 '
b'XBINNING= 1 '
b'YBINNING= 1 '
b'XORGSUBF= 0 '
b'YORGSUBF= 0 '
b'XPOSSUBF= 0 '
b'YPOSSUBF= 0 '
b'CBLACK = 104 '
b'CWHITE = 634 '
b'CCD-TEMP= -10.1 '
b"SWCREATE= 'Artemis Capture' "
b"INPUTFMT= 'FITS ' / Format of file from which image was read "
b"SWMODIFY= 'MaxIm DL Version 6.11 141223 1VH7F' /Name of software "
b"SWSERIAL= '1VH7F-K9Y6J-9C35K-TUXJ7-6J8QF-V2' /Software serial number "
b'HISTORY Bias Subtraction (Bias 1x1_-10, 2749 x 2199, Bin1 x 1, Temp -10C, '
b'HISTORY Exp Time 0ms) '
b"CALSTAT = 'BDF ' "
b'HISTORY Dark Subtraction (Dark 1x1_-10_60s, 2749 x 2199, Bin1 x 1, '
b'HISTORY Temp -10C, Exp Time 60s) '
b'HISTORY Flat Field (Flat 4, 2749 x 2199, Bin1 x 1, Temp -15C, '
b'PEDESTAL= -100 /Correction to add for zero-based ADU '
b"CSTRETCH= 'Medium ' / Initial display stretch mode "
b"SWOWNER = 'Tan Yong Liang' / Licensed owner of software "
b'SNAPSHOT= 19 /Number of images combined '
b'EXPOSURE= 10.000000000000000 /Exposure time in seconds '
b"MIDPOINT= '2022-04-02T22:52:45' /UT of midpoint of exposure "
b'END '
Ahora si podemos cargar y visualizar el fichero corregido:
[4]:
im = fits.open(ficheroCorregido)
data = im[0].data
plt.imshow(data, vmin=np.min(data), vmax=np.max(data)/128)
plt.show()
WARNING: Unexpected extra padding at the end of the file. This padding may not be preserved when saving changes. [astropy.io.fits.header]
