Loading ReducedRuntimeEncoder.ipynb 0 → 100644 +480 −0 Original line number Diff line number Diff line %% Cell type:code id: tags: ``` python import numpy as np from matplotlib import pyplot as plt import os import sys from PIL import Image from collections import Counter import numpy.linalg as la ``` %% Cell type:code id: tags: ``` python def file_extractor(dirname="images"): files = os.listdir(dirname) scenes = [] for file in files: if file == '.DS_Store': continue else: scenes.append(os.path.join(dirname, file)) return scenes def image_extractor(scenes): image_folder = [] for scene in scenes: files = os.listdir(scene) for file in files: if file[-5:] != ".tiff" or file[-7:] == "_6.tiff": continue else: image_folder.append(os.path.join(scene, file)) return image_folder #returns a list of file paths to .tiff files in the specified directory given in file_extractor ``` %% Cell type:code id: tags: ``` python def predict_pix(tiff_image_path, difference = True): """ This function predict the pixel values excluding the boundary. Using the 4 neighbor pixel values and MSE to predict the next pixel value (-1,1) (0,1) (1,1) => relative position of the 4 other given values (-1,0) (0,0) => (0,0) is the one we want to predict take the derivative of mean square error to solve for the system of equation A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) A @ [a, b, c] = [-z0+z2-z3, z0+z1+z2, -z0-z1-z2-z3] where z0 = (-1,1), z1 = (0,1), z2 = (1,1), z3 = (-1,0) and the predicted pixel value is c. Input: tiff_image_path (string): path to the tiff file Return: image ndarray(512 X 640): original image predict ndarray(325380,): predicted image excluding the boundary diff. ndarray(325380,): IF difference = TRUE, difference between the min and max of four neighbors exclude the boundary ELSE: the residuals of the four nearest pixels to a fitted hyperplane error ndarray(325380,): difference between the original image and predicted image A ndarray(3 X 3): system of equation """ image_obj = Image.open(tiff_image_path) #Open the image and read it as an Image object image_array = np.array(image_obj)[1:,:].astype(int) #Convert to an array, leaving out the first row because the first row is just housekeeping data # image_array = image_array.astype(int) A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) # the matrix for system of equation # where z0 = (-1,1), z1 = (0,1), z2 = (1,1), z3 = (-1,0) z0 = image_array[0:-2,0:-2] # get all the first pixel for the entire image z1 = image_array[0:-2,1:-1] # get all the second pixel for the entire image z2 = image_array[0:-2,2::] # get all the third pixel for the entire image z3 = image_array[1:-1,0:-2] # get all the forth pixel for the entire image # calculate the out put of the system of equation y0 = np.ravel(-z0+z2-z3) y1 = np.ravel(z0+z1+z2) y2 = np.ravel(-z0-z1-z2-z3) y = np.vstack((y0,y1,y2)) # use numpy solver to solve the system of equations all at once #predict = np.floor(np.linalg.solve(A,y)[-1]) predict = np.round(np.round((np.linalg.solve(A,y)[-1]),1)) #Matrix system of points that will be used to solve the least squares fitting hyperplane points = np.array([[-1,-1,1], [-1,0,1], [-1,1,1], [0,-1,1]]) # flatten the neighbor pixlels and stack them together z0 = np.ravel(z0) z1 = np.ravel(z1) z2 = np.ravel(z2) z3 = np.ravel(z3) neighbor = np.vstack((z0,z1,z2,z3)).T if difference: # calculate the difference diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1) else: #Compute the best fitting hyperplane using least squares #The res is the residuals of the four points used to fit the hyperplane (summed distance of each of the #points to the hyperplane), it is a measure of gradient f, diff, rank, s = la.lstsq(points, neighbor.T, rcond=None) diff = diff.astype(int) # calculate the error error = np.ravel(image_array[1:-1,1:-1])-predict return image_array, predict, diff, error, A ``` %% Cell type:code id: tags: ``` python """ this huffman encoding code is found online https://favtutor.com/blogs/huffman-coding """ class NodeTree(object): def __init__(self, left=None, right=None): self.left = left self.right = right def children(self): return self.left, self.right def __str__(self): return self.left, self.right def huffman_code_tree(node, binString=''): ''' Function to find Huffman Code ''' if type(node) is str: return {node: binString} (l, r) = node.children() d = dict() d.update(huffman_code_tree(l, binString + '0')) d.update(huffman_code_tree(r, binString + '1')) return d def make_tree(nodes): ''' Function to make tree :param nodes: Nodes :return: Root of the tree ''' while len(nodes) > 1: (key1, c1) = nodes[-1] (key2, c2) = nodes[-2] nodes = nodes[:-2] node = NodeTree(key1, key2) nodes.append((node, c1 + c2)) #reverse True, decending order #There is a huge memory leak here, no idea how or why nodes = sorted(nodes, key=lambda x: x[1], reverse=True) return nodes[0][0] def decode_string(huffman_string,node): if type(node) is str: return huffman_string, int(node) else: if (huffman_string[0] == '0'): return decode_string(huffman_string[1:],node.left) else: return decode_string(huffman_string[1:],node.right) ``` %% Cell type:code id: tags: ``` python def huffman(tiff_image_path, num_bins=4, difference = True): """ This function is used to encode the error based on the difference and split the difference into different bins Input: tiff_image_path (string): path to the tiff file num_bins (int): number of bins Return: huffman_encoding_list list (num_bins + 1): a list of dictionary image_array ndarray (512, 640): original image new_error ndarray (512, 640): error that includes the boundary diff ndarray (510, 638): difference of min and max of the 4 neighbors boundary ndarray (2300,): the boundary values after subtracting the very first pixel value predict ndarray (325380,): the list of predicted values bins list (num_bins - 1,): a list of threshold to cut the bins A ndarray (3 X 3): system of equation """ # get the image_array, etc image_array, predict, diff, error, A = predict_pix(tiff_image_path, difference) # calculate the number of points that will go in each bin data_points_per_bin = diff.size // num_bins # sort the difference and create the bins sorted_diff = np.sort(diff.copy()) bins = [sorted_diff[i*data_points_per_bin] for i in range(1,num_bins)] # get the boundary boundary = np.hstack((image_array[0,:],image_array[-1,:],image_array[1:-1,0],image_array[1:-1,-1])) # take the difference of the boundary with the very first pixel boundary = boundary - image_array[0,0] #boundary is 1dim, so boundary[0] is just the first element boundary[0] = image_array[0,0] # huffman encode the boundary bound_vals_as_string = [str(i) for i in boundary] freq = dict(Counter(bound_vals_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node1 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node1) nodelist = [node1] # create a list of huffman table huffman_encoding_list = [huffman_encoding_dict] n = len(bins) # loop through different bins for i in range (0,n): # the first bin if i == 0 : # get the point within the bin and huffman huffman_encoding_dict mask = diff <= bins[i] line_as_string = [str(i) for i in error[mask].astype(int)] freq = dict(Counter(line_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node2 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node2) huffman_encoding_list.append(huffman_encoding_dict) nodelist.append(node2) # the middle bins else: # get the point within the bin and huffman huffman_encoding_dict mask = diff > bins[i-1] new_error = error[mask] mask2 = diff[mask] <= bins[i] line_as_string = [str(i) for i in new_error[mask2].astype(int)] freq = dict(Counter(line_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node3 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node3) huffman_encoding_list.append(huffman_encoding_dict) nodelist.append(node3) # the last bin # get the point within the bin and huffman huffman_encoding_dict mask = diff > bins[-1] line_as_string = [str(i) for i in error[mask].astype(int)] freq = dict(Counter(line_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node4 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node4) huffman_encoding_list.append(huffman_encoding_dict) nodelist.append(node4) # create a error matrix that includes the boundary (used in encoding matrix) new_error = np.copy(image_array) new_error[1:-1,1:-1] = np.reshape(error,(510, 638)) keep = new_error[0,0] new_error[0,:] = new_error[0,:] - keep new_error[-1,:] = new_error[-1,:] - keep new_error[1:-1,0] = new_error[1:-1,0] - keep new_error[1:-1,-1] = new_error[1:-1,-1] - keep new_error[0,0] = keep # huffman_encoding_list = list(set(huffman_encoding_list)) diff = np.reshape(diff,(510,638)) # return the huffman dictionary return huffman_encoding_list, image_array, new_error, diff, boundary, predict, bins, A, nodelist ``` %% Cell type:code id: tags: ``` python def encoder(error, list_dic, diff, bound, bins): """ This function encode the matrix with huffman coding tables Input: error (512, 640): a matrix with all the errors list_dic (num_dic + 1,): a list of huffman coding table bound (2300,): the boundary values after subtracting the very first pixel value bins (num_bins - 1,): a list of threshold to cut the bins Return: encoded (512, 640): encoded matrix """ returnable_encode = "" # copy the error matrix (including the boundary) encoded = np.copy(error).astype(int).astype(str).astype(object) #diff = np.reshape(diff,(510,638)) # loop through all the pixel to encode for i in range(encoded.shape[0]): for j in range(encoded.shape[1]): if i == 0 or i == encoded.shape[0]-1 or j == 0 or j == encoded.shape[1]-1: returnable_encode += list_dic[0][encoded[i][j]] elif diff[i-1][j-1] <= bins[0]: returnable_encode += list_dic[1][encoded[i][j]] elif diff[i-1][j-1] <= bins[1] and diff[i-1][j-1] > bins[0]: returnable_encode +=list_dic[2][encoded[i][j]] elif diff[i-1][j-1] <= bins[2] and diff[i-1][j-1] > bins[1]: returnable_encode +=list_dic[3][encoded[i][j]] else: returnable_encode += list_dic[4][encoded[i][j]] return returnable_encode ``` %% Cell type:code id: tags: ``` python def decoder(A, encoded_string, list_dic, bins, use_diff, nodes): """ This function decodes the encoded_matrix. Input: A (3 X 3): system of equation list_dic (num_dic + 1,): a list of huffman coding table encoded_matrix (512, 640): encoded matrix bins (num_bins - 1,): a list of threshold to cut the bins Return: decode_matrix (512, 640): decoded matrix """ # change the dictionary back to list # !!!!!WARNING!!!! has to change this part, everytime you change the number of bins the_keys0 = list(list_dic[0].keys()) the_values0 = list(list_dic[0].values()) the_keys1 = list(list_dic[1].keys()) the_values1 = list(list_dic[1].values()) the_keys2 = list(list_dic[2].keys()) the_values2 = list(list_dic[2].values()) the_keys3 = list(list_dic[3].keys()) the_values3 = list(list_dic[3].values()) the_keys4 = list(list_dic[4].keys()) the_values4 = list(list_dic[4].values()) #Matrix system of points that will be used to solve the least squares fitting hyperplane points = np.array([[-1,-1,1], [-1,0,1], [-1,1,1], [0,-1,1]]) decode_matrix = np.zeros((512,640)) # loop through all the element in the matrix for i in range(decode_matrix.shape[0]): for j in range(decode_matrix.shape[1]): # if it's the very first pixel on the image if i == 0 and j == 0: encoded_string, colorvalue = decode_string(encoded_string, nodes[0]) decode_matrix[i][j] = colorvalue # if it's on the boundary (any of the 4 edges) elif i == 0 or i == decode_matrix.shape[0]-1 or j == 0 or j == decode_matrix.shape[1]-1: encoded_string, colorvalue = decode_string(encoded_string, nodes[0]) decode_matrix[i][j] = colorvalue + decode_matrix[0][0] # if not the boundary else: # predict the image with the known pixel value z0 = decode_matrix[i-1][j-1] z1 = decode_matrix[i-1][j] z2 = decode_matrix[i-1][j+1] z3 = decode_matrix[i][j-1] y0 = int(-z0+z2-z3) y1 = int(z0+z1+z2) y2 = int(-z0-z1-z2-z3) y = np.vstack((y0,y1,y2)) if use_diff: difference = max(z0,z1,z2,z3) - min(z0,z1,z2,z3) else: f, difference, rank, s = la.lstsq(points, [z0,z1,z2,z3], rcond=None) difference = difference.astype(int) predict = np.round(np.round(np.linalg.solve(A,y)[-1][0],1)) # add on the difference by searching the dictionary # !!!!!WARNING!!!! has to change this part, eveytime you change the number of bins if difference <= bins[0]: encoded_string, colorvalue = decode_string(encoded_string, nodes[1]) decode_matrix[i][j] = colorvalue + int(predict) elif difference <= bins[1] and difference > bins[0]: encoded_string, colorvalue = decode_string(encoded_string, nodes[2]) decode_matrix[i][j] = colorvalue + int(predict) elif difference <= bins[2] and difference > bins[1]: encoded_string, colorvalue = decode_string(encoded_string, nodes[3]) decode_matrix[i][j] = colorvalue + int(predict) else: encoded_string, colorvalue = decode_string(encoded_string, nodes[4]) decode_matrix[i][j] = colorvalue + int(predict) return decode_matrix.astype(int) ``` %% Cell type:code id: tags: ``` python def compress_rate(image_array, new_error, diff, bound, huffman_encoding_list, bins): ''' This function is used to calculate the compression rate. Input: image_array (512, 640): original_core image new_error (512, 640): error that includes the boundary diff (510, 638): difference of min and max of the 4 neighbors bound (2300,): the boundary values after subtracting the very first pixel value huffman_encoding_list (num_dic + 1,): a list of huffman coding table bins (num_bins - 1,): a list of threshold to cut the bins Return: compression rate ''' # the bits for the original image o_len = 0 # the bits for the compressed image c_len = 0 # initializing the varible #this was unused # im = np.reshape(image,(512, 640)) real_boundary = np.hstack((image_array[0,:],image_array[-1,:],image_array[1:-1,0],image_array[1:-1,-1])) #Bryce's notes: Why are they all reshaped? original_core = image_array[1:-1,1:-1].reshape(-1) diff = diff.reshape(-1) error = new_error[1:-1,1:-1].reshape(-1) # calculate the bit for boundary for i in range(0,len(bound)): o_len += len(bin(real_boundary[i])[2:]) c_len += len(huffman_encoding_list[0][str(bound[i])]) # calculate the bit for the pixels inside the boundary for i in range(0,len(original_core)): # for the original image o_len += len(bin(original_core[i])[2:]) # check the difference and find the coresponding huffman table # !!!!!WARNING!!!! has to change this part, eveytime you change the number of bins if diff[i] <= bins[0]: c_len += len(huffman_encoding_list[1][str(int(error[i]))]) elif diff[i] <= bins[1] and diff[i] > bins[0]: c_len += len(huffman_encoding_list[2][str(int(error[i]))]) elif diff[i] <= bins[2] and diff[i] > bins[1]: c_len += len(huffman_encoding_list[3][str(int(error[i]))]) else: c_len += len(huffman_encoding_list[4][str(int(error[i]))]) return c_len/o_len ``` %% Cell type:code id: tags: ``` python scenes = file_extractor() images = image_extractor(scenes) list_dic, image, new_error, diff, bound, predict, bins, A, nodes = huffman(images[0], 4, False) encoded_string = encoder(new_error, list_dic, diff, bound, bins) reconstruct_image = decoder(A, encoded_string, list_dic, bins, False,nodes) print(np.allclose(image, reconstruct_image)) print(len(list_dic)) ``` %% Output True 5 %% Cell type:code id: tags: ``` python ``` Loading
ReducedRuntimeEncoder.ipynb 0 → 100644 +480 −0 Original line number Diff line number Diff line %% Cell type:code id: tags: ``` python import numpy as np from matplotlib import pyplot as plt import os import sys from PIL import Image from collections import Counter import numpy.linalg as la ``` %% Cell type:code id: tags: ``` python def file_extractor(dirname="images"): files = os.listdir(dirname) scenes = [] for file in files: if file == '.DS_Store': continue else: scenes.append(os.path.join(dirname, file)) return scenes def image_extractor(scenes): image_folder = [] for scene in scenes: files = os.listdir(scene) for file in files: if file[-5:] != ".tiff" or file[-7:] == "_6.tiff": continue else: image_folder.append(os.path.join(scene, file)) return image_folder #returns a list of file paths to .tiff files in the specified directory given in file_extractor ``` %% Cell type:code id: tags: ``` python def predict_pix(tiff_image_path, difference = True): """ This function predict the pixel values excluding the boundary. Using the 4 neighbor pixel values and MSE to predict the next pixel value (-1,1) (0,1) (1,1) => relative position of the 4 other given values (-1,0) (0,0) => (0,0) is the one we want to predict take the derivative of mean square error to solve for the system of equation A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) A @ [a, b, c] = [-z0+z2-z3, z0+z1+z2, -z0-z1-z2-z3] where z0 = (-1,1), z1 = (0,1), z2 = (1,1), z3 = (-1,0) and the predicted pixel value is c. Input: tiff_image_path (string): path to the tiff file Return: image ndarray(512 X 640): original image predict ndarray(325380,): predicted image excluding the boundary diff. ndarray(325380,): IF difference = TRUE, difference between the min and max of four neighbors exclude the boundary ELSE: the residuals of the four nearest pixels to a fitted hyperplane error ndarray(325380,): difference between the original image and predicted image A ndarray(3 X 3): system of equation """ image_obj = Image.open(tiff_image_path) #Open the image and read it as an Image object image_array = np.array(image_obj)[1:,:].astype(int) #Convert to an array, leaving out the first row because the first row is just housekeeping data # image_array = image_array.astype(int) A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) # the matrix for system of equation # where z0 = (-1,1), z1 = (0,1), z2 = (1,1), z3 = (-1,0) z0 = image_array[0:-2,0:-2] # get all the first pixel for the entire image z1 = image_array[0:-2,1:-1] # get all the second pixel for the entire image z2 = image_array[0:-2,2::] # get all the third pixel for the entire image z3 = image_array[1:-1,0:-2] # get all the forth pixel for the entire image # calculate the out put of the system of equation y0 = np.ravel(-z0+z2-z3) y1 = np.ravel(z0+z1+z2) y2 = np.ravel(-z0-z1-z2-z3) y = np.vstack((y0,y1,y2)) # use numpy solver to solve the system of equations all at once #predict = np.floor(np.linalg.solve(A,y)[-1]) predict = np.round(np.round((np.linalg.solve(A,y)[-1]),1)) #Matrix system of points that will be used to solve the least squares fitting hyperplane points = np.array([[-1,-1,1], [-1,0,1], [-1,1,1], [0,-1,1]]) # flatten the neighbor pixlels and stack them together z0 = np.ravel(z0) z1 = np.ravel(z1) z2 = np.ravel(z2) z3 = np.ravel(z3) neighbor = np.vstack((z0,z1,z2,z3)).T if difference: # calculate the difference diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1) else: #Compute the best fitting hyperplane using least squares #The res is the residuals of the four points used to fit the hyperplane (summed distance of each of the #points to the hyperplane), it is a measure of gradient f, diff, rank, s = la.lstsq(points, neighbor.T, rcond=None) diff = diff.astype(int) # calculate the error error = np.ravel(image_array[1:-1,1:-1])-predict return image_array, predict, diff, error, A ``` %% Cell type:code id: tags: ``` python """ this huffman encoding code is found online https://favtutor.com/blogs/huffman-coding """ class NodeTree(object): def __init__(self, left=None, right=None): self.left = left self.right = right def children(self): return self.left, self.right def __str__(self): return self.left, self.right def huffman_code_tree(node, binString=''): ''' Function to find Huffman Code ''' if type(node) is str: return {node: binString} (l, r) = node.children() d = dict() d.update(huffman_code_tree(l, binString + '0')) d.update(huffman_code_tree(r, binString + '1')) return d def make_tree(nodes): ''' Function to make tree :param nodes: Nodes :return: Root of the tree ''' while len(nodes) > 1: (key1, c1) = nodes[-1] (key2, c2) = nodes[-2] nodes = nodes[:-2] node = NodeTree(key1, key2) nodes.append((node, c1 + c2)) #reverse True, decending order #There is a huge memory leak here, no idea how or why nodes = sorted(nodes, key=lambda x: x[1], reverse=True) return nodes[0][0] def decode_string(huffman_string,node): if type(node) is str: return huffman_string, int(node) else: if (huffman_string[0] == '0'): return decode_string(huffman_string[1:],node.left) else: return decode_string(huffman_string[1:],node.right) ``` %% Cell type:code id: tags: ``` python def huffman(tiff_image_path, num_bins=4, difference = True): """ This function is used to encode the error based on the difference and split the difference into different bins Input: tiff_image_path (string): path to the tiff file num_bins (int): number of bins Return: huffman_encoding_list list (num_bins + 1): a list of dictionary image_array ndarray (512, 640): original image new_error ndarray (512, 640): error that includes the boundary diff ndarray (510, 638): difference of min and max of the 4 neighbors boundary ndarray (2300,): the boundary values after subtracting the very first pixel value predict ndarray (325380,): the list of predicted values bins list (num_bins - 1,): a list of threshold to cut the bins A ndarray (3 X 3): system of equation """ # get the image_array, etc image_array, predict, diff, error, A = predict_pix(tiff_image_path, difference) # calculate the number of points that will go in each bin data_points_per_bin = diff.size // num_bins # sort the difference and create the bins sorted_diff = np.sort(diff.copy()) bins = [sorted_diff[i*data_points_per_bin] for i in range(1,num_bins)] # get the boundary boundary = np.hstack((image_array[0,:],image_array[-1,:],image_array[1:-1,0],image_array[1:-1,-1])) # take the difference of the boundary with the very first pixel boundary = boundary - image_array[0,0] #boundary is 1dim, so boundary[0] is just the first element boundary[0] = image_array[0,0] # huffman encode the boundary bound_vals_as_string = [str(i) for i in boundary] freq = dict(Counter(bound_vals_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node1 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node1) nodelist = [node1] # create a list of huffman table huffman_encoding_list = [huffman_encoding_dict] n = len(bins) # loop through different bins for i in range (0,n): # the first bin if i == 0 : # get the point within the bin and huffman huffman_encoding_dict mask = diff <= bins[i] line_as_string = [str(i) for i in error[mask].astype(int)] freq = dict(Counter(line_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node2 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node2) huffman_encoding_list.append(huffman_encoding_dict) nodelist.append(node2) # the middle bins else: # get the point within the bin and huffman huffman_encoding_dict mask = diff > bins[i-1] new_error = error[mask] mask2 = diff[mask] <= bins[i] line_as_string = [str(i) for i in new_error[mask2].astype(int)] freq = dict(Counter(line_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node3 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node3) huffman_encoding_list.append(huffman_encoding_dict) nodelist.append(node3) # the last bin # get the point within the bin and huffman huffman_encoding_dict mask = diff > bins[-1] line_as_string = [str(i) for i in error[mask].astype(int)] freq = dict(Counter(line_as_string)) freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) node4 = make_tree(freq) huffman_encoding_dict = huffman_code_tree(node4) huffman_encoding_list.append(huffman_encoding_dict) nodelist.append(node4) # create a error matrix that includes the boundary (used in encoding matrix) new_error = np.copy(image_array) new_error[1:-1,1:-1] = np.reshape(error,(510, 638)) keep = new_error[0,0] new_error[0,:] = new_error[0,:] - keep new_error[-1,:] = new_error[-1,:] - keep new_error[1:-1,0] = new_error[1:-1,0] - keep new_error[1:-1,-1] = new_error[1:-1,-1] - keep new_error[0,0] = keep # huffman_encoding_list = list(set(huffman_encoding_list)) diff = np.reshape(diff,(510,638)) # return the huffman dictionary return huffman_encoding_list, image_array, new_error, diff, boundary, predict, bins, A, nodelist ``` %% Cell type:code id: tags: ``` python def encoder(error, list_dic, diff, bound, bins): """ This function encode the matrix with huffman coding tables Input: error (512, 640): a matrix with all the errors list_dic (num_dic + 1,): a list of huffman coding table bound (2300,): the boundary values after subtracting the very first pixel value bins (num_bins - 1,): a list of threshold to cut the bins Return: encoded (512, 640): encoded matrix """ returnable_encode = "" # copy the error matrix (including the boundary) encoded = np.copy(error).astype(int).astype(str).astype(object) #diff = np.reshape(diff,(510,638)) # loop through all the pixel to encode for i in range(encoded.shape[0]): for j in range(encoded.shape[1]): if i == 0 or i == encoded.shape[0]-1 or j == 0 or j == encoded.shape[1]-1: returnable_encode += list_dic[0][encoded[i][j]] elif diff[i-1][j-1] <= bins[0]: returnable_encode += list_dic[1][encoded[i][j]] elif diff[i-1][j-1] <= bins[1] and diff[i-1][j-1] > bins[0]: returnable_encode +=list_dic[2][encoded[i][j]] elif diff[i-1][j-1] <= bins[2] and diff[i-1][j-1] > bins[1]: returnable_encode +=list_dic[3][encoded[i][j]] else: returnable_encode += list_dic[4][encoded[i][j]] return returnable_encode ``` %% Cell type:code id: tags: ``` python def decoder(A, encoded_string, list_dic, bins, use_diff, nodes): """ This function decodes the encoded_matrix. Input: A (3 X 3): system of equation list_dic (num_dic + 1,): a list of huffman coding table encoded_matrix (512, 640): encoded matrix bins (num_bins - 1,): a list of threshold to cut the bins Return: decode_matrix (512, 640): decoded matrix """ # change the dictionary back to list # !!!!!WARNING!!!! has to change this part, everytime you change the number of bins the_keys0 = list(list_dic[0].keys()) the_values0 = list(list_dic[0].values()) the_keys1 = list(list_dic[1].keys()) the_values1 = list(list_dic[1].values()) the_keys2 = list(list_dic[2].keys()) the_values2 = list(list_dic[2].values()) the_keys3 = list(list_dic[3].keys()) the_values3 = list(list_dic[3].values()) the_keys4 = list(list_dic[4].keys()) the_values4 = list(list_dic[4].values()) #Matrix system of points that will be used to solve the least squares fitting hyperplane points = np.array([[-1,-1,1], [-1,0,1], [-1,1,1], [0,-1,1]]) decode_matrix = np.zeros((512,640)) # loop through all the element in the matrix for i in range(decode_matrix.shape[0]): for j in range(decode_matrix.shape[1]): # if it's the very first pixel on the image if i == 0 and j == 0: encoded_string, colorvalue = decode_string(encoded_string, nodes[0]) decode_matrix[i][j] = colorvalue # if it's on the boundary (any of the 4 edges) elif i == 0 or i == decode_matrix.shape[0]-1 or j == 0 or j == decode_matrix.shape[1]-1: encoded_string, colorvalue = decode_string(encoded_string, nodes[0]) decode_matrix[i][j] = colorvalue + decode_matrix[0][0] # if not the boundary else: # predict the image with the known pixel value z0 = decode_matrix[i-1][j-1] z1 = decode_matrix[i-1][j] z2 = decode_matrix[i-1][j+1] z3 = decode_matrix[i][j-1] y0 = int(-z0+z2-z3) y1 = int(z0+z1+z2) y2 = int(-z0-z1-z2-z3) y = np.vstack((y0,y1,y2)) if use_diff: difference = max(z0,z1,z2,z3) - min(z0,z1,z2,z3) else: f, difference, rank, s = la.lstsq(points, [z0,z1,z2,z3], rcond=None) difference = difference.astype(int) predict = np.round(np.round(np.linalg.solve(A,y)[-1][0],1)) # add on the difference by searching the dictionary # !!!!!WARNING!!!! has to change this part, eveytime you change the number of bins if difference <= bins[0]: encoded_string, colorvalue = decode_string(encoded_string, nodes[1]) decode_matrix[i][j] = colorvalue + int(predict) elif difference <= bins[1] and difference > bins[0]: encoded_string, colorvalue = decode_string(encoded_string, nodes[2]) decode_matrix[i][j] = colorvalue + int(predict) elif difference <= bins[2] and difference > bins[1]: encoded_string, colorvalue = decode_string(encoded_string, nodes[3]) decode_matrix[i][j] = colorvalue + int(predict) else: encoded_string, colorvalue = decode_string(encoded_string, nodes[4]) decode_matrix[i][j] = colorvalue + int(predict) return decode_matrix.astype(int) ``` %% Cell type:code id: tags: ``` python def compress_rate(image_array, new_error, diff, bound, huffman_encoding_list, bins): ''' This function is used to calculate the compression rate. Input: image_array (512, 640): original_core image new_error (512, 640): error that includes the boundary diff (510, 638): difference of min and max of the 4 neighbors bound (2300,): the boundary values after subtracting the very first pixel value huffman_encoding_list (num_dic + 1,): a list of huffman coding table bins (num_bins - 1,): a list of threshold to cut the bins Return: compression rate ''' # the bits for the original image o_len = 0 # the bits for the compressed image c_len = 0 # initializing the varible #this was unused # im = np.reshape(image,(512, 640)) real_boundary = np.hstack((image_array[0,:],image_array[-1,:],image_array[1:-1,0],image_array[1:-1,-1])) #Bryce's notes: Why are they all reshaped? original_core = image_array[1:-1,1:-1].reshape(-1) diff = diff.reshape(-1) error = new_error[1:-1,1:-1].reshape(-1) # calculate the bit for boundary for i in range(0,len(bound)): o_len += len(bin(real_boundary[i])[2:]) c_len += len(huffman_encoding_list[0][str(bound[i])]) # calculate the bit for the pixels inside the boundary for i in range(0,len(original_core)): # for the original image o_len += len(bin(original_core[i])[2:]) # check the difference and find the coresponding huffman table # !!!!!WARNING!!!! has to change this part, eveytime you change the number of bins if diff[i] <= bins[0]: c_len += len(huffman_encoding_list[1][str(int(error[i]))]) elif diff[i] <= bins[1] and diff[i] > bins[0]: c_len += len(huffman_encoding_list[2][str(int(error[i]))]) elif diff[i] <= bins[2] and diff[i] > bins[1]: c_len += len(huffman_encoding_list[3][str(int(error[i]))]) else: c_len += len(huffman_encoding_list[4][str(int(error[i]))]) return c_len/o_len ``` %% Cell type:code id: tags: ``` python scenes = file_extractor() images = image_extractor(scenes) list_dic, image, new_error, diff, bound, predict, bins, A, nodes = huffman(images[0], 4, False) encoded_string = encoder(new_error, list_dic, diff, bound, bins) reconstruct_image = decoder(A, encoded_string, list_dic, bins, False,nodes) print(np.allclose(image, reconstruct_image)) print(len(list_dic)) ``` %% Output True 5 %% Cell type:code id: tags: ``` python ```