Browse Source

Map overlay, touchups

Add the ability to open a map overlay generated by wxmap (still unstable)
Remove the ability to turn off calibration
Add MCIR images
From now on large changes to neaten up the codebase will be taking place
tags/v1.8.0
Xerbo 4 years ago
parent
commit
1443b9ba68
6 changed files with 240 additions and 165 deletions
  1. +10
    -9
      README.md
  2. +10
    -3
      dsp.c
  3. +2
    -2
      filter.c
  4. +4
    -4
      image.c
  5. +211
    -144
      main.c
  6. +3
    -3
      palette.h

+ 10
- 9
README.md View File

@@ -16,7 +16,7 @@ For each audio file up to 6 images can be generated:
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. False color image
6. Layered image, boosts cloud visibility
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.
Aptdec uses `libsndfile` to read the input audio, so any format supported by `libsndfile` may be used (however it has only tested with `.wav` files). Aptdec uses `libsndfile` to read the input audio, so any format supported by `libsndfile` may be used (however it has only tested with `.wav` files).
@@ -53,7 +53,7 @@ To uninstall
``` ```
-i [r|a|b|c|t|l] -i [r|a|b|c|t|l]
Output image type Output image type
Raw (r), Channel A (a), Channel B (b), False Color (c), Temperature (t), Layered (l)
Raw (r), Channel A (a), Channel B (b), False Color (c), Temperature (t)
Default: "ab" Default: "ab"


-d <dir> -d <dir>
@@ -65,10 +65,13 @@ Satellite number
For temperature calibration For temperature calibration
Default: "19" Default: "19"


-e [c|t|h]
-e [t|h]
Enhancements Enhancements
Contrast calibration (c), Histogram equalise (h), Crop Telemetry (t)
Defaults: "ct"
Histogram equalise (h), Crop Telemetry (t)
Defaults: off

-m <file>
Map overlay generated by wxmap


-c <file> -c <file>
Use configuration file for false color generation. Use configuration file for false color generation.
@@ -85,13 +88,11 @@ Image names are `audiofile-x.png`, where `x` is:
- 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. - `c` for false color.
- `t` for temperature calibrated images - `t` for temperature calibrated images
- `l` for layered images


Currently there are 3 available enhancements: Currently there are 3 available enhancements:


