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;