682 lines
14 KiB
C
682 lines
14 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include "qfits.h"
|
|
#include <getopt.h>
|
|
|
|
|
|
struct image
|
|
{
|
|
int nx, ny;
|
|
char timestamp[64];
|
|
unsigned char *c;
|
|
};
|
|
struct fourframe
|
|
{
|
|
int nx, ny, nt, nlayer;
|
|
char timestamp[64], observer[64];
|
|
double mjd;
|
|
float *z, *dt;
|
|
int cospar, type;
|
|
};
|
|
int fgetline (FILE * file, char *s, int lim);
|
|
void write_fits (char *filename, struct fourframe ff);
|
|
struct image read_pgm (char *filename, int *status);
|
|
double nfd2mjd (char *date);
|
|
double date2mjd (int year, int month, double day);
|
|
void write_pgm (char *filename, struct fourframe ff);
|
|
void mjd2date (double mjd, char *date);
|
|
|
|
void
|
|
usage (void)
|
|
{
|
|
printf ("pgm2fits p:w:h:s:n:Dd:x:y:c:o:gm:t:r:I\n\n");
|
|
printf ("-p image prefix\n");
|
|
printf ("-w image width in pixels\n");
|
|
printf ("-h image height in pixels\n");
|
|
printf ("-s number of first image to process\n");
|
|
printf ("-n number of images to process\n");
|
|
printf ("-D toggle for creating dark frame\n");
|
|
printf ("-d toggle for creating dark frame\n");
|
|
printf ("-d filename of dark frame to substract\n");
|
|
printf ("-m filename of mask frame to apply\n");
|
|
printf ("-x tracking rate in x (pix/s)\n");
|
|
printf ("-y tracking rate in y (pix/s)\n");
|
|
printf ("-c COSPAR [default 4553]\n");
|
|
printf ("-o observer [default \"Cees Bassa\"]\n");
|
|
printf ("-g toggle for guiding??\n");
|
|
printf ("-t time stamp of first image [YYYY-MM-DDTHH:MM:SS.SSS]\n");
|
|
printf ("-r frame rate (frames/s)\n");
|
|
printf ("-I integer output\n");
|
|
exit (0);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
int i, j, k, l, m, k0 = 1, status, nt, darkout = 0, darkin = 0, track =
|
|
0, maskin = 0;
|
|
int n, n0, di, dj, npix;
|
|
struct image *img, drk, msk;
|
|
struct fourframe ff;
|
|
char filename[128], nfd[64];
|
|
float s1, s2, z;
|
|
float avg, std, max, cnt, *trk;
|
|
int *wt;
|
|
int arg = 0;
|
|
char *path, *darkfile, *maskfile;
|
|
double mjd, mjd0 = 0.0;
|
|
float dxdn = 0.0, dydn = 0.0, dx, dy;
|
|
int guide = 0, timereset = 0;
|
|
float framerate = 25.0;
|
|
char *env;
|
|
|
|
// Set defaults
|
|
env = getenv ("ST_COSPAR");
|
|
ff.cospar = atoi (env);
|
|
strcpy (ff.observer, "Cees Bassa");
|
|
ff.type = 0;
|
|
|
|
// Decode options
|
|
if (argc > 1)
|
|
{
|
|
while ((arg =
|
|
getopt (argc, argv, "p:w:h:s:n:Dd:x:y:c:o:gm:t:r:I")) != -1)
|
|
{
|
|
switch (arg)
|
|
{
|
|
case 'p':
|
|
path = optarg;
|
|
break;
|
|
|
|
case 'g':
|
|
guide = 1;
|
|
break;
|
|
|
|
case 'w':
|
|
ff.nx = atoi (optarg);
|
|
break;
|
|
|
|
case 'h':
|
|
ff.ny = atoi (optarg);
|
|
break;
|
|
|
|
case 'I':
|
|
ff.type = 1;
|
|
break;
|
|
|
|
case 'c':
|
|
ff.cospar = atoi (optarg);
|
|
break;
|
|
|
|
case 'o':
|
|
strcpy (ff.observer, optarg);
|
|
break;
|
|
|
|
case 's':
|
|
k0 = atoi (optarg);
|
|
break;
|
|
|
|
case 'n':
|
|
nt = atoi (optarg);
|
|
break;
|
|
|
|
case 'D':
|
|
darkout = 1;
|
|
break;
|
|
|
|
case 'd':
|
|
darkin = 1;
|
|
darkfile = optarg;
|
|
break;
|
|
|
|
case 'm':
|
|
maskin = 1;
|
|
maskfile = optarg;
|
|
break;
|
|
|
|
case 'x':
|
|
dxdn = atof (optarg);
|
|
track = 1;
|
|
break;
|
|
|
|
case 'y':
|
|
dydn = atof (optarg);
|
|
track = 1;
|
|
break;
|
|
|
|
case 't':
|
|
strcpy (nfd, optarg);
|
|
mjd0 = nfd2mjd (nfd);
|
|
timereset = 1;
|
|
break;
|
|
|
|
case 'r':
|
|
framerate = atof (optarg);
|
|
timereset = 1;
|
|
break;
|
|
|
|
default:
|
|
usage ();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
usage ();
|
|
}
|
|
|
|
// Add layer
|
|
if (track == 1)
|
|
ff.nlayer = 5;
|
|
else
|
|
ff.nlayer = 4;
|
|
|
|
// Allocate
|
|
ff.z = (float *) malloc (ff.nlayer * sizeof (float) * ff.nx * ff.ny);
|
|
ff.dt = (float *) malloc (sizeof (float) * nt);
|
|
trk = (float *) malloc (sizeof (float) * ff.nx * ff.ny);
|
|
wt = (int *) malloc (sizeof (float) * ff.nx * ff.ny);
|
|
img = (struct image *) malloc (sizeof (struct image) * nt);
|
|
|
|
// Read dark file
|
|
if (darkin == 1)
|
|
drk = read_pgm (darkfile, &status);
|
|
|
|
// Read mask file
|
|
if (maskin == 1)
|
|
msk = read_pgm (maskfile, &status);
|
|
|
|
// Loop over files
|
|
for (k = 0, l = 0; k < nt; k++)
|
|
{
|
|
sprintf (filename, "%s%06d.pgm", path, k + k0);
|
|
img[l] = read_pgm (filename, &status);
|
|
|
|
// Reset time
|
|
if (timereset == 1)
|
|
{
|
|
mjd = mjd0 + (double) (k + k0) / (86400.0 * framerate);
|
|
mjd2date (mjd, img[l].timestamp);
|
|
}
|
|
|
|
ff.dt[l] =
|
|
86400.0 * (nfd2mjd (img[l].timestamp) - nfd2mjd (img[0].timestamp));
|
|
if (status == 0)
|
|
{
|
|
printf ("Read %s\n", filename);
|
|
l++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
ff.nt = l;
|
|
strcpy (ff.timestamp, img[0].timestamp);
|
|
ff.mjd = nfd2mjd (img[0].timestamp);
|
|
|
|
printf ("Accumulating image statistics\n");
|
|
// Loop over pixels
|
|
for (i = 0; i < ff.nx; i++)
|
|
{
|
|
for (j = 0; j < ff.ny; j++)
|
|
{
|
|
n = i + ff.nx * j;
|
|
|
|
s1 = 0.0;
|
|
s2 = 0.0;
|
|
max = 0.0;
|
|
cnt = 0.0;
|
|
|
|
// Loop over images
|
|
for (k = 0; k < ff.nt; k++)
|
|
{
|
|
if (darkin == 0)
|
|
z = (float) img[k].c[n];
|
|
else if (darkin == 1)
|
|
z = (float) (img[k].c[n] - drk.c[n]);
|
|
s1 += z;
|
|
s2 += z * z;
|
|
if (z > max)
|
|
{
|
|
max = z;
|
|
cnt = (float) k;
|
|
}
|
|
}
|
|
s1 -= max;
|
|
s2 -= max * max;
|
|
avg = s1 / (float) (ff.nt - 1);
|
|
std = sqrt ((s2 - s1 * avg) / (float) (ff.nt - 2));
|
|
|
|
// Reset masked pixels
|
|
if (maskin == 1 && msk.c[n] == 0.0)
|
|
{
|
|
avg = 0.0;
|
|
std = 0.0;
|
|
max = 0.0;
|
|
cnt = 128.0;
|
|
}
|
|
|
|
for (m = 0; m < ff.nlayer; m++)
|
|
{
|
|
l = i + (ff.ny - j - 1) * ff.nx + m * ff.nx * ff.ny;
|
|
if (m == 0)
|
|
ff.z[l] = avg;
|
|
if (m == 1)
|
|
ff.z[l] = std;
|
|
if (m == 2)
|
|
ff.z[l] = max;
|
|
if (m == 3)
|
|
ff.z[l] = cnt;
|
|
if (m == 4)
|
|
ff.z[l] = avg;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create tracked layer
|
|
if (track == 1)
|
|
{
|
|
printf ("Creating tracked layer\n");
|
|
|
|
// Set weights
|
|
for (i = 0; i < ff.nx * ff.ny; i++)
|
|
{
|
|
wt[i] = 0;
|
|
trk[i] = 0.0;
|
|
}
|
|
|
|
// Loop over frames
|
|
for (l = 0; l < ff.nt; l++)
|
|
{
|
|
// Offset
|
|
dx = dxdn * (l - ff.nt / 2);
|
|
dy = dydn * (l - ff.nt / 2);
|
|
|
|
// Integer offset
|
|
di = (int) floor (dx + 0.5);
|
|
dj = (int) floor (dy + 0.5);
|
|
|
|
// Set
|
|
for (i = 0; i < ff.nx; i++)
|
|
{
|
|
for (j = 0; j < ff.ny; j++)
|
|
{
|
|
k = i + ff.nx * j;
|
|
k0 = i + di + ff.nx * (j + dj);
|
|
if (i + di > 0 && i + di < ff.nx && j + dj > 0
|
|
&& j + dj < ff.ny)
|
|
{
|
|
wt[k] += 1;
|
|
trk[k] += (float) img[l].c[k0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Save layer
|
|
for (i = 0; i < ff.nx; i++)
|
|
{
|
|
for (j = 0; j < ff.ny; j++)
|
|
{
|
|
k = i + ff.nx * j;
|
|
if (guide == 0)
|
|
l = i + (ff.ny - j - 1) * ff.nx;
|
|
else
|
|
l = i + (ff.ny - j - 1) * ff.nx + 4 * ff.nx * ff.ny;
|
|
if (wt[k] > 0)
|
|
ff.z[l] = trk[k] / (float) wt[k];
|
|
else
|
|
ff.z[l] = trk[k];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write fits
|
|
if (ff.timestamp != NULL)
|
|
sprintf (filename, "%s.fits", ff.timestamp);
|
|
else
|
|
strcpy (filename, "test.fits");
|
|
write_fits (filename, ff);
|
|
|
|
// Write dark frame
|
|
if (darkout == 1)
|
|
write_pgm ("dark.pgm", ff);
|
|
|
|
// Free
|
|
for (k = 0; k < ff.nt; k++)
|
|
free (img[k].c);
|
|
free (trk);
|
|
free (img);
|
|
free (wt);
|
|
free (ff.dt);
|
|
free (ff.z);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Read pgm file
|
|
struct image
|
|
read_pgm (char *filename, int *status)
|
|
{
|
|
int i;
|
|
struct image img;
|
|
FILE *file;
|
|
char hbuf[64];
|
|
|
|
// Open file
|
|
file = fopen (filename, "rb");
|
|
if (file == NULL)
|
|
{
|
|
*status = 1;
|
|
return img;
|
|
}
|
|
|
|
// Read PGM format
|
|
fgetline (file, hbuf, 64);
|
|
if (strcmp (hbuf, "P5") != 0)
|
|
{
|
|
printf ("Not a valid PGM file!\n");
|
|
exit (0);
|
|
}
|
|
|
|
// Read timestamp/image size
|
|
fgetline (file, hbuf, 64);
|
|
if (strstr (hbuf, "#") != NULL)
|
|
{
|
|
strcpy (img.timestamp, hbuf + 2);
|
|
fgetline (file, hbuf, 64);
|
|
sscanf (hbuf, "%d %d", &img.nx, &img.ny);
|
|
}
|
|
else
|
|
{
|
|
strcpy (img.timestamp, "2012-01-01T00:00:00");
|
|
sscanf (hbuf, "%d %d", &img.nx, &img.ny);
|
|
}
|
|
fgetline (file, hbuf, 64);
|
|
|
|
// Allocate
|
|
img.c = (unsigned char *) malloc (sizeof (unsigned char) * img.nx * img.ny);
|
|
|
|
// Read
|
|
fread (img.c, 1, img.nx * img.ny, file);
|
|
|
|
// Close file
|
|
fclose (file);
|
|
|
|
*status = 0;
|
|
return img;
|
|
}
|
|
|
|
// Get line
|
|
int
|
|
fgetline (FILE * file, char *s, int lim)
|
|
{
|
|
int c, i = 0;
|
|
|
|
while (--lim > 0 && (c = fgetc (file)) != EOF && c != '\n')
|
|
s[i++] = c;
|
|
// if (c=='\n')
|
|
// s[i++]=c;
|
|
s[i] = '\0';
|
|
|
|
return i;
|
|
}
|
|
|
|
// Write fits file
|
|
void
|
|
write_fits (char *filename, struct fourframe ff)
|
|
{
|
|
int i, j, k, l;
|
|
float *fbuf;
|
|
int *ibuf;
|
|
qfitsdumper qd;
|
|
qfits_header *qh;
|
|
char key[FITS_LINESZ + 1];
|
|
char val[FITS_LINESZ + 1];
|
|
char com[FITS_LINESZ + 1];
|
|
char lin[FITS_LINESZ + 1];
|
|
FILE *file;
|
|
|
|
// Create FITS header
|
|
qh = qfits_header_default ();
|
|
|
|
// Add stuff
|
|
if (ff.type == 1)
|
|
qfits_header_add (qh, "BITPIX", "8", " ", NULL);
|
|
else
|
|
qfits_header_add (qh, "BITPIX", "-32", " ", NULL);
|
|
qfits_header_add (qh, "NAXIS", "3", " ", NULL);
|
|
sprintf (val, "%i", ff.nx);
|
|
qfits_header_add (qh, "NAXIS1", val, " ", NULL);
|
|
sprintf (val, "%i", ff.ny);
|
|
qfits_header_add (qh, "NAXIS2", val, " ", NULL);
|
|
sprintf (val, "%i", ff.nlayer);
|
|
qfits_header_add (qh, "NAXIS3", val, " ", NULL);
|
|
qfits_header_add (qh, "BSCALE", "1.0", " ", NULL);
|
|
qfits_header_add (qh, "BZERO", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "DATAMAX", "255.0", " ", NULL);
|
|
qfits_header_add (qh, "DATAMIN", "0.0", " ", NULL);
|
|
sprintf (val, "%s", ff.timestamp);
|
|
qfits_header_add (qh, "DATE-OBS", val, " ", NULL);
|
|
|
|
// MJD-OBS
|
|
sprintf (val, "%lf", ff.mjd);
|
|
qfits_header_add (qh, "MJD-OBS", val, " ", NULL);
|
|
sprintf (val, "%f", ff.dt[ff.nt - 1] - ff.dt[0]);
|
|
qfits_header_add (qh, "EXPTIME", val, " ", NULL);
|
|
sprintf (val, "%d", ff.nt);
|
|
qfits_header_add (qh, "NFRAMES", val, " ", NULL);
|
|
|
|
// Astrometry keywors
|
|
sprintf (val, "%f", ff.nx / 2.0);
|
|
qfits_header_add (qh, "CRPIX1", val, " ", NULL);
|
|
sprintf (val, "%f", ff.ny / 2.0);
|
|
qfits_header_add (qh, "CRPIX2", val, " ", NULL);
|
|
qfits_header_add (qh, "CRVAL1", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "CRVAL2", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "CD1_1", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "CD1_2", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "CD2_1", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "CD2_2", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "CTYPE1", "'RA---TAN'", " ", NULL);
|
|
qfits_header_add (qh, "CTYPE2", "'DEC--TAN'", " ", NULL);
|
|
qfits_header_add (qh, "CUNIT1", "'deg'", " ", NULL);
|
|
qfits_header_add (qh, "CUNIT2", "'deg'", " ", NULL);
|
|
qfits_header_add (qh, "CRRES1", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "CRRES2", "0.0", " ", NULL);
|
|
qfits_header_add (qh, "EQUINOX", "2000.0", " ", NULL);
|
|
qfits_header_add (qh, "RADECSYS", "ICRS", " ", NULL);
|
|
sprintf (val, "%d", ff.cospar);
|
|
qfits_header_add (qh, "COSPAR", val, " ", NULL);
|
|
sprintf (val, "'%s'", ff.observer);
|
|
qfits_header_add (qh, "OBSERVER", val, " ", NULL);
|
|
|
|
// Add timestamps
|
|
for (k = 0; k < ff.nt; k++)
|
|
{
|
|
sprintf (key, "DT%04d", k);
|
|
sprintf (val, "%f", ff.dt[k]);
|
|
qfits_header_add (qh, key, val, " ", NULL);
|
|
}
|
|
|
|
// Dummy keywords
|
|
for (k = 0; k < 10; k++)
|
|
{
|
|
sprintf (key, "DUMY%03d", k);
|
|
qfits_header_add (qh, key, "0.0", " ", NULL);
|
|
}
|
|
|
|
// Dump fitsheader
|
|
// qfits_header_dump(qh,stdout);
|
|
|
|
// Dump to file
|
|
file = fopen (filename, "w");
|
|
qfits_header_dump (qh, file);
|
|
fclose (file);
|
|
|
|
|
|
// Fill buffer
|
|
fbuf = malloc (ff.nlayer * ff.nx * ff.ny * sizeof (float));
|
|
ibuf = malloc (ff.nlayer * ff.nx * ff.ny * sizeof (int));
|
|
for (i = 0, l = 0; i < ff.nx; i++)
|
|
{
|
|
for (j = ff.ny - 1; j >= 0; j--)
|
|
{
|
|
for (k = 0; k < ff.nlayer; k++)
|
|
{
|
|
fbuf[l] = ff.z[l];
|
|
ibuf[l] = (int) ff.z[l];
|
|
|
|
l++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set parameters
|
|
qd.filename = filename;
|
|
qd.npix = ff.nlayer * ff.nx * ff.ny;
|
|
if (ff.type == 1)
|
|
{
|
|
qd.ptype = PTYPE_INT;
|
|
qd.ibuf = ibuf;
|
|
qd.out_ptype = BPP_8_UNSIGNED;
|
|
}
|
|
else
|
|
{
|
|
qd.ptype = PTYPE_FLOAT;
|
|
qd.fbuf = fbuf;
|
|
qd.out_ptype = -32;
|
|
}
|
|
|
|
// Dump
|
|
qfits_pixdump (&qd);
|
|
|
|
free (fbuf);
|
|
free (ibuf);
|
|
|
|
return;
|
|
}
|
|
|
|
// Compute Julian Day from Date
|
|
double
|
|
date2mjd (int year, int month, double day)
|
|
{
|
|
int a, b;
|
|
double jd;
|
|
|
|
if (month < 3)
|
|
{
|
|
year--;
|
|
month += 12;
|
|
}
|
|
|
|
a = floor (year / 100.);
|
|
b = 2. - a + floor (a / 4.);
|
|
|
|
if (year < 1582)
|
|
b = 0;
|
|
if (year == 1582 && month < 10)
|
|
b = 0;
|
|
if (year == 1582 && month == 10 && day <= 4)
|
|
b = 0;
|
|
|
|
jd =
|
|
floor (365.25 * (year + 4716)) + floor (30.6001 * (month + 1)) + day + b -
|
|
1524.5;
|
|
|
|
return jd - 2400000.5;
|
|
}
|
|
|
|
// nfd2mjd
|
|
double
|
|
nfd2mjd (char *date)
|
|
{
|
|
int year, month, day, hour, min;
|
|
double mjd, dday;
|
|
float sec;
|
|
|
|
sscanf (date, "%04d-%02d-%02dT%02d:%02d:%f", &year, &month, &day, &hour,
|
|
&min, &sec);
|
|
dday = day + hour / 24.0 + min / 1440.0 + sec / 86400.0;
|
|
mjd = date2mjd (year, month, dday);
|
|
|
|
return mjd;
|
|
}
|
|
|
|
// Write pgm file
|
|
void
|
|
write_pgm (char *filename, struct fourframe ff)
|
|
{
|
|
int i, j, k;
|
|
FILE *file;
|
|
|
|
file = fopen (filename, "w");
|
|
fprintf (file, "P5\n# 2013-01-01T00:00:00\n%d %d\n255\n", ff.nx, ff.ny);
|
|
for (j = 0; j < ff.ny; j++)
|
|
{
|
|
for (i = 0; i < ff.nx; i++)
|
|
{
|
|
k = i + (ff.ny - j - 1) * ff.nx;
|
|
fprintf (file, "%c", (char) ff.z[k]);
|
|
}
|
|
}
|
|
fclose (file);
|
|
|
|
return;
|
|
}
|
|
|
|
// Compute Date from Julian Day
|
|
void
|
|
mjd2date (double mjd, char *date)
|
|
{
|
|
double f, jd, dday;
|
|
int z, alpha, a, b, c, d, e;
|
|
int year, month, day, hour, min;
|
|
double sec, x;
|
|
|
|
jd = mjd + 2400000.5;
|
|
jd += 0.5;
|
|
|
|
z = floor (jd);
|
|
f = fmod (jd, 1.);
|
|
|
|
if (z < 2299161)
|
|
a = z;
|
|
else
|
|
{
|
|
alpha = floor ((z - 1867216.25) / 36524.25);
|
|
a = z + 1 + alpha - floor (alpha / 4.);
|
|
}
|
|
b = a + 1524;
|
|
c = floor ((b - 122.1) / 365.25);
|
|
d = floor (365.25 * c);
|
|
e = floor ((b - d) / 30.6001);
|
|
|
|
dday = b - d - floor (30.6001 * e) + f;
|
|
if (e < 14)
|
|
month = e - 1;
|
|
else
|
|
month = e - 13;
|
|
|
|
if (month > 2)
|
|
year = c - 4716;
|
|
else
|
|
year = c - 4715;
|
|
|
|
day = (int) floor (dday);
|
|
x = 24.0 * (dday - day);
|
|
x = 3600. * fabs (x);
|
|
sec = fmod (x, 60.);
|
|
x = (x - sec) / 60.;
|
|
min = fmod (x, 60.);
|
|
x = (x - min) / 60.;
|
|
hour = x;
|
|
|
|
sprintf (date, "%04d-%02d-%02dT%02d:%02d:%06.3f", year, month, day, hour,
|
|
min, sec);
|
|
|
|
return;
|
|
}
|