Просмотр исходного кода

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
tags/v1.8.0
Xerbo 5 лет назад
Родитель
Сommit
d8446bc03d
14 измененных файлов: 482 добавлений и 462 удалений
  1. +13
    -13
      LICENSE
  2. +2
    -2
      Makefile
  3. +3
    -3
      README.md
  4. +76
    -74
      dsp.c
  5. +22
    -5
      fcolor.c
  6. +23
    -22
      filter.c
  7. +13
    -16
      filter.h
  8. +18
    -21
      filtercoeff.h
  9. +102
    -117
      image.c
  10. +132
    -188
      main.c
  11. +20
    -1
      messages.h
  12. +20
    -0
      offsets.h
  13. +19
    -0
      palette.h
  14. +19
    -0
      satcal.h

+ 13
- 13
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

+ 2
- 2
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


+ 3
- 3
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



+ 76
- 74
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 <https://www.gnu.org/licenses/>.
*
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#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);
}
}

+ 22
- 5
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 <https://www.gnu.org/licenses/>.
*
*/

#include <stdio.h>
#include <math.h>
#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;


+ 23
- 22
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 <https://www.gnu.org/licenses/>.
*
*/
#include "filter.h"

#include <math.h>

// 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;



+ 13
- 16
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 <https://www.gnu.org/licenses/>.
*
*/


+ 18
- 21
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 <https://www.gnu.org/licenses/>.
*
* 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,


+ 102
- 117
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 <https://www.gnu.org/licenses/>.
*
*/

@@ -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;


+ 132
- 188
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 <https://www.gnu.org/licenses/>.
*
*/

@@ -24,21 +21,17 @@
#include <stdio.h>
#include <string.h>
#include <getopt.h>

#include <libgen.h>

#include <math.h>

#include <sndfile.h>
#include <png.h>

#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);


+ 20
- 1
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 <https://www.gnu.org/licenses/>.
*
*/

#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"
#define VERSION "Aptdec; copyright (c) 2004-2009 Thierry Leconte F4DWV, Xerbo (xerbo@protonmail.com) 2019"

+ 20
- 0
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 <https://www.gnu.org/licenses/>.
*
*/

#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)


colorpalette.h → 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 <https://www.gnu.org/licenses/>.
*
*/

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"

+ 19
- 0
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 <https://www.gnu.org/licenses/>.
*
*/

const struct {
float d[4][3];
struct {


Загрузка…
Отмена
Сохранить