- `c` for calibration, on by default
- `t` for crop telemetry, on by default, only has effects on raw images
- `h` for histogram equalise, make the darkest color black and the brightest white
- `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


## Example ## Example




+ 10
- 3
dsp.c View File

@@ -59,7 +59,7 @@ int init_dsp(double F) {


K1 = DFc / Fe; K1 = DFc / Fe;
K2 = K1 * K1 / 2.0; K2 = K1 * K1 / 2.0;
// Number of samples for each cycle
// Number of samples per cycle
FreqOsc = Fc / Fe; FreqOsc = Fc / Fe;


return(0); return(0);
@@ -209,7 +209,8 @@ int getpixelv(float *pvbuff, int count) {
} }


// Get an entire row of pixels, aligned with sync markers // Get an entire row of pixels, aligned with sync markers
int getpixelrow(float *pixelv) {
double minDoppler = 100;
int getpixelrow(float *pixelv, int nrow, int *zenith) {
static float pixels[PixelLine + SyncFilterLen]; static float pixels[PixelLine + SyncFilterLen];
static int npv; static int npv;
static int synced = 0; static int synced = 0;
@@ -230,11 +231,17 @@ int getpixelrow(float *pixelv) {
if (npv < SyncFilterLen + 2) return(0); if (npv < SyncFilterLen + 2) return(0);
} }


// Calculate the sub-pixel offset
// Calculate the frequency offset
ecorr = fir(pixelv, Sync, SyncFilterLen); ecorr = fir(pixelv, Sync, SyncFilterLen);
corr = fir(&(pixelv[1]), Sync, SyncFilterLen - 1); corr = fir(&(pixelv[1]), Sync, SyncFilterLen - 1);
lcorr = fir(&(pixelv[2]), Sync, SyncFilterLen - 2); lcorr = fir(&(pixelv[2]), Sync, SyncFilterLen - 2);
FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0); FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0);

// Find the point in which ecorr and lcorr intercept, make sure that it's not too perfect
if(fabs(lcorr - ecorr) < minDoppler && fabs(lcorr - ecorr) > 1){
minDoppler = fabs(lcorr - ecorr);
*zenith = nrow;
}
// 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) {


+ 2
- 2
filter.c View File

@@ -36,13 +36,13 @@ float fir(float *buff, const float *coeff, const int len) {
* Turn samples into a single IQ sample * Turn samples into a single IQ sample
*/ */
void iqfir(float *buff, const float *coeff, const int len, double *I, double *Q) { void iqfir(float *buff, const float *coeff, const int len, double *I, double *Q) {
double i, q;
double i = 0.0, q = 0.0;


i = q = 0.0;
for (int k = 0; k < len; k++) { for (int k = 0; k < len; k++) {
q += buff[2*k] * coeff[k]; q += buff[2*k] * coeff[k];
i += buff[2*k]; i += buff[2*k];
} }

i = buff[len-1] - (i / len); i = buff[len-1] - (i / len);
*I = i, *Q = q; *I = i, *Q = q;
} }


+ 4
- 4
image.c View File

@@ -126,7 +126,7 @@ void calibrateBrightness(float **prow, int nrow, int offset, int width, int tele
} }


// Get telemetry data for thermal calibration/equalization // Get telemetry data for thermal calibration/equalization
int calibrate(float **prow, int nrow, int offset, int width, int calibrate) {
int calibrate(float **prow, int nrow, int offset, int width) {
double teleline[3000] = { 0.0 }; double teleline[3000] = { 0.0 };
double wedge[16]; double wedge[16];
rgparam regr[30]; rgparam regr[30];
@@ -236,7 +236,7 @@ int calibrate(float **prow, int nrow, int offset, int width, int calibrate) {
} }
nbtele = k; nbtele = k;


if(calibrate) calibrateBrightness(prow, nrow, offset, width, telestart, regr);
calibrateBrightness(prow, nrow, offset, width, telestart, regr);


return(channel + 1); return(channel + 1);
} }
@@ -308,13 +308,13 @@ static double tempcal(float Ce, tempparam * rgpr) {
} }


// Temperature calibration wrapper // Temperature calibration wrapper
void temperature(float **prow, int nrow, int channel, int offset) {
void temperature(float **prow, int nrow, int ch, int offset){
tempparam temp; tempparam temp;


printf("Temperature... "); printf("Temperature... ");
fflush(stdout); fflush(stdout);


tempcomp(tele, channel, &temp);
tempcomp(tele, ch, &temp);


for (int n = 0; n < nrow; n++) { for (int n = 0; n < nrow; n++) {
float *pixelv = prow[n]; float *pixelv = prow[n];


+ 211
- 144
main.c View File

@@ -30,7 +30,7 @@
#include "offsets.h" #include "offsets.h"
#include "palette.h" #include "palette.h"


extern int getpixelrow(float *pixelv);
extern int getpixelrow(float *pixelv, int nrow, int *zenith);
extern int init_dsp(double F); extern int init_dsp(double F);


static SNDFILE *inwav; static SNDFILE *inwav;
@@ -77,119 +77,185 @@ static png_text text_ptr[] = {
{PNG_TEXT_COMPRESSION_NONE, "Description", "NOAA satellite image", 20} {PNG_TEXT_COMPRESSION_NONE, "Description", "NOAA satellite image", 20}
}; };


// TODO: this function needs to be tidied up
/* Effects
* 0 - Nothing
* 1 - Crop telemetry
* 2 - False color
* 3 - Layered
*/
static int ImageOut(char *filename, char *chid, float **prow, int nrow, int width, int offset, png_color *palette, int effects) {
int mapOverlay(char *filename, float **crow, int nrow, int zenith, int MCIR) {
FILE *fp = fopen(filename, "rb");

// 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 != 1040){
fprintf(stderr, "Map must be 1040px wide.\n");
return 0;
}else if(bit_depth != 16){
fprintf(stderr, "Map must be 16 bit color.\n");
return 0;
}else if(color_type != PNG_COLOR_TYPE_RGB){
fprintf(stderr, "Map must be RGB.\n");
return 0;
}else if(zenith > height/2 || nrow-zenith > height/2){
fprintf(stderr, "WARNING: Map is too short to cover entire image\n");
}

// Create row buffers
png_bytep *mapRows = NULL;
mapRows = (png_bytep *) malloc(sizeof(png_bytep) * height);
for(int y = 0; y < height; y++) mapRows[y] = (png_byte *) malloc(png_get_rowbytes(png, info));

// Read image
png_read_image(png, mapRows);

// Tidy up
fclose(fp);
png_destroy_read_struct(&png, &info, NULL);

int mapOffset = (height/2)-zenith;
for(int y = 0; y < nrow; y++) {
for(int x = 49; x < width - 82; x++){
// Maps are 16 bit / channel
png_bytep px = &mapRows[CLIP(y + mapOffset, 0, height)][x * 6];
uint16_t r = (uint16_t)(px[0] << 8) | px[1];
uint16_t g = (uint16_t)(px[2] << 8) | px[3];
uint16_t b = (uint16_t)(px[4] << 8) | px[5];

// Pointers to the current pixel in each channel
float *cha = &crow[y][(x+36) * 3];
float *chb = &crow[y][(x+CHB_OFFSET-49) * 3];

// Fill in map
if(MCIR){
// Sea
cha[0] = 42; cha[1] = 53; cha[2] = 105;

// Land
if(g > 128){
float vegetation = (r-160) / 96.0;
cha[0] = 120; cha[1] = vegetation*60.0 + 100; cha[2] = 95;
}
}

// Color -> alpha: composite
int composite = r + g + b;
// Color -> alpha: flattern color depth
float factor = (255 * 255 * 2.0) / composite;
r *= factor; g *= factor; b *= factor;
// Color -> alpha: convert black to alpha
float alpha = CLIP(abs(0 - composite) / 65535.0, 0, 1);

// Map overlay on channel A
cha[0] = MCOMPOSITE(r/257, alpha, cha[0], 1);
cha[1] = MCOMPOSITE(g/257, alpha, cha[1], 1);
cha[2] = MCOMPOSITE(b/257, alpha, cha[2], 1);

// Map overlay on channel B
if(!MCIR){
chb[0] = MCOMPOSITE(r/257, alpha, chb[0], 1);
chb[1] = MCOMPOSITE(g/257, alpha, chb[1], 1);
chb[2] = MCOMPOSITE(b/257, alpha, chb[2], 1);
}

// Cloud overlay on channel A
if(MCIR){
float cloud = (chb[0] - 110) / 120;
cha[0] = MCOMPOSITE(240, cloud, cha[0], 1);
cha[1] = MCOMPOSITE(250, cloud, cha[1], 1);
cha[2] = MCOMPOSITE(255, cloud, cha[2], 1);
}
}
}

return 1;
}

// Row where to satellite reaches peak elevation
int zenith = 0;

static int ImageOut(char *filename, char *chid, float **prow, int nrow, int width, int offset, char *palette, char *effects, char *mapFile) {
FILE *pngfile; FILE *pngfile;
png_infop info_ptr;
png_structp png_ptr;


// Reduce the width of the image to componsate for the missing telemetry // Reduce the width of the image to componsate for the missing telemetry
if(effects == 1) width -= TOTAL_TELE;
if(CONTAINS(effects, 't')) width -= TOTAL_TELE;


// Initalise the PNG writer
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
// Create writer
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) { if (!png_ptr) {
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
fprintf(stderr, ERR_PNG_WRITE); fprintf(stderr, ERR_PNG_WRITE);
return(0); return(0);
} }

// Metadata
info_ptr = png_create_info_struct(png_ptr);
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) { if (!info_ptr) {
png_destroy_write_struct(&png_ptr, (png_infopp) NULL); png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
fprintf(stderr, ERR_PNG_INFO); fprintf(stderr, ERR_PNG_INFO);
return(0); return(0);
} }


extern void falsecolor(float vis, float temp, float *r, float *g, float *b);

if(effects == 2){
// 8 bit RGB image
png_set_IHDR(png_ptr, info_ptr, width, nrow,
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
}else if(palette == NULL) {
// Greyscale image
png_set_IHDR(png_ptr, info_ptr, width, nrow,
8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
} else {
// Palleted color image
png_set_IHDR(png_ptr, info_ptr, width, nrow,
8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_PLTE(png_ptr, info_ptr, palette, 256);
}
// 8 bit RGB image
png_set_IHDR(png_ptr, info_ptr, width, nrow,
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);


text_ptr[1].text = chid; text_ptr[1].text = chid;
text_ptr[1].text_length = strlen(chid); text_ptr[1].text_length = strlen(chid);
png_set_text(png_ptr, info_ptr, text_ptr, 3); png_set_text(png_ptr, info_ptr, text_ptr, 3);
png_set_pHYs(png_ptr, info_ptr, 4000, 4000, PNG_RESOLUTION_METER);

if(effects == 2){
printf("Computing false color & writing: %s", filename);
}else{
printf("Writing %s", filename);
}
fflush(stdout);
png_set_pHYs(png_ptr, info_ptr, 4160, 4160, PNG_RESOLUTION_METER);


// Init I/O
pngfile = fopen(filename, "wb"); pngfile = fopen(filename, "wb");
if (pngfile == NULL) {
if (!pngfile) {
fprintf(stderr, ERR_FILE_WRITE, filename); fprintf(stderr, ERR_FILE_WRITE, filename);
return(1); return(1);
} }
png_init_io(png_ptr, pngfile); png_init_io(png_ptr, pngfile);
png_write_info(png_ptr, info_ptr); png_write_info(png_ptr, info_ptr);


for (int n = 0; n < nrow; n++) {
png_color pix[width];
png_byte pixel[width];
// Move prow into crow, crow ~ color rows
float *crow[3000];
for(int i = 0; i < nrow; i++){
crow[i] = (float *) malloc(sizeof(float) * 2080 * 3);


float *pixelv = prow[n];
int f = 0;
for (int i = 0; i < width; i++) {
// Skip parts of the image that are telemetry
if(effects == 1){
switch (i) {
case 0:
f += SYNC_WIDTH + SPC_WIDTH;
break;
case CH_WIDTH:
f += TELE_WIDTH + SYNC_WIDTH + SPC_WIDTH;
break;
case CH_WIDTH*2:
f += TELE_WIDTH;
}
}
for(int x = 0; x < 2080; x++)
crow[i][x*3 + 0] = crow[i][x*3 + 1] = crow[i][x*3 + 2] = prow[i][x];
}


if(effects == 2){
float r = 0, g = 0, b = 0;
falsecolor(pixelv[i+CHA_OFFSET], pixelv[i+CHB_OFFSET], &r, &g, &b);
pix[i].red = r;
pix[i].green = g;
pix[i].blue = b;
}else if(effects == 3){
// Layered image, overlay clouds in channel B over channel A
float cloud = CLIP(pixelv[i+CHB_OFFSET]-141, 0, 255)/114;
pixel[i] = MCOMPOSITE(240, cloud, pixelv[i+CHA_OFFSET], 1);
}else{
pixel[i] = CLIP(pixelv[i + offset + f], 0, 255);
}
if(mapFile != NULL && mapFile[0] != '\0'){
if(mapOverlay(mapFile, crow, nrow, zenith, strcmp(chid, "MCIR") == 0) == 0){
fprintf(stderr, "Skipping MCIR generation; see above.\n");
return 0;
} }
}else if(strcmp(chid, "MCIR")){
fprintf(stderr, "Skipping MCIR generation; no map provided.\n");
return 0;
}


if(effects == 2){
png_write_row(png_ptr, (png_bytep) pix);
}else{
png_write_row(png_ptr, pixel);
printf("Writing %s", filename);

// Build RGB image
for (int n = 0; n < nrow; n++) {
png_color pix[width];

for (int i = 0; i < width; i++) {
float *px = &crow[n][offset*3 + i*3];
pix[i].red = CLIP(px[0], 0, 255);
pix[i].green = CLIP(px[1], 0, 255);
pix[i].blue = CLIP(px[2], 0, 255);
} }
png_write_row(png_ptr, (png_bytep) pix);
} }


// Tidy up
png_write_end(png_ptr, info_ptr); png_write_end(png_ptr, info_ptr);
fclose(pngfile); fclose(pngfile);
printf("\nDone\n"); printf("\nDone\n");
@@ -223,10 +289,10 @@ static void distrib(char *filename, float **prow, int nrow) {
for(int y = 0; y < 256; y++) for(int y = 0; y < 256; y++)
distrib[y][x] = distrib[y][x] / max * 255; distrib[y][x] = distrib[y][x] / max * 255;


ImageOut(filename, "Brightness distribution", distrib, 256, 256, 0, NULL, 0);
ImageOut(filename, "Brightness distribution", distrib, 256, 256, 0, NULL, 0, NULL);
} }


extern int calibrate(float **prow, int nrow, int offset, int width, int calibrate);
extern int calibrate(float **prow, int nrow, int offset, int width);
extern void histogramEqualise(float **prow, int nrow, int offset, int width); extern void histogramEqualise(float **prow, int nrow, int offset, int width);
extern void temperature(float **prow, int nrow, int ch, int offset); extern void temperature(float **prow, int nrow, int ch, int offset);
extern int Ngvi(float **prow, int nrow); extern int Ngvi(float **prow, int nrow);
@@ -240,8 +306,7 @@ int satnum = 4;
static void usage(void) { static void usage(void) {
printf("Aptdec [options] audio files ...\n" printf("Aptdec [options] audio files ...\n"
"Options:\n" "Options:\n"
" -e [c|t] Enhancements\n"
" c: Contrast calibration\n"
" -e [t|h] Enhancements\n"
" t: Crop telemetry\n" " t: Crop telemetry\n"
" h: Histogram equalise\n" " h: Histogram equalise\n"
" -i [r|a|b|c|t] Output image type\n" " -i [r|a|b|c|t] Output image type\n"
@@ -250,26 +315,22 @@ static void usage(void) {
" b: Channel B\n" " b: Channel B\n"
" c: False color\n" " c: False color\n"
" t: Temperature\n" " t: Temperature\n"
" l: Layered\n"
" m: MCIR\n"
" -d <dir> Image destination directory.\n" " -d <dir> Image destination directory.\n"
" -s [15-19] Satellite number\n" " -s [15-19] Satellite number\n"
" -c <file> False color config file\n");
" -c <file> False color config file\n"
" -m <file> Map file\n");
exit(1); exit(1);
} }


int readRawImage(char *filename, float **prow, int *nrow) { int readRawImage(char *filename, float **prow, int *nrow) {
png_bytep *PNGrows = NULL;
FILE *fp = fopen(filename, "r"); FILE *fp = fopen(filename, "r");


// Create read struct
// Create reader
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png) return 0; if(!png) return 0;

// Create info struct
png_infop info = png_create_info_struct(png); png_infop info = png_create_info_struct(png);
if(!info) return 0; if(!info) return 0;

// Init I/O
png_init_io(png, fp); png_init_io(png, fp);


// Read info from header // Read info from header
@@ -281,25 +342,25 @@ int readRawImage(char *filename, float **prow, int *nrow) {


// Check the image // Check the image
if(width != 2080){ if(width != 2080){
fprintf(stderr, "Expected a 2080px wide PNG, got a %ipx wide PNG", width);
fprintf(stderr, "Raw image must be 2080px wide.\n");
return 0; return 0;
}
if(bit_depth != 8){
fprintf(stderr, "Expected an 8 bit PNG, got an %i bit PNG", bit_depth);
}else if(bit_depth != 8){
fprintf(stderr, "Raw image must have 8 bit color.\n");
return 0; return 0;
}
if(color_type != PNG_COLOR_TYPE_GRAY){
fprintf(stderr, "Expected a grayscale PNG");
}else if(color_type != PNG_COLOR_TYPE_GRAY){
fprintf(stderr, "Raw image must be grayscale.\n");
return 0; return 0;
} }


// Create row buffers // Create row buffers
png_bytep *PNGrows = NULL;
PNGrows = (png_bytep *) malloc(sizeof(png_bytep) * height); 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)); for(int y = 0; y < height; y++) PNGrows[y] = (png_byte *) malloc(png_get_rowbytes(png, info));


// Read image
png_read_image(png, PNGrows); png_read_image(png, PNGrows);


// Tidy up
// Tidy up
fclose(fp); fclose(fp);
png_destroy_read_struct(&png, &info, NULL); png_destroy_read_struct(&png, &info, NULL);


@@ -307,6 +368,7 @@ int readRawImage(char *filename, float **prow, int *nrow) {
*nrow = height; *nrow = height;
for(int y = 0; y < height; y++) { for(int y = 0; y < height; y++) {
prow[y] = (float *) malloc(sizeof(float) * width); prow[y] = (float *) malloc(sizeof(float) * width);

for(int x = 0; x < width; x++) for(int x = 0; x < width; x++)
prow[y][x] = (float)PNGrows[y][x]; prow[y][x] = (float)PNGrows[y][x];
} }
@@ -318,11 +380,12 @@ int main(int argc, char **argv) {
char pngfilename[1024]; char pngfilename[1024];
char name[128]; char name[128];
char pngdirname[128] = ""; char pngdirname[128] = "";
char mapFile[256];
char *extension; char *extension;


// Default to a raw image, with equalization and cropped telemetry
// Default to a raw image, with no enhancements
char imgopt[20] = "r"; char imgopt[20] = "r";
char enchancements[20] = "ct";
char enhancements[20] = "";


// Image buffer // Image buffer
float *prow[3000]; float *prow[3000];
@@ -348,7 +411,7 @@ int main(int argc, char **argv) {
usage(); usage();


int c; int c;
while ((c = getopt(argc, argv, "c:d:i:s:e:")) != EOF) {
while ((c = getopt(argc, argv, "c:m:d:i:s:e:")) != EOF) {
switch (c) { switch (c) {
// Output directory name // Output directory name
case 'd': case 'd':
@@ -358,6 +421,10 @@ int main(int argc, char **argv) {
case 'c': case 'c':
readfcconf(optarg); readfcconf(optarg);
break; break;
// Map file
case 'm':
strcpy(mapFile, optarg);
break;
// Output image type // Output image type
case 'i': case 'i':
strncpy(imgopt, optarg, 20); strncpy(imgopt, optarg, 20);
@@ -373,7 +440,7 @@ int main(int argc, char **argv) {
break; break;
// Enchancements // Enchancements
case 'e': case 'e':
strncpy(enchancements, optarg, 20);
strncpy(enhancements, optarg, 20);
break; break;
default: default:
usage(); usage();
@@ -399,7 +466,10 @@ int main(int argc, char **argv) {


if(strcmp(extension, "png") == 0){ if(strcmp(extension, "png") == 0){
printf("Reading %s", argv[optind]); printf("Reading %s", argv[optind]);
readRawImage(argv[optind], prow, &nrow);
if(readRawImage(argv[optind], prow, &nrow) == 0){
fprintf(stderr, "Skipping %s; see above.\n", name);
continue;
}
}else{ }else{
// Open sound file, exit if that fails // Open sound file, exit if that fails
if (initsnd(argv[optind]) == 0) exit(1); if (initsnd(argv[optind]) == 0) exit(1);
@@ -410,7 +480,7 @@ int main(int argc, char **argv) {
prow[nrow] = (float *) malloc(sizeof(float) * 2150); prow[nrow] = (float *) malloc(sizeof(float) * 2150);
// Read into prow and break the loop once we reach the end of the image // Read into prow and break the loop once we reach the end of the image
if (getpixelrow(prow[nrow]) == 0) break;
if (getpixelrow(prow[nrow], nrow, &zenith) == 0) break;


printf("Row: %d\r", nrow); printf("Row: %d\r", nrow);
fflush(stdout); fflush(stdout);
@@ -420,49 +490,61 @@ int main(int argc, char **argv) {
sf_close(inwav); sf_close(inwav);
} }


if(zenith == 0 & mapFile[0] != '\0'){
fprintf(stderr, "WARNING: Guessing peak elevation in image, map will most likely not be aligned.\n");
zenith = nrow / 2;
}

printf("\nTotal rows: %d\n", nrow); printf("\nTotal rows: %d\n", nrow);


chA = calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH, 0);
chB = calibrate(prow, nrow, CHB_OFFSET, CH_WIDTH, 0);
// Calibrate
chA = calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH);
chB = calibrate(prow, nrow, CHB_OFFSET, CH_WIDTH);
printf("Channel A: %s (%s)\n", ch.id[chA], ch.name[chA]); printf("Channel A: %s (%s)\n", ch.id[chA], ch.name[chA]);
printf("Channel B: %s (%s)\n", ch.id[chB], ch.name[chB]); printf("Channel B: %s (%s)\n", ch.id[chB], ch.name[chB]);


// Temperature // Temperature
if (CONTAINS(imgopt, 't') && chB >= 4) { if (CONTAINS(imgopt, 't') && chB >= 4) {
// TODO: Doesn't work with channel 4
temperature(prow, nrow, chB, CHB_OFFSET); temperature(prow, nrow, chB, CHB_OFFSET);
sprintf(pngfilename, "%s/%s-t.png", pngdirname, name); sprintf(pngfilename, "%s/%s-t.png", pngdirname, name);
ImageOut(pngfilename, "Temperature", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)TempPalette, 0);
ImageOut(pngfilename, "Temperature", prow, nrow, 2080, 0, TempPalette, enhancements, mapFile);
} }


// Run the brightness calibration here because the temperature calibration requires raw data
// Layered & false color images both also need brightness calibration
if(CONTAINS(enchancements, 'c') || CONTAINS(enchancements, 'h') || CONTAINS(imgopt, 'l') || CONTAINS(imgopt, 'c'))
calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH+TELE_WIDTH+SYNC_WIDTH+SPC_WIDTH+CH_WIDTH, 1);
// False color image
if(CONTAINS(imgopt, 'c')){
if (chA == 2 && chB >= 4) { // Normal false color
sprintf(pngfilename, "%s/%s-c.png", pngdirname, name);
//ImageRGBOut(pngfilename, prow, nrow);
ImageOut(pngfilename, "False Color", prow, nrow, CH_WIDTH, 0, NULL, enhancements, mapFile);
} else if (chB == 2) { // GVI (global vegetation index) false color
Ngvi(prow, nrow);
sprintf(pngfilename, "%s/%s-c.png", pngdirname, name);
ImageOut(pngfilename, "GVI False Color", prow, nrow, CH_WIDTH, CHB_OFFSET, GviPalette, enhancements, mapFile);
} else {
fprintf(stderr, "Skipping False Color generation; lacking required channels.\n");
}
}

// MCIR
if (CONTAINS(imgopt, 'm')) {
sprintf(pngfilename, "%s/%s-m.png", pngdirname, name);
ImageOut(pngfilename, "MCIR", prow, nrow, 909, CHA_OFFSET, NULL, enhancements, mapFile);
}


// Histogram equalise // Histogram equalise
if(CONTAINS(enchancements, 'h')){
if(CONTAINS(enhancements, 'h')){
histogramEqualise(prow, nrow, CHA_OFFSET, CH_WIDTH); histogramEqualise(prow, nrow, CHA_OFFSET, CH_WIDTH);
histogramEqualise(prow, nrow, CHB_OFFSET, CH_WIDTH); histogramEqualise(prow, nrow, CHB_OFFSET, CH_WIDTH);
} }


// Layered
if (CONTAINS(imgopt, 'l')){
if(chA == 1){
sprintf(pngfilename, "%s/%s-l.png", pngdirname, name);
ImageOut(pngfilename, "Layered", prow, nrow, CH_WIDTH, 0, NULL, 3);
}else{
fprintf(stderr, "Lacking channels required for generting a layered image.\n");
}
}

// Raw image // Raw image
if (CONTAINS(imgopt, 'r')) { if (CONTAINS(imgopt, 'r')) {
int croptele = CONTAINS(enchancements, 't');
char channelstr[45]; char channelstr[45];
sprintf(channelstr, "%s (%s) & %s (%s)", ch.id[chA], ch.name[chA], ch.id[chB], ch.name[chB]); sprintf(channelstr, "%s (%s) & %s (%s)", ch.id[chA], ch.name[chA], ch.id[chB], ch.name[chB]);


sprintf(pngfilename, "%s/%s-r.png", pngdirname, name); sprintf(pngfilename, "%s/%s-r.png", pngdirname, name);
ImageOut(pngfilename, channelstr, prow, nrow, IMG_WIDTH, 0, NULL, croptele ? 1 : 0);
ImageOut(pngfilename, channelstr, prow, nrow, IMG_WIDTH, 0, NULL, enhancements, mapFile);
} }


// Channel A // Channel A
@@ -471,7 +553,7 @@ int main(int argc, char **argv) {
sprintf(channelstr, "%s (%s)", ch.id[chA], ch.name[chA]); sprintf(channelstr, "%s (%s)", ch.id[chA], ch.name[chA]);


sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, ch.id[chA]); sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, ch.id[chA]);
ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH, CHA_OFFSET, NULL, 0);
ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH, CHA_OFFSET, NULL, enhancements, mapFile);
} }


// Channel B // Channel B
@@ -480,7 +562,7 @@ int main(int argc, char **argv) {
sprintf(channelstr, "%s (%s)", ch.id[chB], ch.name[chB]); sprintf(channelstr, "%s (%s)", ch.id[chB], ch.name[chB]);


sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, ch.id[chB]); sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, ch.id[chB]);
ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH , CHB_OFFSET, NULL, 0);
ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH , CHB_OFFSET, NULL, enhancements, mapFile);
} }


// Distribution image // Distribution image
@@ -488,21 +570,6 @@ int main(int argc, char **argv) {
sprintf(pngfilename, "%s/%s-d.png", pngdirname, name); sprintf(pngfilename, "%s/%s-d.png", pngdirname, name);
distrib(pngfilename, prow, nrow); distrib(pngfilename, prow, nrow);
} }

// False color image
if(CONTAINS(imgopt, 'c')){
if (chA == 2 && chB >= 4) { // Normal false color
sprintf(pngfilename, "%s/%s-c.png", pngdirname, name);
//ImageRGBOut(pngfilename, prow, nrow);
ImageOut(pngfilename, "False Color", prow, nrow, CH_WIDTH, 0, NULL, 2);
} else if (chB == 2) { // GVI (global vegetation index) false color
Ngvi(prow, nrow);
sprintf(pngfilename, "%s/%s-c.png", pngdirname, name);
ImageOut(pngfilename, "GVI False Color", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)GviPalette, 0);
} else {
fprintf(stderr, "Lacking channels required for generating a false color image.\n");
}
}
} }


exit(0); exit(0);


+ 3
- 3
palette.h View File

@@ -17,7 +17,7 @@
* *
*/ */


unsigned char GviPalette[256*3] = {
char *GviPalette = {
"\230t\17\233x\22\236{\27\241\200\33\244\203\37\247\210#\252\214'\255\220" "\230t\17\233x\22\236{\27\241\200\33\244\203\37\247\210#\252\214'\255\220"
",\260\2240\264\2305\267\2358\272\240=\274\245A\300\251E\303\255I\306\262" ",\260\2240\264\2305\267\2358\272\240=\274\245A\300\251E\303\255I\306\262"
"M\311\266Q\314\272V\317\276Z\322\302^\325\306b\330\312g\334\317k\337\323" "M\311\266Q\314\272V\317\276Z\322\302^\325\306b\330\312g\334\317k\337\323"
@@ -48,8 +48,8 @@ unsigned char GviPalette[256*3] = {
"M\225\1I\221\2E\217\1@\214\1;\211\1""7\206\1""1\203\1-\200\0(~\1${\0\37y" "M\225\1I\221\2E\217\1@\214\1;\211\1""7\206\1""1\203\1-\200\0(~\1${\0\37y"
"\0\33u\0\25r\0\21p\0\14l\0\7j\0\3" "\0\33u\0\25r\0\21p\0\14l\0\7j\0\3"
}; };
unsigned char TempPalette[256*3] = {
"\376\376\376\376\376\376\375\375\376\374\375\376\374\375\375\374\373\375"
char *TempPalette = {
"\000\000\000\376\376\376\375\375\376\374\375\376\374\375\375\374\373\375"
"\373\373\375\372\373\375\372\373\374\372\372\374\371\372\374\371\371\375" "\373\373\375\372\373\375\372\373\374\372\372\374\371\372\374\371\371\375"
"\370\371\374\367\370\375\367\370\374\367\367\374\366\367\373\366\366\373" "\370\371\374\367\370\375\367\370\374\367\367\374\366\367\373\366\366\373"
"\365\366\373\364\366\373\364\365\374\363\365\373\363\364\373\363\364\373" "\365\366\373\364\366\373\364\365\374\363\365\373\363\364\373\363\364\373"


Loading…
Cancel
Save