@@ -44,6 +44,11 @@ if(PNG_FOUND AND SNDFILE_LIBRARIES AND SNDFILE_INCLUDE_DIR) | |||||
target_compile_options(aptdec-cli PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers) | target_compile_options(aptdec-cli PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers) | ||||
endif() | endif() | ||||
if (USE_ADDRESS_SANITIZER) | |||||
target_compile_options(aptdec-cli PRIVATE -fsanitize=address) | |||||
target_link_options(aptdec-cli PRIVATE -fsanitize=address) | |||||
endif() | |||||
install(TARGETS aptdec-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | install(TARGETS aptdec-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | ||||
file(GLOB LUTS luts/*.png) | file(GLOB LUTS luts/*.png) | ||||
install(FILES ${LUTS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/aptdec/luts) | install(FILES ${LUTS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/aptdec/luts) | ||||
@@ -75,6 +80,10 @@ else() | |||||
target_link_libraries(aptdec PRIVATE m) | target_link_libraries(aptdec PRIVATE m) | ||||
target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers) | target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers) | ||||
endif() | endif() | ||||
if (USE_ADDRESS_SANITIZER) | |||||
target_compile_options(aptdec PRIVATE -fsanitize=address) | |||||
target_link_options(aptdec PRIVATE -fsanitize=address) | |||||
endif() | |||||
install(TARGETS aptdec PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) | install(TARGETS aptdec PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||||
@@ -67,7 +67,6 @@ static int freq_from_filename(const char *filename); | |||||
static int satid_from_freq(int freq); | static int satid_from_freq(int freq); | ||||
static size_t callback(float *samples, size_t count, void *context); | static size_t callback(float *samples, size_t count, void *context); | ||||
static void write_line(writer_t *png, float *row); | static void write_line(writer_t *png, float *row); | ||||
apt_image_t strip(apt_image_t img); | |||||
int array_contains(char **array, char *value, size_t n); | int array_contains(char **array, char *value, size_t n); | ||||
static volatile int sigint_stop = 0; | static volatile int sigint_stop = 0; | ||||
@@ -183,7 +182,7 @@ static int process_file(const char *path, options_t *opts) { | |||||
if (opts->realtime) { | if (opts->realtime) { | ||||
char filename[269] = { 0 }; | char filename[269] = { 0 }; | ||||
sprintf(filename, "%s-decoding.png", name); | sprintf(filename, "%s-decoding.png", name); | ||||
realtime_png = writer_init(filename, APT_REGION_FULL, APTDEC_MAX_HEIGHT, PNG_COLOR_TYPE_GRAY, "Unknown"); | |||||
realtime_png = writer_init(filename, APTDEC_REGION_FULL, APTDEC_MAX_HEIGHT, PNG_COLOR_TYPE_GRAY, "Unknown"); | |||||
// Capture Ctrl+C | // Capture Ctrl+C | ||||
signal(SIGINT, sigint_handler); | signal(SIGINT, sigint_handler); | ||||
@@ -209,10 +208,10 @@ static int process_file(const char *path, options_t *opts) { | |||||
} | } | ||||
// Decode image | // Decode image | ||||
float *data = calloc(APT_IMG_WIDTH * (APTDEC_MAX_HEIGHT+1), sizeof(float)); | |||||
float *data = calloc(APTDEC_IMG_WIDTH * (APTDEC_MAX_HEIGHT+1), sizeof(float)); | |||||
size_t rows; | size_t rows; | ||||
for (rows = 0; rows < APTDEC_MAX_HEIGHT; rows++) { | for (rows = 0; rows < APTDEC_MAX_HEIGHT; rows++) { | ||||
float *row = &data[rows * APT_IMG_WIDTH]; | |||||
float *row = &data[rows * APTDEC_IMG_WIDTH]; | |||||
// Break the loop when there are no more samples or the process has been sent SIGINT | // Break the loop when there are no more samples or the process has been sent SIGINT | ||||
if (aptdec_getrow(aptdec, row, callback, &audioFile) == 0 || sigint_stop) { | if (aptdec_getrow(aptdec, row, callback, &audioFile) == 0 || sigint_stop) { | ||||
@@ -220,7 +219,10 @@ static int process_file(const char *path, options_t *opts) { | |||||
} | } | ||||
if (opts->realtime) { | if (opts->realtime) { | ||||
#pragma GCC diagnostic push | |||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" | |||||
write_line(realtime_png, row); | write_line(realtime_png, row); | ||||
#pragma GCC diagnostic pop | |||||
} | } | ||||
fprintf(stderr, "Row: %zu/%zu\r", rows+1, audioFile.info.frames/audioFile.info.samplerate * 2); | fprintf(stderr, "Row: %zu/%zu\r", rows+1, audioFile.info.frames/audioFile.info.samplerate * 2); | ||||
@@ -245,7 +247,7 @@ static int process_file(const char *path, options_t *opts) { | |||||
// Normalize | // Normalize | ||||
int error; | int error; | ||||
apt_image_t img = apt_normalize(data, rows, opts->satellite, &error); | |||||
aptdec_image_t img = aptdec_normalize(data, rows, opts->satellite, &error); | |||||
free(data); | free(data); | ||||
if (error) { | if (error) { | ||||
error_noexit("Normalization failed"); | error_noexit("Normalization failed"); | ||||
@@ -274,13 +276,13 @@ static int process_file(const char *path, options_t *opts) { | |||||
for (size_t i = 0; i < effects_len; i++) { | for (size_t i = 0; i < effects_len; i++) { | ||||
if (strcmp(effects[i], "crop") == 0) { | if (strcmp(effects[i], "crop") == 0) { | ||||
apt_crop(&img); | |||||
aptdec_crop(&img); | |||||
} else if (strcmp(effects[i], "denoise") == 0) { | } else if (strcmp(effects[i], "denoise") == 0) { | ||||
apt_denoise(&img, APT_REGION_CHA); | |||||
apt_denoise(&img, APT_REGION_CHB); | |||||
aptdec_denoise(&img, APTDEC_REGION_CHA); | |||||
aptdec_denoise(&img, APTDEC_REGION_CHB); | |||||
} else if (strcmp(effects[i], "flip") == 0) { | } else if (strcmp(effects[i], "flip") == 0) { | ||||
apt_flip(&img, APT_REGION_CHA); | |||||
apt_flip(&img, APT_REGION_CHB); | |||||
aptdec_flip(&img, APTDEC_REGION_CHA); | |||||
aptdec_flip(&img, APTDEC_REGION_CHB); | |||||
} | } | ||||
} | } | ||||
@@ -300,11 +302,11 @@ static int process_file(const char *path, options_t *opts) { | |||||
sprintf(description, "Calibrated thermal image, channel %s - %s", channel_name[img.ch[1]], channel_desc[img.ch[1]]); | sprintf(description, "Calibrated thermal image, channel %s - %s", channel_name[img.ch[1]], channel_desc[img.ch[1]]); | ||||
// Perform visible calibration | // Perform visible calibration | ||||
apt_image_t _img = apt_image_clone(img); | |||||
apt_calibrate_thermal(&_img, APT_REGION_CHA); | |||||
aptdec_image_t _img = aptdec_image_clone(img); | |||||
aptdec_calibrate_thermal(&_img, APTDEC_REGION_CHA); | |||||
writer_t *writer = writer_init(filename, APT_REGION_CHB, img.rows, PNG_COLOR_TYPE_RGB, description); | |||||
writer_write_image_gradient(writer, &_img, temperature_gradient); | |||||
writer_t *writer = writer_init(filename, APTDEC_REGION_CHB, img.rows, PNG_COLOR_TYPE_RGB, description); | |||||
writer_write_image_gradient(writer, &_img, aptdec_temperature_gradient); | |||||
writer_free(writer); | writer_free(writer); | ||||
free(_img.data); | free(_img.data); | ||||
@@ -319,10 +321,10 @@ static int process_file(const char *path, options_t *opts) { | |||||
sprintf(description, "Calibrated visible image, channel %s - %s", channel_name[img.ch[0]], channel_desc[img.ch[0]]); | sprintf(description, "Calibrated visible image, channel %s - %s", channel_name[img.ch[0]], channel_desc[img.ch[0]]); | ||||
// Perform visible calibration | // Perform visible calibration | ||||
apt_image_t _img = apt_image_clone(img); | |||||
apt_calibrate_visible(&_img, APT_REGION_CHA); | |||||
aptdec_image_t _img = aptdec_image_clone(img); | |||||
aptdec_calibrate_visible(&_img, APTDEC_REGION_CHA); | |||||
writer_t *writer = writer_init(filename, APT_REGION_CHA, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer_t *writer = writer_init(filename, APTDEC_REGION_CHA, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer_write_image(writer, &_img); | writer_write_image(writer, &_img); | ||||
writer_free(writer); | writer_free(writer); | ||||
@@ -335,11 +337,11 @@ static int process_file(const char *path, options_t *opts) { | |||||
for (size_t i = 0; i < effects_len; i++) { | for (size_t i = 0; i < effects_len; i++) { | ||||
if (strcmp(effects[i], "stretch") == 0) { | if (strcmp(effects[i], "stretch") == 0) { | ||||
apt_stretch(&img, APT_REGION_CHA); | |||||
apt_stretch(&img, APT_REGION_CHB); | |||||
aptdec_stretch(&img, APTDEC_REGION_CHA); | |||||
aptdec_stretch(&img, APTDEC_REGION_CHB); | |||||
} else if (strcmp(effects[i], "equalize") == 0) { | } else if (strcmp(effects[i], "equalize") == 0) { | ||||
apt_equalize(&img, APT_REGION_CHA); | |||||
apt_equalize(&img, APT_REGION_CHB); | |||||
aptdec_equalize(&img, APTDEC_REGION_CHA); | |||||
aptdec_equalize(&img, APTDEC_REGION_CHB); | |||||
} | } | ||||
} | } | ||||
@@ -365,12 +367,13 @@ static int process_file(const char *path, options_t *opts) { | |||||
writer_t *writer; | writer_t *writer; | ||||
if (array_contains(effects, "strip", effects_len)) { | if (array_contains(effects, "strip", effects_len)) { | ||||
writer = writer_init(filename, (apt_region_t){0, APT_CH_WIDTH*2}, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
apt_image_t _img = strip(img); | |||||
writer = writer_init(filename, (aptdec_region_t){0, APTDEC_CH_WIDTH*2}, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
aptdec_image_t _img = aptdec_image_clone(img); | |||||
aptdec_strip(&_img); | |||||
writer_write_image(writer, &_img); | writer_write_image(writer, &_img); | ||||
free(_img.data); | free(_img.data); | ||||
} else { | } else { | ||||
writer = writer_init(filename, APT_REGION_FULL, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer = writer_init(filename, APTDEC_REGION_FULL, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer_write_image(writer, &img); | writer_write_image(writer, &img); | ||||
} | } | ||||
writer_free(writer); | writer_free(writer); | ||||
@@ -389,7 +392,7 @@ static int process_file(const char *path, options_t *opts) { | |||||
png_colorp lut = calloc(256*256, sizeof(png_color)); | png_colorp lut = calloc(256*256, sizeof(png_color)); | ||||
if (read_lut(opts->lut, lut)) { | if (read_lut(opts->lut, lut)) { | ||||
writer_t *writer = writer_init(filename, APT_REGION_CHA, img.rows, PNG_COLOR_TYPE_RGB, description); | |||||
writer_t *writer = writer_init(filename, APTDEC_REGION_CHA, img.rows, PNG_COLOR_TYPE_RGB, description); | |||||
writer_write_image_lut(writer, &img, lut); | writer_write_image_lut(writer, &img, lut); | ||||
writer_free(writer); | writer_free(writer); | ||||
} | } | ||||
@@ -405,12 +408,13 @@ static int process_file(const char *path, options_t *opts) { | |||||
writer_t *writer; | writer_t *writer; | ||||
if (array_contains(effects, "strip", effects_len)) { | if (array_contains(effects, "strip", effects_len)) { | ||||
writer = writer_init(filename, (apt_region_t){0, APT_CH_WIDTH}, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
apt_image_t _img = strip(img); | |||||
writer = writer_init(filename, (aptdec_region_t){0, APTDEC_CH_WIDTH}, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
aptdec_image_t _img = aptdec_image_clone(img); | |||||
aptdec_strip(&_img); | |||||
writer_write_image(writer, &_img); | writer_write_image(writer, &_img); | ||||
free(_img.data); | free(_img.data); | ||||
} else { | } else { | ||||
writer = writer_init(filename, APT_REGION_CHA_FULL, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer = writer_init(filename, APTDEC_REGION_CHA_FULL, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer_write_image(writer, &img); | writer_write_image(writer, &img); | ||||
} | } | ||||
writer_free(writer); | writer_free(writer); | ||||
@@ -422,12 +426,13 @@ static int process_file(const char *path, options_t *opts) { | |||||
writer_t *writer; | writer_t *writer; | ||||
if (array_contains(effects, "strip", effects_len)) { | if (array_contains(effects, "strip", effects_len)) { | ||||
writer = writer_init(filename, (apt_region_t){APT_CH_WIDTH, APT_CH_WIDTH}, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
apt_image_t _img = strip(img); | |||||
writer = writer_init(filename, (aptdec_region_t){APTDEC_CH_WIDTH, APTDEC_CH_WIDTH}, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
aptdec_image_t _img = aptdec_image_clone(img); | |||||
aptdec_strip(&_img); | |||||
writer_write_image(writer, &_img); | writer_write_image(writer, &_img); | ||||
free(_img.data); | free(_img.data); | ||||
} else { | } else { | ||||
writer = writer_init(filename, APT_REGION_CHB_FULL, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer = writer_init(filename, APTDEC_REGION_CHB_FULL, img.rows, PNG_COLOR_TYPE_GRAY, description); | |||||
writer_write_image(writer, &img); | writer_write_image(writer, &img); | ||||
} | } | ||||
writer_free(writer); | writer_free(writer); | ||||
@@ -500,31 +505,17 @@ static size_t callback(float *samples, size_t count, void *context) { | |||||
static void write_line(writer_t *png, float *row) { | static void write_line(writer_t *png, float *row) { | ||||
float min = FLT_MAX; | float min = FLT_MAX; | ||||
float max = FLT_MIN; | float max = FLT_MIN; | ||||
for (int i = 0; i < APT_IMG_WIDTH; i++) { | |||||
for (int i = 0; i < APTDEC_IMG_WIDTH; i++) { | |||||
if (row[i] < min) min = row[i]; | if (row[i] < min) min = row[i]; | ||||
if (row[i] > max) max = row[i]; | if (row[i] > max) max = row[i]; | ||||
} | } | ||||
png_byte pixels[APT_IMG_WIDTH]; | |||||
for (int i = 0; i < APT_IMG_WIDTH; i++) { | |||||
png_byte pixels[APTDEC_IMG_WIDTH]; | |||||
for (int i = 0; i < APTDEC_IMG_WIDTH; i++) { | |||||
pixels[i] = clamp_int(roundf((row[i]-min) / (max-min) * 255.0f), 0, 255); | pixels[i] = clamp_int(roundf((row[i]-min) / (max-min) * 255.0f), 0, 255); | ||||
} | } | ||||
#pragma GCC diagnostic push | |||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" | |||||
png_write_row(png->png, pixels); | png_write_row(png->png, pixels); | ||||
#pragma GCC diagnostic pop | |||||
} | |||||
apt_image_t strip(apt_image_t img) { | |||||
uint8_t *data = calloc(img.rows * APT_IMG_WIDTH, sizeof(uint8_t)); | |||||
for (size_t y = 0; y < img.rows; y++) { | |||||
memcpy(&data[y*APT_IMG_WIDTH], &img.data[y*APT_IMG_WIDTH + APT_CHA_OFFSET], APT_CH_WIDTH); | |||||
memcpy(&data[y*APT_IMG_WIDTH + APT_CH_WIDTH], &img.data[y*APT_IMG_WIDTH + APT_CHB_OFFSET], APT_CH_WIDTH); | |||||
} | |||||
img.data = data; | |||||
return img; | |||||
} | } | ||||
int array_contains(char **array, char *value, size_t n) { | int array_contains(char **array, char *value, size_t n) { | ||||
@@ -24,7 +24,7 @@ | |||||
#include "util.h" | #include "util.h" | ||||
writer_t *writer_init(const char *filename, apt_region_t region, uint32_t height, int color, char *channel) { | |||||
writer_t *writer_init(const char *filename, aptdec_region_t region, uint32_t height, int color, char *channel) { | |||||
writer_t *png = calloc(1, sizeof(writer_t)); | writer_t *png = calloc(1, sizeof(writer_t)); | ||||
png->region = region; | png->region = region; | ||||
@@ -64,17 +64,17 @@ writer_t *writer_init(const char *filename, apt_region_t region, uint32_t height | |||||
return png; | return png; | ||||
} | } | ||||
void writer_write_image(writer_t *png, const apt_image_t *img) { | |||||
void writer_write_image(writer_t *png, const aptdec_image_t *img) { | |||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
png_write_row(png->png, &img->data[y*APT_IMG_WIDTH + png->region.offset]); | |||||
png_write_row(png->png, &img->data[y*APTDEC_IMG_WIDTH + png->region.offset]); | |||||
} | } | ||||
} | } | ||||
void writer_write_image_gradient(writer_t *png, const apt_image_t *img, const uint32_t *gradient) { | |||||
void writer_write_image_gradient(writer_t *png, const aptdec_image_t *img, const uint32_t *gradient) { | |||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
png_color pixels[APT_IMG_WIDTH]; | |||||
for (size_t x = 0; x < APT_IMG_WIDTH; x++) { | |||||
apt_rgb_t pixel = apt_gradient(gradient, img->data[y*APT_IMG_WIDTH + x + png->region.offset]); | |||||
png_color pixels[APTDEC_IMG_WIDTH]; | |||||
for (size_t x = 0; x < APTDEC_IMG_WIDTH; x++) { | |||||
aptdec_rgb_t pixel = aptdec_gradient(gradient, img->data[y*APTDEC_IMG_WIDTH + x + png->region.offset]); | |||||
pixels[x] = (png_color){ pixel.r, pixel.g, pixel.b }; | pixels[x] = (png_color){ pixel.r, pixel.g, pixel.b }; | ||||
} | } | ||||
@@ -82,12 +82,12 @@ void writer_write_image_gradient(writer_t *png, const apt_image_t *img, const ui | |||||
} | } | ||||
} | } | ||||
void writer_write_image_lut(writer_t *png, const apt_image_t *img, const png_colorp lut) { | |||||
void writer_write_image_lut(writer_t *png, const aptdec_image_t *img, const png_colorp lut) { | |||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
png_color pixels[APT_CH_WIDTH]; | |||||
for (size_t x = 0; x < APT_CH_WIDTH; x++) { | |||||
uint8_t a = img->data[y*APT_IMG_WIDTH + x + APT_CHA_OFFSET]; | |||||
uint8_t b = img->data[y*APT_IMG_WIDTH + x + APT_CHB_OFFSET]; | |||||
png_color pixels[APTDEC_CH_WIDTH]; | |||||
for (size_t x = 0; x < APTDEC_CH_WIDTH; x++) { | |||||
uint8_t a = img->data[y*APTDEC_IMG_WIDTH + x + APTDEC_CHA_OFFSET]; | |||||
uint8_t b = img->data[y*APTDEC_IMG_WIDTH + x + APTDEC_CHB_OFFSET]; | |||||
pixels[x] = lut[b*256 + a]; | pixels[x] = lut[b*256 + a]; | ||||
} | } | ||||
@@ -26,15 +26,15 @@ typedef struct { | |||||
png_structp png; | png_structp png; | ||||
png_infop info; | png_infop info; | ||||
FILE *file; | FILE *file; | ||||
apt_region_t region; | |||||
aptdec_region_t region; | |||||
} writer_t; | } writer_t; | ||||
writer_t *writer_init(const char *filename, apt_region_t region, uint32_t height, int color, char *channel); | |||||
writer_t *writer_init(const char *filename, aptdec_region_t region, uint32_t height, int color, char *channel); | |||||
void writer_free(writer_t *png); | void writer_free(writer_t *png); | ||||
void writer_write_image(writer_t *png, const apt_image_t *img); | |||||
void writer_write_image_gradient(writer_t *png, const apt_image_t *img, const uint32_t *gradient); | |||||
void writer_write_image_lut(writer_t *png, const apt_image_t *img, const png_colorp lut); | |||||
void writer_write_image(writer_t *png, const aptdec_image_t *img); | |||||
void writer_write_image_gradient(writer_t *png, const aptdec_image_t *img, const uint32_t *gradient); | |||||
void writer_write_image_lut(writer_t *png, const aptdec_image_t *img, const png_colorp lut); | |||||
int read_lut(const char *filename, png_colorp out); | int read_lut(const char *filename, png_colorp out); | ||||
@@ -112,7 +112,7 @@ const calibration_t calibration[3] = { | |||||
} | } | ||||
}; | }; | ||||
calibration_t get_calibration(apt_satellite_t satid) { | |||||
calibration_t get_calibration(aptdec_satellite_t satid) { | |||||
switch (satid) { | switch (satid) { | ||||
case NOAA15: return calibration[0]; | case NOAA15: return calibration[0]; | ||||
case NOAA18: return calibration[1]; | case NOAA18: return calibration[1]; | ||||
@@ -52,6 +52,6 @@ static const float C1 = 1.1910427e-5f; | |||||
// Second radiation constant (cm-K) | // Second radiation constant (cm-K) | ||||
static const float C2 = 1.4387752f; | static const float C2 = 1.4387752f; | ||||
calibration_t get_calibration(apt_satellite_t satid); | |||||
calibration_t get_calibration(aptdec_satellite_t satid); | |||||
#endif | #endif |
@@ -23,16 +23,16 @@ | |||||
// clang-format off | // clang-format off | ||||
apt_rgb_t apt_gradient(const uint32_t *gradient, uint8_t val) { | |||||
return (apt_rgb_t) { | |||||
aptdec_rgb_t aptdec_gradient(const uint32_t *gradient, uint8_t val) { | |||||
return (aptdec_rgb_t) { | |||||
(gradient[val] & 0x00FF0000) >> 16, | (gradient[val] & 0x00FF0000) >> 16, | ||||
(gradient[val] & 0x0000FF00) >> 8, | (gradient[val] & 0x0000FF00) >> 8, | ||||
(gradient[val] & 0x000000FF) | (gradient[val] & 0x000000FF) | ||||
}; | }; | ||||
} | } | ||||
apt_rgb_t apt_composite_rgb(apt_rgb_t top, float top_alpha, apt_rgb_t bottom, float bottom_alpha) { | |||||
return (apt_rgb_t) { | |||||
aptdec_rgb_t aptdec_composite_rgb(aptdec_rgb_t top, float top_alpha, aptdec_rgb_t bottom, float bottom_alpha) { | |||||
return (aptdec_rgb_t) { | |||||
MCOMPOSITE(top.r, top_alpha, bottom.r, bottom_alpha), | MCOMPOSITE(top.r, top_alpha, bottom.r, bottom_alpha), | ||||
MCOMPOSITE(top.g, top_alpha, bottom.g, bottom_alpha), | MCOMPOSITE(top.g, top_alpha, bottom.g, bottom_alpha), | ||||
MCOMPOSITE(top.b, top_alpha, bottom.b, bottom_alpha) | MCOMPOSITE(top.b, top_alpha, bottom.b, bottom_alpha) | ||||
@@ -40,7 +40,7 @@ apt_rgb_t apt_composite_rgb(apt_rgb_t top, float top_alpha, apt_rgb_t bottom, fl | |||||
} | } | ||||
// Taken from WXtoImg | // Taken from WXtoImg | ||||
const uint32_t temperature_gradient[256] = { | |||||
const uint32_t aptdec_temperature_gradient[256] = { | |||||
0x45008F, 0x460091, 0x470092, 0x480094, 0x490096, 0x4A0098, 0x4B009B, | 0x45008F, 0x460091, 0x470092, 0x480094, 0x490096, 0x4A0098, 0x4B009B, | ||||
0x4D009D, 0x4E00A0, 0x5000A2, 0x5100A5, 0x5200A7, 0x5400AA, 0x5600AE, | 0x4D009D, 0x4E00A0, 0x5000A2, 0x5100A5, 0x5200A7, 0x5400AA, 0x5600AE, | ||||
0x5700B1, 0x5800B4, 0x5A00B7, 0x5C00BA, 0x5E00BD, 0x5F00C0, 0x6100C4, | 0x5700B1, 0x5800B4, 0x5A00B7, 0x5C00BA, 0x5E00BD, 0x5F00C0, 0x6100C4, | ||||
@@ -81,7 +81,7 @@ const uint32_t temperature_gradient[256] = { | |||||
}; | }; | ||||
// Taken from WXtoImg | // Taken from WXtoImg | ||||
const uint32_t precipitation_gradient[58] = { | |||||
const uint32_t aptdec_precipitation_gradient[58] = { | |||||
0x088941, 0x00C544, 0x00D12C, 0x00E31C, 0x00F906, 0x14FF00, 0x3EFF00, | 0x088941, 0x00C544, 0x00D12C, 0x00E31C, 0x00F906, 0x14FF00, 0x3EFF00, | ||||
0x5DFF00, 0x80FF00, 0xABFF00, 0xCDFE00, 0xF8FF00, 0xFFE600, 0xFFB800, | 0x5DFF00, 0x80FF00, 0xABFF00, 0xCDFE00, 0xF8FF00, 0xFFE600, 0xFFB800, | ||||
0xFF9800, 0xFF7500, 0xFF4900, 0xFE2600, 0xFF0400, 0xDF0000, 0xA80000, | 0xFF9800, 0xFF7500, 0xFF4900, 0xFE2600, 0xFF0400, 0xDF0000, 0xA80000, | ||||
@@ -54,7 +54,7 @@ typedef struct { | |||||
size_t ntaps; | size_t ntaps; | ||||
} fir_t; | } fir_t; | ||||
struct aptdec_t { | |||||
struct aptdec { | |||||
float sample_rate; | float sample_rate; | ||||
float sync_frequency; | float sync_frequency; | ||||
@@ -62,7 +62,7 @@ struct aptdec_t { | |||||
fir_t *hilbert; | fir_t *hilbert; | ||||
float low_pass[LOW_PASS_SIZE]; | float low_pass[LOW_PASS_SIZE]; | ||||
float row_buffer[APT_IMG_WIDTH + SYNC_SIZE + 2]; | |||||
float row_buffer[APTDEC_IMG_WIDTH + SYNC_SIZE + 2]; | |||||
float interpolator_buffer[APTDEC_BUFFER_SIZE]; | float interpolator_buffer[APTDEC_BUFFER_SIZE]; | ||||
size_t interpolator_n; | size_t interpolator_n; | ||||
@@ -100,15 +100,15 @@ pll_t *pll_init(float alpha, float beta, float min_freq, float max_freq, float s | |||||
} | } | ||||
aptdec_t *aptdec_init(float sample_rate) { | aptdec_t *aptdec_init(float sample_rate) { | ||||
if (sample_rate > 96000 || sample_rate < (CARRIER_FREQ + APT_IMG_WIDTH) * 2.0f) { | |||||
if (sample_rate > 96000 || sample_rate < (CARRIER_FREQ + APTDEC_IMG_WIDTH) * 2.0f) { | |||||
return NULL; | return NULL; | ||||
} | } | ||||
aptdec_t *apt = calloc(1, sizeof(aptdec_t)); | |||||
apt->sample_rate = sample_rate; | |||||
apt->sync_frequency = 1.0f; | |||||
apt->interpolator_n = APTDEC_BUFFER_SIZE; | |||||
apt->interpolator_offset = 0.0f; | |||||
aptdec_t *aptdec = calloc(1, sizeof(aptdec_t)); | |||||
aptdec->sample_rate = sample_rate; | |||||
aptdec->sync_frequency = 1.0f; | |||||
aptdec->interpolator_n = APTDEC_BUFFER_SIZE; | |||||
aptdec->interpolator_offset = 0.0f; | |||||
// PLL configuration | // PLL configuration | ||||
// https://www.trondeau.com/blog/2011/8/13/control-loop-gain-values.html | // https://www.trondeau.com/blog/2011/8/13/control-loop-gain-values.html | ||||
@@ -116,30 +116,30 @@ aptdec_t *aptdec_init(float sample_rate) { | |||||
float bw = 0.005f; | float bw = 0.005f; | ||||
float alpha = (4.0f * damp * bw) / (1.0f + 2.0f * damp * bw + bw * bw); | float alpha = (4.0f * damp * bw) / (1.0f + 2.0f * damp * bw + bw * bw); | ||||
float beta = (4.0f * bw * bw) / (1.0f + 2.0f * damp * bw + bw * bw); | float beta = (4.0f * bw * bw) / (1.0f + 2.0f * damp * bw + bw * bw); | ||||
apt->pll = pll_init(alpha, beta, CARRIER_FREQ-MAX_CARRIER_OFFSET, CARRIER_FREQ+MAX_CARRIER_OFFSET, sample_rate); | |||||
if (apt->pll == NULL) { | |||||
free(apt); | |||||
aptdec->pll = pll_init(alpha, beta, CARRIER_FREQ-MAX_CARRIER_OFFSET, CARRIER_FREQ+MAX_CARRIER_OFFSET, sample_rate); | |||||
if (aptdec->pll == NULL) { | |||||
free(aptdec); | |||||
return NULL; | return NULL; | ||||
} | } | ||||
// Hilbert transform | // Hilbert transform | ||||
apt->hilbert = fir_init(APTDEC_BUFFER_SIZE, 31); | |||||
if (apt->hilbert == NULL) { | |||||
free(apt->pll); | |||||
free(apt); | |||||
aptdec->hilbert = fir_init(APTDEC_BUFFER_SIZE, 31); | |||||
if (aptdec->hilbert == NULL) { | |||||
free(aptdec->pll); | |||||
free(aptdec); | |||||
return NULL; | return NULL; | ||||
} | } | ||||
design_hilbert(apt->hilbert->taps, apt->hilbert->ntaps); | |||||
design_hilbert(aptdec->hilbert->taps, aptdec->hilbert->ntaps); | |||||
design_low_pass(apt->low_pass, apt->sample_rate, (2080.0f + CARRIER_FREQ) / 2.0f, LOW_PASS_SIZE); | |||||
design_low_pass(aptdec->low_pass, aptdec->sample_rate, (2080.0f + CARRIER_FREQ) / 2.0f, LOW_PASS_SIZE); | |||||
return apt; | |||||
return aptdec; | |||||
} | } | ||||
void aptdec_free(aptdec_t *apt) { | |||||
fir_free(apt->hilbert); | |||||
free(apt->pll); | |||||
free(apt); | |||||
void aptdec_free(aptdec_t *aptdec) { | |||||
fir_free(aptdec->hilbert); | |||||
free(aptdec->pll); | |||||
free(aptdec); | |||||
} | } | ||||
static complexf_t pll_work(pll_t *pll, complexf_t in) { | static complexf_t pll_work(pll_t *pll, complexf_t in) { | ||||
@@ -159,52 +159,52 @@ static complexf_t pll_work(pll_t *pll, complexf_t in) { | |||||
return in; | return in; | ||||
} | } | ||||
static int am_demod(aptdec_t *apt, float *out, size_t count, aptdec_callback_t callback, void *context) { | |||||
size_t read = callback(&apt->hilbert->ring_buffer[apt->hilbert->ntaps], count, context); | |||||
static int am_demod(aptdec_t *aptdec, float *out, size_t count, aptdec_callback_t callback, void *context) { | |||||
size_t read = callback(&aptdec->hilbert->ring_buffer[aptdec->hilbert->ntaps], count, context); | |||||
for (size_t i = 0; i < read; i++) { | for (size_t i = 0; i < read; i++) { | ||||
complexf_t sample = hilbert_transform(&apt->hilbert->ring_buffer[i], apt->hilbert->taps, apt->hilbert->ntaps); | |||||
out[i] = crealf(pll_work(apt->pll, sample)); | |||||
complexf_t sample = hilbert_transform(&aptdec->hilbert->ring_buffer[i], aptdec->hilbert->taps, aptdec->hilbert->ntaps); | |||||
out[i] = crealf(pll_work(aptdec->pll, sample)); | |||||
} | } | ||||
memcpy(apt->hilbert->ring_buffer, &apt->hilbert->ring_buffer[read], apt->hilbert->ntaps*sizeof(float)); | |||||
memcpy(aptdec->hilbert->ring_buffer, &aptdec->hilbert->ring_buffer[read], aptdec->hilbert->ntaps*sizeof(float)); | |||||
return read; | return read; | ||||
} | } | ||||
static int get_pixels(aptdec_t *apt, float *out, size_t count, aptdec_callback_t callback, void *context) { | |||||
float ratio = apt->sample_rate / (4160.0f * apt->sync_frequency); | |||||
static int get_pixels(aptdec_t *aptdec, float *out, size_t count, aptdec_callback_t callback, void *context) { | |||||
float ratio = aptdec->sample_rate / (4160.0f * aptdec->sync_frequency); | |||||
for (size_t i = 0; i < count; i++) { | for (size_t i = 0; i < count; i++) { | ||||
// Get more samples if there are less than `LOW_PASS_SIZE` available | // Get more samples if there are less than `LOW_PASS_SIZE` available | ||||
if (apt->interpolator_n + LOW_PASS_SIZE > APTDEC_BUFFER_SIZE) { | |||||
memcpy(apt->interpolator_buffer, &apt->interpolator_buffer[apt->interpolator_n], (APTDEC_BUFFER_SIZE-apt->interpolator_n) * sizeof(float)); | |||||
if (aptdec->interpolator_n + LOW_PASS_SIZE > APTDEC_BUFFER_SIZE) { | |||||
memcpy(aptdec->interpolator_buffer, &aptdec->interpolator_buffer[aptdec->interpolator_n], (APTDEC_BUFFER_SIZE-aptdec->interpolator_n) * sizeof(float)); | |||||
size_t read = am_demod(apt, &apt->interpolator_buffer[APTDEC_BUFFER_SIZE-apt->interpolator_n], apt->interpolator_n, callback, context); | |||||
if (read != apt->interpolator_n) { | |||||
size_t read = am_demod(aptdec, &aptdec->interpolator_buffer[APTDEC_BUFFER_SIZE-aptdec->interpolator_n], aptdec->interpolator_n, callback, context); | |||||
if (read != aptdec->interpolator_n) { | |||||
return i; | return i; | ||||
} | } | ||||
apt->interpolator_n = 0; | |||||
aptdec->interpolator_n = 0; | |||||
} | } | ||||
out[i] = interpolating_convolve(&apt->interpolator_buffer[apt->interpolator_n], apt->low_pass, LOW_PASS_SIZE, apt->interpolator_offset); | |||||
out[i] = interpolating_convolve(&aptdec->interpolator_buffer[aptdec->interpolator_n], aptdec->low_pass, LOW_PASS_SIZE, aptdec->interpolator_offset); | |||||
// Do not question the sacred code | // Do not question the sacred code | ||||
int shift = ceilf(ratio - apt->interpolator_offset); | |||||
apt->interpolator_offset = shift + apt->interpolator_offset - ratio; | |||||
apt->interpolator_n += shift; | |||||
int shift = ceilf(ratio - aptdec->interpolator_offset); | |||||
aptdec->interpolator_offset = shift + aptdec->interpolator_offset - ratio; | |||||
aptdec->interpolator_n += shift; | |||||
} | } | ||||
return count; | return count; | ||||
} | } | ||||
// Get an entire row of pixels, aligned with sync markers | // Get an entire row of pixels, aligned with sync markers | ||||
int aptdec_getrow(aptdec_t *apt, float *row, aptdec_callback_t callback, void *context) { | |||||
int aptdec_getrow(aptdec_t *aptdec, float *row, aptdec_callback_t callback, void *context) { | |||||
// Wrap the circular buffer | // Wrap the circular buffer | ||||
memcpy(apt->row_buffer, &apt->row_buffer[APT_IMG_WIDTH], (SYNC_SIZE + 2) * sizeof(float)); | |||||
memcpy(aptdec->row_buffer, &aptdec->row_buffer[APTDEC_IMG_WIDTH], (SYNC_SIZE + 2) * sizeof(float)); | |||||
// Get a lines worth (APT_IMG_WIDTH) of samples | |||||
if (get_pixels(apt, &apt->row_buffer[SYNC_SIZE + 2], APT_IMG_WIDTH, callback, context) != APT_IMG_WIDTH) { | |||||
// Get a lines worth (APTDEC_IMG_WIDTH) of samples | |||||
if (get_pixels(aptdec, &aptdec->row_buffer[SYNC_SIZE + 2], APTDEC_IMG_WIDTH, callback, context) != APTDEC_IMG_WIDTH) { | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -214,10 +214,10 @@ int aptdec_getrow(aptdec_t *apt, float *row, aptdec_callback_t callback, void *c | |||||
float right = FLT_MIN; | float right = FLT_MIN; | ||||
size_t phase = 0; | size_t phase = 0; | ||||
for (size_t i = 0; i < APT_IMG_WIDTH; i++) { | |||||
float _left = convolve(&apt->row_buffer[i + 0], sync_pattern, SYNC_SIZE); | |||||
float _middle = convolve(&apt->row_buffer[i + 1], sync_pattern, SYNC_SIZE); | |||||
float _right = convolve(&apt->row_buffer[i + 2], sync_pattern, SYNC_SIZE); | |||||
for (size_t i = 0; i < APTDEC_IMG_WIDTH; i++) { | |||||
float _left = convolve(&aptdec->row_buffer[i + 0], sync_pattern, SYNC_SIZE); | |||||
float _middle = convolve(&aptdec->row_buffer[i + 1], sync_pattern, SYNC_SIZE); | |||||
float _right = convolve(&aptdec->row_buffer[i + 2], sync_pattern, SYNC_SIZE); | |||||
if (_middle > middle) { | if (_middle > middle) { | ||||
left = _left; | left = _left; | ||||
middle = _middle; | middle = _middle; | ||||
@@ -228,11 +228,11 @@ int aptdec_getrow(aptdec_t *apt, float *row, aptdec_callback_t callback, void *c | |||||
// Frequency | // Frequency | ||||
float bias = (left / middle) - (right / middle); | float bias = (left / middle) - (right / middle); | ||||
apt->sync_frequency = 1.0f + bias / APT_IMG_WIDTH / 4.0f; | |||||
aptdec->sync_frequency = 1.0f + bias / APTDEC_IMG_WIDTH / 4.0f; | |||||
// Phase | // Phase | ||||
memcpy(&row[APT_IMG_WIDTH], &apt->row_buffer[phase], (APT_IMG_WIDTH - phase) * sizeof(float)); | |||||
memcpy(&row[APT_IMG_WIDTH - phase], apt->row_buffer, phase * sizeof(float)); | |||||
memcpy(&row[APTDEC_IMG_WIDTH], &aptdec->row_buffer[phase], (APTDEC_IMG_WIDTH - phase) * sizeof(float)); | |||||
memcpy(&row[APTDEC_IMG_WIDTH - phase], aptdec->row_buffer, phase * sizeof(float)); | |||||
return 1; | return 1; | ||||
} | } |
@@ -26,12 +26,12 @@ | |||||
#include "util.h" | #include "util.h" | ||||
#include "filter.h" | #include "filter.h" | ||||
void apt_equalize(apt_image_t *img, apt_region_t region) { | |||||
void aptdec_equalize(aptdec_image_t *img, aptdec_region_t region) { | |||||
// Plot histogram | // Plot histogram | ||||
size_t histogram[256] = {0}; | size_t histogram[256] = {0}; | ||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
for (size_t x = 0; x < region.width; x++) { | for (size_t x = 0; x < region.width; x++) { | ||||
histogram[img->data[y * APT_IMG_WIDTH + x + region.offset]]++; | |||||
histogram[img->data[y * APTDEC_IMG_WIDTH + x + region.offset]]++; | |||||
} | } | ||||
} | } | ||||
@@ -46,8 +46,8 @@ void apt_equalize(apt_image_t *img, apt_region_t region) { | |||||
int area = img->rows * region.width; | int area = img->rows * region.width; | ||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
for (size_t x = 0; x < region.width; x++) { | for (size_t x = 0; x < region.width; x++) { | ||||
int k = (int)img->data[y * APT_IMG_WIDTH + x + region.offset]; | |||||
img->data[y * APT_IMG_WIDTH + x + region.offset] = (255.0f / area) * cf[k]; | |||||
int k = (int)img->data[y * APTDEC_IMG_WIDTH + x + region.offset]; | |||||
img->data[y * APTDEC_IMG_WIDTH + x + region.offset] = (255.0f / area) * cf[k]; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -56,18 +56,18 @@ void apt_equalize(apt_image_t *img, apt_region_t region) { | |||||
static void image_apply_linear(uint8_t *data, int rows, int offset, int width, linear_t regr) { | static void image_apply_linear(uint8_t *data, int rows, int offset, int width, linear_t regr) { | ||||
for (int y = 0; y < rows; y++) { | for (int y = 0; y < rows; y++) { | ||||
for (int x = 0; x < width; x++) { | for (int x = 0; x < width; x++) { | ||||
float pv = linear_calc(data[y * APT_IMG_WIDTH + x + offset], regr); | |||||
data[y * APT_IMG_WIDTH + x + offset] = clamp_int(roundf(pv), 0, 255); | |||||
float pv = linear_calc(data[y * APTDEC_IMG_WIDTH + x + offset], regr); | |||||
data[y * APTDEC_IMG_WIDTH + x + offset] = clamp_int(roundf(pv), 0, 255); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
void apt_stretch(apt_image_t *img, apt_region_t region) { | |||||
void aptdec_stretch(aptdec_image_t *img, aptdec_region_t region) { | |||||
// Plot histogram | // Plot histogram | ||||
size_t histogram[256] = { 0 }; | size_t histogram[256] = { 0 }; | ||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
for (size_t x = 0; x < region.width; x++) { | for (size_t x = 0; x < region.width; x++) { | ||||
histogram[img->data[y*APT_IMG_WIDTH + x + region.offset]]++; | |||||
histogram[img->data[y*APTDEC_IMG_WIDTH + x + region.offset]]++; | |||||
} | } | ||||
} | } | ||||
@@ -99,32 +99,32 @@ void apt_stretch(apt_image_t *img, apt_region_t region) { | |||||
// Median denoise (with deviation threshold) | // Median denoise (with deviation threshold) | ||||
void apt_denoise(apt_image_t *img, apt_region_t region) { | |||||
void aptdec_denoise(aptdec_image_t *img, aptdec_region_t region) { | |||||
for (size_t y = 1; y < img->rows - 1; y++) { | for (size_t y = 1; y < img->rows - 1; y++) { | ||||
for (size_t x = 1; x < region.width - 1; x++) { | for (size_t x = 1; x < region.width - 1; x++) { | ||||
float pixels[9] = { 0.0f }; | float pixels[9] = { 0.0f }; | ||||
int pixeln = 0; | int pixeln = 0; | ||||
for (int y2 = -1; y2 < 2; y2++) { | for (int y2 = -1; y2 < 2; y2++) { | ||||
for (int x2 = -1; x2 < 2; x2++) { | for (int x2 = -1; x2 < 2; x2++) { | ||||
pixels[pixeln++] = img->data[(y + y2) * APT_IMG_WIDTH + (x + region.offset) + x2]; | |||||
pixels[pixeln++] = img->data[(y + y2) * APTDEC_IMG_WIDTH + (x + region.offset) + x2]; | |||||
} | } | ||||
} | } | ||||
if (standard_deviation(pixels, 9) > 15) { | if (standard_deviation(pixels, 9) > 15) { | ||||
img->data[y * APT_IMG_WIDTH + x + region.offset] = medianf(pixels, 9); | |||||
img->data[y * APTDEC_IMG_WIDTH + x + region.offset] = medianf(pixels, 9); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Flips a channel, for northbound passes | // Flips a channel, for northbound passes | ||||
void apt_flip(apt_image_t *img, apt_region_t region) { | |||||
void aptdec_flip(aptdec_image_t *img, aptdec_region_t region) { | |||||
for (size_t y = 1; y < img->rows; y++) { | for (size_t y = 1; y < img->rows; y++) { | ||||
for (int x = 1; x < ceil(region.width / 2.0f); x++) { | for (int x = 1; x < ceil(region.width / 2.0f); x++) { | ||||
// Flip top-left & bottom-right | // Flip top-left & bottom-right | ||||
swap_uint8( | swap_uint8( | ||||
&img->data[(img->rows - y) * APT_IMG_WIDTH + region.offset + x], | |||||
&img->data[y * APT_IMG_WIDTH + region.offset + (region.width - x)] | |||||
&img->data[(img->rows - y) * APTDEC_IMG_WIDTH + region.offset + x], | |||||
&img->data[y * APTDEC_IMG_WIDTH + region.offset + (region.width - x)] | |||||
); | ); | ||||
} | } | ||||
} | } | ||||
@@ -135,7 +135,7 @@ void apt_flip(apt_image_t *img, apt_region_t region) { | |||||
#include "filter.h" | #include "filter.h" | ||||
int apt_crop(apt_image_t *img) { | |||||
int aptdec_crop(aptdec_image_t *img) { | |||||
const float sync_pattern[] = {-1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, | const float sync_pattern[] = {-1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, | ||||
1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 0}; | 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 0}; | ||||
@@ -146,7 +146,7 @@ int apt_crop(apt_image_t *img) { | |||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
float temp[39] = { 0.0f }; | float temp[39] = { 0.0f }; | ||||
for (size_t i = 0; i < 39; i++) { | for (size_t i = 0; i < 39; i++) { | ||||
temp[i] = img->data[y * APT_IMG_WIDTH + i]; | |||||
temp[i] = img->data[y * APTDEC_IMG_WIDTH + i]; | |||||
} | } | ||||
spc_rows[y] = convolve(temp, &sync_pattern[0], 39); | spc_rows[y] = convolve(temp, &sync_pattern[0], 39); | ||||
@@ -170,7 +170,7 @@ int apt_crop(apt_image_t *img) { | |||||
img->rows = (endCrop - startCrop); | img->rows = (endCrop - startCrop); | ||||
// Remove the noisy rows at start | // Remove the noisy rows at start | ||||
memmove(img->data, &img->data[startCrop * APT_IMG_WIDTH], img->rows * APT_IMG_WIDTH * sizeof(float)); | |||||
memmove(img->data, &img->data[startCrop * APTDEC_IMG_WIDTH], img->rows * APTDEC_IMG_WIDTH * sizeof(float)); | |||||
free(spc_rows); | free(spc_rows); | ||||
return startCrop; | return startCrop; | ||||
@@ -27,12 +27,12 @@ | |||||
#include "util.h" | #include "util.h" | ||||
#include "calibration.h" | #include "calibration.h" | ||||
#define APT_COUNT_RATIO (1023.0f/255.0f) | |||||
#define APTDEC_COUNT_RATIO (1023.0f/255.0f) | |||||
apt_image_t apt_image_clone(apt_image_t img) { | |||||
apt_image_t _img = img; | |||||
_img.data = calloc(APT_IMG_WIDTH * img.rows, sizeof(uint8_t)); | |||||
memcpy(_img.data, img.data, APT_IMG_WIDTH * img.rows); | |||||
aptdec_image_t aptdec_image_clone(aptdec_image_t img) { | |||||
aptdec_image_t _img = img; | |||||
_img.data = calloc(APTDEC_IMG_WIDTH * img.rows, sizeof(uint8_t)); | |||||
memcpy(_img.data, img.data, APTDEC_IMG_WIDTH * img.rows); | |||||
return _img; | return _img; | ||||
} | } | ||||
@@ -40,29 +40,29 @@ static void decode_telemetry(const float *data, size_t rows, size_t offset, floa | |||||
// Calculate row average | // Calculate row average | ||||
float *telemetry_rows = calloc(rows, sizeof(float)); | float *telemetry_rows = calloc(rows, sizeof(float)); | ||||
for (size_t y = 0; y < rows; y++) { | for (size_t y = 0; y < rows; y++) { | ||||
telemetry_rows[y] = meanf(&data[y*APT_IMG_WIDTH + offset + APT_CH_WIDTH], APT_TELEMETRY_WIDTH); | |||||
telemetry_rows[y] = meanf(&data[y*APTDEC_IMG_WIDTH + offset + APTDEC_CH_WIDTH], APTDEC_TELEMETRY_WIDTH); | |||||
} | } | ||||
// Calculate relative telemetry offset (via step detection, i.e. wedge 8 to 9) | // Calculate relative telemetry offset (via step detection, i.e. wedge 8 to 9) | ||||
size_t telemetry_offset = 0; | size_t telemetry_offset = 0; | ||||
float max_difference = 0.0f; | float max_difference = 0.0f; | ||||
for (size_t y = APT_WEDGE_HEIGHT; y <= rows - APT_WEDGE_HEIGHT; y++) { | |||||
float difference = sumf(&telemetry_rows[y - APT_WEDGE_HEIGHT], APT_WEDGE_HEIGHT) - sumf(&telemetry_rows[y], APT_WEDGE_HEIGHT); | |||||
for (size_t y = APTDEC_WEDGE_HEIGHT; y <= rows - APTDEC_WEDGE_HEIGHT; y++) { | |||||
float difference = sumf(&telemetry_rows[y - APTDEC_WEDGE_HEIGHT], APTDEC_WEDGE_HEIGHT) - sumf(&telemetry_rows[y], APTDEC_WEDGE_HEIGHT); | |||||
// Find the maximum difference | // Find the maximum difference | ||||
if (difference > max_difference) { | if (difference > max_difference) { | ||||
max_difference = difference; | max_difference = difference; | ||||
telemetry_offset = (y + 64) % APT_FRAME_LEN; | |||||
telemetry_offset = (y + 64) % APTDEC_FRAME_LEN; | |||||
} | } | ||||
} | } | ||||
// Find the least noisy frame (via standard deviation) | // Find the least noisy frame (via standard deviation) | ||||
float best_noise = FLT_MAX; | float best_noise = FLT_MAX; | ||||
size_t best_frame = 0; | size_t best_frame = 0; | ||||
for (size_t y = telemetry_offset; y < rows-APT_FRAME_LEN; y += APT_FRAME_LEN) { | |||||
for (size_t y = telemetry_offset; y < rows-APTDEC_FRAME_LEN; y += APTDEC_FRAME_LEN) { | |||||
float noise = 0.0f; | float noise = 0.0f; | ||||
for (size_t i = 0; i < APT_FRAME_WEDGES; i++) { | |||||
noise += standard_deviation(&telemetry_rows[y + i*APT_WEDGE_HEIGHT], APT_WEDGE_HEIGHT); | |||||
for (size_t i = 0; i < APTDEC_FRAME_WEDGES; i++) { | |||||
noise += standard_deviation(&telemetry_rows[y + i*APTDEC_WEDGE_HEIGHT], APTDEC_WEDGE_HEIGHT); | |||||
} | } | ||||
if (noise < best_noise) { | if (noise < best_noise) { | ||||
@@ -71,22 +71,22 @@ static void decode_telemetry(const float *data, size_t rows, size_t offset, floa | |||||
} | } | ||||
} | } | ||||
for (size_t i = 0; i < APT_FRAME_WEDGES; i++) { | |||||
wedges[i] = meanf(&telemetry_rows[best_frame + i*APT_WEDGE_HEIGHT], APT_WEDGE_HEIGHT); | |||||
for (size_t i = 0; i < APTDEC_FRAME_WEDGES; i++) { | |||||
wedges[i] = meanf(&telemetry_rows[best_frame + i*APTDEC_WEDGE_HEIGHT], APTDEC_WEDGE_HEIGHT); | |||||
} | } | ||||
free(telemetry_rows); | free(telemetry_rows); | ||||
} | } | ||||
static float average_spc(apt_image_t *img, size_t offset) { | |||||
static float average_spc(aptdec_image_t *img, size_t offset) { | |||||
float *rows = calloc(img->rows, sizeof(float)); | float *rows = calloc(img->rows, sizeof(float)); | ||||
float average = 0.0f; | float average = 0.0f; | ||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
float row_average = 0.0f; | float row_average = 0.0f; | ||||
for (size_t x = 0; x < APT_SPC_WIDTH; x++) { | |||||
row_average += img->data[y*APT_IMG_WIDTH + offset - APT_SPC_WIDTH + x]; | |||||
for (size_t x = 0; x < APTDEC_SPC_WIDTH; x++) { | |||||
row_average += img->data[y*APTDEC_IMG_WIDTH + offset - APTDEC_SPC_WIDTH + x]; | |||||
} | } | ||||
row_average /= (float)APT_SPC_WIDTH; | |||||
row_average /= (float)APTDEC_SPC_WIDTH; | |||||
rows[y] = row_average; | rows[y] = row_average; | ||||
average += row_average; | average += row_average; | ||||
@@ -106,8 +106,8 @@ static float average_spc(apt_image_t *img, size_t offset) { | |||||
return weighted_average / (float)n; | return weighted_average / (float)n; | ||||
} | } | ||||
apt_image_t apt_normalize(const float *data, size_t rows, apt_satellite_t satellite, int *error) { | |||||
apt_image_t img; | |||||
aptdec_image_t aptdec_normalize(const float *data, size_t rows, aptdec_satellite_t satellite, int *error) { | |||||
aptdec_image_t img; | |||||
img.rows = rows; | img.rows = rows; | ||||
img.satellite = satellite; | img.satellite = satellite; | ||||
@@ -118,12 +118,12 @@ apt_image_t apt_normalize(const float *data, size_t rows, apt_satellite_t satell | |||||
} | } | ||||
// Decode and average wedges | // Decode and average wedges | ||||
float wedges[APT_FRAME_WEDGES]; | |||||
float wedges_cha[APT_FRAME_WEDGES]; | |||||
float wedges_chb[APT_FRAME_WEDGES]; | |||||
decode_telemetry(data, rows, APT_CHA_OFFSET, wedges_cha); | |||||
decode_telemetry(data, rows, APT_CHB_OFFSET, wedges_chb); | |||||
for (size_t i = 0; i < APT_FRAME_WEDGES; i++) { | |||||
float wedges[APTDEC_FRAME_WEDGES]; | |||||
float wedges_cha[APTDEC_FRAME_WEDGES]; | |||||
float wedges_chb[APTDEC_FRAME_WEDGES]; | |||||
decode_telemetry(data, rows, APTDEC_CHA_OFFSET, wedges_cha); | |||||
decode_telemetry(data, rows, APTDEC_CHB_OFFSET, wedges_chb); | |||||
for (size_t i = 0; i < APTDEC_FRAME_WEDGES; i++) { | |||||
wedges[i] = (wedges_cha[i] + wedges_chb[i]) / 2.0f; | wedges[i] = (wedges_cha[i] + wedges_chb[i]) / 2.0f; | ||||
} | } | ||||
@@ -136,7 +136,7 @@ apt_image_t apt_normalize(const float *data, size_t rows, apt_satellite_t satell | |||||
} | } | ||||
// Normalize telemetry | // Normalize telemetry | ||||
for (size_t i = 0; i < APT_FRAME_WEDGES; i++) { | |||||
for (size_t i = 0; i < APTDEC_FRAME_WEDGES; i++) { | |||||
img.telemetry[0][i] = linear_calc(wedges_cha[i], normalization); | img.telemetry[0][i] = linear_calc(wedges_cha[i], normalization); | ||||
img.telemetry[1][i] = linear_calc(wedges_chb[i], normalization); | img.telemetry[1][i] = linear_calc(wedges_chb[i], normalization); | ||||
} | } | ||||
@@ -148,20 +148,20 @@ apt_image_t apt_normalize(const float *data, size_t rows, apt_satellite_t satell | |||||
if (img.ch[1] < 1 || img.ch[1] > 6) img.ch[1] = AVHRR_CHANNEL_UNKNOWN; | if (img.ch[1] < 1 || img.ch[1] > 6) img.ch[1] = AVHRR_CHANNEL_UNKNOWN; | ||||
// Normalize and quantize image data | // Normalize and quantize image data | ||||
img.data = (uint8_t *)malloc(rows * APT_IMG_WIDTH); | |||||
for (size_t i = 0; i < rows * APT_IMG_WIDTH; i++) { | |||||
img.data = (uint8_t *)malloc(rows * APTDEC_IMG_WIDTH); | |||||
for (size_t i = 0; i < rows * APTDEC_IMG_WIDTH; i++) { | |||||
float count = linear_calc(data[i], normalization); | float count = linear_calc(data[i], normalization); | ||||
img.data[i] = clamp_int(roundf(count), 0, 255); | img.data[i] = clamp_int(roundf(count), 0, 255); | ||||
} | } | ||||
// Get space brightness | // Get space brightness | ||||
img.space_view[0] = average_spc(&img, APT_CHA_OFFSET); | |||||
img.space_view[1] = average_spc(&img, APT_CHB_OFFSET); | |||||
img.space_view[0] = average_spc(&img, APTDEC_CHA_OFFSET); | |||||
img.space_view[1] = average_spc(&img, APTDEC_CHB_OFFSET); | |||||
return img; | return img; | ||||
} | } | ||||
static void make_thermal_lut(apt_image_t *img, avhrr_channel_t ch, int satellite, float *lut) { | |||||
static void make_thermal_lut(aptdec_image_t *img, avhrr_channel_t ch, int satellite, float *lut) { | |||||
ch -= 4; | ch -= 4; | ||||
const calibration_t calibration = get_calibration(satellite); | const calibration_t calibration = get_calibration(satellite); | ||||
const float Ns = calibration.cor[ch].Ns; | const float Ns = calibration.cor[ch].Ns; | ||||
@@ -172,7 +172,7 @@ static void make_thermal_lut(apt_image_t *img, avhrr_channel_t ch, int satellite | |||||
// Compute PRT temperature | // Compute PRT temperature | ||||
float T[4] = { 0.0f }; | float T[4] = { 0.0f }; | ||||
for (size_t n = 0; n < 4; n++) { | for (size_t n = 0; n < 4; n++) { | ||||
T[n] = quadratic_calc(img->telemetry[1][n + 9] * APT_COUNT_RATIO, calibration.prt[n]); | |||||
T[n] = quadratic_calc(img->telemetry[1][n + 9] * APTDEC_COUNT_RATIO, calibration.prt[n]); | |||||
} | } | ||||
float Tbb = meanf(T, 4); // Blackbody temperature | float Tbb = meanf(T, 4); // Blackbody temperature | ||||
@@ -180,11 +180,11 @@ static void make_thermal_lut(apt_image_t *img, avhrr_channel_t ch, int satellite | |||||
float Nbb = C1 * pow(Vc, 3) / (expf(C2 * Vc / Tbbstar) - 1.0f); // Blackbody radiance | float Nbb = C1 * pow(Vc, 3) / (expf(C2 * Vc / Tbbstar) - 1.0f); // Blackbody radiance | ||||
float Cs = img->space_view[1] * APT_COUNT_RATIO; | |||||
float Cb = img->telemetry[1][14] * APT_COUNT_RATIO; | |||||
float Cs = img->space_view[1] * APTDEC_COUNT_RATIO; | |||||
float Cb = img->telemetry[1][14] * APTDEC_COUNT_RATIO; | |||||
for (size_t i = 0; i < 256; i++) { | for (size_t i = 0; i < 256; i++) { | ||||
float Nl = Ns + (Nbb - Ns) * (Cs - i * APT_COUNT_RATIO) / (Cs - Cb); // Linear radiance estimate | |||||
float Nl = Ns + (Nbb - Ns) * (Cs - i * APTDEC_COUNT_RATIO) / (Cs - Cb); // Linear radiance estimate | |||||
float Nc = quadratic_calc(Nl, calibration.cor[ch].quadratic); // Non-linear correction | float Nc = quadratic_calc(Nl, calibration.cor[ch].quadratic); // Non-linear correction | ||||
float Ne = Nl + Nc; // Corrected radiance | float Ne = Nl + Nc; // Corrected radiance | ||||
@@ -196,7 +196,7 @@ static void make_thermal_lut(apt_image_t *img, avhrr_channel_t ch, int satellite | |||||
} | } | ||||
} | } | ||||
int apt_calibrate_thermal(apt_image_t *img, apt_region_t region) { | |||||
int aptdec_calibrate_thermal(aptdec_image_t *img, aptdec_region_t region) { | |||||
if (img->ch[1] != AVHRR_CHANNEL_4 && img->ch[1] != AVHRR_CHANNEL_5 && img->ch[1] != AVHRR_CHANNEL_3B) { | if (img->ch[1] != AVHRR_CHANNEL_4 && img->ch[1] != AVHRR_CHANNEL_5 && img->ch[1] != AVHRR_CHANNEL_3B) { | ||||
return 1; | return 1; | ||||
} | } | ||||
@@ -206,8 +206,8 @@ int apt_calibrate_thermal(apt_image_t *img, apt_region_t region) { | |||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
for (size_t x = 0; x < region.width; x++) { | for (size_t x = 0; x < region.width; x++) { | ||||
float temperature = lut[img->data[y * APT_IMG_WIDTH + region.offset + x]]; | |||||
img->data[y * APT_IMG_WIDTH + region.offset + x] = clamp_int(roundf((temperature + 100.0) / 160.0 * 255.0), 0, 255); | |||||
float temperature = lut[img->data[y * APTDEC_IMG_WIDTH + region.offset + x]]; | |||||
img->data[y * APTDEC_IMG_WIDTH + region.offset + x] = clamp_int(roundf((temperature + 100.0) / 160.0 * 255.0), 0, 255); | |||||
} | } | ||||
} | } | ||||
@@ -216,13 +216,13 @@ int apt_calibrate_thermal(apt_image_t *img, apt_region_t region) { | |||||
static float calibrate_pixel_visible(float value, int channel, calibration_t cal) { | static float calibrate_pixel_visible(float value, int channel, calibration_t cal) { | ||||
if (value > cal.visible[channel].cutoff) { | if (value > cal.visible[channel].cutoff) { | ||||
return linear_calc(value * APT_COUNT_RATIO, cal.visible[channel].high) / 100.0f * 255.0f; | |||||
return linear_calc(value * APTDEC_COUNT_RATIO, cal.visible[channel].high) / 100.0f * 255.0f; | |||||
} else { | } else { | ||||
return linear_calc(value * APT_COUNT_RATIO, cal.visible[channel].low) / 100.0f * 255.0f; | |||||
return linear_calc(value * APTDEC_COUNT_RATIO, cal.visible[channel].low) / 100.0f * 255.0f; | |||||
} | } | ||||
} | } | ||||
int apt_calibrate_visible(apt_image_t *img, apt_region_t region) { | |||||
int aptdec_calibrate_visible(aptdec_image_t *img, aptdec_region_t region) { | |||||
if (img->ch[0] != AVHRR_CHANNEL_1 && img->ch[0] != AVHRR_CHANNEL_2) { | if (img->ch[0] != AVHRR_CHANNEL_1 && img->ch[0] != AVHRR_CHANNEL_2) { | ||||
return 1; | return 1; | ||||
} | } | ||||
@@ -230,10 +230,17 @@ int apt_calibrate_visible(apt_image_t *img, apt_region_t region) { | |||||
calibration_t calibration = get_calibration(img->satellite); | calibration_t calibration = get_calibration(img->satellite); | ||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
for (size_t x = 0; x < region.width; x++) { | for (size_t x = 0; x < region.width; x++) { | ||||
float albedo = calibrate_pixel_visible(img->data[y * APT_IMG_WIDTH + region.offset + x], img->ch[0]-1, calibration); | |||||
img->data[y * APT_IMG_WIDTH + region.offset + x] = clamp_int(roundf(albedo), 0, 255); | |||||
float albedo = calibrate_pixel_visible(img->data[y * APTDEC_IMG_WIDTH + region.offset + x], img->ch[0]-1, calibration); | |||||
img->data[y * APTDEC_IMG_WIDTH + region.offset + x] = clamp_int(roundf(albedo), 0, 255); | |||||
} | } | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
void aptdec_strip(aptdec_image_t* img) { | |||||
for (size_t y = 0; y < img->rows; y++) { | |||||
memcpy(&img->data[y*APTDEC_IMG_WIDTH], &img->data[y*APTDEC_IMG_WIDTH + APTDEC_CHA_OFFSET], APTDEC_CH_WIDTH); | |||||
memcpy(&img->data[y*APTDEC_IMG_WIDTH + APTDEC_CH_WIDTH], &img->data[y*APTDEC_IMG_WIDTH + APTDEC_CHB_OFFSET], APTDEC_CH_WIDTH); | |||||
} | |||||
} |
@@ -40,30 +40,30 @@ extern "C" { | |||||
#endif | #endif | ||||
// Height of a single telemetry wedge | // Height of a single telemetry wedge | ||||
#define APT_WEDGE_HEIGHT 8 | |||||
#define APTDEC_WEDGE_HEIGHT 8 | |||||
// Numbers of wedges in a frame | // Numbers of wedges in a frame | ||||
#define APT_FRAME_WEDGES 16 | |||||
#define APTDEC_FRAME_WEDGES 16 | |||||
// Height of a telemetry frame | // Height of a telemetry frame | ||||
#define APT_FRAME_LEN (APT_WEDGE_HEIGHT * APT_FRAME_WEDGES) | |||||
#define APTDEC_FRAME_LEN (APTDEC_WEDGE_HEIGHT * APTDEC_FRAME_WEDGES) | |||||
// Width of the overall image | // Width of the overall image | ||||
#define APT_IMG_WIDTH 2080 | |||||
#define APTDEC_IMG_WIDTH 2080 | |||||
// Width of sync marker | // Width of sync marker | ||||
#define APT_SYNC_WIDTH 39 | |||||
#define APTDEC_SYNC_WIDTH 39 | |||||
// Width of space view | // Width of space view | ||||
#define APT_SPC_WIDTH 47 | |||||
#define APTDEC_SPC_WIDTH 47 | |||||
// Width of telemetry | // Width of telemetry | ||||
#define APT_TELEMETRY_WIDTH 45 | |||||
#define APTDEC_TELEMETRY_WIDTH 45 | |||||
// Width of a single video channel | // Width of a single video channel | ||||
#define APT_CH_WIDTH 909 | |||||
#define APTDEC_CH_WIDTH 909 | |||||
// Offset to channel A video data | // Offset to channel A video data | ||||
#define APT_CHA_OFFSET (APT_SYNC_WIDTH + APT_SPC_WIDTH) | |||||
#define APTDEC_CHA_OFFSET (APTDEC_SYNC_WIDTH + APTDEC_SPC_WIDTH) | |||||
// Offset to channel B video data | // Offset to channel B video data | ||||
#define APT_CHB_OFFSET (APT_SYNC_WIDTH + APT_SPC_WIDTH + APT_CH_WIDTH + APT_TELEMETRY_WIDTH + APT_SYNC_WIDTH + APT_SPC_WIDTH) | |||||
#define APTDEC_CHB_OFFSET (APTDEC_SYNC_WIDTH + APTDEC_SPC_WIDTH + APTDEC_CH_WIDTH + APTDEC_TELEMETRY_WIDTH + APTDEC_SYNC_WIDTH + APTDEC_SPC_WIDTH) | |||||
// Number of rows needed for apt_normalize to (reliably) work | |||||
#define APTDEC_NORMALIZE_ROWS (APT_FRAME_LEN * 2) | |||||
// Number of rows needed for aptdec_normalize to (reliably) work | |||||
#define APTDEC_NORMALIZE_ROWS (APTDEC_FRAME_LEN * 2) | |||||
// Maximum amount of samples that will be requested from aptdec_callback_t | // Maximum amount of samples that will be requested from aptdec_callback_t | ||||
#define APTDEC_BUFFER_SIZE 16384 | #define APTDEC_BUFFER_SIZE 16384 | ||||
@@ -73,7 +73,7 @@ extern "C" { | |||||
// Channel 3B: mid-infrared (3.55-3.93 um) | // Channel 3B: mid-infrared (3.55-3.93 um) | ||||
// Channel 4: thermal-infrared (10.3-11.3 um) | // Channel 4: thermal-infrared (10.3-11.3 um) | ||||
// Channel 5: thermal-infrared (11.5-12.5 um) | // Channel 5: thermal-infrared (11.5-12.5 um) | ||||
typedef enum apt_channel { | |||||
typedef enum aptdec_channel { | |||||
AVHRR_CHANNEL_UNKNOWN, | AVHRR_CHANNEL_UNKNOWN, | ||||
AVHRR_CHANNEL_1, | AVHRR_CHANNEL_1, | ||||
AVHRR_CHANNEL_2, | AVHRR_CHANNEL_2, | ||||
@@ -83,41 +83,41 @@ typedef enum apt_channel { | |||||
AVHRR_CHANNEL_3B | AVHRR_CHANNEL_3B | ||||
} avhrr_channel_t; | } avhrr_channel_t; | ||||
typedef enum apt_satellite { | |||||
typedef enum aptdec_satellite { | |||||
NOAA15, | NOAA15, | ||||
NOAA18, | NOAA18, | ||||
NOAA19 | NOAA19 | ||||
} apt_satellite_t; | |||||
} aptdec_satellite_t; | |||||
typedef struct { | |||||
typedef struct aptdec_image { | |||||
uint8_t *data; // Image data | uint8_t *data; // Image data | ||||
size_t rows; // Number of rows | size_t rows; // Number of rows | ||||
// Telemetry | // Telemetry | ||||
apt_satellite_t satellite; | |||||
aptdec_satellite_t satellite; | |||||
avhrr_channel_t ch[2]; | avhrr_channel_t ch[2]; | ||||
float space_view[2]; | float space_view[2]; | ||||
float telemetry[2][16]; | float telemetry[2][16]; | ||||
} apt_image_t; | |||||
} aptdec_image_t; | |||||
typedef struct { | |||||
typedef struct aptdec_rgb { | |||||
uint8_t r, g, b; | uint8_t r, g, b; | ||||
} apt_rgb_t; | |||||
} aptdec_rgb_t; | |||||
typedef struct { | |||||
typedef struct aptdec_region { | |||||
size_t offset; | size_t offset; | ||||
size_t width; | size_t width; | ||||
} apt_region_t; | |||||
} aptdec_region_t; | |||||
typedef struct aptdec_t aptdec_t; | |||||
typedef struct aptdec aptdec_t; | |||||
// Callback function to get samples | // Callback function to get samples | ||||
// `context` is the same as passed to aptdec_getrow | // `context` is the same as passed to aptdec_getrow | ||||
typedef size_t (*aptdec_callback_t)(float *samples, size_t count, void *context); | typedef size_t (*aptdec_callback_t)(float *samples, size_t count, void *context); | ||||
// Clone an apt_image_t struct | |||||
// Clone an aptdec_image_t struct | |||||
// Useful for calibration | // Useful for calibration | ||||
APTDEC_API apt_image_t apt_image_clone(apt_image_t img); | |||||
APTDEC_API aptdec_image_t aptdec_image_clone(aptdec_image_t img); | |||||
// Returns version of libaptdec in git tag format | // Returns version of libaptdec in git tag format | ||||
// i.e. v2.0.0 or v2.0.0-1-xxxxxx | // i.e. v2.0.0 or v2.0.0-1-xxxxxx | ||||
@@ -126,43 +126,44 @@ APTDEC_API char *aptdec_get_version(void); | |||||
// Create and destroy libaptdec instances | // Create and destroy libaptdec instances | ||||
// If aptdec_init fails it will return NULL | // If aptdec_init fails it will return NULL | ||||
APTDEC_API aptdec_t *aptdec_init(float sample_rate); | APTDEC_API aptdec_t *aptdec_init(float sample_rate); | ||||
APTDEC_API void aptdec_free(aptdec_t *apt); | |||||
APTDEC_API void aptdec_free(aptdec_t *aptdec); | |||||
// Normalize and quantize raw image data | // Normalize and quantize raw image data | ||||
// Data is arranged so that each row starts at APT_IMG_WIDTH*y | |||||
APTDEC_API apt_image_t apt_normalize(const float *data, size_t rows, apt_satellite_t satellite, int *error); | |||||
// Data is arranged so that each row starts at APTDEC_IMG_WIDTH*y | |||||
APTDEC_API aptdec_image_t aptdec_normalize(const float *data, size_t rows, aptdec_satellite_t satellite, int *error); | |||||
// Get an entire row of pixels | // Get an entire row of pixels | ||||
// Requires that `row` has enough space to store APT_IMG_WIDTH*2 | |||||
// Requires that `row` has enough space to store APTDEC_IMG_WIDTH*2 | |||||
// Returns 0 when `callback` return value != count | // Returns 0 when `callback` return value != count | ||||
APTDEC_API int aptdec_getrow(aptdec_t *apt, float *row, aptdec_callback_t callback, void *context); | |||||
APTDEC_API int aptdec_getrow(aptdec_t *aptdec, float *row, aptdec_callback_t callback, void *context); | |||||
// Calibrate channels | // Calibrate channels | ||||
APTDEC_API int apt_calibrate_thermal(apt_image_t *img, apt_region_t region); | |||||
APTDEC_API int apt_calibrate_visible(apt_image_t *img, apt_region_t region); | |||||
APTDEC_API int aptdec_calibrate_thermal(aptdec_image_t *img, aptdec_region_t region); | |||||
APTDEC_API int aptdec_calibrate_visible(aptdec_image_t *img, aptdec_region_t region); | |||||
APTDEC_API void apt_denoise (apt_image_t *img, apt_region_t region); | |||||
APTDEC_API void apt_flip (apt_image_t *img, apt_region_t region); | |||||
APTDEC_API void apt_stretch (apt_image_t *img, apt_region_t region); | |||||
APTDEC_API void apt_equalize(apt_image_t *img, apt_region_t region); | |||||
APTDEC_API int apt_crop (apt_image_t *img); | |||||
APTDEC_API void aptdec_denoise (aptdec_image_t *img, aptdec_region_t region); | |||||
APTDEC_API void aptdec_flip (aptdec_image_t *img, aptdec_region_t region); | |||||
APTDEC_API void aptdec_stretch (aptdec_image_t *img, aptdec_region_t region); | |||||
APTDEC_API void aptdec_equalize(aptdec_image_t *img, aptdec_region_t region); | |||||
APTDEC_API int aptdec_crop (aptdec_image_t *img); | |||||
APTDEC_API void aptdec_strip (aptdec_image_t* img); | |||||
// Composite two RGB values as layers, in most cases bottom_a will be 1.0f | // Composite two RGB values as layers, in most cases bottom_a will be 1.0f | ||||
APTDEC_API apt_rgb_t apt_composite_rgb(apt_rgb_t top, float top_a, apt_rgb_t bottom, float bottom_a); | |||||
APTDEC_API aptdec_rgb_t aptdec_composite_rgb(aptdec_rgb_t top, float top_a, aptdec_rgb_t bottom, float bottom_a); | |||||
// Apply a gradient such as temperature_gradient | |||||
// Apply a gradient such as aptdec_temperature_gradient | |||||
// If gradient is less than 256 elements it is the callers responsibility | // If gradient is less than 256 elements it is the callers responsibility | ||||
// that `val` does not exceed the length of the gradient | // that `val` does not exceed the length of the gradient | ||||
APTDEC_API apt_rgb_t apt_gradient(const uint32_t *gradient, uint8_t val); | |||||
APTDEC_API aptdec_rgb_t aptdec_gradient(const uint32_t *gradient, uint8_t val); | |||||
static const apt_region_t APT_REGION_CHA = { APT_CHA_OFFSET, APT_CH_WIDTH }; | |||||
static const apt_region_t APT_REGION_CHB = { APT_CHB_OFFSET, APT_CH_WIDTH }; | |||||
static const apt_region_t APT_REGION_CHA_FULL = { 0, APT_IMG_WIDTH/2 }; | |||||
static const apt_region_t APT_REGION_CHB_FULL = { APT_IMG_WIDTH/2, APT_IMG_WIDTH/2 }; | |||||
static const apt_region_t APT_REGION_FULL = { 0, APT_IMG_WIDTH }; | |||||
static const aptdec_region_t APTDEC_REGION_CHA = { APTDEC_CHA_OFFSET, APTDEC_CH_WIDTH }; | |||||
static const aptdec_region_t APTDEC_REGION_CHB = { APTDEC_CHB_OFFSET, APTDEC_CH_WIDTH }; | |||||
static const aptdec_region_t APTDEC_REGION_CHA_FULL = { 0, APTDEC_IMG_WIDTH/2 }; | |||||
static const aptdec_region_t APTDEC_REGION_CHB_FULL = { APTDEC_IMG_WIDTH/2, APTDEC_IMG_WIDTH/2 }; | |||||
static const aptdec_region_t APTDEC_REGION_FULL = { 0, APTDEC_IMG_WIDTH }; | |||||
APTDEC_API extern const uint32_t temperature_gradient[256]; | |||||
APTDEC_API extern const uint32_t precipitation_gradient[58]; | |||||
APTDEC_API extern const uint32_t aptdec_temperature_gradient[256]; | |||||
APTDEC_API extern const uint32_t aptdec_precipitation_gradient[58]; | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||