과학/천문학

[Python] 천문학 데이터 파일 형식 FITS 파일 형식 다루기 (How to using FITS file & About FITS)

AstroPenguin 2020. 12. 31. 22:30
728x90

안녕하십니까 여러분, 2020년의 마지막 게시글로 돌아왔습니다~~

이번 게시글에서는 저번에 언급한 것과 같이 천문학에서 기본적으로 다루는 파일 형식인 FITS파일을

사용하는 간단한 가이드라인에 대해 알려드리도록 하겠습니다.

 

FITS(Flexible Image Transport System)은 천문학에서 주로 쓰이는 확장자,

천체의 관측 사진을 픽셀값으로 변환하여 간편하게 저장하기 위해 사용되는 파일 형식입니다. 사진을 그대로 이용하기 보다는, 픽셀값으로 변환하여 사용한다면, C++ / Python / JAVA / IDL과 같은 프로그램에서 천체의 공간정보와 광도와 같은 jpg와 같은 이미지 파일로는 알 수 없는 정보들을 손 쉽게 처리할 수 있습니다.

 

FITS파일의 또 다른 강점은 하나의 이미지 데이터가 아닌 여러 가지의 데이터를 저장할 수 있다는 것입니다.

FITS파일은 프레임(frame)으로 이루어져 있는데 프레임이란 간단하게 책장입니다.

하나의 책장에 여려 칸이 있다고 생각해보면, 첫 번째 칸에는 천체의 이미지 데이터라는 책을 꽂아두고

두 번째 칸에는 스펙트럼 데이터라는 책들을 꽂아두며, 다른 칸에는 광도곡선 데이터라는 책을 꽂을 수 있습니다.

이처럼 하나의 FITS파일에 여러 종류의 데이터들을 담을 수 있다는 강점이 존재합니다.

 

여기서 의문이 하나 생길 것입니다. FITS는 이미지를 저장하기 위한 확장자인데, 스펙트럼이나 광도곡선같은 데이터들을 담을 수 있는건가요? 라는 의문입니다. 정답은 YES입니다.

FITS는 스펙트럼 데이터, Photon 데이터, 데이터 큐브 등과 같은 구조화된 데이터라면 이미지 데이터가 아니더라고 저장 할 수 있습니다. 그래서 보통은 한 가지 천체를 관측하면 하나의 FITS파일에 프레임을 나누어 이미지, 스펙트럼, 자기장, 광도곡선 등 일정 차원으로 이미지/그래프로 표현할 수 있는 데이터들을 모두 저장합니다.

FITS파일에서 하나의 프레임이 담고 있는 정보는 크게 '데이터(data)''헤더(header)' 두 종류로 나눌 수 있습니다.

 

데이터에서는 이미지 픽셀값, 천체의 flux값, 천체를 관측한 time(또는 timescale), 천체를 관측한 파장 등

우리가 실질적으로 원하는 데이터들이 담겨있습니다.

그리고 헤더는 천체의 관측기, 관측 날짜, 노출 시간, CCD의 사양, 관측 파장 등 천체를 관측한 결과의 데이터가 아닌

관측과 분석에 필요한 관측 자체에 관한 구체적인 정보가 담겨있습니다.

이제 FITS라는 확장자에 대해 알아보았으니,

본격적으로 FITS파일을 다루는 간단한 형식에 대해 알아보도록 하겠습니다.

우선 이미지 데이터를 다룰 때 무조건적으로 필요한 numpy, matplotlib, astropy를 다음과 같이 불러옵니다.

import numpy as np
import matplotlib.pyplot as plt
import astropy.io.fits as fits

다음으로 저장된 파일을 불러옵니다.

다운받은 FITS파일에 마우스 커서를 갖다대고 우클릭 후 [속성]을 누릅니다.

그 후 속성 창에서 해당 파일이 존재하는 경로와 파일명을 각각 복사하여 아래의 코드와 같은 형식이 나오게

순서대로 넣어줍니다.

image_data = fits.open('C:/Users/harry/OneDrive/바탕 화면/ngc5334_image.fits')
image_data.info()

