Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
vor 21 Jahren
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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 <stdio.h>
  20. #include <string.h>
  21. #include <sndfile.h>
  22. #include <math.h>
  23. #include <stdlib.h>
  24. #include "offsets.h"
  25. #include "messages.h"
  26. #define REGORDER 3
  27. typedef struct {
  28. double cf[REGORDER + 1];
  29. } rgparam_t;
  30. typedef struct {
  31. float *prow[MAX_HEIGHT]; // Row buffers
  32. int nrow; // Number of rows
  33. int chA, chB; // ID of each channel
  34. char name[256]; // Stripped filename
  35. } image_t;
  36. typedef struct {
  37. char *type; // Output image type
  38. char *effects;
  39. int satnum; // The satellite number
  40. char *map; // Path to a map file
  41. char *path; // Output directory
  42. int realtime;
  43. } options_t;
  44. extern void polyreg(const int m, const int n, const double x[], const double y[], double c[]);
  45. // Compute regression
  46. static void rgcomp(double x[16], rgparam_t * rgpr) {
  47. // { 0.106, 0.215, 0.324, 0.433, 0.542, 0.652, 0.78, 0.87, 0.0 }
  48. const double y[9] = { 31.07, 63.02, 94.96, 126.9, 158.86, 191.1, 228.62, 255.0, 0.0 };
  49. polyreg(REGORDER, 9, x, y, rgpr -> cf);
  50. }
  51. // Convert a value to 0-255 based off the provided regression curve
  52. static double rgcal(float x, rgparam_t *rgpr) {
  53. double y, p;
  54. int i;
  55. for (i = 0, y = 0.0, p = 1.0; i < REGORDER + 1; i++) {
  56. y += rgpr->cf[i] * p;
  57. p = p * x;
  58. }
  59. return(y);
  60. }
  61. static double tele[16];
  62. static double Cs;
  63. void histogramEqualise(float **prow, int nrow, int offset, int width){
  64. // Plot histogram
  65. int histogram[256] = { 0 };
  66. for(int y = 0; y < nrow; y++)
  67. for(int x = 0; x < width; x++)
  68. histogram[(int)floor(prow[y][x+offset])]++;
  69. // Calculate cumulative frequency
  70. long sum = 0, cf[256] = { 0 };
  71. for(int i = 0; i < 255; i++){
  72. sum += histogram[i];
  73. cf[i] = sum;
  74. }
  75. // Apply histogram
  76. int area = nrow * width;
  77. for(int y = 0; y < nrow; y++){
  78. for(int x = 0; x < width; x++){
  79. int k = prow[y][x+offset];
  80. prow[y][x+offset] = (256.0/area) * cf[k];
  81. }
  82. }
  83. }
  84. // Brightness calibrate, including telemetry
  85. void calibrateImage(float **prow, int nrow, int offset, int width, rgparam_t regr){
  86. offset -= SYNC_WIDTH+SPC_WIDTH;
  87. for (int n = 0; n < nrow; n++) {
  88. float *pixelv = prow[n];
  89. for (int i = 0; i < width+SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH; i++) {
  90. float pv = rgcal(pixelv[i + offset], &regr);
  91. pixelv[i + offset] = CLIP(pv, 0, 255);
  92. }
  93. }
  94. }
  95. double teleNoise(double wedges[16]){
  96. int pattern[9] = { 31, 63, 95, 127, 159, 191, 223, 255, 0 };
  97. double noise = 0;
  98. for(int i = 0; i < 9; i++)
  99. noise += fabs(wedges[i] - (double)pattern[i]);
  100. return noise;
  101. }
  102. // Get telemetry data for thermal calibration/equalization
  103. int calibrate(float **prow, int nrow, int offset, int width) {
  104. double teleline[MAX_HEIGHT] = { 0.0 };
  105. double wedge[16];
  106. rgparam_t regr[30];
  107. int telestart, mtelestart = 0;
  108. int channel = -1;
  109. // The minimum rows required to decode a full frame
  110. if (nrow < 192) {
  111. fprintf(stderr, ERR_TELE_ROW);
  112. return 0;
  113. }
  114. // Calculate average of a row of telemetry
  115. for (int n = 0; n < nrow; n++) {
  116. float *pixelv = prow[n];
  117. // Average the center 40px
  118. for (int i = 3; i < 43; i++)
  119. teleline[n] += pixelv[i + offset + width];
  120. teleline[n] /= 40.0;
  121. }
  122. /* Wedge 7 is white and 8 is black, this will have the largest
  123. * difference in brightness, this will always be in the center of
  124. * the frame and can thus be used to find the start of the frame
  125. */
  126. double max = 0.0;
  127. for (int n = nrow / 3 - 64; n < 2 * nrow / 3 - 64; n++) {
  128. float df;
  129. // (sum 4px below) / (sum 4px above)
  130. df = (teleline[n - 4] + teleline[n - 3] + teleline[n - 2] + teleline[n - 1]) /
  131. (teleline[n + 0] + teleline[n + 1] + teleline[n + 2] + teleline[n + 3]);
  132. // Find the maximum difference
  133. if (df > max) {
  134. mtelestart = n;
  135. max = df;
  136. }
  137. }
  138. // Find the start of the first frame
  139. telestart = (mtelestart - FRAME_LEN/2) % FRAME_LEN;
  140. // Make sure that theres at least one full frame in the image
  141. if (nrow < telestart + FRAME_LEN) {
  142. fprintf(stderr, ERR_TELE_ROW);
  143. return(0);
  144. }
  145. // Find the least noisy frame
  146. double minNoise = -1;
  147. int bestFrame = telestart;
  148. for (int n = telestart, k = 0; n < nrow - FRAME_LEN; n += FRAME_LEN, k++) {
  149. // Turn pixels into wedge values
  150. for (int j = 0; j < 16; j++) {
  151. wedge[j] = 0.0;
  152. // Average the middle 6px
  153. for (int i = 1; i < 7; i++)
  154. wedge[j] += teleline[(j * 8) + i + n];
  155. wedge[j] /= 6;
  156. }
  157. double noise = teleNoise(wedge);
  158. if(noise < minNoise || minNoise == -1){
  159. minNoise = noise;
  160. bestFrame = k;
  161. // Compute & apply regression on the wedges
  162. rgcomp(wedge, &regr[k]);
  163. for (int j = 0; j < 16; j++)
  164. tele[j] = rgcal(wedge[j], &regr[k]);
  165. /* Compare the channel ID wedge to the reference
  166. * wedges, the wedge with the closest match will
  167. * be the channel ID
  168. */
  169. float min = -1;
  170. for (int j = 0; j < 6; j++) {
  171. float df = tele[15] - tele[j];
  172. df *= df;
  173. if (df < min || min == -1) {
  174. channel = j;
  175. min = df;
  176. }
  177. }
  178. }
  179. }
  180. calibrateImage(prow, nrow, offset, width, regr[bestFrame]);
  181. return channel + 1;
  182. }
  183. // --- Temperature Calibration --- //
  184. #include "satcal.h"
  185. typedef struct {
  186. double Nbb;
  187. double Cs;
  188. double Cb;
  189. int ch;
  190. } tempparam_t;
  191. // IR channel temperature compensation
  192. static void tempcomp(double t[16], int ch, int satnum, tempparam_t *tpr) {
  193. double Tbb, T[4];
  194. double C;
  195. tpr -> ch = ch - 4;
  196. // Compute equivalent T blackbody temperature
  197. for (int n = 0; n < 4; n++) {
  198. float d0, d1, d2;
  199. C = t[9 + n] * 4.0;
  200. d0 = satcal[satnum].d[n][0];
  201. d1 = satcal[satnum].d[n][1];
  202. d2 = satcal[satnum].d[n][2];
  203. T[n] = d0;
  204. T[n] += d1 * C;
  205. C = C * C;
  206. T[n] += d2 * C;
  207. }
  208. Tbb = (T[0] + T[1] + T[2] + T[3]) / 4.0;
  209. Tbb = satcal[satnum].rad[tpr->ch].A + satcal[satnum].rad[tpr->ch].B * Tbb;
  210. // Compute radiance blackbody
  211. C = satcal[satnum].rad[tpr->ch].vc;
  212. tpr->Nbb = c1 * C * C * C / (expm1(c2 * C / Tbb));
  213. // Store count blackbody and space
  214. tpr->Cs = Cs * 4.0;
  215. tpr->Cb = t[14] * 4.0;
  216. }
  217. // IR channel temperature calibration
  218. static double tempcal(float Ce, int satnum, tempparam_t * rgpr) {
  219. double Nl, Nc, Ns, Ne;
  220. double T, vc;
  221. Ns = satcal[satnum].cor[rgpr->ch].Ns;
  222. Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb);
  223. Nc = satcal[satnum].cor[rgpr->ch].b[0] +
  224. satcal[satnum].cor[rgpr->ch].b[1] * Nl +
  225. satcal[satnum].cor[rgpr->ch].b[2] * Nl * Nl;
  226. Ne = Nl + Nc;
  227. vc = satcal[satnum].rad[rgpr->ch].vc;
  228. T = c2 * vc / log1p(c1 * vc * vc * vc / Ne);
  229. T = (T - satcal[satnum].rad[rgpr->ch].A) / satcal[satnum].rad[rgpr->ch].B;
  230. // Rescale to 0-255 for -60'C to +40'C
  231. T = (T - 273.15 + 60.0) / 100.0 * 256.0;
  232. return(T);
  233. }
  234. // Temperature calibration wrapper
  235. void temperature(options_t *opts, image_t *img, int offset, int width){
  236. tempparam_t temp;
  237. printf("Temperature... ");
  238. fflush(stdout);
  239. tempcomp(tele, img->chB, opts->satnum - 15, &temp);
  240. for (int y = 0; y < img->nrow; y++) {
  241. float *pixelv = img->prow[y];
  242. for (int x = 0; x < width; x++) {
  243. float pv = tempcal(pixelv[x + offset], opts->satnum - 15, &temp);
  244. pixelv[x + offset] = CLIP(pv, 0, 255);
  245. }
  246. }
  247. printf("Done\n");
  248. }
  249. void distrib(options_t *opts, image_t *img, char *chid) {
  250. int max = 0;
  251. // Options
  252. options_t options;
  253. options.path = opts->path;
  254. // Image options
  255. image_t distrib;
  256. strcpy(distrib.name, img->name);
  257. distrib.nrow = 256;
  258. // Assign memory
  259. for(int i = 0; i < 256; i++)
  260. distrib.prow[i] = (float *) malloc(sizeof(float) * 256);
  261. for(int n = 0; n < img->nrow; n++) {
  262. float *pixelv = img->prow[n];
  263. for(int i = 0; i < CH_WIDTH; i++) {
  264. int y = CLIP((int)pixelv[i + CHA_OFFSET], 0, 255);
  265. int x = CLIP((int)pixelv[i + CHB_OFFSET], 0, 255);
  266. distrib.prow[y][x]++;
  267. if(distrib.prow[y][x] > max)
  268. max = distrib.prow[y][x];
  269. }
  270. }
  271. // Scale to 0-255
  272. for(int x = 0; x < 256; x++)
  273. for(int y = 0; y < 256; y++)
  274. distrib.prow[y][x] = distrib.prow[y][x] / max * 255.0;
  275. extern int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char *chid, char *palette);
  276. ImageOut(&options, &distrib, 0, 256, "Distribution", chid, NULL);
  277. }
  278. extern float quick_select(float arr[], int n);
  279. // Recursive biased median denoise
  280. #define TRIG_LEVEL 40
  281. void denoise(float **prow, int nrow, int offset, int width){
  282. for(int y = 2; y < nrow-2; y++){
  283. for(int x = offset+1; x < offset+width-1; x++){
  284. if(prow[y][x+1] - prow[y][x] > TRIG_LEVEL ||
  285. prow[y][x-1] - prow[y][x] > TRIG_LEVEL ||
  286. prow[y+1][x] - prow[y][x] > TRIG_LEVEL ||
  287. prow[y-1][x] - prow[y][x] > TRIG_LEVEL){
  288. prow[y][x] = quick_select((float[]){
  289. prow[y+2][x-1], prow[y+2][x], prow[y+2][x+1],
  290. prow[y+1][x-1], prow[y+1][x], prow[y+1][x+1],
  291. prow[y-1][x-1], prow[y-1][x], prow[y-1][x+1],
  292. prow[y-2][x-1], prow[y-2][x], prow[y-2][x+1]
  293. }, 12);
  294. }
  295. }
  296. }
  297. }
  298. #undef TRIG_LEVEL