Restructure repository and pep8 changes

Also all executables now use argparse for arguments and helpers.
pull/5/head
Pierros Papadeas 2018-05-06 17:45:51 +03:00
parent 626cbbb3df
commit 96389ccdc8
No known key found for this signature in database
GPG Key ID: AB1301B4FCDFF5D4
14 changed files with 389 additions and 292 deletions

View File

@ -11,7 +11,7 @@ from astropy.coordinates import EarthLocation
from astropy.time import Time from astropy.time import Time
from astropy.io import fits from astropy.io import fits
import astropy.units as u import astropy.units as u
from utils import get_sunset_and_sunrise from stvid.utils import get_sunset_and_sunrise
import logging import logging
import configparser import configparser
import argparse import argparse

View File

@ -1,177 +0,0 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import numpy as np
import astropy.units as u
from astropy.io import fits
from astropy import wcs
from astropy.coordinates import SkyCoord,FK5,ICRS
from astropy.time import Time
from scipy import optimize
# Class for the Tycho 2 catalog
class tycho2_catalog:
"""Tycho2 catalog"""
def __init__(self,maxmag=9.0):
hdu=fits.open(os.path.join(os.getenv("ST_DATADIR"),"data/tyc2.fits"))
ra=hdu[1].data.field('RA')*u.deg
dec=hdu[1].data.field('DEC')*u.deg
mag=hdu[1].data.field('MAG_VT')
c=mag<maxmag
self.ra=ra[c]
self.dec=dec[c]
self.mag=mag[c]
# Estimate the WCS from a reference file
def estimate_wcs_from_reference(ref,fname):
# Read header of reference
hdu=fits.open(ref)
hdu[0].header["NAXIS"]=2
w=wcs.WCS(hdu[0].header)
# Get time and position from reference
tref=Time(hdu[0].header["MJD-OBS"],format="mjd",scale="utc")
pref=SkyCoord(ra=w.wcs.crval[0],dec=w.wcs.crval[1],unit="deg",frame="icrs").transform_to(FK5(equinox=tref))
# Read time from target
hdu=fits.open(fname)
t=Time(hdu[0].header["MJD-OBS"],format="mjd",scale="utc")
# Correct wcs
dra=t.sidereal_time("mean","greenwich")-tref.sidereal_time("mean","greenwich")
p=FK5(ra=pref.ra+dra,dec=pref.dec,equinox=t).transform_to(ICRS)
w.wcs.crval=np.array([p.ra.degree,p.dec.degree])
return w
# Match the astrometry and pixel catalog
def match_catalogs(ast_catalog,pix_catalog,w,rmin):
# Select stars towards pointing center
ra,dec=w.wcs.crval*u.deg
d=np.arccos(np.sin(dec)*np.sin(ast_catalog.dec)+np.cos(dec)*np.cos(ast_catalog.dec)*np.cos(ra-ast_catalog.ra))
c=(d<30.0*u.deg)
ra,dec,mag=ast_catalog.ra[c],ast_catalog.dec[c],ast_catalog.mag[c]
# Convert RA/Dec to pixels
pix=w.wcs_world2pix(np.stack((ra,dec),axis=-1),0)
xs,ys=pix[:,0],pix[:,1]
# Loop over stars
nmatch=0
for i in range(len(pix_catalog.x)):
dx=xs-pix_catalog.x[i]
dy=ys-pix_catalog.y[i]
r=np.sqrt(dx*dx+dy*dy)
if np.min(r)<rmin:
j=np.argmin(r)
pix_catalog.ra[i]=ra[j].value
pix_catalog.dec[i]=dec[j].value
pix_catalog.imag[i]=mag[j]
pix_catalog.flag[i]=1
nmatch+=1
return nmatch
# Residual function
def residual(a,x,y,z):
return z-(a[0]+a[1]*x+a[2]*y)
# Fit transformation
def fit_wcs(w,pix_catalog):
x0,y0=w.wcs.crpix
ra0,dec0=w.wcs.crval
dx,dy=pix_catalog.x-x0,pix_catalog.y-y0
# Iterate to remove outliers
nstars=np.sum(pix_catalog.flag==1)
for j in range(10):
w=wcs.WCS(naxis=2)
w.wcs.crpix=np.array([0.0,0.0])
w.wcs.cd=np.array([[1.0,0.0],[0.0,1.0]])
w.wcs.ctype=["RA---TAN","DEC--TAN"]
w.wcs.set_pv([(2,1,45.0)])
c=pix_catalog.flag==1
# Iterate to move crval to crpix location
for i in range(5):
w.wcs.crval=np.array([ra0,dec0])
world=np.stack((pix_catalog.ra,pix_catalog.dec),axis=-1)
pix=w.wcs_world2pix(world,1)
rx,ry=pix[:,0],pix[:,1]
ax,cov_q,infodict,mesg,ierr=optimize.leastsq(residual,[0.0,0.0,0.0],args=(dx[c],dy[c],rx[c]),full_output=1)
ay,cov_q,infodict,mesg,ierr=optimize.leastsq(residual,[0.0,0.0,0.0],args=(dx[c],dy[c],ry[c]),full_output=1)
ra0,dec0=w.wcs_pix2world([[ax[0],ay[0]]],1)[0]
# Compute residuals
drx=ax[0]+ax[1]*dx+ax[2]*dy-rx
dry=ay[0]+ay[1]*dx+ay[2]*dy-ry
dr=np.sqrt(drx*drx+dry*dry)
rms=np.sqrt(np.sum(dr[c]**2)/len(dr[c]))
dr[~c]=1.0
c=(dr<2.0*rms)
pix_catalog.flag[~c]=0
# Break if converged
if np.sum(c)==nstars:
break
nstars=np.sum(c)
# Compute residuals
rmsx=np.sqrt(np.sum(drx[c]**2)/len(drx[c]))
rmsy=np.sqrt(np.sum(dry[c]**2)/len(dry[c]))
# Store header
w=wcs.WCS(naxis=2)
w.wcs.crpix=np.array([x0,y0])
w.wcs.crval=np.array([ra0,dec0])
w.wcs.cd=np.array([[ax[1],ax[2]],[ay[1],ay[2]]])
w.wcs.ctype=["RA---TAN","DEC--TAN"]
w.wcs.set_pv([(2,1,45.0)])
return w,rmsx,rmsy,rms
def add_wcs(fname,w,rmsx,rmsy):
# Read fits
hdu=fits.open(fname)
whdr={"CRPIX1":w.wcs.crpix[0],"CRPIX2":w.wcs.crpix[1],"CRVAL1":w.wcs.crval[0],"CRVAL2":w.wcs.crval[1],"CD1_1":w.wcs.cd[0,0],"CD1_2":w.wcs.cd[0,1],"CD2_1":w.wcs.cd[1,0],"CD2_2":w.wcs.cd[1,1],"CTYPE1":"RA---TAN","CTYPE2":"DEC--TAN","CUNIT1":"DEG","CUNIT2":"DEG","CRRES1":rmsx,"CRRES2":rmsy}
# Add keywords
hdr=hdu[0].header
for k,v in whdr.items():
hdr[k]=v
hdu=fits.PrimaryHDU(header=hdr,data=hdu[0].data)
hdu.writeto(fname,overwrite=True,output_verify="ignore")
return
def calibrate_from_reference(fname,ref,pix_catalog):
# Estimated WCS
w=estimate_wcs_from_reference(ref,fname)
# Default rms values
rmsx=0.0
rmsy=0.0
# Read catalogs
if (pix_catalog.nstars>4):
ast_catalog=tycho2_catalog(10.0)
# Match catalogs
nmatch=match_catalogs(ast_catalog,pix_catalog,w,10.0)
# Fit transformation
if nmatch>4:
w,rmsx,rmsy,rms=fit_wcs(w,pix_catalog)
# Add wcs
add_wcs(fname,w,rmsx,rmsy)
return w,rmsx,rmsy

View File

@ -1,13 +0,0 @@
#!/bin/bash
# Sleep
sleep 10
# Does /dev/video1 exist
ls -l /dev/video1 >/tmp/camera_1.log 2>&1
# Run mplayer for 10 frames to setup easycap
mplayer -frames 10 tv:// -tv device=/dev/video1 >/tmp/camera_1.log 2>&1
# Start script
python ./acquire.py 1 >/tmp/camera_1.log 2>&1 &

View File

@ -1,13 +0,0 @@
#!/bin/bash
# Sleep
sleep 10
# Does /dev/video2 exist
ls -l /dev/video2 >/tmp/camera_2.log 2>&1
# Run mplayer for 10 frames to setup easycap
mplayer -frames 10 tv:// -tv device=/dev/video2 >/tmp/camera_2.log 2>&1
# Start script
python ./acquire.py 2 >/tmp/camera_2.log 2>&1 &

37
extract_tracks.py 100644 → 100755
View File

@ -1,13 +1,14 @@
#!/usr/bin/env python #!/usr/bin/env python
import time
import os import os
import glob import glob
import shutil import shutil
from stio import fourframe, satid, observation from stvid.stio import fourframe, satid, observation
import numpy as np import numpy as np
import ppgplot as ppg import ppgplot as ppg
from scipy import optimize, ndimage from scipy import optimize, ndimage
import configparser
import argparse
# Gaussian model # Gaussian model
@ -454,15 +455,35 @@ if __name__ == '__main__':
# Minimum track points # Minimum track points
ntrkmin = 10 ntrkmin = 10
# Read commandline options
conf_parser = argparse.ArgumentParser(description='Extract satellite' +
' tracks from frames.')
conf_parser.add_argument("-c", "--conf_file",
help="Specify configuration file. If no file" +
" is specified 'configuration.ini' is used.",
metavar="FILE")
conf_parser.add_argument("-d", "--directory",
help="Specify directory of observations. If no" +
" directory is specified parent will be used.",
metavar='DIR', dest='file_dir', default=".")
args = conf_parser.parse_args()
# Process commandline options and parse configuration
cfg = configparser.ConfigParser(inline_comment_prefixes=('#', ';'))
if args.conf_file:
cfg.read([args.conf_file])
else:
cfg.read('configuration.ini')
# Create output dirs # Create output dirs
path = os.getenv("ST_OBSDIR")+"/"+time.strftime("%Y%m%d/%H%M%S", path = args.file_dir
time.gmtime()) os.makedirs(path+"classfd")
os.makedirs(path+"/classfd") os.makedirs(path+"catalog")
os.makedirs(path+"/catalog") os.makedirs(path+"unid")
os.makedirs(path+"/unid")
# Get files # Get files
files = sorted(glob.glob("2*.fits")) files = sorted(glob.glob(path+"2*.fits"))
# Process files # Process files
for file in files: for file in files:

62
imgstat.py 100644 → 100755
View File

@ -4,38 +4,66 @@ import numpy as np
from astropy.io import ascii from astropy.io import ascii
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import astropy.units as u import astropy.units as u
from astropy.coordinates import SkyCoord,FK5,AltAz,EarthLocation from astropy.coordinates import SkyCoord, AltAz, EarthLocation
from astropy.time import Time from astropy.time import Time
import configparser
import argparse
table=ascii.read("imgstat.csv",format="csv") # Read commandline options
conf_parser = argparse.ArgumentParser(description='Plot image statistics')
conf_parser.add_argument("-c", "--conf_file",
help="Specify configuration file. If no file" +
" is specified 'configuration.ini' is used.",
metavar="FILE")
conf_parser.add_argument("-i", "--input",
help="Specify file to be processed. If no file" +
" is specified ./imgstat.csv will be used.",
metavar='FILE', default="./imgstat.csv")
conf_parser.add_argument("-o", "--output",
help="Specify output file. Default is 'imgstat.png'",
metavar='FILE', default="./imgstat.png")
t=Time(table['mjd'],format="mjd",scale="utc") args = conf_parser.parse_args()
pos=SkyCoord(ra=table['ra'],dec=table['de'],frame="icrs",unit="deg")
loc=EarthLocation(lat=52.8344*u.deg,lon=6.3785*u.deg,height=10*u.m) # Process commandline options and parse configuration
cfg = configparser.ConfigParser(inline_comment_prefixes=('#', ';'))
if args.conf_file:
cfg.read([args.conf_file])
else:
cfg.read('configuration.ini')
pa=pos.transform_to(AltAz(obstime=t,location=loc)) table = ascii.read(args.input, format="csv")
mjd0=np.floor(np.min(table['mjd'])) t = Time(table['mjd'], format="mjd", scale="utc")
pos = SkyCoord(ra=table['ra'], dec=table['de'], frame="icrs", unit="deg")
plt.figure(figsize=(20,10)) # Set location
loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat')*u.deg,
lon=cfg.getfloat('Common', 'observer_lon')*u.deg,
height=cfg.getfloat('Common', 'observer_el')*u.m)
pa = pos.transform_to(AltAz(obstime=t, location=loc))
mjd0 = np.floor(np.min(table['mjd']))
plt.figure(figsize=(20, 10))
plt.subplot(411) plt.subplot(411)
plt.plot(table['mjd']-mjd0,table['mean'],label='Brightness') plt.plot(table['mjd']-mjd0, table['mean'], label='Brightness')
plt.plot(table['mjd']-mjd0,table['std'],label='Variation') plt.plot(table['mjd']-mjd0, table['std'], label='Variation')
plt.ylabel("ADU") plt.ylabel("ADU")
plt.legend() plt.legend()
plt.subplot(412) plt.subplot(412)
plt.plot(table['mjd']-mjd0,pa.az.degree) plt.plot(table['mjd']-mjd0, pa.az.degree)
plt.ylabel("Azimuth (deg)") plt.ylabel("Azimuth (deg)")
plt.subplot(413) plt.subplot(413)
plt.plot(table['mjd']-mjd0,pa.alt.degree) plt.plot(table['mjd']-mjd0, pa.alt.degree)
plt.ylabel("Altitude (deg)") plt.ylabel("Altitude (deg)")
plt.subplot(414) plt.subplot(414)
plt.plot(table['mjd']-mjd0,table['rmsx'],label='RA') plt.plot(table['mjd']-mjd0, table['rmsx'], label='RA')
plt.plot(table['mjd']-mjd0,table['rmsy'],label='Dec') plt.plot(table['mjd']-mjd0, table['rmsy'], label='Dec')
plt.ylim(0,60) plt.ylim(0, 60)
plt.ylabel("Residual (arcseconds)") plt.ylabel("Residual (arcseconds)")
plt.xlabel("MJD - %.0f"%mjd0) plt.xlabel("MJD - %.0f" % mjd0)
plt.legend() plt.legend()
plt.savefig("imgstat.png") plt.savefig(args.output)