위의 코드대로 복사하시면 아마 슬래시(/)가 아닌 방향이 반대인 역슬래시로 표시될 것입니다. 역슬래시는 모두 슬래시(/)로 바꾸어 주셔야합니다. (예시 : 'C:/User/000/폴더1/폴더2/FITS파일명.fits' ) (맨 끝에 .fits라고 확장자를 써줘야 함)

참고로 fits.open('파일경로/파일명')은 해당 경로에 있는 해당 파일을 해당 콘솔창에서 불러온다는 뜻입니다.

 

그리고 image_data.info()를 통해 어떤 프레임에 어떤 데이터가 들어가있는지 확인합니다.

(image_data는 임의로 지정한 변수로, 사용자에 편한 단어로 바꾸시면 됩니다. 다만, 남들도 이 코드를 보았을 때 이해할 수 있게끔 코드를 작성하는 것도 중요합니다!!)

불러온 결과값

데이터를 불러왔으면, 아래 코드블럭의 맨위 두 줄과 같이 data와 header를 지정합니다.

 

보통은 빨간색 박스 안의 ImageHDU라고 적힌 부분을 이용하여 image_data[1].data와 같이 적어야 하지만

파란색 박스 안의 Dimension을 보시면, ImageHDU라고 적힌 부분을 이용하여 image_data[1]이 1차원적인 값이라는 것을 볼 수 있어 사용하기에 적절하지 않습니다.

이 부분은 여러분들이 다운받는 데이터마다 다르기 때문에, 대괄호 안에 모든 숫자들을 직접 입력해서 출력해보시거나, Dimension과 같은 부분들을 세심하게 살펴보아서 결정하셔야 합니다.

그러므로 저는 이번 데이터에서 1차원 데이터인 image_data[1].data이 아닌 유일한 2차원 데이터인 image_data[0].data를 이용하였습니다.

header를 출력한다면, 관측에 사용된 관측기, 적경과 적위, 노출시간, 관측파장 등 관측에 대한 정보를 볼 수 있습니다.

data = image_data[0].data
header = image_data[0].header

image = np.array(data)

max_value = np.percentile(image,99.8)
min_value = np.percentile(image,15)

plt.figure(figsize=(8,6))
plt.imshow(image, cmap='gray', vmax = max_value, vmin = min_value, origin = 'lower')
plt.xlim(1000,1750)
plt.ylim(300,1000)
plt.show()

데이터와 헤더를 표현했으면, 이미지 픽셀 데이터들을 그래프로 나타내기 위해 모두 numpy array로 변환하여 줍니다.

(왜냐하면 matplotlib.pyplot은 array형식의 데이터를 그래프로 그릴 수 있기 때문이다)

 

그 후 max_value와  min_value를 np.percentile를 통해 지정합니다.

np.percentile(image,0~100까지의 숫자)가 뜻하는 의미는 다음과 같습니다.

np.percentile(image,0~100까지의 숫자)는 image의 array중에 0~100까지의 숫자 퍼센트에 나타내는 값을 반영한다는 뜻입니다. max_value와  min_value를 np.percentile를 통해 지정하면 천체 이미지의 밝기의 최대/최솟값을 지정할 수 있다는 뜻이 됩니다. 천체 이미지 밝기의 최대 최소 표출값을 지정하는 이유는 이미지를 matplotlib.pyplot를 통해 plot할 때 파라메타로 밝기의 최대/최솟값을 넣어야 하기 때문입니다.

 

다음으로 plt.figure와 plt.imshow 그리고 plt.show구문을 필수적으로 사용하여 천체의 이미지를 표출합니다.

imshow의 색깔을 나타내는 파라메타에 관한 정보는 아래 글의 맨 밑부분에서 참고하실 수 있습니다.

himbopsa.tistory.com/32

 

