2013-05-23 14:11:53 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
from __future__ import division
|
2013-11-22 16:05:13 +00:00
|
|
|
from sstv import byte_to_freq, FREQ_BLACK, FREQ_WHITE, FREQ_VIS_START
|
2013-05-23 14:11:53 +00:00
|
|
|
from grayscale import GrayscaleSSTV
|
2013-11-22 16:05:13 +00:00
|
|
|
from itertools import chain
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-06-18 22:15:18 +00:00
|
|
|
|
2013-07-02 09:17:40 +00:00
|
|
|
RED, GREEN, BLUE = range(3)
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-07-02 09:17:40 +00:00
|
|
|
class ColorSSTV(GrayscaleSSTV):
|
2013-06-18 22:15:18 +00:00
|
|
|
def encode_line(self, line):
|
|
|
|
msec_pixel = self.SCAN / self.WIDTH
|
2013-07-01 14:20:19 +00:00
|
|
|
image = self.image.load()
|
2013-07-02 09:12:09 +00:00
|
|
|
for index in self.COLOR_SEQ:
|
2013-06-18 22:15:18 +00:00
|
|
|
for item in self.before_channel(index):
|
|
|
|
yield item
|
|
|
|
for col in xrange(self.WIDTH):
|
2013-07-01 14:20:19 +00:00
|
|
|
pixel = image[col, line]
|
2013-06-18 22:15:18 +00:00
|
|
|
freq_pixel = byte_to_freq(pixel[index])
|
|
|
|
yield freq_pixel, msec_pixel
|
|
|
|
for item in self.after_channel(index):
|
|
|
|
yield item
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-06-18 22:15:18 +00:00
|
|
|
def before_channel(self, index):
|
|
|
|
return []
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-06-18 22:15:18 +00:00
|
|
|
after_channel = before_channel
|
2013-05-30 17:00:00 +00:00
|
|
|
|
2013-05-23 14:11:53 +00:00
|
|
|
|
|
|
|
class MartinM1(ColorSSTV):
|
2013-07-02 09:17:40 +00:00
|
|
|
COLOR_SEQ = (GREEN, BLUE, RED)
|
2013-06-18 22:15:18 +00:00
|
|
|
VIS_CODE = 0x2c
|
|
|
|
WIDTH = 320
|
|
|
|
HEIGHT = 256
|
|
|
|
SYNC = 4.862
|
|
|
|
SCAN = 146.432
|
|
|
|
INTER_CH_GAP = 0.572
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-06-18 22:15:18 +00:00
|
|
|
def before_channel(self, index):
|
2013-07-02 09:17:40 +00:00
|
|
|
if index == GREEN:
|
2013-06-18 22:15:18 +00:00
|
|
|
yield FREQ_BLACK, self.INTER_CH_GAP
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-06-18 22:15:18 +00:00
|
|
|
def after_channel(self, index):
|
|
|
|
yield FREQ_BLACK, self.INTER_CH_GAP
|
2013-05-30 17:00:16 +00:00
|
|
|
|
2013-05-23 14:11:53 +00:00
|
|
|
|
|
|
|
class MartinM2(MartinM1):
|
2013-06-18 22:15:18 +00:00
|
|
|
VIS_CODE = 0x28
|
|
|
|
WIDTH = 160
|
|
|
|
SCAN = 73.216
|
2013-05-23 14:11:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ScottieS1(MartinM1):
|
2013-06-18 22:15:18 +00:00
|
|
|
VIS_CODE = 0x3c
|
|
|
|
SYNC = 9
|
|
|
|
INTER_CH_GAP = 1.5
|
|
|
|
SCAN = 138.24 - INTER_CH_GAP
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-06-18 22:15:18 +00:00
|
|
|
def horizontal_sync(self):
|
|
|
|
return []
|
2013-05-23 14:11:53 +00:00
|
|
|
|
2013-06-18 22:15:18 +00:00
|
|
|
def before_channel(self, index):
|
|
|
|
if index == ColorSSTV.RED:
|
|
|
|
for item in MartinM1.horizontal_sync(self):
|
|
|
|
yield item
|
|
|
|
yield FREQ_BLACK, self.INTER_CH_GAP
|
2013-05-23 14:11:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ScottieS2(ScottieS1):
|
2013-06-18 22:15:18 +00:00
|
|
|
VIS_CODE = 0x38
|
|
|
|
SCAN = 88.064 - ScottieS1.INTER_CH_GAP
|
|
|
|
WIDTH = 160
|
2013-06-17 11:02:16 +00:00
|
|
|
|
2013-11-22 16:05:13 +00:00
|
|
|
|
|
|
|
class Robot36(ColorSSTV):
|
|
|
|
VIS_CODE = 0x08
|
|
|
|
WIDTH = 320
|
|
|
|
HEIGHT = 240
|
|
|
|
SYNC = 9
|
|
|
|
INTER_CH_GAP = 4.5
|
|
|
|
Y_SCAN = 88
|
|
|
|
C_SCAN = 44
|
|
|
|
PORCH = 1.5
|
|
|
|
SYNC_PORCH = 3
|
|
|
|
INTER_CH_FREQS = [FREQ_BLACK, FREQ_WHITE]
|
|
|
|
CHANNEL_COEFFS = [
|
|
|
|
(128.0, 112.439, -94.154, -18.285),
|
|
|
|
(128.0, -37.945, -74.494, 112.439)]
|
|
|
|
|
|
|
|
def encode_line(self, line):
|
|
|
|
image = self.image.load()
|
|
|
|
pixels = [image[col, line] for col in xrange(self.WIDTH)]
|
|
|
|
channel = line % 2
|
|
|
|
return chain(
|
|
|
|
[(FREQ_BLACK, self.SYNC_PORCH)],
|
|
|
|
encode_robot_pixels(pixels, (16.0, 65.738, 129.057, 25.064),
|
|
|
|
self.Y_SCAN / self.WIDTH),
|
|
|
|
[(self.INTER_CH_FREQS[channel], self.INTER_CH_GAP),
|
|
|
|
(FREQ_VIS_START, self.PORCH)],
|
|
|
|
encode_robot_pixels(pixels, self.CHANNEL_COEFFS[channel],
|
|
|
|
self.C_SCAN / self.WIDTH))
|
|
|
|
|
|
|
|
def encode_robot_pixels(pixels, coeffs, pixel_time):
|
|
|
|
cs, cr, cg, cb = coeffs
|
|
|
|
for pixel in pixels:
|
|
|
|
value = cs + (0.003906 * ((cr * pixel[RED]) +
|
|
|
|
(cg * pixel[GREEN]) + (cb * pixel[BLUE])))
|
|
|
|
yield byte_to_freq(value), pixel_time
|
|
|
|
|
|
|
|
|
|
|
|
MODES = (MartinM1, MartinM2, ScottieS1, ScottieS2, Robot36)
|