#!/usr/bin/env python
# Both Python 2 and Python 3 will work
import sys, math
FORMAT = '%.50f'
DELIMITER = ', '
def _divrow(R, d):
return [c / d for c in R]
def _subrow(A, B, m):
return [a - b * m for a, b in zip(A, B)]
def transpose(M):
r, c = len(M), len(M[0])
return [[M[y][x] for y in range(r)] for x in range(c)]
def to_vector(M):
if len(M[0]) == 1:
return tuple(R[0] for R in M)
elif len(M) == 1:
return M[0]
raise Exception('Invalid arguments')
def _multiply(A, B):
if isinstance(A[0], int) or isinstance(A[0], float):
A = [A]
if isinstance(B[0], int) or isinstance(B[0], float):
B = [B]
ar, ac, br, bc = len(A), len(A[0]), len(B), len(B[0])
if ac != br:
if ac == bc:
B, br, bc = transpose(B), bc, br
elif ar == br:
A, ar, ac = transpose(A), ac, ar
else:
raise Exception('Invalid arguments')
return [[sum(A[r][i] * B[i][c] for i in range(ac)) for c in range(bc)] for r in range(ar)]
def multiply(*Ms):
R, Ms = Ms[-1], list(Ms)[-2::-1]
for M in Ms:
R = _multiply(M, R)
return R
def invert(M):
r, c = len(M), len(M[0])
if r != c:
raise Exception('Invalid arguments')
I = [[1 if x == y else 0 for x in range(c)] for y in range(r)]
M = [MR + IR for MR, IR in zip(M, I)]
for r1 in range(r):
if M[r1][r1] == 0:
for r2 in range(r1 + 1, r):
if M[r2][r1] != 0:
break
if r2 == r:
raise Exception('Not invertable')
M[r1], M[r2] = M[r2], M[r1]
M[r1] = _divrow(M[r1], M[r1][r1])
for r2 in range(r1 + 1, r):
M[r2] = _subrow(M[r2], M[r1], M[r2][r1])
for r1 in reversed(range(r)):
for r2 in reversed(range(r1)):
M[r2] = _subrow(M[r2], M[r1], M[r2][r1])
return [R[c:] for R in M]
def str_matrix(M):
rfmt = '%s%s%s%s%s' % (FORMAT, DELIMITER, FORMAT, DELIMITER, FORMAT)
fmt = '%s\n%s\n%s' % (rfmt, rfmt, rfmt)
return fmt % tuple(M[0] + M[1] +M[2])
def print_matrix(M):
print(str_matrix(M))
def matrix(m11, m12, m13, m21, m22, m23, m31, m32, m33):
return [[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]]
def _cos(deg):
return math.cos(deg * math.pi / 180.)
def _sin(deg):
return math.sin(deg * math.pi / 180.)
def _yiq_i(k, a, b):
return 0.877 * _cos(33.) * (a - k) - (0.492 * _sin(33.)) * (b - k)
def _yiq_q(k, a, b):
return 0.877 * _sin(33.) * (a - k) + (0.492 * _cos(33.)) * (b - k)
matrices = {
('srgb', 'yes') : matrix(0.253, 0.684, 0.063,
0.50, -0.50, 0.,
0.25, 0.25, -0.50),
('ycgco', 'srgb') : matrix(1., -1., 1.,
1., 1., 0.,
1., -1., -1.),
('srgb', 'yiq') : matrix(0.299, 0.587, 0.114,
_yiq_i(0.299, 1, 0), _yiq_i(0.587, 0, 0), _yiq_i(0.114, 0, 1),
_yiq_q(0.299, 1, 0), _yiq_q(0.587, 0, 0), _yiq_q(0.114, 0, 1)),
('srgb', 'ydbdr') : matrix( 0.299, 0.587, 0.114,
-0.450, -0.883, 1.333,
-1.333, 1.116, 0.217),
('srgb', 'ypbpr') : matrix( 0.2126, 0.7152, 0.0722,
-0.2126, -0.7152, 1 - 0.0722,
1 - 0.2126, -0.7152, -0.0722),
('srgb', 'ciexyz') : matrix(0.412457445582367576708548995157,
0.357575865245515878143578447634,
0.180437247826399665973085006954,
0.212673370378408277403536885686,
0.715151730491031756287156895269,
0.072174899130559869164791564344,
0.019333942761673460208893260415,
0.119191955081838593666354597644,
0.950302838552371742508739771438),
('yuv', 'ydbdr') : matrix(1., 0., 0.,
0., 3.069, 0.,
0., 0., -2.169),
}
if __name__ == '__main__':
models = set()
for (f, t) in list(matrices.keys()):
models.add(f)
models.add(t)
if (t, f) not in matrices:
matrices[(t, f)] = invert(matrices[(f, t)])
while True:
ms = list(matrices.keys())
added = 0
for m1 in models:
for m2 in models:
if m1 == m2:
continue
for m3 in models:
if m1 == m3 or m2 == m3:
continue
if (m1, m3) in ms:
continue
if (m1, m2) not in ms:
continue
if (m2, m3) not in ms:
continue
added += 1
m = multiply(matrices[(m2, m3)], matrices[(m1, m2)])
matrices[(m1, m3)] = m
if not added:
break
for (f, t) in sorted(matrices.keys()):
M = multiply(matrices[(t, f)], matrices[(f, t)])
for r in range(len(M)):
for c in range(len(M[r])):
x = M[r][c]
x -= 1 if r == c else 0
x *= x
if x > 0.0001:
sys.stderr.write('(%s, %s)(%s, %s) != I\n' % (t, f, f, t))
for r in M:
for c in r:
sys.stderr.write('\t%lg' % c)
sys.stderr.write('\n')
sys.exit(1)
for (f, t) in sorted(matrices.keys()):
M = matrices[(f, t)]
macro = '%s_TO_%s' % (f.upper(), t.upper())
print('')
print('#ifndef %s' % macro)
print('# define %s MATRIX(\\' % macro)
for row in M:
a = ', '.join([FORMAT] * len(row))
b = ')' if row is M[-1] else ',\\'
print(('\t' + a + b) % tuple(row))
print('#endif')