Browse Source

Add palette support, remove falsecolor image type

I will tidy this up in the next few commits
tags/v1.8.0
Xerbo 4 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 # Program specifics
*.png *.png
!textlogo.png !textlogo.png
!palettes/*
*.wav *.wav
aptdec aptdec


# VSCode # VSCode
.vscode
.vscode

+ 1
- 1
Makefile View File

@@ -1,7 +1,7 @@
CC = gcc CC = gcc
BIN = /usr/bin BIN = /usr/bin
INCLUDES = -I. 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 OBJS = main.o image.o dsp.o filter.o reg.o pngio.o median.o color.o


aptdec: $(OBJS) 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 2. Calibrated channel A image
3. Calibrated channel B image 3. Calibrated channel B image
4. Temperature compensated IR image 4. Temperature compensated IR image
5. False color image
5. Palleted image
6. MCIR (Map Color InfraRed) 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. 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 ## Options


``` ```
-i [r|a|b|c|t|m]
-i [r|a|b|t|m|p]
Output image type 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" Default: "ab"


-d <dir> -d <dir>
@@ -88,18 +88,18 @@ Image names are `audiofile-x.png`, where `x` is:


- `r` for raw images - `r` for raw images
- Sensor ID (`1`, `2`, `3A`, `3B`, `4`, `5`) for channel A|B 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 - `t` for temperature calibrated images
- `m` for MCIR images - `m` for MCIR images


Currently there are 6 available effects: Currently there are 6 available effects:


- `t` for crop telemetry, off by default, only has effects on raw images - `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 - `d` for a median denoise filter
- `p` for a precipitation overlay - `p` for a precipitation overlay
- `f` to flip the image (for southbound passes) - `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 ## 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. 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 ## Realtime decoding


As of recently a realtime output was added allowing realtime decoding of images. 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 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 ## Further reading




+ 2
- 0
common.h View File

@@ -34,6 +34,7 @@ typedef struct {
int nrow; // Number of rows int nrow; // Number of rows
int chA, chB; // ID of each channel int chA, chB; // ID of each channel
char name[256]; // Stripped filename char name[256]; // Stripped filename
char *palette; // Filename of palette
} image_t; } image_t;
typedef struct { typedef struct {
char *type; // Output image type char *type; // Output image type
@@ -43,4 +44,5 @@ typedef struct {
char *path; // Output directory char *path; // Output directory
int realtime; // Realtime decoding int realtime; // Realtime decoding
char *filename; // Output filename char *filename; // Output filename
char *palette; // Filename of palette
} options_t; } 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 // The point in which the pixel offset is recalculated
if (corr < 0.75 * max) { if (corr < 0.75 * max) {
//synced = 0;
synced = 0;
FreqLine = 1.0; FreqLine = 1.0;
} }
max = corr; max = corr;


+ 25
- 23
main.c View File

@@ -80,7 +80,7 @@ int main(int argc, char **argv) {


// Parse arguments // Parse arguments
int opt; 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) { switch (opt) {
case 'd': case 'd':
opts.path = optarg; opts.path = optarg;
@@ -107,6 +107,9 @@ int main(int argc, char **argv) {
case 'o': case 'o':
opts.filename = optarg; opts.filename = optarg;
break; break;
case 'p':
opts.palette = optarg;
break;
default: default:
usage(); usage();
} }
@@ -235,21 +238,19 @@ static int processAudio(char *filename, options_t *opts){
histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); 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 // Raw image
if (CONTAINS(opts->type, 'r')) { 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]); 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); 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 // Channel A
if (CONTAINS(opts->type, 'a')) { if (CONTAINS(opts->type, 'a')) {
sprintf(desc, "%s (%s)", ch.id[img.chA], ch.name[img.chA]); 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" "Aptdec [options] audio files ...\n"
"Options:\n" "Options:\n"
" -e [t|h|d|p|f|l] Effects\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" " -d <dir> Image destination directory.\n"
" -o <name> Output filename\n" " -o <name> Output filename\n"
" -s [15-19] Satellite number\n" " -s [15-19] Satellite number\n"
" -m <file> Map file\n" " -m <file> Map file\n"
" -r Realtime decode\n" " -r Realtime decode\n"
" -p Path to palette\n"
"\nRefer to the README for more infomation\n"); "\nRefer to the README for more infomation\n");


exit(EINVAL); 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; 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 meta[] = {
{PNG_TEXT_COMPRESSION_NONE, "Software", VERSION}, {PNG_TEXT_COMPRESSION_NONE, "Software", VERSION},
{PNG_TEXT_COMPRESSION_NONE, "Channel", "Unknown", 7}, {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 fc = (chid[0] == 'c');
int greyscale = 0; int greyscale = 0;
int skiptele = 0; int skiptele = 0;
int imgpalette = (chid[0] == 'p');
if(opts->effects != NULL && CONTAINS(opts->effects, 't')){ if(opts->effects != NULL && CONTAINS(opts->effects, 't')){
width -= TOTAL_TELE; width -= TOTAL_TELE;
skiptele = 1; skiptele = 1;
@@ -235,7 +297,7 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c
return 0; 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 = 1;


// Greyscale image // 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); printf("Writing %s", outName);


rgb_t *pal_row[256];
if(imgpalette){
if(!readPalette(img->palette, pal_row)){
return 0;
}
}

// Build image // Build image
for (int y = 0; y < img->nrow; y++) { for (int y = 0; y < img->nrow; y++) {
png_color pix[width]; // Color 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 + CHA_OFFSET], 0, 255),
CLIP(img->prow[y][x + CHB_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{ }else{
pix[x] = (png_color){ pix[x] = (png_color){
crow[y][x + skip + offset].r, crow[y][x + skip + offset].r,
@@ -414,4 +491,4 @@ void closeWriter(){
png_write_end(rt_png_ptr, rt_info_ptr); png_write_end(rt_png_ptr, rt_info_ptr);
fclose(rt_pngfile); fclose(rt_pngfile);
png_destroy_write_struct(&rt_png_ptr, &rt_info_ptr); png_destroy_write_struct(&rt_png_ptr, &rt_info_ptr);
}
}

Loading…
Cancel
Save