aboutsummaryrefslogtreecommitdiffstats
path: root/matrices.py
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2017-06-14 21:04:36 +0200
committerMattias Andrée <maandree@kth.se>2017-06-14 21:04:36 +0200
commit2baa9bd9cd9a5365b6b826de2377a6a29ff1dd3b (patch)
tree8c8ab45dc0a1dd9f9127f40acd6626b1ca19235c /matrices.py
parentUpdate todo (diff)
downloadlibcolour-2baa9bd9cd9a5365b6b826de2377a6a29ff1dd3b.tar.gz
libcolour-2baa9bd9cd9a5365b6b826de2377a6a29ff1dd3b.tar.bz2
libcolour-2baa9bd9cd9a5365b6b826de2377a6a29ff1dd3b.tar.xz
Add YES colour model, generate the conversion matrices, and add more direct conversions
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rwxr-xr-xmatrices.py184
1 files changed, 184 insertions, 0 deletions
diff --git a/matrices.py b/matrices.py
new file mode 100755
index 0000000..485374c
--- /dev/null
+++ b/matrices.py
@@ -0,0 +1,184 @@
+#!/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')