65
process.py 100644 → 100755
View File

@ -2,46 +2,79 @@
from __future__ import print_function from __future__ import print_function
import glob import glob
import numpy as np import numpy as np
from stio import fourframe from stvid.stio import fourframe
from stars import pixel_catalog, generate_star_catalog from stvid.stars import generate_star_catalog
from astrometry import calibrate_from_reference from stvid.astrometry import calibrate_from_reference
import astropy.units as u import astropy.units as u
from astropy.utils.exceptions import AstropyWarning from astropy.utils.exceptions import AstropyWarning
from astropy.coordinates import EarthLocation, AltAz from astropy.coordinates import EarthLocation
import warnings import warnings
import configparser
import argparse
if __name__ == "__main__": if __name__ == "__main__":
# Read commandline options
conf_parser = argparse.ArgumentParser(description='Process captured' +
' video frames.')
conf_parser.add_argument("-c", "--conf_file",
help="Specify configuration file. If no file" +
" is specified 'configuration.ini' is used.",
metavar="FILE")
conf_parser.add_argument("-d", "--directory",
help="Specify directory of observations. If no" +
" directory is specified parent will be used.",
metavar='DIR', dest='file_dir', default=".")
args = conf_parser.parse_args()
# Process commandline options and parse configuration
cfg = configparser.ConfigParser(inline_comment_prefixes=('#', ';'))
if args.conf_file:
cfg.read([args.conf_file])
else:
cfg.read('configuration.ini')
# Set warnings # Set warnings
warnings.filterwarnings("ignore", category=UserWarning, append=True) warnings.filterwarnings("ignore", category=UserWarning, append=True)
warnings.simplefilter("ignore", AstropyWarning) warnings.simplefilter("ignore", AstropyWarning)
# Set location # Set location
loc=EarthLocation(lat=52.8344*u.deg,lon=6.3785*u.deg,height=10*u.m) loc = EarthLocation(lat=cfg.getfloat('Common', 'observer_lat')*u.deg,
lon=cfg.getfloat('Common', 'observer_lon')*u.deg,
height=cfg.getfloat('Common', 'observer_el')*u.m)
# Get files # Get files
files=sorted(glob.glob("2*.fits")) files = sorted(glob.glob(args.file_dir+"2*.fits"))
# Statistics file # Statistics file
fstat=open("imgstat.csv","w") fstat = open(args.file_dir+"imgstat.csv", "w")
fstat.write("fname,mjd,ra,de,rmsx,rmsy,mean,std,nstars,nused\n") fstat.write("fname,mjd,ra,de,rmsx,rmsy,mean,std,nstars,nused\n")
# Loop over files # Loop over files
for fname in files: for fname in files:
# Generate star catalog # Generate star catalog
pix_catalog=generate_star_catalog(fname) pix_catalog = generate_star_catalog(fname)
# Calibrate astrometry # Calibrate astrometry
calibrate_from_reference(fname,"test.fits",pix_catalog) calibrate_from_reference(fname, args.file_dir+"test.fits", pix_catalog)
# Stars available and used # Stars available and used
nused=np.sum(pix_catalog.flag==1) nused = np.sum(pix_catalog.flag == 1)
nstars=pix_catalog.nstars nstars = pix_catalog.nstars
# Get properties # Get properties
ff=fourframe(fname) ff = fourframe(fname)
print("%s,%.8lf,%.6f,%.6f,%.3f,%.3f,%.3f,%.3f,%d,%d"%(ff.fname,ff.mjd,ff.crval[0],ff.crval[1],3600*ff.crres[0],3600*ff.crres[1],np.mean(ff.zavg),np.std(ff.zavg),nstars,nused))
fstat.write("%s,%.8lf,%.6f,%.6f,%.3f,%.3f,%.3f,%.3f,%d,%d\n"%(ff.fname,ff.mjd,ff.crval[0],ff.crval[1],3600*ff.crres[0],3600*ff.crres[1],np.mean(ff.zavg),np.std(ff.zavg),nstars,nused))
print(("%s,%.8lf,%.6f,%.6f,%.3f,%.3f," +
"%.3f,%.3f,%d,%d") % (ff.fname, ff.mjd, ff.crval[0],
ff.crval[1], 3600*ff.crres[0],
3600*ff.crres[1], np.mean(ff.zavg),
np.std(ff.zavg), nstars, nused))
fstat.write(("%s,%.8lf,%.6f,%.6f,%.3f,%.3f,%.3f," +
"%.3f,%d,%d\n") % (ff.fname, ff.mjd, ff.crval[0],
ff.crval[1], 3600*ff.crres[0],
3600*ff.crres[1], np.mean(ff.zavg),
np.std(ff.zavg), nstars, nused))
fstat.close() fstat.close()

