From d4146f4eb934fb286def05a28fad2a56292c083a Mon Sep 17 00:00:00 2001 From: Xerbo Date: Sun, 14 Aug 2022 22:32:49 +0100 Subject: [PATCH] Rewrite thermal calibration (and add visible calibration) --- CMakeLists.txt | 2 +- src/algebra.h | 2 +- src/apt.h | 5 +- src/calibration.c | 120 ++++++++++++++ src/calibration.h | 55 +++++++ src/common.h | 3 +- src/image.c | 105 ++++++------ src/libs/argparse.c | 384 -------------------------------------------- src/libs/argparse.h | 130 --------------- src/main.c | 18 ++- src/satcal.h | 125 -------------- 11 files changed, 255 insertions(+), 694 deletions(-) create mode 100644 src/calibration.c create mode 100644 src/calibration.h delete mode 100644 src/libs/argparse.c delete mode 100644 src/libs/argparse.h delete mode 100644 src/satcal.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 24117c8..a89a9d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ find_package(PNG) # libsndfile find_package(LibSndFile) -set(LIB_C_SOURCE_FILES src/color.c src/dsp.c src/filter.c src/image.c src/algebra.c src/libs/median.c src/util.c) +set(LIB_C_SOURCE_FILES src/color.c src/dsp.c src/filter.c src/image.c src/algebra.c src/libs/median.c src/util.c src/calibration.c) set(EXE_C_SOURCE_FILES src/main.c src/pngio.c src/argparse/argparse.c src/util.c) set(LIB_C_HEADER_FILES src/apt.h) diff --git a/src/algebra.h b/src/algebra.h index adbf932..08b46af 100644 --- a/src/algebra.h +++ b/src/algebra.h @@ -33,6 +33,6 @@ typedef struct { linear_t linear_regression(const float *independent, const float *dependent, size_t len); float linear_calc(float x, linear_t line); -float quadratic_calc(float x, quadratic_t line); +float quadratic_calc(float x, quadratic_t quadratic); #endif diff --git a/src/apt.h b/src/apt.h index 19d0a09..2478e9e 100644 --- a/src/apt.h +++ b/src/apt.h @@ -100,7 +100,10 @@ apt_channel_t APT_API apt_calibrate(float **prow, int nrow, int offset, int widt void APT_API apt_denoise(float **prow, int nrow, int offset, int width); void APT_API apt_flipImage(apt_image_t *img, int width, int offset); int APT_API apt_cropNoise(apt_image_t *img); -void APT_API apt_temperature(int satnum, apt_image_t *img, int offset, int width); +void APT_API apt_calibrate_thermal(int satnum, apt_image_t *img, int offset, int width); +void APT_API apt_calibrate_visible(int satnum, apt_image_t *img, int offset, int width); +// Moved to apt_calibrate_thermal +#define apt_temperature apt_calibrate_thermal apt_rgb_t APT_API apt_applyPalette(char *palette, int val); apt_rgb_t APT_API apt_RGBcomposite(apt_rgb_t top, float top_a, apt_rgb_t bottom, float bottom_a); diff --git a/src/calibration.c b/src/calibration.c new file mode 100644 index 0000000..b2c7a27 --- /dev/null +++ b/src/calibration.c @@ -0,0 +1,120 @@ +/* + * aptdec - A lightweight FOSS (NOAA) APT decoder + * Copyright (C) 2019-2022 Xerbo (xerbo@protonmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "calibration.h" +#include "util.h" + +const calibration_t calibration[3] = { + { + .name = "NOAA-15", + .prt = { + { 1.36328e-06f, 0.051045f, 276.60157f }, // PRT 1 + { 1.47266e-06f, 0.050909f, 276.62531f }, // PRT 2 + { 1.47656e-06f, 0.050907f, 276.67413f }, // PRT 3 + { 1.47656e-06f, 0.050966f, 276.59258f } // PRT 4 + }, + .visible = { + { + .low = { 0.0568f, -2.1874f }, + .high = { 0.1633f, -54.9928f }, + .cutoff = 496.0f + }, { + .low = { 0.0596f, -2.4096f }, + .high = { 0.1629f, -55.2436f }, + .cutoff = 511.0f + } + }, + .rad = { + { 925.4075f, 0.337810f, 0.998719f }, // Channel 4 + { 839.8979f, 0.304558f, 0.999024f }, // Channel 5 + { 2695.9743f, 1.621256f, 0.998015f } // Channel 3B + }, + .cor = { + { -4.50f, { 0.0004524f, -0.0932f, 4.76f } }, // Channel 4 + { -3.61f, { 0.0002811f, -0.0659f, 3.83f } }, // Channel 5 + { 0.0f, { 0.0f, 0.0f , 0.0f } } // Channel 3B + } + }, { + .name = "NOAA-18", + .prt = { + { 1.657e-06f, 0.05090f, 276.601f }, // PRT 1 + { 1.482e-06f, 0.05101f, 276.683f }, // PRT 2 + { 1.313e-06f, 0.05117f, 276.565f }, // PRT 3 + { 1.484e-06f, 0.05103f, 276.615f } // PRT 4 + }, + .visible = { + { + .low = { 0.06174f, -2.434f }, + .high = { 0.1841f, -63.31f }, + .cutoff = 501.54f + }, { + .low = { 0.07514f, -2.960f }, + .high = { 0.2254f, -78.55f }, + .cutoff = 500.40f + } + }, + .rad = { + { 928.1460f, 0.436645f, 0.998607f }, // Channel 4 + { 833.2532f, 0.253179f, 0.999057f }, // Channel 5 + { 2659.7952f, 1.698704f, 0.996960f } // Channel 3B + }, + .cor = { + { -5.53f, { 0.00052337f, -0.11069f, 5.82f } }, // Channel 4 + { -2.22f, { 0.00017715f, -0.04360f, 2.67f } }, // Channel 5 + { 0.0f, { 0.0f, 0.0f, 0.0f } } // Channel 3B + } + }, { + .name = "NOAA-19", + .prt = { + { 1.405783e-06f, 0.051111f, 276.6067f }, // PRT 1 + { 1.496037e-06f, 0.051090f, 276.6119f }, // PRT 2 + { 1.496990e-06f, 0.051033f, 276.6311f }, // PRT 3 + { 1.493110e-06f, 0.051058f, 276.6268f } // PRT 4 + }, + .visible = { + { + .low = { 0.05555f, -2.159f }, + .high = { 0.1639f, -56.33f }, + .cutoff = 496.43f + }, { + .low = { 0.06614f, -2.565f }, + .high = { 0.1970f, -68.01f }, + .cutoff = 500.37f + } + }, + .rad = { + { 928.9f, 0.53959f, 0.998534f }, // Channel 4 + { 831.9f, 0.36064f, 0.998913f }, // Channel 5 + { 2670.0f, 1.67396f, 0.997364f } // Channel 3B + }, + .cor = { + { -5.49f, { 0.00054668f, -0.11187f, 5.70f } }, // Channel 4 + { -3.39f, { 0.00024985f, -0.05991f, 3.58f } }, // Channel 5 + { 0.0f, { 0.0f, 0.0f, 0.0f } } // Channel 3B + } + } +}; + +calibration_t get_calibration(int satid) { + switch (satid) { + case 15: return calibration[0]; + case 18: return calibration[1]; + case 19: return calibration[2]; + default: error("Invalid satid in get_calibration()"); /* following is only to shut up the compiler */ return calibration[0]; + } +} diff --git a/src/calibration.h b/src/calibration.h new file mode 100644 index 0000000..c41aa04 --- /dev/null +++ b/src/calibration.h @@ -0,0 +1,55 @@ +/* + * aptdec - A lightweight FOSS (NOAA) APT decoder + * Copyright (C) 2019-2022 Xerbo (xerbo@protonmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef APTDEC_CALIBRATION_H +#define APTDEC_CALIBRATION_H +#include "algebra.h" + +typedef struct { + char *name; + + // Quadratics for calculating PRT temperature + quadratic_t prt[4]; + + // Visible calibration coefficients + struct { + linear_t low; + linear_t high; + float cutoff; + } visible[2]; + + // Radiance coefficients + struct { + float vc, A, B; + } rad[3]; + + // Non linear correction coefficients + struct { + float Ns; + quadratic_t quadratic; + } cor[3]; +} calibration_t; + +// First radiation constant (mW/(m2-sr-cm-4)) +static const float C1 = 1.1910427e-5f; +// Second radiation constant (cm-K) +static const float C2 = 1.4387752f; + +calibration_t get_calibration(int satid); + +#endif diff --git a/src/common.h b/src/common.h index 26f34b7..71e0e7c 100644 --- a/src/common.h +++ b/src/common.h @@ -47,7 +47,8 @@ enum imagetypes { Temperature='t', Channel_A='a', Channel_B='b', - Distribution='d' + Distribution='d', + Visible='v' }; enum effects { Crop_Telemetry='t', diff --git a/src/image.c b/src/image.c index 5e87254..3a8e4c0 100644 --- a/src/image.c +++ b/src/image.c @@ -310,8 +310,8 @@ int apt_cropNoise(apt_image_t *img){ return startCrop; } -// --- Temperature Calibration --- // -#include "satcal.h" +// --- Visible and Temperature Calibration --- // +#include "calibration.h" typedef struct { float Nbb; @@ -321,71 +321,78 @@ typedef struct { } tempparam_t; // IR channel temperature compensation -static void tempcomp(float t[16], int ch, int satnum, tempparam_t *tpr) { - float Tbb, T[4]; - float C; - - tpr->ch = ch - 4; - - // Compute equivalent T blackbody temperature - for (int n = 0; n < 4; n++) { - float d0, d1, d2; - - C = t[9 + n] * 4.0; - d0 = satcal[satnum].d[n][0]; - d1 = satcal[satnum].d[n][1]; - d2 = satcal[satnum].d[n][2]; - T[n] = d0; - T[n] += d1 * C; - C *= C; - T[n] += d2 * C; +tempparam_t tempcomp(float t[16], int ch, int satnum) { + tempparam_t tpr; + tpr.ch = ch - 4; + + const calibration_t calibration = get_calibration(satnum); + const float Vc = calibration.rad[tpr.ch].vc; + const float A = calibration.rad[tpr.ch].A; + const float B = calibration.rad[tpr.ch].B; + + // Compute PRT temperature + float T[4]; + for (size_t n = 0; n < 4; n++) { + T[n] = quadratic_calc(t[n+9] * 4.0, calibration.prt[n]); } - Tbb = (T[0] + T[1] + T[2] + T[3]) / 4.0; - Tbb = satcal[satnum].rad[tpr->ch].A + satcal[satnum].rad[tpr->ch].B * Tbb; - // Compute blackbody radiance temperature - C = satcal[satnum].rad[tpr->ch].vc; - tpr->Nbb = c1 * C * C * C / (expm1(c2 * C / Tbb)); + float Tbb = (T[0]+T[1]+T[2]+T[3]) / 4.0; // Blackbody temperature + float Tbbstar = A + Tbb*B; // Effective blackbody temperature - // Store blackbody count and space - tpr->Cs = Cs * 4.0; - tpr->Cb = t[14] * 4.0; + tpr.Nbb = C1 * pow(Vc, 3) / (expf(C2 * Vc / Tbbstar) - 1.0f); // Blackbody radiance + + tpr.Cs = 246.4 * 4.0; // FIXME + tpr.Cb = t[14] * 4.0; + return tpr; } // IR channel temperature calibration -static float tempcal(float Ce, int satnum, tempparam_t * rgpr) { - float Nl, Nc, Ns, Ne; - float T, vc; - - Ns = satcal[satnum].cor[rgpr->ch].Ns; - Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb); - Nc = satcal[satnum].cor[rgpr->ch].b[0] + - satcal[satnum].cor[rgpr->ch].b[1] * Nl + - satcal[satnum].cor[rgpr->ch].b[2] * Nl * Nl; +static float tempcal(float Ce, int satnum, tempparam_t tpr) { + const calibration_t calibration = get_calibration(satnum); + const float Ns = calibration.cor[tpr.ch].Ns; + const float Vc = calibration.rad[tpr.ch].vc; + const float A = calibration.rad[tpr.ch].A; + const float B = calibration.rad[tpr.ch].B; - Ne = Nl + Nc; + float Nl = Ns + (tpr.Nbb - Ns) * (tpr.Cs - Ce * 4.0) / (tpr.Cs - tpr.Cb); // Linear radiance estimate + float Nc = quadratic_calc(Nl, calibration.cor[tpr.ch].quadratic); // Non-linear correction + float Ne = Nl + Nc; // Corrected radiance - vc = satcal[satnum].rad[rgpr->ch].vc; - T = c2 * vc / log(c1 * vc * vc * vc / Ne + 1.0); - T = (T - satcal[satnum].rad[rgpr->ch].A) / satcal[satnum].rad[rgpr->ch].B; + float Testar = C2 * Vc / logf(C1 * powf(Vc, 3) / Ne + 1.0); // Equivlent black body temperature + float Te = (Testar - A) / B; // Temperature (kelvin) // Convert to celsius - T -= 273.15; + Te -= 273.15; // Rescale to 0-255 for -100°C to +60°C - T = (T + 100.0) / 160.0 * 255.0; - - return T; + return (Te + 100.0) / 160.0 * 255.0; } // Temperature calibration wrapper -void apt_temperature(int satnum, apt_image_t *img, int offset, int width){ - tempparam_t temp; +void apt_calibrate_thermal(int satnum, apt_image_t *img, int offset, int width) { + tempparam_t temp = tempcomp(tele, img->chB, satnum); + + for (int y = 0; y < img->nrow; y++) { + for (int x = 0; x < width; x++) { + img->prow[y][x + offset] = (float)tempcal(img->prow[y][x + offset], satnum, temp); + } + } +} + +float calibrate_pixel(float value, int channel, calibration_t cal) { + if (value > cal.visible[channel].cutoff) { + return linear_calc(value*4.0f, cal.visible[channel].high) * 255.0f/100.0f; + } else { + return linear_calc(value*4.0f, cal.visible[channel].low) * 255.0f/100.0f; + } +} - tempcomp(tele, img->chB, satnum - 15, &temp); +void apt_calibrate_visible(int satnum, apt_image_t *img, int offset, int width) { + const calibration_t calibration = get_calibration(satnum); + int channel = img->chA-1; for (int y = 0; y < img->nrow; y++) { for (int x = 0; x < width; x++) { - img->prow[y][x + offset] = (float)tempcal(img->prow[y][x + offset], satnum - 15, &temp); + img->prow[y][x + offset] = clamp(calibrate_pixel(img->prow[y][x + offset], channel, calibration), 255.0f, 0.0f); } } } diff --git a/src/libs/argparse.c b/src/libs/argparse.c deleted file mode 100644 index ec86bba..0000000 --- a/src/libs/argparse.c +++ /dev/null @@ -1,384 +0,0 @@ -/** - * Copyright (C) 2012-2015 Yecheng Fu - * All rights reserved. - * - * Use of this source code is governed by a MIT-style license that can be found - * in the LICENSE file. - */ -#include -#include -#include -#include -#include -#include "argparse.h" - -#define OPT_UNSET 1 -#define OPT_LONG (1 << 1) - -static const char * -prefix_skip(const char *str, const char *prefix) -{ - size_t len = strlen(prefix); - return strncmp(str, prefix, len) ? NULL : str + len; -} - -static int -prefix_cmp(const char *str, const char *prefix) -{ - for (;; str++, prefix++) - if (!*prefix) { - return 0; - } else if (*str != *prefix) { - return (unsigned char)*prefix - (unsigned char)*str; - } -} - -static void -argparse_error(struct argparse *self, const struct argparse_option *opt, - const char *reason, int flags) -{ - (void)self; - if (flags & OPT_LONG) { - fprintf(stderr, "error: option `--%s` %s\n", opt->long_name, reason); - } else { - fprintf(stderr, "error: option `-%c` %s\n", opt->short_name, reason); - } - exit(1); -} - -static int -argparse_getvalue(struct argparse *self, const struct argparse_option *opt, - int flags) -{ - const char *s = NULL; - if (!opt->value) - goto skipped; - switch (opt->type) { - case ARGPARSE_OPT_BOOLEAN: - if (flags & OPT_UNSET) { - *(int *)opt->value = *(int *)opt->value - 1; - } else { - *(int *)opt->value = *(int *)opt->value + 1; - } - if (*(int *)opt->value < 0) { - *(int *)opt->value = 0; - } - break; - case ARGPARSE_OPT_BIT: - if (flags & OPT_UNSET) { - *(int *)opt->value &= ~opt->data; - } else { - *(int *)opt->value |= opt->data; - } - break; - case ARGPARSE_OPT_STRING: - if (self->optvalue) { - *(const char **)opt->value = self->optvalue; - self->optvalue = NULL; - } else if (self->argc > 1) { - self->argc--; - *(const char **)opt->value = *++self->argv; - } else { - argparse_error(self, opt, "requires a value", flags); - } - break; - case ARGPARSE_OPT_INTEGER: - errno = 0; - if (self->optvalue) { - *(int *)opt->value = strtol(self->optvalue, (char **)&s, 0); - self->optvalue = NULL; - } else if (self->argc > 1) { - self->argc--; - *(int *)opt->value = strtol(*++self->argv, (char **)&s, 0); - } else { - argparse_error(self, opt, "requires a value", flags); - } - if (errno) - argparse_error(self, opt, strerror(errno), flags); - if (s[0] != '\0') - argparse_error(self, opt, "expects an integer value", flags); - break; - case ARGPARSE_OPT_FLOAT: - errno = 0; - if (self->optvalue) { - *(float *)opt->value = strtof(self->optvalue, (char **)&s); - self->optvalue = NULL; - } else if (self->argc > 1) { - self->argc--; - *(float *)opt->value = strtof(*++self->argv, (char **)&s); - } else { - argparse_error(self, opt, "requires a value", flags); - } - if (errno) - argparse_error(self, opt, strerror(errno), flags); - if (s[0] != '\0') - argparse_error(self, opt, "expects a numerical value", flags); - break; - default: - assert(0); - } - -skipped: - if (opt->callback) { - return opt->callback(self, opt); - } - - return 0; -} - -static void -argparse_options_check(const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - switch (options->type) { - case ARGPARSE_OPT_END: - case ARGPARSE_OPT_BOOLEAN: - case ARGPARSE_OPT_BIT: - case ARGPARSE_OPT_INTEGER: - case ARGPARSE_OPT_FLOAT: - case ARGPARSE_OPT_STRING: - case ARGPARSE_OPT_GROUP: - continue; - default: - fprintf(stderr, "wrong option type: %d", options->type); - break; - } - } -} - -static int -argparse_short_opt(struct argparse *self, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - if (options->short_name == *self->optvalue) { - self->optvalue = self->optvalue[1] ? self->optvalue + 1 : NULL; - return argparse_getvalue(self, options, 0); - } - } - return -2; -} - -static int -argparse_long_opt(struct argparse *self, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - const char *rest; - int opt_flags = 0; - if (!options->long_name) - continue; - - rest = prefix_skip(self->argv[0] + 2, options->long_name); - if (!rest) { - // negation disabled? - if (options->flags & OPT_NONEG) { - continue; - } - // only OPT_BOOLEAN/OPT_BIT supports negation - if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != - ARGPARSE_OPT_BIT) { - continue; - } - - if (prefix_cmp(self->argv[0] + 2, "no-")) { - continue; - } - rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name); - if (!rest) - continue; - opt_flags |= OPT_UNSET; - } - if (*rest) { - if (*rest != '=') - continue; - self->optvalue = rest + 1; - } - return argparse_getvalue(self, options, opt_flags | OPT_LONG); - } - return -2; -} - -int -argparse_init(struct argparse *self, struct argparse_option *options, - const char *const *usages, int flags) -{ - memset(self, 0, sizeof(*self)); - self->options = options; - self->usages = usages; - self->flags = flags; - self->description = NULL; - self->epilog = NULL; - return 0; -} - -void -argparse_describe(struct argparse *self, const char *description, - const char *epilog) -{ - self->description = description; - self->epilog = epilog; -} - -int -argparse_parse(struct argparse *self, int argc, const char **argv) -{ - self->argc = argc - 1; - self->argv = argv + 1; - self->out = argv; - - argparse_options_check(self->options); - - for (; self->argc; self->argc--, self->argv++) { - const char *arg = self->argv[0]; - if (arg[0] != '-' || !arg[1]) { - if (self->flags & ARGPARSE_STOP_AT_NON_OPTION) { - goto end; - } - // if it's not option or is a single char '-', copy verbatim - self->out[self->cpidx++] = self->argv[0]; - continue; - } - // short option - if (arg[1] != '-') { - self->optvalue = arg + 1; - switch (argparse_short_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - while (self->optvalue) { - switch (argparse_short_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - } - continue; - } - // if '--' presents - if (!arg[2]) { - self->argc--; - self->argv++; - break; - } - // long option - switch (argparse_long_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - continue; - -unknown: - fprintf(stderr, "error: unknown option `%s`\n", self->argv[0]); - argparse_usage(self); - exit(1); - } - -end: - memmove(self->out + self->cpidx, self->argv, - self->argc * sizeof(*self->out)); - self->out[self->cpidx + self->argc] = NULL; - - return self->cpidx + self->argc; -} - -void -argparse_usage(struct argparse *self) -{ - if (self->usages) { - fprintf(stdout, "Usage: %s\n", *self->usages++); - while (*self->usages && **self->usages) - fprintf(stdout, " or: %s\n", *self->usages++); - } else { - fprintf(stdout, "Usage:\n"); - } - - // print description - if (self->description) - fprintf(stdout, "%s\n", self->description); - - fputc('\n', stdout); - - const struct argparse_option *options; - - // figure out best width - size_t usage_opts_width = 0; - size_t len; - options = self->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - len = 0; - if ((options)->short_name) { - len += 2; - } - if ((options)->short_name && (options)->long_name) { - len += 2; // separator ", " - } - if ((options)->long_name) { - len += strlen((options)->long_name) + 2; - } - if (options->type == ARGPARSE_OPT_INTEGER) { - len += strlen("="); - } - if (options->type == ARGPARSE_OPT_FLOAT) { - len += strlen("="); - } else if (options->type == ARGPARSE_OPT_STRING) { - len += strlen("="); - } - len = (len + 3) - ((len + 3) & 3); - if (usage_opts_width < len) { - usage_opts_width = len; - } - } - usage_opts_width += 4; // 4 spaces prefix - - options = self->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - size_t pos = 0; - int pad = 0; - if (options->type == ARGPARSE_OPT_GROUP) { - fputc('\n', stdout); - fprintf(stdout, "%s", options->help); - fputc('\n', stdout); - continue; - } - pos = fprintf(stdout, " "); - if (options->short_name) { - pos += fprintf(stdout, "-%c", options->short_name); - } - if (options->long_name && options->short_name) { - pos += fprintf(stdout, ", "); - } - if (options->long_name) { - pos += fprintf(stdout, "--%s", options->long_name); - } - if (options->type == ARGPARSE_OPT_INTEGER) { - pos += fprintf(stdout, "="); - } else if (options->type == ARGPARSE_OPT_FLOAT) { - pos += fprintf(stdout, "="); - } else if (options->type == ARGPARSE_OPT_STRING) { - pos += fprintf(stdout, "="); - } - if (pos <= usage_opts_width) { - pad = usage_opts_width - pos; - } else { - fputc('\n', stdout); - pad = usage_opts_width; - } - fprintf(stdout, "%*s%s\n", pad + 2, "", options->help); - } - - // print epilog - if (self->epilog) - fprintf(stdout, "%s\n", self->epilog); -} - -int -argparse_help_cb(struct argparse *self, const struct argparse_option *option) -{ - (void)option; - argparse_usage(self); - exit(0); -} diff --git a/src/libs/argparse.h b/src/libs/argparse.h deleted file mode 100644 index 44ce835..0000000 --- a/src/libs/argparse.h +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Copyright (C) 2012-2015 Yecheng Fu - * All rights reserved. - * - * Use of this source code is governed by a MIT-style license that can be found - * in the LICENSE file. - */ -#ifndef ARGPARSE_H -#define ARGPARSE_H - -/* For c++ compatibility */ -#ifdef __cplusplus -extern "C" { -#endif - -#include - -struct argparse; -struct argparse_option; - -typedef int argparse_callback (struct argparse *self, - const struct argparse_option *option); - -enum argparse_flag { - ARGPARSE_STOP_AT_NON_OPTION = 1, -}; - -enum argparse_option_type { - /* special */ - ARGPARSE_OPT_END, - ARGPARSE_OPT_GROUP, - /* options with no arguments */ - ARGPARSE_OPT_BOOLEAN, - ARGPARSE_OPT_BIT, - /* options with arguments (optional or required) */ - ARGPARSE_OPT_INTEGER, - ARGPARSE_OPT_FLOAT, - ARGPARSE_OPT_STRING, -}; - -enum argparse_option_flags { - OPT_NONEG = 1, /* disable negation */ -}; - -/** - * argparse option - * - * `type`: - * holds the type of the option, you must have an ARGPARSE_OPT_END last in your - * array. - * - * `short_name`: - * the character to use as a short option name, '\0' if none. - * - * `long_name`: - * the long option name, without the leading dash, NULL if none. - * - * `value`: - * stores pointer to the value to be filled. - * - * `help`: - * the short help message associated to what the option does. - * Must never be NULL (except for ARGPARSE_OPT_END). - * - * `callback`: - * function is called when corresponding argument is parsed. - * - * `data`: - * associated data. Callbacks can use it like they want. - * - * `flags`: - * option flags. - */ -struct argparse_option { - enum argparse_option_type type; - const char short_name; - const char *long_name; - void *value; - const char *help; - argparse_callback *callback; - intptr_t data; - int flags; -}; - -/** - * argpparse - */ -struct argparse { - // user supplied - const struct argparse_option *options; - const char *const *usages; - int flags; - const char *description; // a description after usage - const char *epilog; // a description at the end - // internal context - int argc; - const char **argv; - const char **out; - int cpidx; - const char *optvalue; // current option value -}; - -// built-in callbacks -int argparse_help_cb(struct argparse *self, - const struct argparse_option *option); - -// built-in option macros -#define OPT_END() { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 } -#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ } -#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ } -#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ } -#define OPT_FLOAT(...) { ARGPARSE_OPT_FLOAT, __VA_ARGS__ } -#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ } -#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 } -#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, \ - "show this help message and exit", \ - argparse_help_cb, 0, OPT_NONEG) - -int argparse_init(struct argparse *self, struct argparse_option *options, - const char *const *usages, int flags); -void argparse_describe(struct argparse *self, const char *description, - const char *epilog); -int argparse_parse(struct argparse *self, int argc, const char **argv); -void argparse_usage(struct argparse *self); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/main.c b/src/main.c index 21d06c6..7e2efbe 100644 --- a/src/main.c +++ b/src/main.c @@ -29,7 +29,7 @@ #include #include #include -#include "libs/argparse.h" +#include "argparse/argparse.h" #include "common.h" #include "apt.h" @@ -222,10 +222,24 @@ static int processAudio(char *filename, options_t *opts){ } // Perform temperature calibration - apt_temperature(opts->satnum, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH); + apt_calibrate_thermal(opts->satnum, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH); ImageOut(opts, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH, "Temperature", Temperature, (char *)apt_TempPalette); } + // Temperature + if (CONTAINS(opts->type, Visible) && img.chA <= 2) { + // Create another buffer as to not modify the orignal + apt_image_t tmpimg = img; + for(int i = 0; i < img.nrow; i++){ + tmpimg.prow[i] = (float *) malloc(sizeof(float) * APT_PROW_WIDTH); + memcpy(tmpimg.prow[i], img.prow[i], sizeof(float) * APT_PROW_WIDTH); + } + + // Perform visible calibration + apt_calibrate_visible(opts->satnum, &tmpimg, APT_CHA_OFFSET, APT_CH_WIDTH); + ImageOut(opts, &tmpimg, APT_CHA_OFFSET, APT_CH_WIDTH, "Visible", Visible, (char *)apt_TempPalette); + } + // MCIR if (CONTAINS(opts->type, MCIR)) ImageOut(opts, &img, APT_CHA_OFFSET, APT_CH_WIDTH, "MCIR", MCIR, NULL); diff --git a/src/satcal.h b/src/satcal.h deleted file mode 100644 index 34b76d2..0000000 --- a/src/satcal.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file is part of Aptdec. - * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2022 - * - * Aptdec is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -const struct { - float d[4][3]; - struct { - float vc, A, B; - } rad[3]; - struct { - float Ns; - float b[3]; - } cor[3]; -/* Calibration corficcients taken from the NOAA KLM satellite user guide - * https://web.archive.org/web/20141220021557/https://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/klm/tables.htm - */ -} satcal[] = { -{ // NOAA 15 - { // PRT coefficient d0, d1, d2 - {276.60157f, 0.051045f, 1.36328E-06f}, - {276.62531f, 0.050909f, 1.47266E-06f}, - {276.67413f, 0.050907f, 1.47656E-06f}, - {276.59258f, 0.050966f, 1.47656E-06f} - }, - { // Channel radiance coefficient vc, A, B - {925.4075f, 0.337810f, 0.998719f}, // Channel 4 - {839.8979f, 0.304558f, 0.999024f}, // Channel 5 - {2695.9743f, 1.621256f, 0.998015f} // Channel 3B - }, - { // Nonlinear radiance correction Ns, b0, b1, b2 - {-4.50f, {4.76f, -0.0932f, 0.0004524f}}, // Channel 4 - {-3.61f, {3.83f, -0.0659f, 0.0002811f}}, // Channel 5 - {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B - } -}, -{ // NOAA 16 - { // PRT coeff d0, d1, d2 - {276.355f, 5.562E-02f, -1.590E-05f}, - {276.142f, 5.605E-02f, -1.707E-05f}, - {275.996f, 5.486E-02f, -1.223E-05f}, - {276.132f, 5.494E-02f, -1.344E-05f} - }, - { // Channel radiance coefficient vc, A, B - {917.2289f, 0.332380f, 0.998522f}, // Channel 4 - {838.1255f, 0.674623f, 0.998363f}, // Channel 5 - {2700.1148f, 1.592459f, 0.998147f} // Channel 3B - }, - { // Nonlinear radiance correction Ns, b0, b1, b2 - {-2.467f, {2.96f, -0.05411f, 0.00024532f}}, // Channel 4 - {-2.009f, {2.25f, -0.03665f, 0.00014854f}}, // Channel 5 - {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B - } -}, -{ // NOAA 17 - { // PRT coefficient d0, d1, d2 - {276.628f, 0.05098f, 1.371e-06f}, - {276.538f, 0.05098f, 1.371e-06f}, - {276.761f, 0.05097f, 1.369e-06f}, - {276.660f, 0.05100f, 1.348e-06f} - }, - { // Channel radiance coefficient vc, A, B - {926.2947f, 0.271683f, 0.998794f}, // Channel 4 - {839.8246f, 0.309180f, 0.999012f}, // Channel 5 - {2669.3554f, 1.702380f, 0.997378f} // Channel 3B - }, - { // Nonlinear radiance correction Ns, b0, b1, b2 - {-8.55f, {8.22f, -0.15795f, 0.00075579f}}, // Channel 4 - {-3.97f, {4.31f, -0.07318f, 0.00030976f}}, // Channel 5 - {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B - } -}, -{ // NOAA 18 - { // PRT coefficient d0, d1, d2 - {276.601f, 0.05090f, 1.657e-06f}, - {276.683f, 0.05101f, 1.482e-06f}, - {276.565f, 0.05117f, 1.313e-06f}, - {276.615f, 0.05103f, 1.484e-06f} - }, - { // Channel radiance coefficient vc, A, B - {928.1460f, 0.436645f, 0.998607f}, // Channel 4 - {833.2532f, 0.253179f, 0.999057f}, // Channel 5 - {2659.7952f, 1.698704f, 0.996960f} // Channel 3B - }, - { // Nonlinear radiance correction Ns, b0, b1, b2 - {-5.53f, {5.82f, -0.11069f, 0.00052337f}}, // Channel 4 - {-2.22f, {2.67f, -0.04360f, 0.00017715f}}, // Channel 5 - {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B - } -}, -{ // NOAA 19 - { // PRT coefficient d0, d1, d2 - {276.6067f, 0.051111f, 1.405783E-06f}, - {276.6119f, 0.051090f, 1.496037E-06f}, - {276.6311f, 0.051033f, 1.496990E-06f}, - {276.6268f, 0.051058f, 1.493110E-06f} - }, - { // Channel radiance coefficient vc, A, B - {928.9f, 0.53959f, 0.998534f}, // Channel 4 - {831.9f, 0.36064f, 0.998913f}, // Channel 5 - {2670.0f, 1.67396f, 0.997364f} // Channel 3B - }, - { // Nonlinear radiance correction Ns, b0, b1, b2 - {-5.49f, {5.70f, -0.11187f, 0.00054668f}}, // Channel 4 - {-3.39f, {3.58f, -0.05991f, 0.00024985f}}, // Channel 5 - {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B - } -}}; - -const float c1 = 1.1910427e-5f; -const float c2 = 1.4387752f;