1
0
Fork 0

Improved formatting

master
colaclanth 2019-07-15 17:46:41 +01:00
parent 282d933517
commit 8ecf722670
6 changed files with 58 additions and 39 deletions

View File

@ -1,2 +1,4 @@
#!/usr/bin/env python
from .command import SSTVCommand
from .decode import SSTVDecoder

View File

@ -1,9 +1,12 @@
#!/usr/bin/env python
import sstv
def main():
with sstv.SSTVCommand() as prog:
prog.start()
if __name__ == "__main__":
main()

View File

@ -1,9 +1,10 @@
#!usr/bin/env python
from sys import exit
from os import path
from .decode import SSTVDecoder
import argparse
class SSTVCommand(object):
""" Main class to handle the command line features """
@ -48,7 +49,8 @@ examples:
help="desination of output file",
default="result.png",
dest="output_file")
parser.add_argument("-V", "--version", action="version", version=version)
parser.add_argument("-V", "--version", action="version",
version=version)
parser.add_argument("-v", "--verbose", action="count", default=1,
help="increase output to the terminal")
parser.add_argument("--list-modes", action="store_true",
@ -69,7 +71,7 @@ examples:
self._audio_file = args.audio_file
self._output_file = args.output_file
if args.list_modes:
self.list_supported_modes()
exit(0)
@ -93,7 +95,7 @@ examples:
img.save(self._output_file)
except KeyError:
img.save("result.png")
def close(self):
""" Closes any input/output files if they exist """
if self._output_file is not None and not self._output_file.closed:

View File

@ -1,7 +1,9 @@
#!usr/bin/env python
from sys import stderr, stdout
from os import get_terminal_size
def log_message(message="", show=True, err=False, recur=False, prefix=True):
if not show:
return
@ -18,7 +20,8 @@ def log_message(message="", show=True, err=False, recur=False, prefix=True):
message = ' '.join(["[SSTV]", message])
print(message, file=out, end=end)
def progress_bar(progress, complete, message="", show=True):
if not show:
return
@ -38,8 +41,8 @@ def progress_bar(progress, complete, message="", show=True):
percent = ""
if percent_on:
percent = "{:4.0f}%".format(level * 100)
align_size = cols - len(message) - len(percent)
align = cols - len(message) - len(percent)
not_end = not progress == complete
log_message("{}{:>{width}}{}".format(message, bar, percent,
width=align_size), recur=not_end, prefix=False)
log_message("{}{:>{width}}{}".format(message, bar, percent, width=align),
recur=not_end, prefix=False)

View File

@ -1,7 +1,8 @@
#!usr/bin/env python
from . import spec
from .common import log_message, progress_bar
from PIL import Image, ImageDraw
from PIL import Image
from scipy.signal.windows import hann
import soundfile
import numpy as np
@ -12,7 +13,7 @@ class SSTVDecoder(object):
def __init__(self, audio_file):
"""
Initialise SSTV decoder
audio_data - Can be a path to an audio file OR a tuple containing
samples and the sampling rate of audio data
"""
@ -39,7 +40,7 @@ class SSTVDecoder(object):
def decode(self, skip=0):
"""
Attempts to decode the audio data as an SSTV signal
Returns a PIL image on success, and None on error
"""
@ -61,7 +62,7 @@ class SSTVDecoder(object):
return None
return self._draw_image(image_data)
def close(self):
""" Closes any input files if they exist """
if self._audio_file is not None and not self._audio_file.closed:
@ -149,7 +150,8 @@ class SSTVDecoder(object):
for bit_idx in range(8):
bit_offset = bit_idx * bit_size
freq = self._peak_fft_freq(vis_section[bit_offset:bit_offset+bit_size])
section = vis_section[bit_offset:bit_offset+bit_size]
freq = self._peak_fft_freq(section)
vis_bits.append(int(freq <= 1200))
# check for even parity in last bit
@ -182,14 +184,6 @@ class SSTVDecoder(object):
else:
return lum
#def _yuv_to_rgb(y, ry, by):
# red = 0.003906 * ((298.082 * (y - 16.0)) + (408.583 * (ry - 128.0)))
# green = 0.003906 * ((298.082 * (y - 16.0)) + (-100.291 * (by - 128.0)) \
# + (-208.12 * (ry - 128.0)))
# blue = 0.003906 * ((298.082 * (y - 16.0)) + (516.411 * (by - 128.0)))
# rgb = round(red), round(green), round(blue)
# return rgb
def _align_sync(self, align_section, start_of_sync=True):
# Returns sample where the beginning of the sync pulse was found
sync_window = round(self.mode.SYNC_PULSE * 1.4 * self._sample_rate)
@ -197,7 +191,8 @@ class SSTVDecoder(object):
current_sample = 0
while current_sample < search_end:
freq = self._peak_fft_freq(align_section[current_sample:current_sample+sync_window])
section = align_section[current_sample:current_sample+sync_window]
freq = self._peak_fft_freq(section)
if freq > 1350:
break
current_sample += 1
@ -219,7 +214,8 @@ class SSTVDecoder(object):
if self.mode == spec.R36:
window_factor = 7.83
pixel_window = round(self.mode.PIXEL_TIME * window_factor * self._sample_rate)
pixel_window = round(self.mode.PIXEL_TIME * window_factor *
self._sample_rate)
centre_window_time = (self.mode.PIXEL_TIME * window_factor) / 2
image_data = []
@ -234,16 +230,18 @@ class SSTVDecoder(object):
image_data.append([])
if self.mode.CHAN_SYNC > 0 and line == 0:
# align seq_start to the beginning of the sync pulse in the past
seq_start -= round((self.mode.CHAN_OFFSETS[self.mode.CHAN_SYNC] \
+ self.mode.SCAN_TIME) * self._sample_rate)
# align seq_start to the beginning of the previous sync pulse
sync_offset = self.mode.CHAN_OFFSETS[self.mode.CHAN_SYNC]
seq_start -= round((sync_offset + self.mode.SCAN_TIME)
* self._sample_rate)
for chan in range(self.mode.CHAN_COUNT):
image_data[line].append([])
if chan == self.mode.CHAN_SYNC:
if line > 0 or chan > 0:
seq_start += round(self.mode.LINE_TIME * self._sample_rate)
seq_start += round(self.mode.LINE_TIME *
self._sample_rate)
# align to start of sync pulse
seq_start += self._align_sync(transmission[seq_start:])
@ -253,20 +251,22 @@ class SSTVDecoder(object):
if chan % 2 == 1:
pixel_time = self.mode.MERGE_PIXEL_TIME
pixel_window = round(pixel_time * window_factor * self._sample_rate)
pixel_window = round(pixel_time * window_factor *
self._sample_rate)
centre_window_time = (pixel_time * window_factor) / 2
for px in range(self.mode.LINE_WIDTH):
chan_offset = self.mode.CHAN_OFFSETS[chan]
px_sample = round(seq_start + (chan_offset + px * pixel_time \
- centre_window_time) * self._sample_rate)
freq = self._peak_fft_freq(transmission[px_sample:px_sample+pixel_window])
px_sample = round(seq_start + (chan_offset + px *
pixel_time - centre_window_time) *
self._sample_rate)
section = transmission[px_sample:px_sample+pixel_window]
freq = self._peak_fft_freq(section)
image_data[line][chan].append(SSTVDecoder._calc_lum(freq))
progress_bar(line, self.mode.LINE_COUNT - 1,
"Decoding image... ", self.log_basic)
@ -281,7 +281,8 @@ class SSTVDecoder(object):
else:
col_mode = "RGB"
image = Image.new(col_mode, (self.mode.LINE_WIDTH, self.mode.LINE_COUNT))
image = Image.new(col_mode,
(self.mode.LINE_WIDTH, self.mode.LINE_COUNT))
pixel_data = image.load()
for y in range(self.mode.LINE_COUNT):
@ -290,12 +291,17 @@ class SSTVDecoder(object):
for x in range(self.mode.LINE_WIDTH):
if self.mode.COLOR == spec.COL_FMT.GBR:
pixel = image_data[y][2][x], image_data[y][0][x], image_data[y][1][x]
pixel = (image_data[y][2][x],
image_data[y][0][x],
image_data[y][1][x])
elif self.mode.COLOR == spec.COL_FMT.YUV:
pixel = (image_data[y][0][x], image_data[y-ryby][1][x],
image_data[y-(ryby-1)][1][x])
pixel = (image_data[y][0][x],
image_data[y-ryby][1][x],
image_data[y-(ryby-1)][1][x])
else:
pixel = image_data[y][0][x], image_data[y][1][x], image_data[y][2][x]
pixel = (image_data[y][0][x],
image_data[y][1][x],
image_data[y][2][x])
pixel_data[x, y] = pixel
if self.mode.COLOR == spec.COL_FMT.YUV:

View File

@ -1,4 +1,5 @@
#!usr/bin/env python
from enum import Enum
BREAK_OFFSET = 0.300
@ -10,17 +11,20 @@ HDR_WINDOW_SIZE = 0.010
VIS_BIT_SIZE = 0.030
class COL_FMT(Enum):
RGB = 1
GBR = 2
YUV = 3
BW = 4
class SSTV(object):
HAS_START_SYNC = False
HAS_MERGE_SCAN = False
CHAN_SYNC = 0
class M1(SSTV):
NAME = "Martin 1"
VIS_CODE = 44
@ -35,7 +39,6 @@ class M1(SSTV):
CHAN_COUNT = 3
CHAN_TIME = SEP_PULSE + SCAN_TIME
# CHAN_OFFSETS = [SYNC_PULSE + SYNC_PORCH + c * CHAN_TIME for c in range(CHAN_COUNT)]
CHAN_OFFSETS = [SYNC_PULSE + SYNC_PORCH]
CHAN_OFFSETS.append(CHAN_OFFSETS[0] + CHAN_TIME)
CHAN_OFFSETS.append(CHAN_OFFSETS[1] + CHAN_TIME)