View File

@ -3,3 +3,10 @@ numpy==1.14.2
opencv-python==3.4.0.12 opencv-python==3.4.0.12
scipy==1.0.1 scipy==1.0.1
git+https://github.com/cbassa/ppgplot.git@master git+https://github.com/cbassa/ppgplot.git@master
cycler==0.10.0
kiwisolver==1.0.1
matplotlib==2.2.2
pyparsing==2.2.0
python-dateutil==2.7.2
pytz==2018.4
six==1.11.0

View File

@ -1,47 +0,0 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import subprocess
import numpy as np
class pixel_catalog:
"""Pixel catalog"""
def __init__(self,fname):
d=np.loadtxt(fname)
if len(d.shape)==2:
self.x=d[:,0]
self.y=d[:,1]
self.mag=d[:,2]
self.ra=np.empty_like(self.x)
self.dec=np.empty_like(self.x)
self.imag=np.empty_like(self.x)
self.flag=np.zeros_like(self.x)
self.nstars=len(self.mag)
else:
self.x=None
self.y=None
self.mag=None
self.ra=None
self.dec=None
self.imag=None
self.flag=None
self.nstars=0
def generate_star_catalog(fname):
# Skip if file already exists
if not os.path.exists(fname+".cat"):
# Get sextractor location
env=os.getenv("ST_DATADIR")
# Format command
command="sextractor %s -c %s/sextractor/default.sex"%(fname,env)
# Run sextractor
output=subprocess.check_output(command,shell=True,stderr=subprocess.STDOUT)
# Rename file
if os.path.exists("test.cat"):
os.rename("test.cat",fname+".cat")
return pixel_catalog(fname+".cat")

View File

208
stvid/astrometry.py 100644
View File

