Skip to content

Instantly share code, notes, and snippets.

@OzTamir
Forked from metula/matrix.py
Last active August 29, 2015 13:57
Show Gist options
  • Save OzTamir/9758299 to your computer and use it in GitHub Desktop.
Save OzTamir/9758299 to your computer and use it in GitHub Desktop.
Represent a picture matrix - grayscale and colours!
#############################################################################
######### class Matrix with display() function for image visualization
#############################################################################
class Matrix:
"""
Represents a rectangular matrix with n rows and m columns.
"""
def __init__(self, n, m, val=0):
"""
Create an n-by-m matrix of val's.
Inner representation: list of lists (rows)
"""
assert n > 0 and m > 0
self._rows = [[val] * m for i in range(n)]
def dim(self):
return len(self._rows), len(self._rows[0])
def pretty_print(self, fmt="{}", max_rows=10, max_per_row=10):
n, m = self.dim()
print("Matrix {}x{}:".format(n, m))
for row in self._rows[:min(n, max_rows)]:
s = ", ".join([fmt.format(x) for x in row[:max_per_row]])
if m > max_per_row:
s += ", ..."
print("[{}]".format(s))
if n > max_rows:
print(" ... ")
def __repr__(self):
n, m = self.dim()
content = ""
if n > 10 or m > 10:
content = "[...]"
else:
content = str(self._rows)
return "<Matrix {}x{}: {}>".format(n, m, content)
def __eq__(self, other):
return isinstance(other, Matrix) and self._rows == other._rows
def items(self):
n, m = self.dim()
for i in range(n):
for j in range(m):
yield self[i, j]
def __iter__(self):
return self.items()
# cell/sub-matrix access/assignment
####################################
def __getitem__(self, ij): #ij is a tuple (i,j). Allows m[i,j] instead m[i][j]
i, j = ij
if isinstance(i, int) and isinstance(j, int):
return self._rows[i][j]
elif isinstance(i, slice) and isinstance(j, slice):
mat = Matrix(1, 1) # to be overwritten
mat._rows = [row[j] for row in self._rows[i]]
return mat
else:
return NotImplemented
def __setitem__(self, ij, val): #ij is a tuple (i,j). Allows m[i,j] instead m[i][j]
i, j = ij
if isinstance(i, int) and isinstance(j, int):
assert isinstance(val, (int, float, complex, list))
self._rows[i][j] = val
elif isinstance(i, slice) and isinstance(j, slice):
assert isinstance(val, Matrix)
n, m = val.dim()
s_rows = self._rows[i]
assert len(s_rows) == n and len(s_rows[0][j]) == m
for s_row, v_row in zip(s_rows, val._rows):
s_row[j] = v_row
else:
return NotImplemented
# operations
########################
def self_op(self, op):
n, m = self.dim()
mat = Matrix(n, m)
for i in range(n):
for j in range(m):
mat[i, j] = op(self[i, j])
return mat
def pair_op(self, other, op):
assert self.dim() == other.dim()
n, m = self.dim()
mat = Matrix(n, m)
for i in range(n):
for j in range(m):
mat[i, j] = op(self[i, j], other[i, j])
return mat
def apply_op(self, other, op):
if isinstance(other, Matrix):
return self.pair_op(other, op)
elif isinstance(other, (int, float, complex)):
return self.self_op(lambda x: op(x, other))
else:
raise NotImplemented
def __add__(self, other):
return self.apply_op(other, lambda x, y: x + y)
def __sub__(self, other):
return self.apply_op(other, lambda x, y: x - y)
def __rsub__(self, other):
return self.apply_op(other, lambda x, y: y - x)
def __mul__(self, other):
if isinstance(other, (int, float, complex)):
return self.self_op(lambda x: x * other)
else:
return NotImplemented
def __mod__(self, other):
return self.self_op(lambda x: x % other)
def __neg__(self):
return self.self_op(lambda x: -x)
def dot_product(self, other):
assert isinstance(other, Matrix)
return self.pair_op(other, lambda x, y: x * y)
__radd__ = __add__
__rmul__ = __mul__
# Input/output
###############
def save(self, filename):
f = open(filename, 'w')
n, m = self.dim()
print(n, m, file=f)
for row in self._rows:
for e in row:
print(e, end=" ", file=f)
print("", file=f) #newline
f.close()
@staticmethod
def load(filename):
f = open(filename)
line = f.readline()
n, m = [int(x) for x in line.split()]
result = Matrix(n, m)
for i in range(n):
line = f.readline()
row = [int(x) for x in line.split()]
assert len(row) == m
result._rows[i] = row
return result
def display(self, title=None, zoom=None):
# This function build a string of the hex represention of the pixel value
ps = lambda pixel: '{:02x}'.format(int(pixel) % 256)
height, width = self.dim()
# Changed: the pixel is represented as a list, not a number, with three items - RGB values.
pixels = " ".join('{' + ' '.join('#'+ ps(pixel[0]) + ps(pixel[1]) + ps(pixel[2])
for pixel in row) + '}'
for row in self._rows)
def tk_worker(root):
# should not use touch 'self' directly. (That's what she said)
pi = tkinter.PhotoImage(width=width,height=height)
pi.put(pixels)
if zoom is not None:
assert zoom > 0
if zoom > 1:
pi = pi.zoom(zoom)
elif zoom < 1:
pi = pi.subsample(zoom)
tl = tkinter.Toplevel(master=root)
tl.title('Matrix' if title is None else title)
lb = tkinter.Label(master=tl, image=pi)
lb.pi = pi
lb.pack()
return tl
if TKTHREAD_ENABLED:
with _TkThread.the_lock:
_TkThread.the_queue.append(tk_worker)
else:
root = tkinter.Tk()
root.withdraw()
tl = tk_worker(root)
tl.protocol("WM_DELETE_WINDOW", root.destroy)
root.mainloop()
def synthetic(n, m, red, green=None, blue=None):
# If no function was specified for G or B, make it the same as the function for R
if green is None:
green = red
if blue is None:
blue = red
mat = Matrix(n, m)
for i in range(n):
for j in range(m):
mat[i, j] = [red(i, j) % 256, green(i, j) % 256, blue(i, j) % 256]
return mat
def join(mat1, mat2, space=5):
n1, m1 = mat1.dim()
n2, m2 = mat2.dim()
mat = Matrix(max(n1, n2), m1 + m2 + space, 128)
mat[:n1, :m1] = mat1
mat[:n2, m1 + space:] = mat2
return mat
## Examples
def examples():
import math
import random
synthetic(50, 50, lambda i, j: 255 * (i % 2)).display(zoom=10)
synthetic(50, 50, lambda i, j: 255 * ((i * j) % 2)).display(zoom=10)
synthetic(512, 512, lambda i, j: 255*(i + j)).display()
synthetic(512, 512, lambda i, j: max(i, j)).display()
synthetic(256, 256, lambda i, j: i ^ j).display(zoom=2)
synthetic(512, 512, lambda i, j: (abs(i-256)+abs(j-256))).display()
synthetic(512, 512, lambda i, j: ((i-256)**2+(j-256)**2)).display()
synthetic(128, 16, lambda i, j: 255 * ((i & (2**j)) >> j)).display(zoom=5)
synthetic(256, 256, lambda i, j: 128 + 127*round((random.random() - 0.5)*1.01)).display(zoom=2)
synthetic(100, 100, lambda i, j: random.gauss(128, 10)).display(zoom=4)
synthetic(512, 512, lambda i, j: int(math.sin(j / 20) * 255)).display()
synthetic(512, 512, lambda i, j: int(math.sin(i / 20) * math.sin(j / 20) * 255)).display()
synthetic(512, 512, lambda i, j: int((math.sin(i / 20) + math.sin(j / 20)) * 255)).display()
synthetic(512, 512, lambda i, j: int((math.sin(i / 30) + math.sin(j / 20)) * 255)).display()
################# Code for image visualization
# Enabled only for linux/windows machines.
import sys
import tkinter
import time
TKTHREAD_ENABLED = sys.platform in ('win32', 'linux')
if TKTHREAD_ENABLED:
import threading
class _TkThread(threading.Thread):
the_lock = threading.RLock()
the_queue = []
def __init__(self, *args, **kwargs):
threading.Thread.__init__(self, *args, **kwargs)
self.setDaemon(True)
def run(self):
root = tkinter.Tk()
root.withdraw()
while True:
with self.the_lock:
func = self.the_queue.pop() if self.the_queue else None
if func is not None:
func(root)
root.update()
time.sleep(.1)
_TkThread().start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment