diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b59dae..936782e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) 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}) file(GLOB LUTS luts/*.png) install(FILES ${LUTS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/aptdec/luts) @@ -75,6 +80,10 @@ else() target_link_libraries(aptdec PRIVATE m) target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers) 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}) diff --git a/aptdec-cli/main.c b/aptdec-cli/main.c index c9da9e0..de76ce6 100644 --- a/aptdec-cli/main.c +++ b/aptdec-cli/main.c @@ -67,7 +67,6 @@ static int freq_from_filename(const char *filename); static int satid_from_freq(int freq); static size_t callback(float *samples, size_t count, void *context); 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); static volatile int sigint_stop = 0; @@ -183,7 +182,7 @@ static int process_file(const char *path, options_t *opts) { if (opts->realtime) { char filename[269] = { 0 }; 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 signal(SIGINT, sigint_handler); @@ -209,10 +208,10 @@ static int process_file(const char *path, options_t *opts) { } // 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; 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 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) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" write_line(realtime_png, row); +#pragma GCC diagnostic pop } 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 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); if (error) { 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++) { if (strcmp(effects[i], "crop") == 0) { - apt_crop(&img); + aptdec_crop(&img); } 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) { - 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]]); // 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); 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]]); // 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_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++) { 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) { - 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; 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); free(_img.data); } 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_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)); 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_free(writer); } @@ -405,12 +408,13 @@ static int process_file(const char *path, options_t *opts) { writer_t *writer; 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); free(_img.data); } 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_free(writer); @@ -422,12 +426,13 @@ static int process_file(const char *path, options_t *opts) { writer_t *writer; 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); free(_img.data); } 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_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) { float min = FLT_MAX; 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] > 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); } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 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) { diff --git a/aptdec-cli/pngio.c b/aptdec-cli/pngio.c index c60feaf..cf83b2f 100644 --- a/aptdec-cli/pngio.c +++ b/aptdec-cli/pngio.c @@ -24,7 +24,7 @@ #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)); png->region = region; @@ -64,17 +64,17 @@ writer_t *writer_init(const char *filename, apt_region_t region, uint32_t height 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++) { - 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++) { - 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 }; } @@ -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++) { - 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]; } diff --git a/aptdec-cli/pngio.h b/aptdec-cli/pngio.h index e71d632..c4b2c91 100644 --- a/aptdec-cli/pngio.h +++ b/aptdec-cli/pngio.h @@ -26,15 +26,15 @@ typedef struct { png_structp png; png_infop info; FILE *file; - apt_region_t region; + aptdec_region_t region; } 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_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); diff --git a/libaptdec/calibration.c b/libaptdec/calibration.c index 0bec609..443aedc 100644 --- a/libaptdec/calibration.c +++ b/libaptdec/calibration.c @@ -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) { case NOAA15: return calibration[0]; case NOAA18: return calibration[1]; diff --git a/libaptdec/calibration.h b/libaptdec/calibration.h index 46313e2..1050241 100644 --- a/libaptdec/calibration.h +++ b/libaptdec/calibration.h @@ -52,6 +52,6 @@ static const float C1 = 1.1910427e-5f; // Second radiation constant (cm-K) static const float C2 = 1.4387752f; -calibration_t get_calibration(apt_satellite_t satid); +calibration_t get_calibration(aptdec_satellite_t satid); #endif diff --git a/libaptdec/color.c b/libaptdec/color.c index 43bacb2..befd854 100644 --- a/libaptdec/color.c +++ b/libaptdec/color.c @@ -23,16 +23,16 @@ // 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] & 0x0000FF00) >> 8, (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.g, top_alpha, bottom.g, 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 -const uint32_t temperature_gradient[256] = { +const uint32_t aptdec_temperature_gradient[256] = { 0x45008F, 0x460091, 0x470092, 0x480094, 0x490096, 0x4A0098, 0x4B009B, 0x4D009D, 0x4E00A0, 0x5000A2, 0x5100A5, 0x5200A7, 0x5400AA, 0x5600AE, 0x5700B1, 0x5800B4, 0x5A00B7, 0x5C00BA, 0x5E00BD, 0x5F00C0, 0x6100C4, @@ -81,7 +81,7 @@ const uint32_t temperature_gradient[256] = { }; // Taken from WXtoImg -const uint32_t precipitation_gradient[58] = { +const uint32_t aptdec_precipitation_gradient[58] = { 0x088941, 0x00C544, 0x00D12C, 0x00E31C, 0x00F906, 0x14FF00, 0x3EFF00, 0x5DFF00, 0x80FF00, 0xABFF00, 0xCDFE00, 0xF8FF00, 0xFFE600, 0xFFB800, 0xFF9800, 0xFF7500, 0xFF4900, 0xFE2600, 0xFF0400, 0xDF0000, 0xA80000, diff --git a/libaptdec/dsp.c b/libaptdec/dsp.c index c82a412..d0eef34 100644 --- a/libaptdec/dsp.c +++ b/libaptdec/dsp.c @@ -54,7 +54,7 @@ typedef struct { size_t ntaps; } fir_t; -struct aptdec_t { +struct aptdec { float sample_rate; float sync_frequency; @@ -62,7 +62,7 @@ struct aptdec_t { fir_t *hilbert; 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]; 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) { - 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; } - 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 // 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 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); - 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; } // 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; } - 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) { @@ -159,52 +159,52 @@ static complexf_t pll_work(pll_t *pll, complexf_t 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++) { - 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; } -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++) { // 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; } - 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 - 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; } // 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 - 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; } @@ -214,10 +214,10 @@ int aptdec_getrow(aptdec_t *apt, float *row, aptdec_callback_t callback, void *c float right = FLT_MIN; 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) { left = _left; middle = _middle; @@ -228,11 +228,11 @@ int aptdec_getrow(aptdec_t *apt, float *row, aptdec_callback_t callback, void *c // Frequency 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 - 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; } diff --git a/libaptdec/effects.c b/libaptdec/effects.c index 1afec32..37b875d 100644 --- a/libaptdec/effects.c +++ b/libaptdec/effects.c @@ -26,12 +26,12 @@ #include "util.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 size_t histogram[256] = {0}; for (size_t y = 0; y < img->rows; y++) { 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; for (size_t y = 0; y < img->rows; y++) { 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) { for (int y = 0; y < rows; y++) { 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 size_t histogram[256] = { 0 }; for (size_t y = 0; y < img->rows; y++) { 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) -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 x = 1; x < region.width - 1; x++) { float pixels[9] = { 0.0f }; int pixeln = 0; for (int y2 = -1; y2 < 2; y2++) { 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) { - 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 -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 (int x = 1; x < ceil(region.width / 2.0f); x++) { // Flip top-left & bottom-right 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" -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, 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++) { float temp[39] = { 0.0f }; 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); @@ -170,7 +170,7 @@ int apt_crop(apt_image_t *img) { img->rows = (endCrop - startCrop); // 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); return startCrop; diff --git a/libaptdec/image.c b/libaptdec/image.c index e6498bd..b3a878d 100644 --- a/libaptdec/image.c +++ b/libaptdec/image.c @@ -27,12 +27,12 @@ #include "util.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; } @@ -40,29 +40,29 @@ static void decode_telemetry(const float *data, size_t rows, size_t offset, floa // Calculate row average float *telemetry_rows = calloc(rows, sizeof(float)); 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) size_t telemetry_offset = 0; 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 if (difference > max_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) float best_noise = FLT_MAX; 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; - 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) { @@ -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); } -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 average = 0.0f; for (size_t y = 0; y < img->rows; y++) { 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; average += row_average; @@ -106,8 +106,8 @@ static float average_spc(apt_image_t *img, size_t offset) { 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.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 - 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; } @@ -136,7 +136,7 @@ apt_image_t apt_normalize(const float *data, size_t rows, apt_satellite_t satell } // 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[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; // 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); img.data[i] = clamp_int(roundf(count), 0, 255); } // 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; } -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; const calibration_t calibration = get_calibration(satellite); 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 float T[4] = { 0.0f }; 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 @@ -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 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++) { - 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 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) { 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 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) { 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 { - 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) { 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); for (size_t y = 0; y < img->rows; y++) { 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; } + +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); + } +} diff --git a/libaptdec/include/aptdec.h b/libaptdec/include/aptdec.h index 9d3cc5b..a730c5e 100644 --- a/libaptdec/include/aptdec.h +++ b/libaptdec/include/aptdec.h @@ -40,30 +40,30 @@ extern "C" { #endif // Height of a single telemetry wedge -#define APT_WEDGE_HEIGHT 8 +#define APTDEC_WEDGE_HEIGHT 8 // Numbers of wedges in a frame -#define APT_FRAME_WEDGES 16 +#define APTDEC_FRAME_WEDGES 16 // 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 -#define APT_IMG_WIDTH 2080 +#define APTDEC_IMG_WIDTH 2080 // Width of sync marker -#define APT_SYNC_WIDTH 39 +#define APTDEC_SYNC_WIDTH 39 // Width of space view -#define APT_SPC_WIDTH 47 +#define APTDEC_SPC_WIDTH 47 // Width of telemetry -#define APT_TELEMETRY_WIDTH 45 +#define APTDEC_TELEMETRY_WIDTH 45 // Width of a single video channel -#define APT_CH_WIDTH 909 +#define APTDEC_CH_WIDTH 909 // 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 -#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 #define APTDEC_BUFFER_SIZE 16384 @@ -73,7 +73,7 @@ extern "C" { // Channel 3B: mid-infrared (3.55-3.93 um) // Channel 4: thermal-infrared (10.3-11.3 um) // Channel 5: thermal-infrared (11.5-12.5 um) -typedef enum apt_channel { +typedef enum aptdec_channel { AVHRR_CHANNEL_UNKNOWN, AVHRR_CHANNEL_1, AVHRR_CHANNEL_2, @@ -83,41 +83,41 @@ typedef enum apt_channel { AVHRR_CHANNEL_3B } avhrr_channel_t; -typedef enum apt_satellite { +typedef enum aptdec_satellite { NOAA15, NOAA18, NOAA19 -} apt_satellite_t; +} aptdec_satellite_t; -typedef struct { +typedef struct aptdec_image { uint8_t *data; // Image data size_t rows; // Number of rows // Telemetry - apt_satellite_t satellite; + aptdec_satellite_t satellite; avhrr_channel_t ch[2]; float space_view[2]; float telemetry[2][16]; -} apt_image_t; +} aptdec_image_t; -typedef struct { +typedef struct aptdec_rgb { uint8_t r, g, b; -} apt_rgb_t; +} aptdec_rgb_t; -typedef struct { +typedef struct aptdec_region { size_t offset; 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 // `context` is the same as passed to aptdec_getrow 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 -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 // 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 // If aptdec_init fails it will return NULL 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 -// 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 -// 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 -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 -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 -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 // 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 }