您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

498 行
14 KiB

  1. /*
  2. * Aptdec
  3. * Copyright (c) 2004-2005 by Thierry Leconte (F4DWV)
  4. *
  5. * $Id$
  6. *
  7. * This library is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Library General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. *
  21. */
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <getopt.h>
  26. #include <libgen.h>
  27. #include <math.h>
  28. #include <sndfile.h>
  29. #include <png.h>
  30. #include "messages.h"
  31. #include "offsets.h"
  32. #include "colorpalette.h"
  33. extern int getpixelrow(float *pixelv);
  34. extern int init_dsp(double F);;
  35. static SNDFILE *inwav;
  36. static int initsnd(char *filename) {
  37. SF_INFO infwav;
  38. int res;
  39. // Open audio file
  40. infwav.format = 0;
  41. inwav = sf_open(filename, SFM_READ, &infwav);
  42. if (inwav == NULL) {
  43. fprintf(stderr, ERR_FILE_READ, filename);
  44. return(0);
  45. }
  46. res = init_dsp(infwav.samplerate);
  47. printf("Input file: %s\n", filename);
  48. if(res < 0) {
  49. fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate);
  50. return(0);
  51. }else if(res > 0) {
  52. fprintf(stderr, "Input sample rate too high: %d\n", infwav.samplerate);
  53. return(0);
  54. }
  55. printf("Input sample rate: %d\n", infwav.samplerate);
  56. if (infwav.channels != 1) {
  57. fprintf(stderr, "Too many channels in input file: %d\n", infwav.channels);
  58. return(0);
  59. }
  60. return(1);
  61. }
  62. // Get a sample from the wave file
  63. int getsample(float *sample, int nb) {
  64. return sf_read_float(inwav, sample, nb);
  65. }
  66. static png_text text_ptr[] = {
  67. {PNG_TEXT_COMPRESSION_NONE, "Software", VERSION},
  68. {PNG_TEXT_COMPRESSION_NONE, "Channel", NULL, 0},
  69. {PNG_TEXT_COMPRESSION_NONE, "Description", "NOAA satellite image", 20}
  70. };
  71. static int ImageOut(char *filename, char *chid, float **prow, int nrow, int width, int offset, png_color *palette, int croptele, int layered) {
  72. FILE *pngfile;
  73. png_infop info_ptr;
  74. png_structp png_ptr;
  75. // Reduce the width of the image to componsate for the missing telemetry
  76. if(croptele) width -= TOTAL_TELE;
  77. // Initalise the PNG writer
  78. png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  79. if (!png_ptr) {
  80. fprintf(stderr, ERR_PNG_WRITE);
  81. return(0);
  82. }
  83. // Metadata
  84. info_ptr = png_create_info_struct(png_ptr);
  85. if (!info_ptr) {
  86. png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
  87. fprintf(stderr, ERR_PNG_INFO);
  88. return(0);
  89. }
  90. if(palette == NULL) {
  91. // Greyscale image
  92. png_set_IHDR(png_ptr, info_ptr, width, nrow,
  93. 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
  94. PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  95. } else {
  96. // Palleted color image
  97. png_set_IHDR(png_ptr, info_ptr, width, nrow,
  98. 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
  99. PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  100. png_set_PLTE(png_ptr, info_ptr, palette, 256);
  101. }
  102. text_ptr[1].text = chid;
  103. text_ptr[1].text_length = strlen(chid);
  104. png_set_text(png_ptr, info_ptr, text_ptr, 3);
  105. png_set_pHYs(png_ptr, info_ptr, 4000, 4000, PNG_RESOLUTION_METER);
  106. printf("Writing %s ", filename);
  107. fflush(stdout);
  108. pngfile = fopen(filename, "wb");
  109. if (pngfile == NULL) {
  110. fprintf(stderr, ERR_FILE_WRITE, filename);
  111. return(1);
  112. }
  113. png_init_io(png_ptr, pngfile);
  114. png_write_info(png_ptr, info_ptr);
  115. for (int n = 0; n < nrow; n++) {
  116. float *pixelv;
  117. png_byte pixel[2*IMG_WIDTH];
  118. pixelv = prow[n];
  119. int f = 0;
  120. for (int i = 0; i < width; i++) {
  121. // Skip parts of the image that are telemtry
  122. if(croptele){
  123. switch (i) {
  124. case 0:
  125. f += SYNC_WIDTH + SPC_WIDTH;
  126. break;
  127. case CH_WIDTH:
  128. f += TELE_WIDTH + SYNC_WIDTH + SPC_WIDTH;
  129. break;
  130. case CH_WIDTH*2:
  131. f += TELE_WIDTH;
  132. }
  133. }
  134. if(layered){
  135. // Layered image, overlay highlights in channel B over channel A
  136. float cloud = CLIP(pixelv[i+CHB_OFFSET]-141, 0, 255)/114;
  137. pixel[i] = MCOMPOSITE(255, cloud, pixelv[i+CHA_OFFSET], 1);
  138. }else{
  139. pixel[i] = pixelv[i + offset + f];
  140. }
  141. }
  142. png_write_row(png_ptr, pixel);
  143. }
  144. png_write_end(png_ptr, info_ptr);
  145. fclose(pngfile);
  146. printf("\nDone\n");
  147. png_destroy_write_struct(&png_ptr, &info_ptr);
  148. return(1);
  149. }
  150. static int ImageRGBOut(char *filename, float **prow, int nrow) {
  151. FILE *pngfile;
  152. png_infop info_ptr;
  153. png_structp png_ptr;
  154. extern void falsecolor(float vis, float temp, float *r, float *g, float *b);
  155. // Initalise the PNG writer
  156. png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  157. if (!png_ptr) {
  158. fprintf(stderr, ERR_PNG_WRITE);
  159. return(1);
  160. }
  161. info_ptr = png_create_info_struct(png_ptr);
  162. if (!info_ptr) {
  163. png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
  164. fprintf(stderr, ERR_PNG_WRITE);
  165. return(1);
  166. }
  167. png_set_IHDR(png_ptr, info_ptr, CH_WIDTH, nrow,
  168. 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
  169. PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  170. png_set_pHYs(png_ptr, info_ptr, 4000, 4000, PNG_RESOLUTION_METER);
  171. text_ptr[1].text = "False Color";
  172. text_ptr[1].text_length = strlen(text_ptr[1].text);
  173. png_set_text(png_ptr, info_ptr, text_ptr, 3);
  174. printf("Computing false color & writing: %s", filename);
  175. fflush(stdout);
  176. pngfile = fopen(filename, "wb");
  177. if (pngfile == NULL) {
  178. fprintf(stderr, ERR_FILE_WRITE, filename);
  179. return(1);
  180. }
  181. png_init_io(png_ptr, pngfile);
  182. png_write_info(png_ptr, info_ptr);
  183. for (int n = 0; n < nrow ; n++) {
  184. png_color pix[CH_WIDTH];
  185. float *pixelc;
  186. pixelc = prow[n];
  187. for (int i = 0; i < CH_WIDTH - 1; i++) {
  188. float r = 0, g = 0, b = 0;
  189. // False color computation
  190. falsecolor(pixelc[i+CHA_OFFSET], pixelc[i+CHB_OFFSET], &r, &g, &b);
  191. pix[i].red = r;
  192. pix[i].green = g;
  193. pix[i].blue = b;
  194. }
  195. png_write_row(png_ptr, (png_bytep) pix);
  196. }
  197. png_write_end(png_ptr, info_ptr);
  198. fclose(pngfile);
  199. printf("\nDone\n");
  200. png_destroy_write_struct(&png_ptr, &info_ptr);
  201. return(0);
  202. }
  203. // Distribution of values between Channel A and Channel B
  204. static void Distrib(char *filename, float **prow, int nrow) {
  205. unsigned int distrib[256][256];
  206. int n;
  207. int x, y;
  208. int max = 0;
  209. FILE *df;
  210. for(y = 0; y < 256; y++)
  211. for(x = 0; x < 256; x++)
  212. distrib[y][x] = 0;
  213. for(n = 0; n < nrow; n++) {
  214. float *pixelv;
  215. int i;
  216. pixelv = prow[n];
  217. for(i = 0; i < CH_WIDTH; i++) {
  218. y = (int)(pixelv[i + CHA_OFFSET]);
  219. x = (int)(pixelv[i + CHB_OFFSET]);
  220. distrib[y][x] += 1;
  221. if(distrib[y][x] > max) max=distrib[y][x];
  222. }
  223. }
  224. df = fopen(filename,"w");
  225. printf("Writing %s\n",filename);
  226. fprintf(df,"P2\n#max %d\n",max);
  227. fprintf(df,"256 256\n255\n");
  228. for(y = 0; y < 256; y++)
  229. for(x = 0; x < 256; x++)
  230. fprintf(df, "%d\n", (int)((255.0 * (double)(distrib[y][x])) / (double)max));
  231. fclose(df);
  232. }
  233. extern int calibrate(float **prow, int nrow, int offset, int contrastBoost);
  234. extern void Temperature(float **prow, int nrow, int ch, int offset);
  235. extern int Ngvi(float **prow, int nrow);
  236. extern void readfcconf(char *file);
  237. extern int optind;
  238. extern char *optarg;
  239. // Default to NOAA 19
  240. int satnum = 4;
  241. static void usage(void) {
  242. printf("Aptdec [options] audio files ...\n"
  243. "Options:\n"
  244. " -e [c|t] Enhancements\n"
  245. " c: Contrast enhance\n"
  246. " t: Crop telemetry\n"
  247. " -i [r|a|b|c|t] Output image type\n"
  248. " r: Raw\n"
  249. " a: A channel\n"
  250. " b: B channel\n"
  251. " c: False color\n"
  252. " t: Temperature\n"
  253. " l: Layered\n"
  254. " -d <dir> Image destination directory.\n"
  255. " -s [15-19] Satellite number\n"
  256. " -c <file> False color config file\n");
  257. exit(1);
  258. }
  259. int main(int argc, char **argv) {
  260. char pngfilename[1024];
  261. char name[500];
  262. char pngdirname[500] = "";
  263. // Images to create, default to a channel A and channel B image with contrast enhancement and cropped telemetry
  264. char imgopt[20] = "ab";
  265. char enchancements[20] = "ct";
  266. // Image buffer
  267. float *prow[3000];
  268. int nrow;
  269. // Mapping between wedge value and channel ID
  270. char *chid[] = { "?", "1", "2", "3A", "4", "5", "3B" };
  271. char *chname[] = { "unknown", "visble", "near-infrared", "near-infrared", "thermal-infrared", "thermal-infrared", "thermal-infrared" };
  272. // The active sensor in each channel
  273. int chA, chB;
  274. // Print version
  275. printf("%s\n", VERSION);
  276. // Print usage if there are no arguments
  277. if(argc == 1)
  278. usage();
  279. int c;
  280. while ((c = getopt(argc, argv, "c:d:i:s:e:")) != EOF) {
  281. switch (c) {
  282. // Output directory name
  283. case 'd':
  284. strcpy(pngdirname, optarg);
  285. break;
  286. // False color config file
  287. case 'c':
  288. readfcconf(optarg);
  289. break;
  290. // Output image type
  291. case 'i':
  292. strcpy(imgopt, optarg);
  293. break;
  294. // Satellite number (for calibration)
  295. case 's':
  296. satnum = atoi(optarg)-15;
  297. // Check if it's within the valid range
  298. if (satnum < 0 || satnum > 4) {
  299. fprintf(stderr, "Invalid satellite number, it must be the range [15-19]\n");
  300. exit(1);
  301. }
  302. break;
  303. // Enchancements
  304. case 'e':
  305. strcpy(enchancements, optarg);
  306. break;
  307. default:
  308. usage();
  309. }
  310. }
  311. if(optind == argc){
  312. printf("No audio files provided.\n");
  313. usage();
  314. }
  315. // Pull this in from filtercoeff.h
  316. extern float Sync[32];
  317. // Loop through the provided files
  318. for (; optind < argc; optind++) {
  319. chA = chB = 0;
  320. // Generate output name
  321. strcpy(pngfilename, argv[optind]);
  322. strcpy(name, basename(pngfilename));
  323. strtok(name, ".");
  324. if (pngdirname[0] == '\0')
  325. strcpy(pngdirname, dirname(pngfilename));
  326. // Open sound file, exit if that fails
  327. if (initsnd(argv[optind]) == 0)
  328. exit(1);
  329. // Main image building loop
  330. for (nrow = 0; nrow < 3000; nrow++) {
  331. // Allocate 2150 floats worth of memory for every line of the image
  332. prow[nrow] = (float *) malloc(sizeof(float) * 2150);
  333. // Read into prow and break the loop once we reach the end of the image
  334. if (getpixelrow(prow[nrow]) == 0)
  335. break;
  336. // Signal level
  337. double signal = 0;
  338. for (int i = 0; i < 32; i++) signal += prow[nrow][i] - Sync[i];
  339. // Signal level bar
  340. char bar[30];
  341. for (int i = 0; i < 30; i++) {
  342. bar[i] = ' ';
  343. if(i < signal/2000*30) bar[i] = '#';
  344. }
  345. printf("Row: %d, Signal Strength: %s\r", nrow, bar);
  346. fflush(stdout);
  347. }
  348. printf("\nTotal rows: %d\n", nrow);
  349. sf_close(inwav);
  350. // Layered images require contrast enhancements
  351. int contrastBoost = CONTAINS(enchancements, 'c') || CONTAINS(imgopt, 'l') || CONTAINS(imgopt, 'c');
  352. chA = calibrate(prow, nrow, CHA_OFFSET, 0);
  353. chB = calibrate(prow, nrow, CHB_OFFSET, 0);
  354. printf("Channel A: %s (%s)\n", chid[chA], chname[chA]);
  355. printf("Channel B: %s (%s)\n", chid[chB], chname[chB]);
  356. // Temperature
  357. if (CONTAINS(imgopt, 't') && chB >= 4) {
  358. Temperature(prow, nrow, chB, CHB_OFFSET);
  359. sprintf(pngfilename, "%s/%s-t.png", pngdirname, name);
  360. ImageOut(pngfilename, "Temperature", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)TempPalette, 0, 0);
  361. }
  362. // We have to run the contrast enhance here because the temperature calibration requires real data
  363. // Yes, this requires running a large chunk of code again, but this will be addressed in the future
  364. chA = calibrate(prow, nrow, CHA_OFFSET, contrastBoost);
  365. chB = calibrate(prow, nrow, CHB_OFFSET, contrastBoost);
  366. // Layered
  367. if (CONTAINS(imgopt, 'l')){
  368. sprintf(pngfilename, "%s/%s-l.png", pngdirname, name);
  369. ImageOut(pngfilename, "Layered", prow, nrow, CH_WIDTH, 0, NULL, 0, 1);
  370. }
  371. // Raw image
  372. if (CONTAINS(imgopt, 'r')) {
  373. int croptele = CONTAINS(enchancements, 't');
  374. char channelstr[45];
  375. sprintf(channelstr, "%s (%s) & %s (%s)", chid[chA], chname[chA], chid[chB], chname[chB]);
  376. sprintf(pngfilename, "%s/%s-r.png", pngdirname, name);
  377. ImageOut(pngfilename, channelstr, prow, nrow, IMG_WIDTH, 0, NULL, croptele, 0);
  378. }
  379. // Channel A
  380. if (CONTAINS(imgopt, 'a')) {
  381. char channelstr[21];
  382. sprintf(channelstr, "%s (%s)", chid[chA], chname[chA]);
  383. sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, chid[chA]);
  384. ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH, CHA_OFFSET, NULL, 0, 0);
  385. }
  386. // Channel B
  387. if (CONTAINS(imgopt, 'b')) {
  388. char channelstr[21];
  389. sprintf(channelstr, "%s (%s)", chid[chB], chname[chB]);
  390. sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, chid[chB]);
  391. ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH , CHB_OFFSET, NULL, 0, 0);
  392. }
  393. // Distribution map
  394. if (CONTAINS(imgopt, 'd')) {
  395. sprintf(pngfilename, "%s/%s-d.pnm", pngdirname, name);
  396. Distrib(pngfilename, prow, nrow);
  397. }
  398. // False color image
  399. if(CONTAINS(imgopt, 'c')){
  400. if (chA == 2 && chB >= 4) { // Normal false color
  401. sprintf(pngfilename, "%s/%s-c.png", pngdirname, name);
  402. ImageRGBOut(pngfilename, prow, nrow);
  403. } else if (chA == 1 && chB == 2) { // GVI (global vegetation index) false color
  404. Ngvi(prow, nrow);
  405. sprintf(pngfilename, "%s/%s-c.png", pngdirname, name);
  406. ImageOut(pngfilename, "GVI False Color", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)GviPalette, 0, 0);
  407. } else {
  408. fprintf(stderr, "Lacking channels required for false color computation.\n");
  409. }
  410. }
  411. // Free the allocated memory
  412. for(int i = 0; i < 3000; i++) free(prow[i]);
  413. }
  414. exit(0);
  415. }