@ -0,0 +1,208 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import numpy as np
import astropy.units as u
from astropy.io import fits
from astropy import wcs
from astropy.coordinates import SkyCoord, FK5, ICRS
from astropy.time import Time
from scipy import optimize
# Class for the Tycho 2 catalog
class tycho2_catalog:
"""Tycho2 catalog"""
def __init__(self, maxmag=9.0):
hdu = fits.open(os.path.join(os.getenv("ST_DATADIR"),
"data/tyc2.fits"))
ra = hdu[1].data.field('RA')*u.deg
dec = hdu[1].data.field('DEC')*u.deg
mag = hdu[1].data.field('MAG_VT')
c = mag < maxmag
self.ra = ra[c]
self.dec = dec[c]
self.mag = mag[c]
# Estimate the WCS from a reference file
def estimate_wcs_from_reference(ref, fname):
# Read header of reference
hdu = fits.open(ref)
hdu[0].header["NAXIS"] = 2
w = wcs.WCS(hdu[0].header)
# Get time and position from reference
tref = Time(hdu[0].header["MJD-OBS"], format="mjd", scale="utc")
pref = SkyCoord(ra=w.wcs.crval[0],
dec=w.wcs.crval[1],
unit="deg",
frame="icrs").transform_to(FK5(equinox=tref))
# Read time from target
hdu = fits.open(fname)
t = Time(hdu[0].header["MJD-OBS"], format="mjd", scale="utc")
# Correct wcs
dra = (t.sidereal_time("mean", "greenwich")
- tref.sidereal_time("mean", "greenwich"))
p = FK5(ra=pref.ra+dra, dec=pref.dec, equinox=t).transform_to(ICRS)
w.wcs.crval = np.array([p.ra.degree, p.dec.degree])
return w
# Match the astrometry and pixel catalog
def match_catalogs(ast_catalog, pix_catalog, w, rmin):
# Select stars towards pointing center
ra, dec = w.wcs.crval*u.deg
d = np.arccos(np.sin(dec)
* np.sin(ast_catalog.dec)
+ np.cos(dec)
* np.cos(ast_catalog.dec)
* np.cos(ra-ast_catalog.ra))
c = (d < 30.0*u.deg)
ra, dec, mag = ast_catalog.ra[c], ast_catalog.dec[c], ast_catalog.mag[c]
# Convert RA/Dec to pixels
pix = w.wcs_world2pix(np.stack((ra, dec), axis=-1), 0)
xs, ys = pix[:, 0], pix[:, 1]
# Loop over stars
nmatch = 0
for i in range(len(pix_catalog.x)):
dx = xs-pix_catalog.x[i]
dy = ys-pix_catalog.y[i]
r = np.sqrt(dx*dx+dy*dy)
if np.min(r) < rmin:
j = np.argmin(r)
pix_catalog.ra[i] = ra[j].value
pix_catalog.dec[i] = dec[j].value
pix_catalog.imag[i] = mag[j]
pix_catalog.flag[i] = 1
nmatch += 1
return nmatch
# Residual function
def residual(a, x, y, z):
return z-(a[0]+a[1]*x+a[2]*y)
# Fit transformation
def fit_wcs(w, pix_catalog):
x0, y0 = w.wcs.crpix
ra0, dec0 = w.wcs.crval
dx, dy = pix_catalog.x-x0, pix_catalog.y-y0
# Iterate to remove outliers
nstars = np.sum(pix_catalog.flag == 1)
for j in range(10):
w = wcs.WCS(naxis=2)
w.wcs.crpix = np.array([0.0, 0.0])
w.wcs.cd = np.array([[1.0, 0.0], [0.0, 1.0]])
w.wcs.ctype = ["RA---TAN", "DEC--TAN"]
w.wcs.set_pv([(2, 1, 45.0)])
c = pix_catalog.flag == 1
# Iterate to move crval to crpix location
for i in range(5):
w.wcs.crval = np.array([ra0, dec0])
world = np.stack((pix_catalog.ra, pix_catalog.dec), axis=-1)
pix = w.wcs_world2pix(world, 1)
rx, ry = pix[:, 0], pix[:, 1]
ax, cov_q, infodict, mesg, ierr = optimize.leastsq(residual,
[0.0, 0.0, 0.0],
args=(dx[c],
dy[c],
rx[c]),
full_output=1)
ay, cov_q, infodict, mesg, ierr = optimize.leastsq(residual,
[0.0, 0.0, 0.0],
args=(dx[c],
dy[c],
ry[c]),
full_output=1)
ra0, dec0 = w.wcs_pix2world([[ax[0], ay[0]]], 1)[0]
# Compute residuals
drx = ax[0]+ax[1]*dx+ax[2]*dy-rx
dry = ay[0]+ay[1]*dx+ay[2]*dy-ry
dr = np.sqrt(drx*drx+dry*dry)
rms = np.sqrt(np.sum(dr[c]**2)/len(dr[c]))
dr[~c] = 1.0
c = (dr < 2.0*rms)
pix_catalog.flag[~c] = 0
# Break if converged
if np.sum(c) == nstars:
break
nstars = np.sum(c)
# Compute residuals
rmsx = np.sqrt(np.sum(drx[c]**2)/len(drx[c]))
rmsy = np.sqrt(np.sum(dry[c]**2)/len(dry[c]))
# Store header
w = wcs.WCS(naxis=2)
w.wcs.crpix = np.array([x0, y0])
w.wcs.crval = np.array([ra0, dec0])
w.wcs.cd = np.array([[ax[1], ax[2]], [ay[1], ay[2]]])
w.wcs.ctype = ["RA---TAN", "DEC--TAN"]
w.wcs.set_pv([(2, 1, 45.0)])
return w, rmsx, rmsy, rms
def add_wcs(fname, w, rmsx, rmsy):
# Read fits
hdu = fits.open(fname)
whdr = {"CRPIX1": w.wcs.crpix[0], "CRPIX2": w.wcs.crpix[1],
"CRVAL1": w.wcs.crval[0], "CRVAL2": w.wcs.crval[1],
"CD1_1": w.wcs.cd[0, 0], "CD1_2": w.wcs.cd[0, 1],
"CD2_1": w.wcs.cd[1, 0], "CD2_2": w.wcs.cd[1, 1],
"CTYPE1": "RA---TAN", "CTYPE2": "DEC--TAN", "CUNIT1": "DEG",
"CUNIT2": "DEG", "CRRES1": rmsx, "CRRES2": rmsy}
# Add keywords
hdr = hdu[0].header
for k, v in whdr.items():
hdr[k] = v
hdu = fits.PrimaryHDU(header=hdr, data=hdu[0].data)
hdu.writeto(fname, overwrite=True, output_verify="ignore")
return
def calibrate_from_reference(fname, ref, pix_catalog):
# Estimated WCS
w = estimate_wcs_from_reference(ref, fname)
# Default rms values
rmsx = 0.0
rmsy = 0.0
# Read catalogs
if (pix_catalog.nstars > 4):
ast_catalog = tycho2_catalog(10.0)
# Match catalogs
nmatch = match_catalogs(ast_catalog, pix_catalog, w, 10.0)
# Fit transformation
if nmatch > 4:
w, rmsx, rmsy, rms = fit_wcs(w, pix_catalog)
# Add wcs
add_wcs(fname, w, rmsx, rmsy)
return w, rmsx, rmsy

50
stvid/stars.py 100644
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import subprocess
import numpy as np
class pixel_catalog:
"""Pixel catalog"""
def __init__(self, fname):
d = np.loadtxt(fname)
if len(d.shape) == 2:
self.x = d[:, 0]
self.y = d[:, 1]
self.mag = d[:, 2]
self.ra = np.empty_like(self.x)
self.dec = np.empty_like(self.x)
self.imag = np.empty_like(self.x)
self.flag = np.zeros_like(self.x)
self.nstars = len(self.mag)
else:
self.x = None
self.y = None
self.mag = None
self.ra = None
self.dec = None
self.imag = None
self.flag = None
self.nstars = 0
def generate_star_catalog(fname):
# Skip if file already exists
if not os.path.exists(fname+".cat"):
# Get sextractor location
env = os.getenv("ST_DATADIR")
# Format command
command = "sextractor %s -c %s/sextractor/default.sex" % (fname, env)
# Run sextractor
output = subprocess.check_output(command, shell=True,
stderr=subprocess.STDOUT)
# Rename file
if os.path.exists("test.cat"):
os.rename("test.cat", fname+".cat")
return pixel_catalog(fname+".cat")