I will tidy this up in the next few commitstags/v1.8.0
@@ -43,8 +43,9 @@ | |||
# Program specifics | |||
*.png | |||
!textlogo.png | |||
!palettes/* | |||
*.wav | |||
aptdec | |||
# VSCode | |||
.vscode | |||
.vscode |
@@ -1,7 +1,7 @@ | |||
CC = gcc | |||
BIN = /usr/bin | |||
INCLUDES = -I. | |||
CFLAGS = -O3 -DNDEBUG -Wall -Wextra $(INCLUDES) | |||
CFLAGS = -O3 -g -Wall -Wextra $(INCLUDES) | |||
OBJS = main.o image.o dsp.o filter.o reg.o pngio.o median.o color.o | |||
aptdec: $(OBJS) | |||
@@ -15,7 +15,7 @@ For each audio file up to 6 images can be generated: | |||
2. Calibrated channel A image | |||
3. Calibrated channel B image | |||
4. Temperature compensated IR image | |||
5. False color image | |||
5. Palleted image | |||
6. MCIR (Map Color InfraRed) image | |||
The input audio file must be mono with a sample rate in the range of 4160-62400 Hz, lower samples rates will process faster. | |||
@@ -51,9 +51,9 @@ To uninstall | |||
## Options | |||
``` | |||
-i [r|a|b|c|t|m] | |||
-i [r|a|b|t|m|p] | |||
Output image type | |||
Raw (r), Channel A (a), Channel B (b), False Color (c), Temperature (t) or MCIR (m) | |||
Raw (r), Channel A (a), Channel B (b), Palleted (p), Temperature (t) or MCIR (m) | |||
Default: "ab" | |||
-d <dir> | |||
@@ -88,18 +88,18 @@ Image names are `audiofile-x.png`, where `x` is: | |||
- `r` for raw images | |||
- Sensor ID (`1`, `2`, `3A`, `3B`, `4`, `5`) for channel A|B images | |||
- `c` for false color | |||
- `p` for a paletted image | |||
- `t` for temperature calibrated images | |||
- `m` for MCIR images | |||
Currently there are 6 available effects: | |||
- `t` for crop telemetry, off by default, only has effects on raw images | |||
- `h` for histogram equalise, stretch the colors in the image to black and white | |||
- `h` for histogram equalise | |||
- `d` for a median denoise filter | |||
- `p` for a precipitation overlay | |||
- `f` to flip the image (for southbound passes) | |||
- `l` to linearly equalise the image (recommended for falsecolor images) | |||
- `l` to linearly equalise the image, stretch the colors in the image to black and white | |||
## Examples | |||
@@ -111,6 +111,10 @@ This will process all `.wav` files in the current directory, generate calibrated | |||
Decode `audio.wav` with denoise and histogram equalization and save it into the current directory. | |||
`aptdec -e d -p palettes/N19-June-High-Vegetation.png -i p audio.wav` | |||
Create a false color image from the `N19-June-High-Vegetation.pn` palette. | |||
## Realtime decoding | |||
As of recently a realtime output was added allowing realtime decoding of images. | |||
@@ -121,7 +125,7 @@ aptdec /tmp/aptaudio | |||
sox -t pulseaudio alsa_output.pci-0000_00_1b.0.analog-stereo.monitor -c 1 -t wav /tmp/aptaudio | |||
``` | |||
Perform a realtime decode with the audio being played out of `alsa_output.pci-0000_00_1b.0.analog`. | |||
Perform a realtime decode with the audio being played out of `alsa_output.pci-0000_00_1b.0.analog`. To stop the decode kill the `sox` process | |||
## Further reading | |||
@@ -34,6 +34,7 @@ typedef struct { | |||
int nrow; // Number of rows | |||
int chA, chB; // ID of each channel | |||
char name[256]; // Stripped filename | |||
char *palette; // Filename of palette | |||
} image_t; | |||
typedef struct { | |||
char *type; // Output image type | |||
@@ -43,4 +44,5 @@ typedef struct { | |||
char *path; // Output directory | |||
int realtime; // Realtime decoding | |||
char *filename; // Output filename | |||
char *palette; // Filename of palette | |||
} options_t; |
@@ -248,7 +248,7 @@ int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { | |||
// The point in which the pixel offset is recalculated | |||
if (corr < 0.75 * max) { | |||
//synced = 0; | |||
synced = 0; | |||
FreqLine = 1.0; | |||
} | |||
max = corr; | |||
@@ -80,7 +80,7 @@ int main(int argc, char **argv) { | |||
// Parse arguments | |||
int opt; | |||
while ((opt = getopt(argc, argv, "o:m:d:i:s:e:r")) != EOF) { | |||
while ((opt = getopt(argc, argv, "o:m:d:i:s:e:rp:")) != EOF) { | |||
switch (opt) { | |||
case 'd': | |||
opts.path = optarg; | |||
@@ -107,6 +107,9 @@ int main(int argc, char **argv) { | |||
case 'o': | |||
opts.filename = optarg; | |||
break; | |||
case 'p': | |||
opts.palette = optarg; | |||
break; | |||
default: | |||
usage(); | |||
} | |||
@@ -235,21 +238,19 @@ static int processAudio(char *filename, options_t *opts){ | |||
histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); | |||
} | |||
// False color | |||
if(CONTAINS(opts->type, 'c')){ | |||
if(img.chA == 2 && img.chB >= 4){ | |||
ImageOut(opts, &img, 0, CH_WIDTH, "False Color", "c", NULL); | |||
}else{ | |||
fprintf(stderr, "Lacking channels required for false color computation\n"); | |||
} | |||
} | |||
// Raw image | |||
if (CONTAINS(opts->type, 'r')) { | |||
sprintf(desc, "%s (%s) & %s (%s)", ch.id[img.chA], ch.name[img.chA], ch.id[img.chB], ch.name[img.chB]); | |||
ImageOut(opts, &img, 0, IMG_WIDTH, desc, "r", NULL); | |||
} | |||
// Palette image | |||
if (CONTAINS(opts->type, 'p')) { | |||
img.palette = opts->palette; | |||
strcpy(desc, "Palette composite"); | |||
ImageOut(opts, &img, 0, 909, desc, "p", NULL); | |||
} | |||
// Channel A | |||
if (CONTAINS(opts->type, 'a')) { | |||
sprintf(desc, "%s (%s)", ch.id[img.chA], ch.name[img.chA]); | |||
@@ -317,24 +318,25 @@ static void usage(void) { | |||
"Aptdec [options] audio files ...\n" | |||
"Options:\n" | |||
" -e [t|h|d|p|f|l] Effects\n" | |||
" t: Crop telemetry\n" | |||
" h: Histogram equalise\n" | |||
" d: Denoise\n" | |||
" p: Precipitation\n" | |||
" f: Flip image\n" | |||
" l: Linear equalise\n" | |||
" -i [r|a|b|c|t|m] Output image\n" | |||
" r: Raw\n" | |||
" a: Channel A\n" | |||
" b: Channel B\n" | |||
" c: False color\n" | |||
" t: Temperature\n" | |||
" m: MCIR\n" | |||
" t: Crop telemetry\n" | |||
" h: Histogram equalise\n" | |||
" d: Denoise\n" | |||
" p: Precipitation\n" | |||
" f: Flip image\n" | |||
" l: Linear equalise\n" | |||
" -i [r|a|b|c|t|m|p] Output image\n" | |||
" r: Raw\n" | |||
" a: Channel A\n" | |||
" b: Channel B\n" | |||
" t: Temperature\n" | |||
" m: MCIR\n" | |||
" p: Paletted image\n" | |||
" -d <dir> Image destination directory.\n" | |||
" -o <name> Output filename\n" | |||
" -s [15-19] Satellite number\n" | |||
" -m <file> Map file\n" | |||
" -r Realtime decode\n" | |||
" -p Path to palette\n" | |||
"\nRefer to the README for more infomation\n"); | |||
exit(EINVAL); | |||
@@ -193,6 +193,67 @@ int readRawImage(char *filename, float **prow, int *nrow) { | |||
return 1; | |||
} | |||
int readPalette(char *filename, rgb_t **crow) { | |||
FILE *fp = fopen(filename, "r"); | |||
if(!fp) { | |||
fprintf(stderr, "Cannot open %s\n", filename); | |||
return 0; | |||
} | |||
// Create reader | |||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |||
if(!png) return 0; | |||
png_infop info = png_create_info_struct(png); | |||
if(!info) return 0; | |||
png_init_io(png, fp); | |||
// Read info from header | |||
png_read_info(png, info); | |||
int width = png_get_image_width(png, info); | |||
int height = png_get_image_height(png, info); | |||
png_byte color_type = png_get_color_type(png, info); | |||
png_byte bit_depth = png_get_bit_depth(png, info); | |||
// Check the image | |||
if(width != 256 && height != 256){ | |||
fprintf(stderr, "Palette must be 256x256.\n"); | |||
return 0; | |||
}else if(bit_depth != 8){ | |||
fprintf(stderr, "Palette must be 8 bit color.\n"); | |||
return 0; | |||
}else if(color_type != PNG_COLOR_TYPE_RGBA){ | |||
fprintf(stderr, "Palette must be RGB.\n"); | |||
return 0; | |||
} | |||
// Create row buffers | |||
png_bytep *PNGrows = NULL; | |||
PNGrows = (png_bytep *) malloc(sizeof(png_bytep) * height); | |||
for(int y = 0; y < height; y++) | |||
PNGrows[y] = (png_byte *) malloc(png_get_rowbytes(png, info)); | |||
// Read image | |||
png_read_image(png, PNGrows); | |||
// Tidy up | |||
fclose(fp); | |||
png_destroy_read_struct(&png, &info, NULL); | |||
// Put into crow | |||
for(int y = 0; y < height; y++) { | |||
crow[y] = (rgb_t *) malloc(sizeof(rgb_t) * width); | |||
for(int x = 0; x < width; x++) | |||
crow[y][x] = (rgb_t){ | |||
PNGrows[y][x*4], | |||
PNGrows[y][x*4 + 1], | |||
PNGrows[y][x*4 + 2] | |||
}; | |||
} | |||
return 1; | |||
} | |||
png_text meta[] = { | |||
{PNG_TEXT_COMPRESSION_NONE, "Software", VERSION}, | |||
{PNG_TEXT_COMPRESSION_NONE, "Channel", "Unknown", 7}, | |||
@@ -216,6 +277,7 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||
int fc = (chid[0] == 'c'); | |||
int greyscale = 0; | |||
int skiptele = 0; | |||
int imgpalette = (chid[0] == 'p'); | |||
if(opts->effects != NULL && CONTAINS(opts->effects, 't')){ | |||
width -= TOTAL_TELE; | |||
skiptele = 1; | |||
@@ -235,7 +297,7 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||
return 0; | |||
} | |||
if(palette == NULL && !CONTAINS(opts->effects, 'p') && !fc && opts->map[0] == '\0' && chid[0] != 'm'){ | |||
if(palette == NULL && !CONTAINS(opts->effects, 'p') && !fc && opts->map[0] == '\0' && chid[0] != 'm' && !imgpalette){ | |||
greyscale = 1; | |||
// Greyscale image | |||
@@ -300,6 +362,13 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||
printf("Writing %s", outName); | |||
rgb_t *pal_row[256]; | |||
if(imgpalette){ | |||
if(!readPalette(img->palette, pal_row)){ | |||
return 0; | |||
} | |||
} | |||
// Build image | |||
for (int y = 0; y < img->nrow; y++) { | |||
png_color pix[width]; // Color | |||
@@ -326,6 +395,14 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c | |||
CLIP(img->prow[y][x + CHA_OFFSET], 0, 255), | |||
CLIP(img->prow[y][x + CHB_OFFSET], 0, 255) | |||
}; | |||
}else if(imgpalette){ | |||
int cha = img->prow[y][x + CHA_OFFSET]; | |||
int cbb = img->prow[y][x + CHB_OFFSET]; | |||
pix[x] = (png_color){ | |||
pal_row[cbb][cha].r, | |||
pal_row[cbb][cha].g, | |||
pal_row[cbb][cha].b | |||
}; | |||
}else{ | |||
pix[x] = (png_color){ | |||
crow[y][x + skip + offset].r, | |||
@@ -414,4 +491,4 @@ void closeWriter(){ | |||
png_write_end(rt_png_ptr, rt_info_ptr); | |||
fclose(rt_pngfile); | |||
png_destroy_write_struct(&rt_png_ptr, &rt_info_ptr); | |||
} | |||
} |