From d8446bc03d672faa29de6e775e057670d2df3507 Mon Sep 17 00:00:00 2001 From: Xerbo Date: Sun, 15 Dec 2019 19:55:37 +0000 Subject: [PATCH] I don't really know what happened, but I can think of these off the top of my head Improved commenting in dsp.c Updated copyright notices Code tidy up in some parts --- LICENSE | 26 +-- Makefile | 4 +- README.md | 6 +- dsp.c | 150 ++++++++--------- fcolor.c | 27 ++- filter.c | 45 ++--- filter.h | 29 ++-- filtercoeff.h | 39 ++--- image.c | 219 ++++++++++++------------ main.c | 320 +++++++++++++++--------------------- messages.h | 21 ++- offsets.h | 20 +++ colorpalette.h => palette.h | 19 +++ satcal.h | 19 +++ 14 files changed, 482 insertions(+), 462 deletions(-) rename colorpalette.h => palette.h (87%) diff --git a/LICENSE b/LICENSE index c7aea18..d8cf7d4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,4 +277,4 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS diff --git a/Makefile b/Makefile index 2ea66df..08f62f4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CC = clang +CC = gcc BIN = /usr/bin INCLUDES = -I. CFLAGS = -O3 -Wall $(INCLUDES) @@ -7,7 +7,7 @@ OBJS = main.o image.o dsp.o filter.o reg.o fcolor.o aptdec: $(OBJS) $(CC) -o $@ $(OBJS) -lm -lsndfile -lpng -main.o: main.c colorpalette.h offsets.h messages.h +main.o: main.c palette.h offsets.h messages.h dsp.o: dsp.c filtercoeff.h filter.h filter.o: filter.c filter.h image.o: image.c satcal.h offsets.h messages.h diff --git a/README.md b/README.md index 203a29c..93dbe05 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Aptdec logo](textlogo.png) -Thierry Leconte F4DWV (c) 2004-2009 +Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 ## Description @@ -89,14 +89,14 @@ Image names are `audiofile-x.png`, where `x` is: Currently there are 2 available enchancements: - - `c` for contrast enhancements, on by default + - `c` for contrast equalise, on by default - `t` for crop telemetry, on by default, only has effects on raw images ## Example `aptdec -d images -i ab *.wav` -This will process all `.wav` files in the current directory, generate contrast enhanced channel A and B images and put them in the `images` directory. +This will process all `.wav` files in the current directory, generate equalised channel A and B images and put them in the `images` directory. ## Further reading diff --git a/dsp.c b/dsp.c index c9ec059..2924578 100755 --- a/dsp.c +++ b/dsp.c @@ -1,44 +1,37 @@ -/* - * Aptdec - * Copyright (c) 2004 by Thierry Leconte (F4DWV) +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 * - * $Id$ + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ + #include #include #include #include -#ifndef M_PI -#define M_PI 3.1415926535 // For OS's that don't include it -#endif + #include "filter.h" #include "filtercoeff.h" -/* WARNING - * The comments in this file are at best educated guesses. - * I am not a DSP god and can not figure out what a complicated - * math function does just by looking at it. - */ - -extern int getsample(float *inbuff, int nb); +// In case your C compiler is so old that Pi hadn't been invented yet +#ifndef M_PI +#define M_PI 3.141592653589793 +#endif +// Block sizes #define BLKAMP 1024 -// Block size #define BLKIN 1024 #define Fc 2400.0 @@ -48,6 +41,8 @@ extern int getsample(float *inbuff, int nb); #define RSMULT 15 #define Fi (Fp * RSMULT) +extern int getsample(float *inbuff, int count); + static double Fe; static double offset = 0.0; @@ -56,7 +51,7 @@ static double FreqLine = 1.0; static double FreqOsc; static double K1, K2; -// Check if the input sample rate is correct +// Check the input sample rate and calculate some constants int init_dsp(double F) { if(F > Fi) return(1); if(F < Fp) return(-1); @@ -64,13 +59,15 @@ int init_dsp(double F) { K1 = DFc / Fe; K2 = K1 * K1 / 2.0; + // Number of samples for each cycle FreqOsc = Fc / Fe; return(0); } -// Fast phase estimator -// Calculates the phase angle of a signal from a IQ sample +/* Fast phase estimator + * Calculates the phase angle of a signal from a IQ sample + */ static inline double Phase(double I, double Q) { double angle, r; int s; @@ -99,8 +96,11 @@ static inline double Phase(double I, double Q) { return(-angle); } -// Phase locked loop -// Used to get value from an IQ sample with noise reduction +/* Phase locked loop + * https://en.wikipedia.org/wiki/Phase-locked_loop + * https://arachnoid.com/phase_locked_loop/ + * https://simple.wikipedia.org/wiki/Phase-locked_loop + */ static double pll(double I, double Q) { // PLL coefficient static double PhaseOsc = 0.0; @@ -133,17 +133,16 @@ static double pll(double I, double Q) { return(Ip); } -// Convert audio samples into a pixel -static int getamp(double *ambuff, int nb) { +// Convert samples into pixels +static int getamp(double *ampbuff, int count) { static float inbuff[BLKIN]; static int idxin = 0; static int nin = 0; - int n; - for (n = 0; n < nb; n++) { + for (int n = 0; n < count; n++) { double I, Q; - // If the amount of samples is small enough to be processed + // Get some more samples when needed if (nin < IQFilterLen * 2 + 2) { // Number of samples read int res; @@ -153,50 +152,52 @@ static int getamp(double *ambuff, int nb) { // Read some samples res = getsample(&(inbuff[nin]), BLKIN - nin); nin += res; - // If we haven't read any more samples, return how far we got + + // Make sure there is enough samples to continue if (nin < IQFilterLen * 2 + 2) return(n); } // Process read samples into a brightness value iqfir(&inbuff[idxin], iqfilter, IQFilterLen, &I, &Q); - ambuff[n] = pll(I, Q); + ampbuff[n] = pll(I, Q); - idxin += 1; - nin -= 1; + // Increment current sample + idxin++; + nin--; } - return(n); + return(count); } -// Get an entire row of pixels, without alignment -int getpixelv(float *pvbuff, int nb) { +// Sub-pixel offsetting + FIR compensation +int getpixelv(float *pvbuff, int count) { // Amplitude buffer - static double ambuff[BLKAMP]; + static double ampbuff[BLKAMP]; static int nam = 0; static int idxam = 0; - int n, m; double mult; + // Sub-pixel offset mult = (double) Fi / Fe * FreqLine; - m = RSFilterLen / mult + 1; + int m = RSFilterLen / mult + 1; - for (n = 0; n < nb; n++) { + for (int n = 0; n < count; n++) { int shift; if (nam < m) { int res; - memmove(ambuff, &(ambuff[idxam]), nam * sizeof(double)); + memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(double)); idxam = 0; - res = getamp(&(ambuff[nam]), BLKAMP - nam); + res = getamp(&(ampbuff[nam]), BLKAMP - nam); nam += res; if (nam < m) return(n); } - // Denoise - pvbuff[n] = rsfir(&(ambuff[idxam]), rsfilter, RSFilterLen, offset, mult) * mult * 256.0; + // Gaussian FIR compensation filter + pvbuff[n] = rsfir(&(ampbuff[idxam]), rsfilter, RSFilterLen, offset, mult) * mult * 256.0; shift = ((int) floor((RSMULT - offset) / mult)) + 1; offset = shift * mult + offset - RSMULT; @@ -204,44 +205,45 @@ int getpixelv(float *pvbuff, int nb) { idxam += shift; nam -= shift; } - return(nb); + return(count); } -// Align this line based off of the synchronisation markers +// Get an entire row of pixels, aligned with sync markers int getpixelrow(float *pixelv) { - // Create an array for this row static float pixels[PixelLine + SyncFilterLen]; - static int npv = 0; + static int npv; static int synced = 0; - static double max = 0.0; + static double max = 0; double corr, ecorr, lcorr; int res; + // Move the row buffer into the the image buffer if (npv > 0) memmove(pixelv, pixels, npv * sizeof(float)); + // Get the sync line if (npv < SyncFilterLen + 2) { res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv); npv += res; - if (npv < SyncFilterLen + 2) - return(0); + // Exit if there are no pixels left + if (npv < SyncFilterLen + 2) return(0); } - // Test current synchronisation + // Calculate the sub-pixel offset ecorr = fir(pixelv, Sync, SyncFilterLen); corr = fir(&(pixelv[1]), Sync, SyncFilterLen - 1); lcorr = fir(&(pixelv[2]), Sync, SyncFilterLen - 2); - // Calculate the per pixel offset FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0); - // Maximum acceptable offset + + // The point in which the pixel offset is recalculated if (corr < 0.75 * max) { synced = 0; FreqLine = 1.0; } max = corr; - if (synced < 8) { + if (synced < 8) { int mshift; if (npv < PixelLine + SyncFilterLen) { @@ -251,9 +253,9 @@ int getpixelrow(float *pixelv) { return(0); } - // Shift this line until we see the best results + // Test every possible position until we get the best result mshift = 0; - for (int shift = 1; shift < PixelLine; shift++) { + for (int shift = 0; shift < PixelLine; shift++) { double corr; corr = fir(&(pixelv[shift + 1]), Sync, SyncFilterLen); @@ -263,32 +265,32 @@ int getpixelrow(float *pixelv) { } } - // Shift memory, shifting this row - if (mshift != 0) { + // If we are already as aligned as we can get, just continue + if (mshift == 0) { + synced++; + } else { memmove(pixelv, &(pixelv[mshift]), (npv - mshift) * sizeof(float)); npv -= mshift; synced = 0; FreqLine = 1.0; - } else - synced += 1; + } } - // If there are not enough pixels try to grab some more + // Get the rest of this row if (npv < PixelLine) { res = getpixelv(&(pixelv[npv]), PixelLine - npv); npv += res; - // If we fail this then exit with 0 (which breaks the loop at main.c:338) if (npv < PixelLine) return(0); } - // If we're finished reset npv to 0 + // Move the sync lines into the output buffer with the calculated offset if (npv == PixelLine) { npv = 0; - } else { // Move the pixel build buffer to the output buffer + } else { memmove(pixels, &(pixelv[PixelLine]), (npv - PixelLine) * sizeof(float)); npv -= PixelLine; } return(1); -} +} \ No newline at end of file diff --git a/fcolor.c b/fcolor.c index a3a98e1..ba00dca 100644 --- a/fcolor.c +++ b/fcolor.c @@ -1,3 +1,22 @@ +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 + * + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #include #include #include "offsets.h" @@ -18,8 +37,8 @@ static struct { int Cloudthreshold; int Cloudintensity; } fcinfo = { - {28, 44, 95, 1}, - {23, 78, 37, 1}, + {28, 44, 95, 1}, + {23, 78, 37, 1}, {240, 250, 255, 1}, 50, 0.5, @@ -89,9 +108,7 @@ void Ngvi(float **prow, int nrow) { fflush(stdout); for (int n = 0; n < nrow; n++) { - float *pixelv; - - pixelv = prow[n]; + float *pixelv = prow[n]; for (int i = 0; i < CH_WIDTH; i++) { float pv; double gvi; diff --git a/filter.c b/filter.c index b655cda..919297b 100755 --- a/filter.c +++ b/filter.c @@ -1,28 +1,27 @@ -/* - * Aptdec - * Copyright (c) 2004 by Thierry Leconte (F4DWV) +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 * - * $Id$ + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ -#include "filter.h" + #include -// Sum of a matrix multiplication of 2 arrays +#include "filter.h" + +// Finite impulse response float fir(float *buff, const float *coeff, const int len) { double r; @@ -33,22 +32,24 @@ float fir(float *buff, const float *coeff, const int len) { return(r); } -// Create an IQ sample from a sample buffer +/* IQ finite impulse response + * Turn samples into a single IQ sample + */ void iqfir(float *buff, const float *coeff, const int len, double *I, double *Q) { double i, q; i = q = 0.0; for (int k = 0; k < len; k++) { q += buff[2*k] * coeff[k]; - // Average out the I samples, which gives us the DC offset i += buff[2*k]; } - // Grab the peak value of the wave and subtract the DC offset i = buff[len-1] - (i / len); *I = i, *Q = q; } -// Denoise, I don't know how it works, but it does +/* Gaussian finite impulse responce compensation + * https://www.recordingblogs.com/wiki/gaussian-window + */ float rsfir(double *buff, const float *coeff, const int len, const double offset, const double delta) { double out; diff --git a/filter.h b/filter.h index 8d94d5d..037d560 100755 --- a/filter.h +++ b/filter.h @@ -1,22 +1,19 @@ -/* - * Aptdec - * Copyright (c) 2003 by Thierry Leconte (F4DWV) +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 * - * $Id$ + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ diff --git a/filtercoeff.h b/filtercoeff.h index d76a573..df9eece 100755 --- a/filtercoeff.h +++ b/filtercoeff.h @@ -1,38 +1,35 @@ -/* - * Aptdec - * Copyright (c) 2003 by Thierry Leconte (F4DWV) +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 * - * $Id$ + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - + */ + +// IQ finite impulse response filter #define IQFilterLen 32 const float iqfilter[IQFilterLen] = { 0.0205361, 0.0219524, 0.0235785, 0.0254648, 0.0276791, 0.0303152, 0.0335063, 0.0374482, 0.0424413, 0.0489708, 0.0578745, 0.0707355, 0.0909457, 0.127324, 0.212207, 0.63662, -0.63662, -0.212207, -0.127324, -0.0909457, -0.0707355, -0.0578745, -0.0489708, -0.0424413, -0.0374482, -0.0335063, -0.0303152, -0.0276791, -0.0254648, -0.0235785, -0.0219524, -0.0205361 }; -// Length of Sync -#define SyncFilterLen 32 // Pattern of a NOAA sync line +#define SyncFilterLen 32 const float Sync[SyncFilterLen] = { -14, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, -14 }; - +// Gaussian finite impulse response compensation filter #define RSFilterLen 437 const float rsfilter[RSFilterLen] = { -3.37279e-04, -8.80292e-06, -3.96418e-04, -1.78544e-04, -5.27511e-04, -3.75376e-04, -6.95337e-04, -5.93148e-04, -8.79730e-04, -8.15327e-04, -1.05669e-03, -1.01377e-03, diff --git a/image.c b/image.c index 744ef76..9122c63 100644 --- a/image.c +++ b/image.c @@ -1,22 +1,19 @@ -/* - * Aptdec - * Copyright (c) 2004 by Thierry Leconte (F4DWV) +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 * - * $Id$ + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ @@ -33,18 +30,21 @@ typedef struct { double cf[REGORDER + 1]; } rgparam; +extern void polyreg(const int m, const int n, const double x[], const double y[], double c[]); + +// Compute regression static void rgcomp(double x[16], rgparam * rgpr) { - //const double y[9] = { 0.106, 0.215, 0.324, 0.433, 0.542, 0.652, 0.78, 0.87, 0.0 }; + // { 0.106, 0.215, 0.324, 0.433, 0.542, 0.652, 0.78, 0.87, 0.0 } const double y[9] = { 31.07, 63.02, 94.96, 126.9, 158.86, 191.1, 228.62, 255.0, 0.0 }; - extern void polyreg(const int m, const int n, const double x[], const double y[], double c[]); polyreg(REGORDER, 9, x, y, rgpr -> cf); } -static double rgcal(float x, rgparam * rgpr) { +// Convert a value to 0-255 based off the provided regression curve +static double rgcal(float x, rgparam *rgpr) { double y, p; - int i; - + int i; + for (i = 0, y = 0.0, p = 1.0; i < REGORDER + 1; i++) { y += rgpr->cf[i] * p; p = p * x; @@ -56,35 +56,39 @@ static double tele[16]; static double Cs; static int nbtele; -// Contrast enchance -void equalise(float **prow, int nrow, int offset, int telestart, rgparam regr[30]){ - for (int n = 0; n < nrow; n++) { - float *pixelv; - int i; +// Brightness equalise, including telemetry +void equalise(float **prow, int nrow, int offset, int width, int telestart, rgparam regr[30]){ + offset -= SYNC_WIDTH+SPC_WIDTH; - pixelv = prow[n]; - for (i = 0; i < CH_WIDTH; i++) { - float pv; - int k, kof; + for (int n = 0; n < nrow; n++) { + float *pixelv = prow[n]; - pv = pixelv[i + offset]; + for (int i = 0; i < width+SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH; i++) { + float pv = pixelv[i + offset]; - k = (n - telestart) / 128; + // Blend between the calculated regression curves + /* TODO: this can actually make the image look *worse* + * if the signal has a constant input gain. + */ + int k, kof; + k = (n - telestart) / FRAME_LEN; if (k >= nbtele) k = nbtele - 1; - kof = (n - telestart) % 128; + kof = (n - telestart) % FRAME_LEN; if (kof < 64) { if (k < 1) { pv = rgcal(pv, &(regr[k])); } else { - pv = rgcal(pv, &(regr[k])) * (64 + kof) / 128.0 + rgcal(pv, &(regr[k - 1])) * (64 - kof) / 128.0; + pv = rgcal(pv, &(regr[k])) * (64 + kof) / FRAME_LEN + + rgcal(pv, &(regr[k - 1])) * (64 - kof) / FRAME_LEN; } } else { if ((k + 1) >= nbtele) { pv = rgcal(pv, &(regr[k])); } else { - pv = rgcal(pv, &(regr[k])) * (192 - kof) / 128.0 + rgcal(pv, &(regr[k + 1])) * (kof - 64) / 128.0; + pv = rgcal(pv, &(regr[k])) * (192 - kof) / FRAME_LEN + + rgcal(pv, &(regr[k + 1])) * (kof - 64) / FRAME_LEN; } } @@ -94,119 +98,105 @@ void equalise(float **prow, int nrow, int offset, int telestart, rgparam regr[30 } } -// Get telemetry data for thermal calibration -int calibrate(float **prow, int nrow, int offset, int contrastBoost) { +// Get telemetry data for thermal calibration/equalization +int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualise) { double teleline[3000]; double wedge[16]; rgparam regr[30]; - int n; - int k; - int mtelestart, telestart; + int n, k; + int mtelestart = 0, telestart; int channel = -1; - float max; - // Extract telemetry data, for a single pixel row + // Calculate average of a row of telemetry for (n = 0; n < nrow; n++) { - int i; + float *pixelv = prow[n]; + // Average the center 40px teleline[n] = 0.0; - // Average the 40 center pixels from the telemetry block - for (i = 3; i < 43; i++) { - teleline[n] += prow[n][i + offset + CH_WIDTH]; - } - // Compute the average + for (int i = 3; i < 43; i++) teleline[n] += pixelv[i + offset + width]; teleline[n] /= 40.0; } - // A good minimum amount of pixels to find the telemetry start + // The minimum rows required to decode a full frame if (nrow < 192) { fprintf(stderr, ERR_TELE_ROW); return(0); } - // Find the biggest contrast in the telemetry - max = 0.0; - mtelestart = 0; - - // Only check the center of the image, where the signal is most likely strongest + /* Wedge 7 is white and 8 is black, which will have the largest + * difference in brightness, this will always be in the center of + * the frame and can thus be used to find the start of the frame + */ + float max = 0; for (n = nrow / 3 - 64; n < 2 * nrow / 3 - 64; n++) { float df; - // Calculate the contrast, in other words // (sum 4px below) / (sum 4px above) - df = (teleline[n - 4] + teleline[n - 3] + teleline[n - 2] + - teleline[n - 1]) / (teleline[n] + teleline[n + 1] + - teleline[n + 2] + teleline[n + 3]); - // Find the biggest contrast + df = (teleline[n - 4] + teleline[n - 3] + teleline[n - 2] + teleline[n - 1]) / + (teleline[n + 0] + teleline[n + 1] + teleline[n + 2] + teleline[n + 3]); + + // Find the maximum difference if (df > max) { mtelestart = n; max = df; } } - // Calculate relative offset - telestart = (mtelestart - 64) % 128; + // Find the start of the first frame + telestart = (mtelestart - FRAME_LEN/2) % FRAME_LEN; - // If we cannot find the start of the telemetry or if there is not enough of it - if (mtelestart < 0 || nrow < telestart + 128) { + // Make sure that theres at least one full frame in the image + if (nrow < telestart + FRAME_LEN) { fprintf(stderr, ERR_TELE_ROW); return(0); } - /* Compute wedges and regression - * - * This loop loops every 128 pixels after the relative telemetry start. - * Gets the values of where the wedges should be and then feeds into a - * regression algorithm which calculates the amount of noise on the - * telemetry. - * - * It then finds the part of the telemetry data with the least noise and - * turns it into digital values. - */ - for (n = telestart, k = 0; n < nrow - 128; n += 128, k++) { + // For each frame + for (n = telestart, k = 0; n < nrow - FRAME_LEN; n += FRAME_LEN, k++) { + float *pixelv = prow[n]; int j; - // Loop through the 16 wedges + // Turn each wedge into a value for (j = 0; j < 16; j++) { - int i; - + // Average the middle 6px wedge[j] = 0.0; - // Center 6 pixels - for (i = 1; i < 7; i++){ - wedge[j] += teleline[(j * 8) + n + i]; - } - // Average + for (int i = 1; i < 7; i++) wedge[j] += teleline[(j * 8) + n + i]; wedge[j] /= 6; } + // Compute regression on the wedges rgcomp(wedge, &(regr[k])); - if (k == nrow / 256) { - int i, l; + // Read the telemetry values from the middle of the image + if (k == nrow / (2*FRAME_LEN)) { + int l; - // Telemetry calibration - for (j = 0; j < 16; j++) { - tele[j] = rgcal(wedge[j], &(regr[k])); - } + // Equalise + for (j = 0; j < 16; j++) tele[j] = rgcal(wedge[j], &(regr[k])); - // Channel ID - for (j = 0, max = 10000.0, channel = -1; j < 6; j++) { + /* Compare the channel ID wedge to the reference + * wedges, the wedge with the closest match will + * be the channel ID + */ + float min = 10000; + for (j = 0; j < 6; j++) { float df; - df = wedge[15] - wedge[j]; - df = df * df; - if (df < max) { + df = tele[15] - tele[j]; + df *= df; + if (df < min) { channel = j; - max = df; + min = df; } } - /* Cs computation */ - for (Cs = 0.0, i = 0, j = n; j < n + 128; j++) { + // Cs computation, still have no idea what this does + int i; + for (Cs = 0.0, i = 0, j = n; j < n + FRAME_LEN; j++) { double csline; for (csline = 0.0, l = 3; l < 43; l++) - csline += prow[n][l + offset -SPC_WIDTH]; + csline += pixelv[l + offset - SPC_WIDTH]; csline /= 40.0; if (csline > 50.0) { @@ -220,8 +210,7 @@ int calibrate(float **prow, int nrow, int offset, int contrastBoost) { } nbtele = k; - // Image contrast - if(contrastBoost) equalise(prow, nrow, offset, telestart, regr); + if(contrastEqualise) equalise(prow, nrow, offset, width, telestart, regr); return(channel + 1); } @@ -237,16 +226,15 @@ typedef struct { int ch; } tempparam; -/* temperature compensation for IR channel */ -static void tempcomp(double t[16], int ch, tempparam * tpr) { +// IR channel temperature compensation +static void tempcomp(double t[16], int ch, tempparam *tpr) { double Tbb, T[4]; double C; - int n; tpr -> ch = ch - 4; - /* compute equivalent T black body */ - for (n = 0; n < 4; n++) { + // Compute equivalent T blackbody temperature + for (int n = 0; n < 4; n++) { float d0, d1, d2; C = t[9 + n] * 4.0; @@ -261,15 +249,16 @@ static void tempcomp(double t[16], int ch, tempparam * tpr) { Tbb = (T[0] + T[1] + T[2] + T[3]) / 4.0; Tbb = satcal[satnum].rad[tpr->ch].A + satcal[satnum].rad[tpr->ch].B * Tbb; - /* compute radiance Black body */ + // Compute radiance blackbody C = satcal[satnum].rad[tpr->ch].vc; tpr->Nbb = c1 * C * C * C / (expm1(c2 * C / Tbb)); - /* store Count Blackbody and space */ + // Store count blackbody and space tpr->Cs = Cs * 4.0; tpr->Cb = t[14] * 4.0; } +// IR channel temperature calibration static double tempcal(float Ce, tempparam * rgpr) { double Nl, Nc, Ns, Ne; double T, vc; @@ -286,30 +275,26 @@ static double tempcal(float Ce, tempparam * rgpr) { T = c2 * vc / log1p(c1 * vc * vc * vc / Ne); T = (T - satcal[satnum].rad[rgpr->ch].A) / satcal[satnum].rad[rgpr->ch].B; - /* rescale to range 0-255 for -60 +40 'C */ + // Rescale to 0-255 for -60'C to +40'C T = (T - 273.15 + 60.0) / 100.0 * 256.0; return(T); } -void Temperature(float **prow, int nrow, int channel, int offset) { +// Temperature calibration wrapper +void temperature(float **prow, int nrow, int channel, int offset) { tempparam temp; - int n; printf("Temperature... "); fflush(stdout); tempcomp(tele, channel, &temp); - for (n = 0; n < nrow; n++) { - float *pixelv; - int i; - - pixelv = prow[n]; - for (i = 0; i < CH_WIDTH; i++) { - float pv; + for (int n = 0; n < nrow; n++) { + float *pixelv = prow[n]; - pv = tempcal(pixelv[i + offset], &temp); + for (int i = 0; i < CH_WIDTH; i++) { + float pv = tempcal(pixelv[i + offset], &temp); pv = CLIP(pv, 0, 255); pixelv[i + offset] = pv; diff --git a/main.c b/main.c index 16138e8..c949a8a 100644 --- a/main.c +++ b/main.c @@ -1,22 +1,19 @@ -/* - * Aptdec - * Copyright (c) 2004-2005 by Thierry Leconte (F4DWV) +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 * - * $Id$ + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ @@ -24,21 +21,17 @@ #include #include #include - #include - #include - #include #include #include "messages.h" #include "offsets.h" - -#include "colorpalette.h" +#include "palette.h" extern int getpixelrow(float *pixelv); -extern int init_dsp(double F);; +extern int init_dsp(double F); static SNDFILE *inwav; @@ -73,7 +66,7 @@ static int initsnd(char *filename) { return(1); } -// Get a sample from the wave file +// Get samples from the wave file int getsample(float *sample, int nb) { return sf_read_float(inwav, sample, nb); } @@ -84,13 +77,20 @@ static png_text text_ptr[] = { {PNG_TEXT_COMPRESSION_NONE, "Description", "NOAA satellite image", 20} }; -static int ImageOut(char *filename, char *chid, float **prow, int nrow, int width, int offset, png_color *palette, int croptele, int layered) { +// TODO: this function needs to be tidied up +/* Effects + * 0 - Nothing + * 1 - Crop telemetry + * 2 - False color + * 3 - Layered + */ +static int ImageOut(char *filename, char *chid, float **prow, int nrow, int width, int offset, png_color *palette, int effects) { FILE *pngfile; png_infop info_ptr; png_structp png_ptr; // Reduce the width of the image to componsate for the missing telemetry - if(croptele) width -= TOTAL_TELE; + if(effects == 1) width -= TOTAL_TELE; // Initalise the PNG writer png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); @@ -107,7 +107,14 @@ static int ImageOut(char *filename, char *chid, float **prow, int nrow, int widt return(0); } - if(palette == NULL) { + extern void falsecolor(float vis, float temp, float *r, float *g, float *b); + + if(effects == 2){ + // 8 bit RGB image + png_set_IHDR(png_ptr, info_ptr, width, nrow, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + }else if(palette == NULL) { // Greyscale image png_set_IHDR(png_ptr, info_ptr, width, nrow, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, @@ -125,8 +132,13 @@ static int ImageOut(char *filename, char *chid, float **prow, int nrow, int widt png_set_text(png_ptr, info_ptr, text_ptr, 3); png_set_pHYs(png_ptr, info_ptr, 4000, 4000, PNG_RESOLUTION_METER); - printf("Writing %s ", filename); + if(effects == 2){ + printf("Computing false color & writing: %s", filename); + }else{ + printf("Writing %s", filename); + } fflush(stdout); + pngfile = fopen(filename, "wb"); if (pngfile == NULL) { fprintf(stderr, ERR_FILE_WRITE, filename); @@ -136,14 +148,14 @@ static int ImageOut(char *filename, char *chid, float **prow, int nrow, int widt png_write_info(png_ptr, info_ptr); for (int n = 0; n < nrow; n++) { - float *pixelv; - png_byte pixel[2*IMG_WIDTH]; + png_color pix[width]; + png_byte pixel[width]; - pixelv = prow[n]; + float *pixelv = prow[n]; int f = 0; for (int i = 0; i < width; i++) { - // Skip parts of the image that are telemtry - if(croptele){ + // Skip parts of the image that are telemetry + if(effects == 1){ switch (i) { case 0: f += SYNC_WIDTH + SPC_WIDTH; @@ -156,128 +168,67 @@ static int ImageOut(char *filename, char *chid, float **prow, int nrow, int widt } } - if(layered){ - // Layered image, overlay highlights in channel B over channel A + if(effects == 2){ + float r = 0, g = 0, b = 0; + falsecolor(pixelv[i+CHA_OFFSET], pixelv[i+CHB_OFFSET], &r, &g, &b); + pix[i].red = r; + pix[i].green = g; + pix[i].blue = b; + }else if(effects == 3){ + // Layered image, overlay clouds in channel B over channel A float cloud = CLIP(pixelv[i+CHB_OFFSET]-141, 0, 255)/114; pixel[i] = MCOMPOSITE(255, cloud, pixelv[i+CHA_OFFSET], 1); }else{ pixel[i] = pixelv[i + offset + f]; } } - png_write_row(png_ptr, pixel); - - } - png_write_end(png_ptr, info_ptr); - fclose(pngfile); - printf("\nDone\n"); - png_destroy_write_struct(&png_ptr, &info_ptr); - return(1); -} - -static int ImageRGBOut(char *filename, float **prow, int nrow) { - FILE *pngfile; - png_infop info_ptr; - png_structp png_ptr; - extern void falsecolor(float vis, float temp, float *r, float *g, float *b); - - // Initalise the PNG writer - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { - fprintf(stderr, ERR_PNG_WRITE); - return(1); - } - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - fprintf(stderr, ERR_PNG_WRITE); - return(1); - } - - png_set_IHDR(png_ptr, info_ptr, CH_WIDTH, nrow, - 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_set_pHYs(png_ptr, info_ptr, 4000, 4000, PNG_RESOLUTION_METER); - - text_ptr[1].text = "False Color"; - text_ptr[1].text_length = strlen(text_ptr[1].text); - png_set_text(png_ptr, info_ptr, text_ptr, 3); - - printf("Computing false color & writing: %s", filename); - fflush(stdout); - pngfile = fopen(filename, "wb"); - if (pngfile == NULL) { - fprintf(stderr, ERR_FILE_WRITE, filename); - return(1); - } - png_init_io(png_ptr, pngfile); - png_write_info(png_ptr, info_ptr); - - for (int n = 0; n < nrow ; n++) { - png_color pix[CH_WIDTH]; - float *pixelc; - - pixelc = prow[n]; - - for (int i = 0; i < CH_WIDTH - 1; i++) { - float r = 0, g = 0, b = 0; - - // False color computation - falsecolor(pixelc[i+CHA_OFFSET], pixelc[i+CHB_OFFSET], &r, &g, &b); - - pix[i].red = r; - pix[i].green = g; - pix[i].blue = b; + if(effects == 2){ + png_write_row(png_ptr, (png_bytep) pix); + }else{ + png_write_row(png_ptr, pixel); } - png_write_row(png_ptr, (png_bytep) pix); } + png_write_end(png_ptr, info_ptr); fclose(pngfile); printf("\nDone\n"); png_destroy_write_struct(&png_ptr, &info_ptr); - return(0); + + return(1); } -// Distribution of values between Channel A and Channel B -static void Distrib(char *filename, float **prow, int nrow) { - unsigned int distrib[256][256]; - int n; - int x, y; +// Outputs a image with the value distribution between channel A and B +static void distrib(char *filename, float **prow, int nrow) { + float *distrib[256]; int max = 0; - FILE *df; - - for(y = 0; y < 256; y++) - for(x = 0; x < 256; x++) - distrib[y][x] = 0; - for(n = 0; n < nrow; n++) { - float *pixelv; - int i; + // Assign memory + for(int i = 0; i < 256; i++) + distrib[i] = (float *) malloc(sizeof(float) * 256); - pixelv = prow[n]; - for(i = 0; i < CH_WIDTH; i++) { - y = (int)(pixelv[i + CHA_OFFSET]); - x = (int)(pixelv[i + CHB_OFFSET]); + for(int n = 0; n < nrow; n++) { + float *pixelv = prow[n]; + + for(int i = 0; i < CH_WIDTH; i++) { + int y = (int)(pixelv[i + CHA_OFFSET]); + int x = (int)(pixelv[i + CHB_OFFSET]); distrib[y][x] += 1; - if(distrib[y][x] > max) max=distrib[y][x]; + if(distrib[y][x] > max) max = distrib[y][x]; } } - df = fopen(filename,"w"); - printf("Writing %s\n",filename); + // Scale to 0-255 + for(int x = 0; x < 256; x++) + for(int y = 0; y < 256; y++) + distrib[y][x] = distrib[y][x] / max * 255; - fprintf(df,"P2\n#max %d\n",max); - fprintf(df,"256 256\n255\n"); - for(y = 0; y < 256; y++) - for(x = 0; x < 256; x++) - fprintf(df, "%d\n", (int)((255.0 * (double)(distrib[y][x])) / (double)max)); - fclose(df); + + ImageOut(filename, "Value distribution", distrib, 256, 256, 0, NULL, 0); } -extern int calibrate(float **prow, int nrow, int offset, int contrastBoost); -extern void Temperature(float **prow, int nrow, int ch, int offset); +extern int calibrate(float **prow, int nrow, int offset, int width, int contrastEqualise); +extern void temperature(float **prow, int nrow, int ch, int offset); extern int Ngvi(float **prow, int nrow); extern void readfcconf(char *file); extern int optind; @@ -290,12 +241,12 @@ static void usage(void) { printf("Aptdec [options] audio files ...\n" "Options:\n" " -e [c|t] Enhancements\n" - " c: Contrast enhance\n" + " c: Contrast equalise\n" " t: Crop telemetry\n" " -i [r|a|b|c|t] Output image type\n" " r: Raw\n" - " a: A channel\n" - " b: B channel\n" + " a: Channel A\n" + " b: Channel B\n" " c: False color\n" " t: Temperature\n" " l: Layered\n" @@ -310,23 +261,28 @@ int main(int argc, char **argv) { char name[500]; char pngdirname[500] = ""; - // Images to create, default to a channel A and channel B image with contrast enhancement and cropped telemetry - char imgopt[20] = "ab"; + // Default to a raw image, with equalization and cropped telemetry + char imgopt[20] = "r"; char enchancements[20] = "ct"; // Image buffer float *prow[3000]; int nrow; - // Mapping between wedge value and channel ID - char *chid[] = { "?", "1", "2", "3A", "4", "5", "3B" }; - char *chname[] = { "unknown", "visble", "near-infrared", "near-infrared", "thermal-infrared", "thermal-infrared", "thermal-infrared" }; - + // Mapping between telemetry wedge value and channel + static struct { + char *id[7]; + char *name[7]; + } ch = { + { "?", "1", "2", "3A", "4", "5", "3B" }, + { "unknown", "visble", "near-infrared", "mid-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" } + }; + // The active sensor in each channel int chA, chB; // Print version - printf("%s\n", VERSION); + printf(VERSION"\n"); // Print usage if there are no arguments if(argc == 1) @@ -345,7 +301,7 @@ int main(int argc, char **argv) { break; // Output image type case 'i': - strcpy(imgopt, optarg); + strncpy(imgopt, optarg, 20); break; // Satellite number (for calibration) case 's': @@ -358,7 +314,7 @@ int main(int argc, char **argv) { break; // Enchancements case 'e': - strcpy(enchancements, optarg); + strncpy(enchancements, optarg, 20); break; default: usage(); @@ -369,10 +325,7 @@ int main(int argc, char **argv) { usage(); } - // Pull this in from filtercoeff.h - extern float Sync[32]; - - // Loop through the provided files + // Process the provided files for (; optind < argc; optind++) { chA = chB = 0; @@ -397,100 +350,91 @@ int main(int argc, char **argv) { if (getpixelrow(prow[nrow]) == 0) break; - // Signal level - double signal = 0; - for (int i = 0; i < 32; i++) signal += prow[nrow][i] - Sync[i]; - - // Signal level bar - char bar[30]; - for (int i = 0; i < 30; i++) { - bar[i] = ' '; - if(i < signal/2000*30) bar[i] = '#'; - } - printf("Row: %d, Signal Strength: %s\r", nrow, bar); + printf("Row: %d\r", nrow); fflush(stdout); } printf("\nTotal rows: %d\n", nrow); sf_close(inwav); - // Layered images require contrast enhancements - int contrastBoost = CONTAINS(enchancements, 'c') || CONTAINS(imgopt, 'l') || CONTAINS(imgopt, 'c'); + // Layered & false color images both need brightness equalization + int contrastEqualise = CONTAINS(enchancements, 'c') || CONTAINS(imgopt, 'l') || CONTAINS(imgopt, 'c'); - chA = calibrate(prow, nrow, CHA_OFFSET, 0); - chB = calibrate(prow, nrow, CHB_OFFSET, 0); - printf("Channel A: %s (%s)\n", chid[chA], chname[chA]); - printf("Channel B: %s (%s)\n", chid[chB], chname[chB]); + chA = calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH, 0); + chB = calibrate(prow, nrow, CHB_OFFSET, CH_WIDTH, 0); + printf("Channel A: %s (%s)\n", ch.id[chA], ch.name[chA]); + printf("Channel B: %s (%s)\n", ch.id[chB], ch.name[chB]); // Temperature if (CONTAINS(imgopt, 't') && chB >= 4) { - Temperature(prow, nrow, chB, CHB_OFFSET); + temperature(prow, nrow, chB, CHB_OFFSET); sprintf(pngfilename, "%s/%s-t.png", pngdirname, name); - ImageOut(pngfilename, "Temperature", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)TempPalette, 0, 0); + ImageOut(pngfilename, "Temperature", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)TempPalette, 0); } - // We have to run the contrast enhance here because the temperature calibration requires real data - // Yes, this requires running a large chunk of code again, but this will be addressed in the future - chA = calibrate(prow, nrow, CHA_OFFSET, contrastBoost); - chB = calibrate(prow, nrow, CHB_OFFSET, contrastBoost); + // Run the contrast equalise here because the temperature calibration requires raw data + if(contrastEqualise) + calibrate(prow, nrow, CHA_OFFSET, CH_WIDTH+TELE_WIDTH+SYNC_WIDTH+SPC_WIDTH+CH_WIDTH, 1); // Layered if (CONTAINS(imgopt, 'l')){ - sprintf(pngfilename, "%s/%s-l.png", pngdirname, name); - ImageOut(pngfilename, "Layered", prow, nrow, CH_WIDTH, 0, NULL, 0, 1); + if(chA == 1){ + sprintf(pngfilename, "%s/%s-l.png", pngdirname, name); + ImageOut(pngfilename, "Layered", prow, nrow, CH_WIDTH, 0, NULL, 3); + }else{ + fprintf(stderr, "Lacking channels required for generting a layered image.\n"); + } } // Raw image if (CONTAINS(imgopt, 'r')) { int croptele = CONTAINS(enchancements, 't'); char channelstr[45]; - sprintf(channelstr, "%s (%s) & %s (%s)", chid[chA], chname[chA], chid[chB], chname[chB]); + sprintf(channelstr, "%s (%s) & %s (%s)", ch.id[chA], ch.name[chA], ch.id[chB], ch.name[chB]); sprintf(pngfilename, "%s/%s-r.png", pngdirname, name); - ImageOut(pngfilename, channelstr, prow, nrow, IMG_WIDTH, 0, NULL, croptele, 0); + ImageOut(pngfilename, channelstr, prow, nrow, IMG_WIDTH, 0, NULL, croptele ? 1 : 0); } // Channel A if (CONTAINS(imgopt, 'a')) { char channelstr[21]; - sprintf(channelstr, "%s (%s)", chid[chA], chname[chA]); + sprintf(channelstr, "%s (%s)", ch.id[chA], ch.name[chA]); - sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, chid[chA]); - ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH, CHA_OFFSET, NULL, 0, 0); + sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, ch.id[chA]); + ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH, CHA_OFFSET, NULL, 0); } // Channel B if (CONTAINS(imgopt, 'b')) { char channelstr[21]; - sprintf(channelstr, "%s (%s)", chid[chB], chname[chB]); + sprintf(channelstr, "%s (%s)", ch.id[chB], ch.name[chB]); - sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, chid[chB]); - ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH , CHB_OFFSET, NULL, 0, 0); + sprintf(pngfilename, "%s/%s-%s.png", pngdirname, name, ch.id[chB]); + ImageOut(pngfilename, channelstr, prow, nrow, CH_WIDTH , CHB_OFFSET, NULL, 0); } - // Distribution map + // Distribution image if (CONTAINS(imgopt, 'd')) { - sprintf(pngfilename, "%s/%s-d.pnm", pngdirname, name); - Distrib(pngfilename, prow, nrow); + sprintf(pngfilename, "%s/%s-d.png", pngdirname, name); + distrib(pngfilename, prow, nrow); } // False color image if(CONTAINS(imgopt, 'c')){ if (chA == 2 && chB >= 4) { // Normal false color sprintf(pngfilename, "%s/%s-c.png", pngdirname, name); - ImageRGBOut(pngfilename, prow, nrow); - } else if (chA == 1 && chB == 2) { // GVI (global vegetation index) false color + //ImageRGBOut(pngfilename, prow, nrow); + ImageOut(pngfilename, "False Color", prow, nrow, CH_WIDTH, 0, NULL, 2); + } else if (chB == 2) { // GVI (global vegetation index) false color Ngvi(prow, nrow); sprintf(pngfilename, "%s/%s-c.png", pngdirname, name); - ImageOut(pngfilename, "GVI False Color", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)GviPalette, 0, 0); + ImageOut(pngfilename, "GVI False Color", prow, nrow, CH_WIDTH, CHB_OFFSET, (png_color*)GviPalette, 0); } else { - fprintf(stderr, "Lacking channels required for false color computation.\n"); + fprintf(stderr, "Lacking channels required for generating a false color image.\n"); } } - - // Free the allocated memory - for(int i = 0; i < 3000; i++) free(prow[i]); } exit(0); diff --git a/messages.h b/messages.h index 702ade2..b7b29eb 100644 --- a/messages.h +++ b/messages.h @@ -1,6 +1,25 @@ +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 + * + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #define ERR_FILE_WRITE "Could not open %s for writing\n" #define ERR_FILE_READ "Could not open %s for reading\n" #define ERR_PNG_WRITE "Could not create a PNG write struct\n" #define ERR_PNG_INFO "Could not create a PNG info struct\n" #define ERR_TELE_ROW "Telemetry decoding error, not enough rows.\n" -#define VERSION "Aptdec CVS version (c) 2004-2005 Thierry Leconte F4DWV" \ No newline at end of file +#define VERSION "Aptdec; copyright (c) 2004-2009 Thierry Leconte F4DWV, Xerbo (xerbo@protonmail.com) 2019" \ No newline at end of file diff --git a/offsets.h b/offsets.h index 453e4fc..6051ea4 100644 --- a/offsets.h +++ b/offsets.h @@ -1,7 +1,27 @@ +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 + * + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #define SYNC_WIDTH 39 #define SPC_WIDTH 47 #define TELE_WIDTH 45 #define CH_WIDTH 909 +#define FRAME_LEN 128 #define CH_OFFSET (SYNC_WIDTH+SPC_WIDTH+CH_WIDTH+TELE_WIDTH) #define IMG_WIDTH 2080 #define CHA_OFFSET (SYNC_WIDTH+SPC_WIDTH) diff --git a/colorpalette.h b/palette.h similarity index 87% rename from colorpalette.h rename to palette.h index de3d95d..52182d0 100644 --- a/colorpalette.h +++ b/palette.h @@ -1,3 +1,22 @@ +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 + * + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + unsigned char GviPalette[256*3] = { "\230t\17\233x\22\236{\27\241\200\33\244\203\37\247\210#\252\214'\255\220" ",\260\2240\264\2305\267\2358\272\240=\274\245A\300\251E\303\255I\306\262" diff --git a/satcal.h b/satcal.h index ebe897c..ecaa0e8 100644 --- a/satcal.h +++ b/satcal.h @@ -1,3 +1,22 @@ +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019 + * + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + const struct { float d[4][3]; struct {