Added to tempest module utilities functions

This commit is contained in:
Emilio Martínez 2023-02-25 12:21:59 -03:00
parent e4dcb863b8
commit 8711529c5f
4 changed files with 503 additions and 306 deletions

View File

@ -4,7 +4,7 @@ category: '[Tempest]'
templates:
imports: import tempest
make: tempest.TMDS_image_source(${image_file}, ${mode})
make: tempest.TMDS_image_source(${image_file}, ${mode}, ${blanking})
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
@ -22,6 +22,11 @@ parameters:
options: ['1', '2','3','4']
option_labels: ['Repeat with TMDS', 'Repeat, no TMDS','No repeat with TMDS','No repeat, no TMDS']
- id: blanking
label: Use blanking
dtype: bool
options: ['True', 'False']
option_labels: ['True', 'False']
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:

View File

@ -36,6 +36,7 @@ GR_PYTHON_INSTALL(
message_to_var.py
tempest_msgbtn.py
TMDS_image_source.py
DTutils.py
TMDS_decoder.py DESTINATION ${GR_PYTHON_DIR}/tempest
)

View File

@ -0,0 +1,465 @@
import numpy as np
from matplotlib import pyplot as plt
from scipy import signal
from scipy.fft import fft, ifft, fftshift
def autocorr(x):
"""Compute autocorrelation function of 1-D array
Input:
x: 1-D array
Output:
autocorr: autocorrelation function of x
"""
# Use FFT method, which has more computing efectiveness for 1-D numpy arrays
autocorr = signal.correlate(x,x,mode='full', method= 'fft')
# Fix some shifts due FFT
half_idx =int(autocorr.size/2)
max_ind = np.argmax(autocorr[half_idx:])+half_idx
autocorr = autocorr[max_ind:]
# Normalise output
return autocorr/autocorr[0]
def uint8_to_binarray(integer):
"""Convert integer into fixed-length 8-bit binary array. LSB in [0].
Extended and modified code from https://github.com/projf/display_controller/blob/master/model/tmds.py
"""
b_array = [int(i) for i in reversed(bin(integer)[2:])]
b_array += [0]*(8-len(b_array))
return b_array
def uint16_to_binarray(integer):
"""Convert integer into fixed-length 16-bit binary array. LSB in [0].
Extended and modified code from https://github.com/projf/display_controller/blob/master/model/tmds.py
"""
b_array = [int(i) for i in reversed(bin(integer)[2:])]
b_array += [0]*(16-len(b_array))
return b_array
def binarray_to_uint(binarray):
array = binarray[::-1]
num = array[0]
for n in range(1,len(binarray)):
num = (num << 1) + array[n]
return num
def TMDS_pixel (pix,cnt=0):
"""8bit pixel TMDS coding
Inputs:
- pix: 8-bit pixel
- cnt: 0's and 1's balance. Default in 0 (balanced)
Outputs:
- pix_out: TDMS coded 16-bit pixel (only 10 useful)
- cnt: 0's and 1's balance updated with new pixel coding
"""
# Convert 8-bit pixel to binary list D
D = uint8_to_binarray(pix)
# Initialize output q
qm = [D[0]]
# 1's unbalanced condition at current pixel
N1_D = np.sum(D)
if N1_D>4 or (N1_D==4 and not(D[0])):
# XNOR of consecutive bits
for k in range(1,8):
qm.append( not(qm[k-1] ^ D[k]) )
qm.append(0)
else:
# XOR of consecutive bits
for k in range(1,8):
qm.append( qm[k-1] ^ D[k] )
qm.append(1)
# Initialize output qout
qout = qm.copy()
# Unbalanced condition with previous and current pixels
N1_qm = np.sum(qm[:8])
N0_qm = 8 - N1_qm
if cnt==0 or N1_qm==4:
qout.append(not(qm[8]))
qout[8] = qm[8]
qout[:8]=qm[:8] if qm[8] else np.logical_not(qm[:8])
if not(qm[8]):
cnt += N0_qm - N1_qm
else:
cnt += N1_qm - N0_qm
else:
if (cnt>0 and N1_qm>4) or (cnt<0 and N1_qm<4):
qout.append(1)
qout[8] = qm[8]
qout[:8] = np.logical_not(qm[:8])
cnt += 2*qm[8] + N0_qm - N1_qm
else:
qout.append(0)
qout[8] = qm[8]
qout[:8] = qm[:8]
cnt += -2*(not(qm[8])) + N1_qm - N0_qm
# Return the TMDS coded pixel as uint and 0's y 1's balance
return binarray_to_uint(qout), cnt
def TMDS_encoding_original (I, blanking = False):
"""TMDS image coding
Inputs:
- I: 2-D image array
- blanking: Boolean that specifies if horizontal and vertical blanking is applied
Output:
- I_c: TDMS coded 16-bit image (only 10 useful)
"""
# Create "ghost dimension" if I is gray-scale image (not RGB)
if len(I.shape)!= 3:
I = np.repeat(I[:, :, np.newaxis], 3, axis=2).astype('uint8')
chs = 3
# Get image resolution
v_in, h_in = I.shape[:2]
if blanking:
# Get blanking resolution for input image
v = (v_in==1080)*1125 + (v_in==720)*750 + (v_in==600)*628 + (v_in==480)*525
h = (h_in==1920)*2200 + (h_in==1280)*1650 + (h_in==800)*1056 + (h_in==640)*800
vdiff = v - v_in
hdiff = h - h_in
# Create image with blanking and change type to uint16
# Assuming the blanking corresponds to 10bit number [0, 0, 1, 0, 1, 0, 1, 0, 1, 1] (LSB first)
I_c = 852*np.ones((v,h,chs)).astype('uint16')
else:
v_diff = 0
h_diff = 0
I_c = np.zeros((v_in,h_in,chs)).astype('uint16')
# Iterate over channels and pixels
for c in range(chs):
for i in range(v_in):
cnt=[0,0,0]
for j in range(h_in):
# Get pixel and code it TMDS between blanking
pix = I[i,j,c]
I_c[i + v_diff//2 , j + h_diff//2, c], cnt[c] = TMDS_pixel (pix,cnt[c])
return I_c
def TMDS_pixel_cntdiff (pix,cnt=0):
"""8bit pixel TMDS coding
Inputs:
- pix: 8-bit pixel
- cnt: 0's and 1's balance. Default in 0 (balanced)
Outputs:
- pix_out: TDMS coded 16-bit pixel (only 10 useful)
- cntdiff: balance difference given by the actual coded pixel
"""
# Convert 8-bit pixel to binary list D
D = uint8_to_binarray(pix)
# Initialize output q
qm = [D[0]]
# 1's unbalanced condition at current pixelo
N1_D = np.sum(D)
if N1_D>4 or (N1_D==4 and not(D[0])):
# XNOR of consecutive bits
for k in range(1,8):
qm.append( not(qm[k-1] ^ D[k]) )
qm.append(0)
else:
# XOR of consecutive bits
for k in range(1,8):
qm.append( qm[k-1] ^ D[k] )
qm.append(1)
# Initialize output qout
qout = qm.copy()
# Unbalanced condition with previous and current pixels
N1_qm = np.sum(qm[:8])
N0_qm = 8 - N1_qm
if cnt==0 or N1_qm==4:
qout.append(not(qm[8]))
qout[8]=qm[8]
qout[:8]=qm[:8] if qm[8] else [not(val) for val in qm[:8]]
if not(qm[8]):
cnt_diff = N0_qm - N1_qm
else:
cnt_diff = N1_qm - N0_qm
else:
if (cnt>0 and N1_qm>4) or (cnt<0 and N1_qm<4):
qout.append(1)
qout[8]=qm[8]
qout[:8] = [not(val) for val in qm[:8]]
cnt_diff = 2*qm[8] +N0_qm -N1_qm
else:
qout.append(0)
qout[8]=qm[8]
qout[:8] = qm[:8]
cnt_diff = -2*(not(qm[8])) + N1_qm - N0_qm
# Return the TMDS coded pixel as uint and 0's y 1's balance difference
uint_out = binarray_to_uint(qout)
return uint_out, cnt_diff
### Create TMDS LookUp Tables for fast encoding (3 times faster than the other implementation)
byte_range = np.arange(256)
# Initialize pixel coding and cnt-difference arrays
TMDS_pix_table = np.zeros((256,3),dtype='uint16')
TMDS_cntdiff_table = np.zeros((256,3),dtype='int8')
for byte in byte_range:
p0,p_null, p1 = TMDS_pixel_cntdiff(byte,-1),TMDS_pixel_cntdiff(byte,0),TMDS_pixel_cntdiff(byte,1) # 0's and 1's unbalance respect.
TMDS_pix_table[byte,0] = p0[0]
TMDS_pix_table[byte,1] = p_null[0]
TMDS_pix_table[byte,2] = p1[0]
TMDS_cntdiff_table[byte,0] = p0[1]
TMDS_cntdiff_table[byte,1] = p_null[1]
TMDS_cntdiff_table[byte,2] = p1[1]
def pixel_fastencoding(pix,cnt_prev=0):
"""8bit pixel TMDS fast coding
Inputs:
- pix: 8-bit pixel
- cnt: 0's and 1's balance. Default in 0 (balanced)
Outputs:
- pix_out: TDMS coded 16-bit pixel (only 10 useful)
- cnt: 0's and 1's balance updated with new pixel coding
"""
balance_idx = int(np.sign(cnt_prev))+1
pix_out = TMDS_pix_table[pix,balance_idx]
cnt = cnt_prev + TMDS_cntdiff_table[pix,balance_idx]
return pix_out, cnt
def TMDS_blanking (h_total, v_total, h_active, v_active, h_front_porch, v_front_porch, h_back_porch, v_back_porch):
# Initialize blanking image
img_blank = np.zeros((v_total,h_total))
# Get the total blanking on vertical an horizontal axis
h_blank = h_total - h_active
v_blank = v_total - v_active
# (C1,C0)=(0,0) region
img_blank[:v_front_porch,:h_front_porch] = 0b1101010100
img_blank[:v_front_porch,h_blank-h_back_porch:] = 0b1101010100
img_blank[v_blank-v_back_porch:v_blank,:h_front_porch] = 0b1101010100
img_blank[v_blank-v_back_porch:v_blank,h_blank-h_back_porch:] = 0b1101010100
img_blank[v_blank:,:h_blank] = 0b1101010100
# (C1,C0)=(0,1) region
img_blank[:v_front_porch,h_front_porch:h_blank-h_back_porch] = 0b0010101011
img_blank[v_blank-v_back_porch:,h_front_porch:h_blank-h_back_porch] = 0b0010101011
# (C1,C0)=(1,0) region
img_blank[v_front_porch:v_blank-v_back_porch,:h_front_porch] = 0b0101010100
img_blank[v_front_porch:v_blank-v_back_porch,h_blank-h_back_porch:] = 0b0101010100
# (C1,C0)=(1,1) region
img_blank[v_front_porch:v_blank-v_back_porch,v_front_porch:h_blank-h_back_porch] = 0b1010101011
return(img_blank)
def TMDS_encoding (I, blanking = False):
"""TMDS image coding
Inputs:
- I: 2D/3D image array (v_size, h_size, channels)
- blanking: Boolean that specifies if horizontal and vertical blanking is applied or not
Output:
- I_c: 3D TDMS coded 16-bit (only 10 useful) image array
"""
# Create "ghost dimension" if I is gray-scale image (not RGB)
if len(I.shape)!= 3:
# Gray-scale image
I = np.repeat(I[:, :, np.newaxis], 3, axis=2).astype('uint8')
chs = 1
else:
# RGB image
chs = 3
# Get image resolution
v_in, h_in = I.shape[:2]
if blanking:
# Get blanking resolution for input image
v = (v_in==1080)*1125 + (v_in==900)*1000 + (v_in==720)*750 + (v_in==600)*628 + (v_in==480)*525
h = (h_in==1920)*2200 + (h_in==1600)*1800 + (h_in==1280)*1650 + (h_in==800)*1056 + (h_in==640)*800
v_diff = v - v_in
h_diff = h - h_in
v_front_porch = (v_in==1080)*4 + (v_in==900)*1 + (v_in==720)*5 + (v_in==600)*1 + (v_in==480)*2
v_back_porch = (v_in==1080)*36 + (v_in==900)*96 + (v_in==720)*20 + (v_in==600)*23 + (v_in==480)*25
h_front_porch = (h_in==1920)*88 + (h_in==1600)*24 + (h_in==1280)*110 + (h_in==800)*40 + (h_in==640)*8
h_back_porch = (h_in==1920)*148 + (h_in==1600)*96 + (h_in==1280)*220 + (h_in==800)*88 + (h_in==640)*40
# Create image with blanking and change type to uint16
# Assuming the blanking corresponds to 10bit number
# [0, 0, 1, 0, 1, 0, 1, 0, 1, 1] (LSB first) for channels R and G
I_c = 852*np.ones((v,h,chs)).astype('uint16')
I_c[:,:,2] = TMDS_blanking(h_total=h, v_total=v, h_active=h_in, v_active=v_in,
h_front_porch=h_front_porch, v_front_porch=v_front_porch, h_back_porch=h_back_porch, v_back_porch=v_back_porch)
else:
v_diff = 0
h_diff = 0
I_c = np.zeros((v_in,h_in,chs)).astype('uint16')
# Iterate over channels and pixels
for c in range(chs):
for i in range(v_in):
cnt = [0,0,0]
for j in range(h_in):
# Get pixel and code it TMDS between blanking
pix = I[i,j,c]
I_c[i + v_diff, j + h_diff, c], cnt[c] = pixel_fastencoding (pix,cnt[c])
return I_c
def DecTMDS_pixel (pix):
"""10-bit pixel TMDS decoding
Inputs:
- pix: 16-bit pixel (only 10 first bits useful)
Output:
- pix_out: 8-bit TMDS decoded pixel
"""
D = uint16_to_binarray(pix)[:10]
if D[9]:
D[:8] = np.logical_not(D[:8])
Q = D.copy()[:8]
if D[8]:
for k in range(1,8):
Q[k] = D[k] ^ D[k-1]
else:
for k in range(1,8):
Q[k] = not(D[k] ^ D[k-1])
# Return pixel as uint
return binarray_to_uint(Q)
def TMDS_decoding (Ic):
"""Image TMDS decoding
Inputs:
- Ic: TMDS coded image
Output:
- Idec: 8-bit decoded image
"""
# Create "ghost dimension" if gray-scale image (not RGB)
if len(Ic.shape)!= 3:
Ic = Ic.reshape(Ic.shape[0],Ic.shape[1],1)
Idec = Ic.copy()
# Get image dimensions
Nx, Ny, Nz = Ic.shape
# Iterate over channels and pixels
for c in np.arange(Nz):
for i in np.arange(Nx):
for j in np.arange(Ny):
# Get pixel and use TMDS decoding
pix = Ic[i,j,c]
Idec[i,j,c] = DecTMDS_pixel (pix)
return Idec
def TMDS_serial(I):
'''
Serialize an image as an 1D binary array given a 10bit pixel value.
Inputs:
- I: TMDS image to serialize. Pixel values must be between 0 and 1023
Output:
- Iserials: 1D binary array per image channel which represents
the voltage value to be transmitted
'''
assert np.min(I)>=0 and np.max(I)<= 1023, "Pixel values must be between 0 and 1023"
# Initialize lists per channel
Iserials = []
n_rows,n_columns, n_channels = I.shape
# Iterate over pixel
for c in range(n_channels):
channel_list = []
for i in range(n_rows):
for j in range(n_columns):
# Get pixel value and cast it as binary string
binstring = bin(I[i,j,c])[2:]
# Fill string with 0's to get length 10
binstring = '0'*(10-len(binstring))+binstring
# Re-order string for LSB first
binstring = binstring[::-1]
binarray = list(binstring)
# Extend the bit stream
channel_list.extend(binarray)
Iserials.append(channel_list)
# Digital to analog value mapping: [0,1]-->[-A,A] (A=1)
Iserials = np.sum(2*np.array(Iserials,dtype='int32') - 1, axis=0)
del(channel_list)
return Iserials

View File

@ -26,296 +26,10 @@
import numpy as np
from skimage.io import imread
# from DTutils import TMDS_pix_table, TMDS_cntdiff_table, pixel_fastencoding, TMDS_encoding
from PIL import Image
from tempest.DTutils import TMDS_pix_table, TMDS_cntdiff_table, pixel_fastencoding, TMDS_encoding
from gnuradio import gr
def uint8_to_binarray(integer):
"""Convert integer into fixed-length 8-bit binary array. LSB in [0].
Extended and modified code from https://github.com/projf/display_controller/blob/master/model/tmds.py
"""
b_array = [int(i) for i in reversed(bin(integer)[2:])]
b_array += [0]*(8-len(b_array))
return b_array
def uint16_to_binarray(integer):
"""Convert integer into fixed-length 16-bit binary array. LSB in [0].
Extended and modified code from https://github.com/projf/display_controller/blob/master/model/tmds.py
"""
b_array = [int(i) for i in reversed(bin(integer)[2:])]
b_array += [0]*(16-len(b_array))
return b_array
def binarray_to_uint(binarray):
array = binarray[::-1]
num = array[0]
for n in range(1,len(binarray)):
num = (num << 1) + array[n]
return num
def TMDS_pixel (pix,cnt=0):
"""8bit pixel TMDS coding
Inputs:
- pix: 8-bit pixel
- cnt: 0's and 1's balance. Default in 0 (balanced)
Outputs:
- pix_out: TDMS coded 16-bit pixel (only 10 useful)
- cnt: 0's and 1's balance updated with new pixel coding
"""
# Convert 8-bit pixel to binary list D
D = uint8_to_binarray(pix)
# Initialize output q
qm = [D[0]]
# 1's unbalanced condition at current pixel
N1_D = np.sum(D)
if N1_D>4 or (N1_D==4 and not(D[0])):
# XNOR of consecutive bits
for k in range(1,8):
qm.append( not(qm[k-1] ^ D[k]) )
qm.append(0)
else:
# XOR of consecutive bits
for k in range(1,8):
qm.append( qm[k-1] ^ D[k] )
qm.append(1)
# Initialize output qout
qout = qm.copy()
# Unbalanced condition with previous and current pixels
N1_qm = np.sum(qm[:8])
N0_qm = 8 - N1_qm
if cnt==0 or N1_qm==4:
qout.append(not(qm[8]))
qout[8] = qm[8]
qout[:8]=qm[:8] if qm[8] else np.logical_not(qm[:8])
if not(qm[8]):
cnt += N0_qm - N1_qm
else:
cnt += N1_qm - N0_qm
else:
if (cnt>0 and N1_qm>4) or (cnt<0 and N1_qm<4):
qout.append(1)
qout[8] = qm[8]
qout[:8] = np.logical_not(qm[:8])
cnt += 2*qm[8] + N0_qm - N1_qm
else:
qout.append(0)
qout[8] = qm[8]
qout[:8] = qm[:8]
cnt += -2*(not(qm[8])) + N1_qm - N0_qm
# Return the TMDS coded pixel as uint and 0's y 1's balance
return binarray_to_uint(qout), cnt
def TMDS_pixel_cntdiff (pix,cnt=0):
"""8bit pixel TMDS coding
Inputs:
- pix: 8-bit pixel
- cnt: 0's and 1's balance. Default in 0 (balanced)
Outputs:
- pix_out: TDMS coded 16-bit pixel (only 10 useful)
- cntdiff: balance difference given by the actual coded pixel
"""
# Convert 8-bit pixel to binary list D
D = uint8_to_binarray(pix)
# Initialize output q
qm = [D[0]]
# 1's unbalanced condition at current pixelo
N1_D = np.sum(D)
if N1_D>4 or (N1_D==4 and not(D[0])):
# XNOR of consecutive bits
for k in range(1,8):
qm.append( not(qm[k-1] ^ D[k]) )
qm.append(0)
else:
# XOR of consecutive bits
for k in range(1,8):
qm.append( qm[k-1] ^ D[k] )
qm.append(1)
# Initialize output qout
qout = qm.copy()
# Unbalanced condition with previous and current pixels
N1_qm = np.sum(qm[:8])
N0_qm = 8 - N1_qm
if cnt==0 or N1_qm==4:
qout.append(not(qm[8]))
qout[8]=qm[8]
qout[:8]=qm[:8] if qm[8] else [not(val) for val in qm[:8]]
if not(qm[8]):
cnt_diff = N0_qm - N1_qm
else:
cnt_diff = N1_qm - N0_qm
else:
if (cnt>0 and N1_qm>4) or (cnt<0 and N1_qm<4):
qout.append(1)
qout[8]=qm[8]
qout[:8] = [not(val) for val in qm[:8]]
cnt_diff = 2*qm[8] +N0_qm -N1_qm
else:
qout.append(0)
qout[8]=qm[8]
qout[:8] = qm[:8]
cnt_diff = -2*(not(qm[8])) + N1_qm - N0_qm
# Return the TMDS coded pixel as uint and 0's y 1's balance difference
uint_out = binarray_to_uint(qout)
return uint_out, cnt_diff
### Create TMDS LookUp Tables for fast encoding (3 times faster than the other implementation)
byte_range = np.arange(256)
# Initialize pixel coding and cnt-difference arrays
TMDS_pix_table = np.zeros((256,3),dtype='uint16')
TMDS_cntdiff_table = np.zeros((256,3),dtype='int8')
for byte in byte_range:
p0,p_null, p1 = TMDS_pixel_cntdiff(byte,-1),TMDS_pixel_cntdiff(byte,0),TMDS_pixel_cntdiff(byte,1) # 0's and 1's unbalance respect.
TMDS_pix_table[byte,0] = p0[0]
TMDS_pix_table[byte,1] = p_null[0]
TMDS_pix_table[byte,2] = p1[0]
TMDS_cntdiff_table[byte,0] = p0[1]
TMDS_cntdiff_table[byte,1] = p_null[1]
TMDS_cntdiff_table[byte,2] = p1[1]
def pixel_fastencoding(pix,cnt_prev=0):
"""8bit pixel TMDS fast coding
Inputs:
- pix: 8-bit pixel
- cnt: 0's and 1's balance. Default in 0 (balanced)
Outputs:
- pix_out: TDMS coded 16-bit pixel (only 10 useful)
- cnt: 0's and 1's balance updated with new pixel coding
"""
balance_idx = int(np.sign(cnt_prev))+1
pix_out = TMDS_pix_table[pix,balance_idx]
cnt = cnt_prev + TMDS_cntdiff_table[pix,balance_idx]
return pix_out, cnt
def TMDS_blanking (h_total, v_total, h_active, v_active, h_front_porch, v_front_porch, h_back_porch, v_back_porch):
# Initialize blanking image
img_blank = np.zeros((v_total,h_total))
# Get the total blanking on vertical an horizontal axis
h_blank = h_total - h_active
v_blank = v_total - v_active
# (C1,C0)=(0,0) region
img_blank[:v_front_porch,:h_front_porch] = 0b1101010100
img_blank[:v_front_porch,h_blank-h_back_porch:] = 0b1101010100
img_blank[v_blank-v_back_porch:v_blank,:h_front_porch] = 0b1101010100
img_blank[v_blank-v_back_porch:v_blank,h_blank-h_back_porch:] = 0b1101010100
img_blank[v_blank:,:h_blank] = 0b1101010100
# (C1,C0)=(0,1) region
img_blank[:v_front_porch,h_front_porch:h_blank-h_back_porch] = 0b0010101011
img_blank[v_blank-v_back_porch:,h_front_porch:h_blank-h_back_porch] = 0b0010101011
# (C1,C0)=(1,0) region
img_blank[v_front_porch:v_blank-v_back_porch,:h_front_porch] = 0b0101010100
img_blank[v_front_porch:v_blank-v_back_porch,h_blank-h_back_porch:] = 0b0101010100
# (C1,C0)=(1,1) region
img_blank[v_front_porch:v_blank-v_back_porch,v_front_porch:h_blank-h_back_porch] = 0b1010101011
return(img_blank)
def TMDS_encoding (I, blanking = False):
"""TMDS image coding
Inputs:
- I: 3-D image array (v_size, h_size, channels)
- blanking: Boolean that specifies if horizontal and vertical blanking is applied or not
Output:
- I_c: TDMS coded 16-bit image (only 10 useful)
"""
# Create "ghost dimension" if I is gray-scale image (not RGB)
if len(I.shape)!= 3:
I = np.repeat(I[:, :, np.newaxis], 3, axis=2).astype('uint8')
chs = 3
# Get image resolution
v_in, h_in = I.shape[:2]
if blanking:
# Get blanking resolution for input image
v = (v_in==1080)*1125 + (v_in==900)*1000 + (v_in==720)*750 + (v_in==600)*628 + (v_in==480)*525
h = (h_in==1920)*2200 + (h_in==1600)*1800 + (h_in==1280)*1650 + (h_in==800)*1056 + (h_in==640)*800
v_diff = v - v_in
h_diff = h - h_in
v_front_porch = (v_in==1080)*4 + (v_in==900)*1 + (v_in==720)*5 + (v_in==600)*1 + (v_in==480)*2
v_back_porch = (v_in==1080)*36 + (v_in==900)*96 + (v_in==720)*20 + (v_in==600)*23 + (v_in==480)*25
h_front_porch = (h_in==1920)*88 + (h_in==1600)*24 + (h_in==1280)*110 + (h_in==800)*40 + (h_in==640)*8
h_back_porch = (h_in==1920)*148 + (h_in==1600)*96 + (h_in==1280)*220 + (h_in==800)*88 + (h_in==640)*40
# Create image with blanking and change type to uint16
# Assuming the blanking corresponds to 10bit number
# [0, 0, 1, 0, 1, 0, 1, 0, 1, 1] (LSB first) for channels R and G
I_c = 852*np.ones((v,h,chs)).astype('uint16')
I_c[:,:,2] = TMDS_blanking(h_total=h, v_total=v, h_active=h_in, v_active=v_in,
h_front_porch=h_front_porch, v_front_porch=v_front_porch, h_back_porch=h_back_porch, v_back_porch=v_back_porch)
else:
v_diff = 0
h_diff = 0
I_c = 255*np.ones((v_in,h_in,chs)).astype('uint16')
# Iterate over channels and pixels
for c in range(chs):
for i in range(v_in):
cnt = [0,0,0]
for j in range(h_in):
# Get pixel and code it TMDS between blanking
pix = I[i,j,c]
I_c[i + v_diff, j + h_diff, c], cnt[c] = pixel_fastencoding (pix,cnt[c])
return I_c
class TMDS_image_source(gr.sync_block):
"""
@ -327,7 +41,7 @@ class TMDS_image_source(gr.sync_block):
* 1920x1080
"""
def __init__(self, image_file, mode):
def __init__(self, image_file, mode, blanking):
gr.sync_block.__init__(self,
name="TMDS_image_source",
in_sig=None,
@ -335,33 +49,45 @@ class TMDS_image_source(gr.sync_block):
self.image_file = image_file
self.mode = mode
self.blanking = blanking
self.load_image()
def load_image(self):
"""Decode the image into a buffer and encode it (or not) TMDS with blanking"""
self.image_data = imread(self.image_file)
"""Decode the image into a buffer and encode it (or not) TMDS"""
self.image_data = np.array(Image.open(self.image_file))
# Check if mode uses TMDS encoding
if (self.mode==1 or self.mode==3):
#Encode the image with TMDS
self.image_data = TMDS_encoding(self.image_data,blanking = True)
self.image_data = TMDS_encoding(self.image_data,blanking = self.blanking)
print('TMDS encoding ready!!!')
else:
# Do not encode TMDS. Use blanking
v_in, h_in = self.image_data.shape[:2]
v = (v_in==1080)*1125 + (v_in==900)*1000 + (v_in==720)*750 + (v_in==600)*628 + (v_in==480)*525
h = (h_in==1920)*2200 + (h_in==1600)*1800 + (h_in==1280)*1650 + (h_in==800)*1056 + (h_in==640)*800
image_blank = 255*np.ones((v,h,3))
# Create "ghost dimension" if image_data is gray-scale image (not RGB)
else:
# Do not encode TMDS
# Create "ghost dimension" if I is gray-scale image (not RGB)
if len(self.image_data.shape)!= 3:
self.image_data = np.repeat(self.image_data[:, :, np.newaxis], 3, axis=2).astype('uint8')
# image_blank = np.zeros((v,h,3))
hdiff = (h-h_in)//2
vdiff = (v-v_in)//2
image_blank[vdiff:vdiff+v_in,hdiff:hdiff+h_in] = self.image_data[:,:,:3]
self.image_data = image_blank[:,:,:3]
# Gray-scale image
self.image_data = np.repeat(self.image_data[:, :, np.newaxis], 3, axis=2).astype('uint8')
chs = 1
else:
# RGB image
chs = 3
if self.blanking:
# Use blanking
v_in, h_in = self.image_data.shape[:2]
v = (v_in==1080)*1125 + (v_in==900)*1000 + (v_in==720)*750 + (v_in==600)*628 + (v_in==480)*525
h = (h_in==1920)*2200 + (h_in==1600)*1800 + (h_in==1280)*1650 + (h_in==800)*1056 + (h_in==640)*800
image_blank = 255*np.ones((v,h,chs))
hdiff = (h-h_in)//2
vdiff = (v-v_in)//2
image_blank[vdiff:vdiff+v_in,hdiff:hdiff+h_in] = self.image_data[:,:,:3]
self.image_data = image_blank[:,:,:3]
(self.image_height, self.image_width) = self.image_data.shape[:2]