You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4 vuotta sitten
21 vuotta sitten
21 vuotta sitten
21 vuotta sitten
21 vuotta sitten
19 vuotta sitten
21 vuotta sitten
19 vuotta sitten
21 vuotta sitten
21 vuotta sitten
21 vuotta sitten
19 vuotta sitten
21 vuotta sitten
21 vuotta sitten
21 vuotta sitten
21 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * This file is part of Aptdec.
  3. * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2020
  4. *
  5. * Aptdec is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <getopt.h>
  23. #include <libgen.h>
  24. #include <math.h>
  25. #include <sndfile.h>
  26. #include <errno.h>
  27. #include "messages.h"
  28. #include "offsets.h"
  29. #define FAILURE 0
  30. #define SUCCESS 1
  31. typedef struct {
  32. char *type; // Output image type
  33. char *effects;
  34. int satnum; // The satellite number
  35. char *map; // Path to a map file
  36. char *path; // Output directory
  37. } options_t;
  38. typedef struct {
  39. float *prow[3000]; // Row buffers
  40. int nrow; // Number of rows
  41. int chA, chB; // ID of each channel
  42. char name[256]; // Stripped filename
  43. } image_t;
  44. // DSP
  45. extern int getpixelrow(float *pixelv, int nrow, int *zenith);
  46. extern int init_dsp(double F);
  47. // I/O
  48. extern int readfcconf(char *file);
  49. extern int readRawImage(char *filename, float **prow, int *nrow);
  50. extern int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char *chid, char *palette);
  51. // Image functions
  52. extern int calibrate(float **prow, int nrow, int offset, int width);
  53. extern void histogramEqualise(float **prow, int nrow, int offset, int width);
  54. extern void temperature(options_t *opts, image_t *img, int offset, int width);
  55. extern int Ngvi(float **prow, int nrow);
  56. extern void denoise(float **prow, int nrow, int offset, int width);
  57. extern void distrib(options_t *opts, image_t *img, char *chid);
  58. // Palettes
  59. extern char GviPalette[256*3];
  60. extern char TempPalette[256*3];
  61. // Row where the satellite is closest to the observer
  62. int zenith = 0;
  63. // Audio file
  64. static SNDFILE *audioFile;
  65. static int initsnd(char *filename);
  66. int getsample(float *sample, int nb);
  67. static int processAudio(char *filename, options_t *opts);
  68. static void usage(void);
  69. int main(int argc, char **argv) {
  70. fprintf(stderr, VERSION"\n");
  71. if(argc == 1)
  72. usage();
  73. // Check if there are actually any input files
  74. if(optind == argc){
  75. fprintf(stderr, "No input files provided.\n");
  76. usage();
  77. }
  78. options_t opts = { "r", "", 19, "", "." };
  79. // Parse arguments
  80. int opt;
  81. while ((opt = getopt(argc, argv, "c:m:d:i:s:e:")) != EOF) {
  82. switch (opt) {
  83. case 'd':
  84. opts.path = optarg;
  85. break;
  86. case 'c':
  87. readfcconf(optarg);
  88. break;
  89. case 'm':
  90. opts.map = optarg;
  91. break;
  92. case 'i':
  93. opts.type = optarg;
  94. break;
  95. case 's':
  96. opts.satnum = atoi(optarg);
  97. if(opts.satnum < 15 || opts.satnum > 19){
  98. fprintf(stderr, "Invalid satellite number, it must be the range 15-19\n");
  99. exit(EPERM);
  100. }
  101. break;
  102. case 'e':
  103. opts.effects = optarg;
  104. break;
  105. default:
  106. usage();
  107. }
  108. }
  109. // Process the files
  110. for (; optind < argc; optind++) {
  111. processAudio(argv[optind], &opts);
  112. }
  113. exit(0);
  114. }
  115. static int processAudio(char *filename, options_t *opts){
  116. // Image info struct
  117. image_t img;
  118. // Mapping between wedge value and channel ID
  119. static struct {
  120. char *id[7];
  121. char *name[7];
  122. } ch = {
  123. { "?", "1", "2", "3A", "4", "5", "3B" },
  124. { "unknown", "visble", "near-infrared", "mid-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" }
  125. };
  126. // Buffer for image channel
  127. char desc[60];
  128. // Parse file path
  129. char path[256], extension[32];
  130. strcpy(path, filename);
  131. strcpy(path, dirname(path));
  132. sscanf(basename(filename), "%[^.].%s", img.name, extension);
  133. if(strcmp(extension, "png") == 0){
  134. // Read PNG into image buffer
  135. printf("Reading %s", filename);
  136. if(readRawImage(filename, img.prow, &img.nrow) == 0){
  137. fprintf(stderr, "Skipping %s; see above.\n", img.name);
  138. return FAILURE;
  139. }
  140. }else{
  141. // Attempt to open the audio file
  142. if (initsnd(filename) == 0)
  143. exit(EPERM);
  144. // Build image
  145. for (img.nrow = 0; img.nrow < 3000; img.nrow++) {
  146. // Allocate memory for this row
  147. img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150);
  148. // Write into memory and break the loop when there are no more samples to read
  149. if (getpixelrow(img.prow[img.nrow], img.nrow, &zenith) == 0)
  150. break;
  151. fprintf(stderr, "Row: %d\r", img.nrow);
  152. fflush(stderr);
  153. }
  154. // Close stream
  155. sf_close(audioFile);
  156. }
  157. printf("\nTotal rows: %d\n", img.nrow);
  158. // Fallback for detecting the zenith
  159. // TODO: encode zenith in raw images
  160. if(opts->map != NULL && opts->map[0] != '\0' && zenith == 0){
  161. fprintf(stderr, "Guessing zenith in image, map will most likely be misaligned.\n");
  162. zenith = img.nrow / 2;
  163. }
  164. // Calibrate
  165. img.chA = calibrate(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  166. img.chB = calibrate(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  167. printf("Channel A: %s (%s)\n", ch.id[img.chA], ch.name[img.chA]);
  168. printf("Channel B: %s (%s)\n", ch.id[img.chB], ch.name[img.chB]);
  169. // Denoise
  170. if(CONTAINS(opts->effects, 'd')){
  171. denoise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  172. denoise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  173. }
  174. // Temperature
  175. if (CONTAINS(opts->type, 't') && img.chB >= 4) {
  176. temperature(opts, &img, CHB_OFFSET, CH_WIDTH);
  177. ImageOut(opts, &img, CHB_OFFSET, CH_WIDTH, "Temperature", "t", (char *)TempPalette);
  178. }
  179. // False color image
  180. if(CONTAINS(opts->type, 'c')){
  181. if (img.chA == 2 && img.chB >= 4) { // Normal false color
  182. // TODO: use real MSA
  183. // TODO: provide more than just "natural" color images
  184. ImageOut(opts, &img, 0, CH_WIDTH, "False Color", "c", NULL);
  185. } else if (img.chB == 2) { // GVI (global vegetation index) false color
  186. Ngvi(img.prow, img.nrow);
  187. ImageOut(opts, &img, CHB_OFFSET, CH_WIDTH, "GVI False Color", "c", (char *)GviPalette);
  188. } else {
  189. fprintf(stderr, "Skipping False Color generation; lacking required channels.\n");
  190. }
  191. }
  192. // MCIR
  193. if (CONTAINS(opts->type, 'm'))
  194. ImageOut(opts, &img, 0, IMG_WIDTH, "MCIR", "m", NULL);
  195. // Histogram equalise
  196. if(CONTAINS(opts->effects, 'h')){
  197. histogramEqualise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  198. histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  199. }
  200. // Raw image
  201. if (CONTAINS(opts->type, 'r')) {
  202. sprintf(desc, "%s (%s) & %s (%s)", ch.id[img.chA], ch.name[img.chA], ch.id[img.chB], ch.name[img.chB]);
  203. ImageOut(opts, &img, 0, IMG_WIDTH, desc, "r", NULL);
  204. }
  205. // Channel A
  206. if (CONTAINS(opts->type, 'a')) {
  207. sprintf(desc, "%s (%s)", ch.id[img.chA], ch.name[img.chA]);
  208. ImageOut(opts, &img, CHA_OFFSET, CH_WIDTH, desc, ch.id[img.chA], NULL);
  209. }
  210. // Channel B
  211. if (CONTAINS(opts->type, 'b')) {
  212. sprintf(desc, "%s (%s)", ch.id[img.chB], ch.name[img.chB]);
  213. ImageOut(opts, &img, CHB_OFFSET, CH_WIDTH, desc, ch.id[img.chA], NULL);
  214. }
  215. // Distribution image
  216. if (CONTAINS(opts->type, 'd'))
  217. distrib(opts, &img, "d");
  218. return SUCCESS;
  219. }
  220. static int initsnd(char *filename) {
  221. SF_INFO infwav;
  222. int res;
  223. // Open audio file
  224. infwav.format = 0;
  225. audioFile = sf_open(filename, SFM_READ, &infwav);
  226. if (audioFile == NULL) {
  227. fprintf(stderr, ERR_FILE_READ, filename);
  228. return FAILURE;
  229. }
  230. res = init_dsp(infwav.samplerate);
  231. printf("Input file: %s\n", filename);
  232. if(res < 0) {
  233. fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate);
  234. return FAILURE;
  235. }else if(res > 0) {
  236. fprintf(stderr, "Input sample rate too high: %d\n", infwav.samplerate);
  237. return FAILURE;
  238. }
  239. printf("Input sample rate: %d\n", infwav.samplerate);
  240. // TODO: accept stereo audio
  241. if (infwav.channels != 1) {
  242. fprintf(stderr, "Too many channels in input file: %d\n", infwav.channels);
  243. return FAILURE;
  244. }
  245. return SUCCESS;
  246. }
  247. // Read samples from the wave file
  248. int getsample(float *sample, int nb) {
  249. return sf_read_float(audioFile, sample, nb);
  250. }
  251. static void usage(void) {
  252. fprintf(stderr,
  253. "Aptdec [options] audio files ...\n"
  254. "Options:\n"
  255. " -e [t|h] Effects\n"
  256. " t: Crop telemetry\n"
  257. " h: Histogram equalise\n"
  258. " d: Denoise\n"
  259. " p: Precipitation\n"
  260. " -i [r|a|b|c|t] Output image\n"
  261. " r: Raw\n"
  262. " a: Channel A\n"
  263. " b: Channel B\n"
  264. " c: False color\n"
  265. " t: Temperature\n"
  266. " m: MCIR\n"
  267. " -d <dir> Image destination directory.\n"
  268. " -s [15-19] Satellite number\n"
  269. " -c <file> False color config file\n"
  270. " -m <file> Map file\n");
  271. exit(EINVAL);
  272. }