-
-
Save OzTamir/9758299 to your computer and use it in GitHub Desktop.
Represent a picture matrix - grayscale and colours!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
############################################################################# | |
######### 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