No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

image.c 7.7 KiB

hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
hace 20 años
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * This file is part of Aptdec.
  3. * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019
  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 "offsets.h"
  24. #include "messages.h"
  25. #define REGORDER 3
  26. typedef struct {
  27. double cf[REGORDER + 1];
  28. } rgparam;
  29. extern void polyreg(const int m, const int n, const double x[], const double y[], double c[]);
  30. // Compute regression
  31. static void rgcomp(double x[16], rgparam * rgpr) {
  32. // { 0.106, 0.215, 0.324, 0.433, 0.542, 0.652, 0.78, 0.87, 0.0 }
  33. const double y[9] = { 31.07, 63.02, 94.96, 126.9, 158.86, 191.1, 228.62, 255.0, 0.0 };
  34. polyreg(REGORDER, 9, x, y, rgpr -> cf);
  35. }
  36. // Convert a value to 0-255 based off the provided regression curve
  37. static double rgcal(float x, rgparam *rgpr) {
  38. double y, p;
  39. int i;
  40. for (i = 0, y = 0.0, p = 1.0; i < REGORDER + 1; i++) {
  41. y += rgpr->cf[i] * p;
  42. p = p * x;
  43. }
  44. return(y);
  45. }
  46. static double tele[16];
  47. static double Cs;
  48. static int nbtele;
  49. // Brightness equalise, including telemetry
  50. void equalise(float **prow, int nrow, int offset, int width, int telestart, rgparam regr[30]){
  51. offset -= SYNC_WIDTH+SPC_WIDTH;
  52. for (int n = 0; n < nrow; n++) {
  53. float *pixelv = prow[n];
  54. for (int i = 0; i < width+SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH; i++) {
  55. float pv = pixelv[i + offset];
  56. // Blend between the calculated regression curves
  57. /* TODO: this can actually make the image look *worse*
  58. * if the signal has a constant input gain.
  59. */
  60. int k, kof;
  61. k = (n - telestart) / FRAME_LEN;
  62. if (k >= nbtele)
  63. k = nbtele - 1;
  64. kof = (n - telestart) % FRAME_LEN;
  65. if (kof < 64) {
  66. if (k < 1) {
  67. pv = rgcal(pv, &(regr[k]));
  68. } else {
  69. pv = rgcal(pv, &(regr[k])) * (64 + kof) / FRAME_LEN +
  70. rgcal(pv, &(regr[k - 1])) * (64 - kof) / FRAME_LEN;
  71. }
  72. } else {
  73. if ((k + 1) >= nbtele) {
  74. pv = rgcal(pv, &(regr[k]));
  75. } else {
  76. pv = rgcal(pv, &(regr[k])) * (192 - kof) / FRAME_LEN +
  77. rgcal(pv, &(regr[k + 1])) * (kof - 64) / FRAME_LEN;
  78. }
  79. }
  80. pv = CLIP(pv, 0, 255);
  81. pixelv[i + offset] = pv;
  82. }
  83. }
  84. }
  85. // Get telemetry data for thermal calibration/equalization
  86. int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualise) {
  87. double teleline[3000];
  88. double wedge[16];
  89. rgparam regr[30];
  90. int n, k;
  91. int mtelestart = 0, telestart;
  92. int channel = -1;
  93. // Calculate average of a row of telemetry
  94. for (n = 0; n < nrow; n++) {
  95. float *pixelv = prow[n];
  96. // Average the center 40px
  97. teleline[n] = 0.0;
  98. for (int i = 3; i < 43; i++) teleline[n] += pixelv[i + offset + width];
  99. teleline[n] /= 40.0;
  100. }
  101. // The minimum rows required to decode a full frame
  102. if (nrow < 192) {
  103. fprintf(stderr, ERR_TELE_ROW);
  104. return(0);
  105. }
  106. /* Wedge 7 is white and 8 is black, which will have the largest
  107. * difference in brightness, this will always be in the center of
  108. * the frame and can thus be used to find the start of the frame
  109. */
  110. float max = 0;
  111. for (n = nrow / 3 - 64; n < 2 * nrow / 3 - 64; n++) {
  112. float df;
  113. // (sum 4px below) / (sum 4px above)
  114. df = (teleline[n - 4] + teleline[n - 3] + teleline[n - 2] + teleline[n - 1]) /
  115. (teleline[n + 0] + teleline[n + 1] + teleline[n + 2] + teleline[n + 3]);
  116. // Find the maximum difference
  117. if (df > max) {
  118. mtelestart = n;
  119. max = df;
  120. }
  121. }
  122. // Find the start of the first frame
  123. telestart = (mtelestart - FRAME_LEN/2) % FRAME_LEN;
  124. // Make sure that theres at least one full frame in the image
  125. if (nrow < telestart + FRAME_LEN) {
  126. fprintf(stderr, ERR_TELE_ROW);
  127. return(0);
  128. }
  129. // For each frame
  130. for (n = telestart, k = 0; n < nrow - FRAME_LEN; n += FRAME_LEN, k++) {
  131. float *pixelv = prow[n];
  132. int j;
  133. // Turn each wedge into a value
  134. for (j = 0; j < 16; j++) {
  135. // Average the middle 6px
  136. wedge[j] = 0.0;
  137. for (int i = 1; i < 7; i++) wedge[j] += teleline[(j * 8) + n + i];
  138. wedge[j] /= 6;
  139. }
  140. // Compute regression on the wedges
  141. rgcomp(wedge, &(regr[k]));
  142. // Read the telemetry values from the middle of the image
  143. if (k == nrow / (2*FRAME_LEN)) {
  144. int l;
  145. // Equalise
  146. for (j = 0; j < 16; j++) tele[j] = rgcal(wedge[j], &(regr[k]));
  147. /* Compare the channel ID wedge to the reference
  148. * wedges, the wedge with the closest match will
  149. * be the channel ID
  150. */
  151. float min = 10000;
  152. for (j = 0; j < 6; j++) {
  153. float df;
  154. df = tele[15] - tele[j];
  155. df *= df;
  156. if (df < min) {
  157. channel = j;
  158. min = df;
  159. }
  160. }
  161. // Cs computation, still have no idea what this does
  162. int i;
  163. for (Cs = 0.0, i = 0, j = n; j < n + FRAME_LEN; j++) {
  164. double csline;
  165. for (csline = 0.0, l = 3; l < 43; l++)
  166. csline += pixelv[l + offset - SPC_WIDTH];
  167. csline /= 40.0;
  168. if (csline > 50.0) {
  169. Cs += csline;
  170. i++;
  171. }
  172. }
  173. Cs /= i;
  174. Cs = rgcal(Cs, &(regr[k]));
  175. }
  176. }
  177. nbtele = k;
  178. if(contrastEqualise) equalise(prow, nrow, offset, width, telestart, regr);
  179. return(channel + 1);
  180. }
  181. // --- Temperature Calibration --- //
  182. extern int satnum;
  183. #include "satcal.h"
  184. typedef struct {
  185. double Nbb;
  186. double Cs;
  187. double Cb;
  188. int ch;
  189. } tempparam;
  190. // IR channel temperature compensation
  191. static void tempcomp(double t[16], int ch, tempparam *tpr) {
  192. double Tbb, T[4];
  193. double C;
  194. tpr -> ch = ch - 4;
  195. // Compute equivalent T blackbody temperature
  196. for (int n = 0; n < 4; n++) {
  197. float d0, d1, d2;
  198. C = t[9 + n] * 4.0;
  199. d0 = satcal[satnum].d[n][0];
  200. d1 = satcal[satnum].d[n][1];
  201. d2 = satcal[satnum].d[n][2];
  202. T[n] = d0;
  203. T[n] += d1 * C;
  204. C = C * C;
  205. T[n] += d2 * C;
  206. }
  207. Tbb = (T[0] + T[1] + T[2] + T[3]) / 4.0;
  208. Tbb = satcal[satnum].rad[tpr->ch].A + satcal[satnum].rad[tpr->ch].B * Tbb;
  209. // Compute radiance blackbody
  210. C = satcal[satnum].rad[tpr->ch].vc;
  211. tpr->Nbb = c1 * C * C * C / (expm1(c2 * C / Tbb));
  212. // Store count blackbody and space
  213. tpr->Cs = Cs * 4.0;
  214. tpr->Cb = t[14] * 4.0;
  215. }
  216. // IR channel temperature calibration
  217. static double tempcal(float Ce, tempparam * rgpr) {
  218. double Nl, Nc, Ns, Ne;
  219. double T, vc;
  220. Ns = satcal[satnum].cor[rgpr->ch].Ns;
  221. Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb);
  222. Nc = satcal[satnum].cor[rgpr->ch].b[0] +
  223. satcal[satnum].cor[rgpr->ch].b[1] * Nl +
  224. satcal[satnum].cor[rgpr->ch].b[2] * Nl * Nl;
  225. Ne = Nl + Nc;
  226. vc = satcal[satnum].rad[rgpr->ch].vc;
  227. T = c2 * vc / log1p(c1 * vc * vc * vc / Ne);
  228. T = (T - satcal[satnum].rad[rgpr->ch].A) / satcal[satnum].rad[rgpr->ch].B;
  229. // Rescale to 0-255 for -60'C to +40'C
  230. T = (T - 273.15 + 60.0) / 100.0 * 256.0;
  231. return(T);
  232. }
  233. // Temperature calibration wrapper
  234. void temperature(float **prow, int nrow, int channel, int offset) {
  235. tempparam temp;
  236. printf("Temperature... ");
  237. fflush(stdout);
  238. tempcomp(tele, channel, &temp);
  239. for (int n = 0; n < nrow; n++) {
  240. float *pixelv = prow[n];
  241. for (int i = 0; i < CH_WIDTH; i++) {
  242. float pv = tempcal(pixelv[i + offset], &temp);
  243. pv = CLIP(pv, 0, 255);
  244. pixelv[i + offset] = pv;
  245. }
  246. }
  247. printf("Done\n");
  248. }