Browse Source

Add palette support, remove falsecolor image type

I will tidy this up in the next few commits
tags/v1.8.0
Xerbo 3 years ago
parent
commit
f397b84513
8 changed files with 121 additions and 35 deletions
  1. +2
    -1
      .gitignore
  2. +1
    -1
      Makefile
  3. +11
    -7
      README.md
  4. +2
    -0
      common.h
  5. +1
    -1
      dsp.c
  6. +25
    -23
      main.c
  7. BIN
      palettes/N19-June-High-Vegetation.png
  8. +79
    -2
      pngio.c

+ 2
- 1
.gitignore View File

@@ -43,8 +43,9 @@
# Program specifics
*.png
!textlogo.png
!palettes/*
*.wav
aptdec

# VSCode
.vscode
.vscode

+ 1
- 1
Makefile View File

@@ -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)


+ 11
- 7
README.md View File

@@ -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



+ 2
- 0
common.h View File

@@ -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;

+ 1
- 1
dsp.c View File

@@ -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;


+ 25
- 23
main.c View File

@@ -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);


BIN
palettes/N19-June-High-Vegetation.png View File

Before After
Width: 256  |  Height: 256  |  Size: 78 KiB

+ 79
- 2
pngio.c View File

@@ -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);
}
}

Loading…
Cancel
Save