[Python] 허블 아카이브를 이용한 '폭발적 항성 생성 은하' 이미지 표출하기 (Expressing images of 'Starbur

himbopsa.tistory.com/26 [Python] 허블 아카이브를 이용한 '폭발적 항성 생성 은하' 이미지 표출하기 (Expressing images of 'Starbur 안녕하십니까, 새로운 글로 찾아뵙게 된 AstroPenguin입니다~~(격한환영) 여..

himbopsa.tistory.com

이제 코드를 알맞게 작성하셨다면 다음과 같은 결과가 나옵니다.

만약 특정 구간만 보고 싶다면 저처럼 plt.xlim(처음x값, 나중x값) 또는 plt.ylim(처음y값, 나중y값)를 통해 이미지를 표출하는 구간을 지정할 수 있습니다.

이제까지 이미지 데이터를 표출하였으니,

지금부터는 이미지 데이터가 아닌 그래프 형식으로 나타낼 수 있는 데이터를 표출해보도록 하겠습니다.

이미지가 아닌 데이터는 여태까지와는 다르게, 데이터의 종류마다 데이터를 다루는 방식과 그래프로 표출하기까지의 데이터 끼리의 합성/변환과 같은 과정들이 천차만별로 다릅니다.

이미지가 아닌 다른 데이터들을 변환하는 대표적인 예시가 케플러 미션을 통한 외계행성 탐사를 위한 광도곡선을 그리는 것입니다. 아래의 링크를 참고하시면 그 차이점을 볼 수 있습니다.

himbopsa.tistory.com/18

 

[Python] Lightcurve(광도곡선)을 이용한 외계행성탐사 및 물리량 측정

안녕하세요~~!! 다시 돌아온 AstroPeguin입니다~~(와-아 짴짴짴~~) 기말고사가 끝나고 종강을 해서 다시 글을 쓰게 되었습니다. (소-리질러ㅓㅓㅓ) 오늘은 식현상을 이용한 외계행성의 검출과 물리량

himbopsa.tistory.com

 

이번에는 NGC 5334은하의 스펙트럼 데이터를 표출해보도록 하겠습니다.

코드만 첨부하고, 자세한 과정과 이론은 추후에 다른 게시글로 찾아뵙도록 하겠습니다.

(추신!! 데이터를 불러오고 정보를 확인하고 data와 header를 선언하는 과정까지는 항상 일치합니다.)

specdata = fits.open('ngc5334_spec.fits')
specdata.info()
spectrum = specdata[1].data
header = specdata[1].header
print(header)

flux = []
loglam = []

for i in range(len(spectrum)):
    flux.append(spectrum[i][0])
    loglam.append(spectrum[i][1])
    
flux = np.array(flux)
lam = 10**np.array(loglam)
plt.figure(figsize=(10,7))
plt.plot(lam,flux,c='black')
plt.title('Spectrum lines of NGC 5334', fontsize=20)
plt.xlabel('Wavelength (Angstroms)', fontsize=15)
plt.ylabel('Flux', fontsize=15)
plt.axvspan(5520,5650,facecolor='r', alpha=0.5)

여기서 FITS파일을 불러와도 정상적으로 데이터가 불러올 수 있는 이유는 딱 한 가지 경우입니다.

해당 파이썬 파일과 다뤄야 할 FITS파일이 같은 폴더에 있으면, 경로 지정 없이도 바로 불러올 수 있습니다.

이 점은 알아두시면, 두 파일으르 같은 폴더에 담아두고 간편하게 불러오실 수 있습니다.

위의 코드를 통해 불러온 이미지는 다음과 같습니다.

이번 게시글에서는 천문학에서 가장 기본적으로 쓰이는 파일의 확장자인 FITS에 대해 알아보고,

FITS형식의 파일들을 다루어 이미지를 표출하는 자세한 과정에 대해 알아보았습니다.

만약 천문학을 좋아하시거나 진로로 생각하신다면,

다른건 몰라도 이 게시글 하나만큼은 꼭!! 숙지하셨으면 좋겠습니다.

다음번에도 FITS파일을 이용한 다양한 글들로 찾아오겠습니다.

 

새해 복 많이 받으시고 내년에 뵐게욥~~~뿅!!

728x90