Commit 279ebc7a authored by Kelly Chang's avatar Kelly Chang

take out kelly's

parent e7d79230
No preview for this file type
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 34,
"id": "14f74f21",
"metadata": {},
"outputs": [],
......@@ -24,7 +24,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 35,
"id": "c16af61f",
"metadata": {},
"outputs": [],
......@@ -78,7 +78,7 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 36,
"id": "aceba613",
"metadata": {},
"outputs": [],
......@@ -139,7 +139,7 @@
},
{
"cell_type": "code",
"execution_count": 15,
"execution_count": 37,
"id": "6b965751",
"metadata": {},
"outputs": [],
......@@ -192,7 +192,7 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 38,
"id": "b7561883",
"metadata": {},
"outputs": [],
......@@ -300,14 +300,23 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 39,
"id": "2eb774d2",
"metadata": {},
"outputs": [],
"source": [
"def encoder(error, list_dic, diff, bound, bins):\n",
" \"\"\"\n",
" This function en\n",
" This function encode the matrix with huffman coding tables\n",
" \n",
" Input:\n",
" error (512, 640): a matrix with all the errors\n",
" list_dic (num_dic + 1,): a list of huffman coding table \n",
" bound (2300,): the boundary values after subtracting the very first pixel value\n",
" bins (num_bins - 1,): a list of threshold to cut the bins\n",
" \n",
" Return:\n",
" encoded (512, 640): encoded matrix\n",
" \"\"\"\n",
" # copy the error matrix (including the boundary)\n",
" encoded = np.copy(error).astype(int).astype(str).astype(object)\n",
......@@ -331,15 +340,21 @@
},
{
"cell_type": "code",
"execution_count": 23,
"execution_count": 40,
"id": "8eeb40d0",
"metadata": {},
"outputs": [],
"source": [
"def decoder(A, encoded_matrix, list_dic, bins):\n",
" \"\"\"\n",
" Function that accecpts the prediction matrix A for the linear system,\n",
" the encoded matrix of error values, and the encoding dicitonary.\n",
" This function decodes the encoded_matrix.\n",
" Input:\n",
" A (3 X 3): system of equation\n",
" list_dic (num_dic + 1,): a list of huffman coding table \n",
" encoded_matrix (512, 640): encoded matrix\n",
" bins (num_bins - 1,): a list of threshold to cut the bins\n",
" Return:\n",
" decode_matrix (512, 640): decoded matrix\n",
" \"\"\"\n",
" # change the dictionary back to list\n",
" # !!!!!WARNING!!!! has to change this part, eveytime you change the number of bins\n",
......@@ -358,23 +373,23 @@
" the_keys4 = list(list_dic[4].keys())\n",
" the_values4 = list(list_dic[4].values())\n",
" \n",
" error_matrix = np.zeros((512,640))\n",
" decode_matrix = np.zeros((512,640))\n",
" # loop through all the element in the matrix\n",
" for i in range(error_matrix.shape[0]):\n",
" for j in range(error_matrix.shape[1]):\n",
" for i in range(decode_matrix.shape[0]):\n",
" for j in range(decode_matrix.shape[1]):\n",
" # if it's the very first pixel on the image\n",
" if i == 0 and j == 0:\n",
" error_matrix[i][j] = int(the_keys0[the_values0.index(encoded_matrix[i,j])])\n",
" decode_matrix[i][j] = int(the_keys0[the_values0.index(encoded_matrix[i,j])])\n",
" # if it's on the boundary\n",
" elif i == 0 or i == error_matrix.shape[0]-1 or j == 0 or j == error_matrix.shape[1]-1:\n",
" error_matrix[i][j] = int(the_keys0[the_values0.index(encoded_matrix[i,j])]) + error_matrix[0][0]\n",
" elif i == 0 or i == decode_matrix.shape[0]-1 or j == 0 or j == decode_matrix.shape[1]-1:\n",
" decode_matrix[i][j] = int(the_keys0[the_values0.index(encoded_matrix[i,j])]) + decode_matrix[0][0]\n",
" # if not the boundary\n",
" else:\n",
" # predict the image with the known pixel value\n",
" z0 = error_matrix[i-1][j-1]\n",
" z1 = error_matrix[i-1][j]\n",
" z2 = error_matrix[i-1][j+1]\n",
" z3 = error_matrix[i][j-1]\n",
" z0 = decode_matrix[i-1][j-1]\n",
" z1 = decode_matrix[i-1][j]\n",
" z2 = decode_matrix[i-1][j+1]\n",
" z3 = decode_matrix[i][j-1]\n",
" y0 = int(-z0+z2-z3)\n",
" y1 = int(z0+z1+z2)\n",
" y2 = int(-z0-z1-z2-z3)\n",
......@@ -385,26 +400,30 @@
" # add on the difference by searching the dictionary\n",
" # !!!!!WARNING!!!! has to change this part, eveytime you change the number of bins\n",
" if difference <= bins[0]:\n",
" error_matrix[i][j] = int(the_keys1[the_values1.index(encoded_matrix[i,j])]) + int(predict)\n",
" decode_matrix[i][j] = int(the_keys1[the_values1.index(encoded_matrix[i,j])]) + int(predict)\n",
" elif difference <= bins[1] and difference > bins[0]:\n",
" error_matrix[i][j] = int(the_keys2[the_values2.index(encoded_matrix[i,j])]) + int(predict)\n",
" decode_matrix[i][j] = int(the_keys2[the_values2.index(encoded_matrix[i,j])]) + int(predict)\n",
" elif difference <= bins[2] and difference > bins[1]:\n",
" error_matrix[i][j] = int(the_keys3[the_values3.index(encoded_matrix[i,j])]) + int(predict)\n",
" decode_matrix[i][j] = int(the_keys3[the_values3.index(encoded_matrix[i,j])]) + int(predict)\n",
" else:\n",
" error_matrix[i][j] = int(the_keys4[the_values4.index(encoded_matrix[i,j])]) + int(predict)\n",
" decode_matrix[i][j] = int(the_keys4[the_values4.index(encoded_matrix[i,j])]) + int(predict)\n",
" \n",
" \n",
" return error_matrix.astype(int)"
" return decode_matrix.astype(int)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 41,
"id": "f959fe93",
"metadata": {},
"outputs": [],
"source": [
"def compress_rate(image, error, diff, bound, list_dic, bins):\n",
" '''\n",
" This function is used to calculate the compression rate.\n",
" \n",
" '''\n",
" # the bits for the original image\n",
" o_len = 0\n",
" # the bits for the compressed image\n",
......@@ -444,7 +463,7 @@
},
{
"cell_type": "code",
"execution_count": 25,
"execution_count": 42,
"id": "3e0e9742",
"metadata": {},
"outputs": [
......@@ -470,7 +489,7 @@
},
{
"cell_type": "code",
"execution_count": 32,
"execution_count": 33,
"id": "004e8ba8",
"metadata": {},
"outputs": [
......@@ -478,13 +497,13 @@
"name": "stdout",
"output_type": "stream",
"text": [
"[26, 40, 62]\n"
"(512, 640)\n"
]
}
],
"source": [
"\n",
"print(bins)"
"print(encoded_matrix.shape)"
]
},
{
......
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "dbef8759",
"metadata": {
"id": "dbef8759"
},
"outputs": [],
"source": [
"import numpy as np\n",
"from prediction_MSE_Scout import file_extractor, image_extractor, im_distribution\n",
"from matplotlib import pyplot as plt\n",
"from itertools import product\n",
"import os\n",
"import sys\n",
"from PIL import Image\n",
"from scipy.optimize import minimize\n",
"from time import time\n",
"from numpy import linalg as la\n",
"from scipy.stats import gaussian_kde\n",
"import seaborn as sns\n",
"from collections import Counter\n",
"import pandas as pd\n",
"import scipy as sp"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "9ed20f84",
"metadata": {
"id": "9ed20f84"
},
"outputs": [],
"source": [
"def predict(tiff_list, i=0):\n",
" \"\"\"\n",
" This function predicts the pixel values based on a linear combination\n",
" of the MSE from the three pixels above it and the one to the left. It\n",
" uses a system of equations to fit the plane ax + by + c and takes c\n",
" as the prediction for the unknown pixel. It does this all at once\n",
" by constructing vectors and matrices of the surrounding pixels and solving each system simultaneously\n",
" so as not to iterate through each one.\n",
" \n",
" Parameters:\n",
" tiff_list: list, list of names of image file paths to access. These should be strings\n",
" in the form of a path to the image\n",
" \n",
" i: int, which index in the tiff_list of images we want to predict on\n",
" \n",
" Returns:\n",
" prediction: matrix (ndarray), the matrix of predicted values\n",
" for the image using the previous four piexels\n",
" \n",
" diff: matrix (ndarray), the difference between the highest and lowest valued surrounding four pixels\n",
" \n",
" image_int: matrix (ndarray), the original image, changed into integers\n",
" \n",
" error: matrix (ndarray), a matrix of errors, so each entry is the \n",
" difference between the integer predicted value and the actual value. Should\n",
" be all integers\n",
" \n",
" A: matrix (3,3 ndarray), the matrix used to solve the MSE system\n",
" \"\"\"\n",
" \n",
" image = tiff_list[i]\n",
" image = Image.open(image) #Open the image and read it as an Image object\n",
" image = np.array(image)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
" image_int = image.astype(int)\n",
" \n",
" A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) # the matrix for system of equation\n",
" \n",
" z0 = image_int[0:-2,0:-2] # get all the first pixel for the entire image\n",
" z1 = image_int[0:-2,1:-1] # get all the second pixel for the entire image\n",
" z2 = image_int[0:-2,2::] # get all the third pixel for the entire image\n",
" z3 = image_int[1:-1,0:-2] # get all the fourth pixel for the entire image\n",
" \n",
" # calculate the out put of the system of equation\n",
" y0 = np.ravel(-z0+z2-z3)\n",
" y1 = np.ravel(z0+z1+z2)\n",
" y2 = np.ravel(-z0-z1-z2-z3)\n",
" y = np.vstack((y0,y1,y2))\n",
" \n",
" # use numpy solver to solve the system of equations all at once\n",
" #predict = np.linalg.solve(A,y)[-1]\n",
" prediction = np.floor(np.linalg.solve(A,y)[-1]).astype(int)\n",
" #predict = []\n",
" \n",
" # flatten the neighbor pixels and stack them together\n",
" z0 = np.ravel(z0)\n",
" z1 = np.ravel(z1)\n",
" z2 = np.ravel(z2)\n",
" z3 = np.ravel(z3)\n",
" neighbor = np.vstack((z0,z1,z2,z3)).T\n",
" \n",
" # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\n",
" #diff = np.pad(diff.reshape(510,638), pad_width=1)\n",
" \n",
" # flatten the image to a vector\n",
" small_image = image_int[1:-1,1:-1]\n",
" \n",
" #Reshape the predictions to be a 2D array\n",
" prediction = np.pad(prediction.reshape(510,638), pad_width=1)\n",
" \n",
" \n",
" #Calculate the error between the original image and our predictions\n",
" #Note that we only predicted on the inside square of the original image, excluding\n",
" #The first row, column and last row, column\n",
" #error = (image_int - predict).astype(int) #Experiment\n",
" \n",
" #this one works\n",
" error = image_int - prediction\n",
"\n",
" \n",
" return prediction, diff, image_int, error[1:-1,1:-1], A"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ba2881d9",
"metadata": {},
"outputs": [],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"11\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "11e95c34",
"metadata": {},
"outputs": [],
"source": [
"prediction, diff, im, err, A = predict(images, 2)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "434e4d2f",
"metadata": {},
"outputs": [],
"source": [
"def reconstruct(error, A):\n",
" \"\"\"\n",
" Function that reconstructs the original image\n",
" from the error matrix and using the predictive\n",
" algorithm developed in the encoding.\n",
" \n",
" Parameters:\n",
" error (array): matrix of errors computed in encoding. Same \n",
" shape as the original image (512, 640) in this case\n",
" A (array): Matrix used for the system of equations to create predictions\n",
" Returns:\n",
" image (array): The reconstructed image\n",
" \"\"\"\n",
" new_e = error.copy()\n",
" rows, columns = new_e.shape\n",
"\n",
" for r in range(1, rows-1): #Iterate through the inside square of the error matrix\n",
" for c in range(1, columns-1):\n",
" z0, z1, z2, z3 = new_e[r-1][c-1], new_e[r-1][c], new_e[r-1][c+1], new_e[r][c-1] #Grab the four nearest pixels\n",
" y = np.vstack((-z0+z2-z3, z0+z1+z2, -z0-z1-z2-z3)) #Create a vector of the linear combinations for the\n",
" #solution to be solved\n",
" \n",
" new_e[r][c] = np.round(new_e[r][c] + np.linalg.solve(A,y)[-1], 1) #Add the error to the solved system solution\n",
" #rounding the result because np.linalg.solve(A,y)\n",
" #can be a float. Since we did np.floor on it in\n",
" #prediction, we round to the nearest integer here\n",
" return new_e.astype(int)\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "3cc609dc",
"metadata": {},
"outputs": [],
"source": [
"new_error = reconstruct(err, A)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "5d290a0c",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\calle\\AppData\\Local\\Temp/ipykernel_23384/389333.py:1: DeprecationWarning: elementwise comparison failed; this will raise an error in the future.\n",
" im == new_error\n"
]
},
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"im == new_error"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "bb11dcd0",
"metadata": {},
"outputs": [],
"source": [
"class NodeTree(object):\n",
" def __init__(self, left=None, right=None):\n",
" self.left = left\n",
" self.right = right\n",
"\n",
" def children(self):\n",
" return self.left, self.right\n",
"\n",
" def __str__(self):\n",
" return self.left, self.right\n",
"\n",
"\n",
"def huffman_code_tree(node, binString=''):\n",
" '''\n",
" Function to find Huffman Code\n",
" '''\n",
" if type(node) is str:\n",
" return {node: binString}\n",
" (l, r) = node.children()\n",
" d = dict()\n",
" d.update(huffman_code_tree(l, binString + '0'))\n",
" d.update(huffman_code_tree(r, binString + '1'))\n",
" return d\n",
"\n",
"\n",
"def make_tree(nodes):\n",
" '''\n",
" Function to make tree\n",
" :param nodes: Nodes\n",
" :return: Root of the tree\n",
" '''\n",
" while len(nodes) > 1:\n",
" (key1, c1) = nodes[-1]\n",
" (key2, c2) = nodes[-2]\n",
" nodes = nodes[:-2]\n",
" node = NodeTree(key1, key2)\n",
" nodes.append((node, c1 + c2))\n",
" nodes = sorted(nodes, key=lambda x: x[1], reverse=True)\n",
" return nodes[0][0]"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "c01fda28",
"metadata": {},
"outputs": [],
"source": [
"def encoder(images, i, plot=True):\n",
" \"\"\"\n",
" Function that creates Huffman encodings out of the error values\n",
" for a given image. The encodings are more efficient ways to store \n",
" large integer values that the original image contains.\n",
" \n",
" Parameters:\n",
" images (list): list of file paths to the images that\n",
" will be encoded.\n",
" \n",
" i (int): which index of the images list to grab and\n",
" then encode.\n",
" \n",
" plot (bool): if true, this plots the error matrix to \n",
" show the distribution of values.\n",
" \"\"\"\n",
" \n",
" prediction, diff, original, error, A = predict(images, i) #Predict the values and return the error for the specified image\n",
" image = original \n",
" new_error = np.copy(image) #Create a new matrix that is a copy of the original image, this is the matrix we will\n",
" #update on throughout\n",
" #new_error[1:-1,1:-1] = np.reshape(error[1:-1,1:-1],(510, 638))\n",
" new_error[1:-1, 1:-1] = error[1:-1, 1:-1] #Set the inside of the updating matrix to be the same as the \n",
" #error matrix retreived from predicting\n",
" keep = new_error[0,0] #The top left entry stays the same\n",
" new_error[0,:] = new_error[0,:] - keep #All edge pixels are set to be the difference between themselves and\n",
" new_error[-1,:] = new_error[-1,:] - keep #the top left entry named \"keep\". This reduces their size to a more\n",
" new_error[1:-1,0] = new_error[1:-1,0] - keep #manageable integer and makes them encodeable with the other error values\n",
" new_error[1:-1,-1] = new_error[1:-1,-1] - keep\n",
" new_error[0,0] = keep\n",
" \n",
" new_error = np.ravel(new_error) #Unravel it to plot it\n",
" if plot:\n",
" plt.hist(new_error[1:],bins=100)\n",
" plt.show()\n",
" \n",
"\n",
" string = [str(i) for i in new_error] #Create strings out of the integers in the new_error matrix\n",
" \n",
" freq = dict(Counter(string)) #Initialize a dictionary that maps integers to the string values\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) #Create a frequency mapping of how often the string\n",
" #values occur in the dictionary\n",
" node = make_tree(freq) #Use the Huffman code given above to make a Huffman tree\n",
" \n",
" encoding_dict = huffman_code_tree(node) #Create the Huffman dictionary\n",
" \n",
" #encoded = [\"1\"+encoding[str(-i)] if i < 0 else \"0\"+encoding[str(i)] for i in error]\n",
"\n",
" encoded = new_error.reshape((512,640)).copy().astype(str).astype(object) #Reshape the error matrix and make a copy that\n",
" #that is all strings so we can call the \n",
" #dictionary on its entries\n",
" for i in range(encoded.shape[0]): #Iterate through the string valued error dictionary\n",
" for j in range(encoded.shape[1]):\n",
" if i == 0 and j == 0:\n",
" encoded[i][j] = encoded[i][j] #Replace each value in the dictionary with its encoding from the dictionary\n",
" else:\n",
" encoded[i][j] = encoding_dict[encoded[i][j]]\n",
" \n",
" return encoding_dict, encoded, new_error.reshape((512,640)), image\n",
" #print(encoding)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "ffa858e8",
"metadata": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "could not broadcast input array from shape (508,636) into shape (510,638)",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2620/384786850.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mencode_dict\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencoding\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0merror\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0morig_image\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mencoder\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimages\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mplot\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2620/3253315524.py\u001b[0m in \u001b[0;36mencoder\u001b[1;34m(images, i, plot)\u001b[0m\n\u001b[0;32m 21\u001b[0m \u001b[1;31m#update on throughout\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 22\u001b[0m \u001b[1;31m#new_error[1:-1,1:-1] = np.reshape(error[1:-1,1:-1],(510, 638))\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 23\u001b[1;33m \u001b[0mnew_error\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0merror\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;31m#Set the inside of the updating matrix to be the same as the\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 24\u001b[0m \u001b[1;31m#error matrix retreived from predicting\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 25\u001b[0m \u001b[0mkeep\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnew_error\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;31m#The top left entry stays the same\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: could not broadcast input array from shape (508,636) into shape (510,638)"
]
}
],
"source": [
"encode_dict, encoding, error, orig_image = encoder(images, 2, plot=False)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "825cc48c",
"metadata": {},
"outputs": [],
"source": [
"def decoder(A, encoded_matrix, encoding_dict):\n",
" \"\"\"\n",
" Function that accecpts the prediction matrix A for the linear system,\n",
" the encoded matrix of error values, and the encoding dicitonary.\n",
" \"\"\"\n",
" the_keys = list(encoding_dict.keys())\n",
" the_values = list(encoding_dict.values())\n",
" error_matrix = encoded_matrix.copy()\n",
" \n",
" for i in range(error_matrix.shape[0]):\n",
" for j in range(error_matrix.shape[1]):\n",
" if i == 0 and j == 0:\n",
" error_matrix[i][j] = int(encoded_matrix[i][j])\n",
" \n",
" elif i == 0 or i == error_matrix.shape[0]-1 or j == 0 or j == error_matrix.shape[1]-1:\n",
" error_matrix[i][j] = int(the_keys[the_values.index(error_matrix[i,j])]) + error_matrix[0][0]\n",
" else:\n",
" \"\"\"z0, z1, z2, z3 = error_matrix[i-1][j-1], error_matrix[i-1][j], \\\n",
" error_matrix[i-1][j+1], error_matrix[i][j-1]\n",
" y = np.vstack((-z0+z2-z3, z0+z1+z2, -z0-z1-z2-z3))\"\"\"\n",
" \n",
" error_matrix[i][j] = int(the_keys[the_values.index(error_matrix[i,j])])\n",
" \n",
" return error_matrix.astype(int)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "ba1d2c2c",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'encoding' is not defined",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_23384/3979147550.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mem\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdecoder\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mA\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencoding\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode_dict\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;31mNameError\u001b[0m: name 'encoding' is not defined"
]
}
],
"source": [
"em = decoder(A, encoding, encode_dict)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "b2cdce6d",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'em' is not defined",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_23384/2268978435.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mhopefully\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mreconstruct\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mem\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mA\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2\u001b[0m \u001b[1;31m#22487 22483 22521 22464\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mNameError\u001b[0m: name 'em' is not defined"
]
}
],
"source": [
"hopefully = reconstruct(em, A)\n",
"#22487 22483 22521 22464"
]
},
{
"cell_type": "code",
"execution_count": 124,
"id": "285efcf0",
"metadata": {},
"outputs": [],
"source": [
"def test_decoder():\n",
" n = len(images)//12\n",
" fails = 0\n",
" for i in range(n):\n",
" encode_dict1, encoding1, error1, orig_image1 = encoder(images, i, plot=False)\n",
" new_error = decoder(A, encoding1, encode_dict1)\n",
" reconstructed_image = reconstruct(new_error, A)\n",
" if False in np.ravel(reconstructed_image == orig_image):\n",
" fails += 0\n",
" return fails/n\n",
"f = test_decoder()"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "30b1c87e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6.7830123821108295\n"
]
}
],
"source": [
"def entropy_func(images):\n",
" \"\"\"\n",
" Computes the entropy for all pictures (tiff files) in the images list.\n",
" This gives an idea of how many bits it would take on average to encode the\n",
" given image. The output is a list of entropies, one per image.\n",
" \"\"\"\n",
" entr = []\n",
" for i in range(len(images)):\n",
" prediction, diff, im, err, A = predict(images, i)\n",
" panda_im = pd.Series(np.ravel(im))\n",
" counts = panda_im.value_counts()\n",
" entr.append(sp.stats.entropy(counts))\n",
" return entr\n",
"\n",
"e = entropy_func(images)\n",
"print(np.mean(e))"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "4c268907",
"metadata": {},
"outputs": [
{
"ename": "IndexError",
"evalue": "boolean index did not match indexed array along dimension 0; dimension is 510 but corresponding boolean dimension is 512",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2620/1618652474.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 72\u001b[0m \u001b[0mscenes\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfile_extractor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 73\u001b[0m \u001b[0mimages\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimage_extractor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mscenes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 74\u001b[1;33m \u001b[0mencode1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode4\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode5\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0merror\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnew_error\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdiff\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mboundary\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbins\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mhuffman\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimages\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2620/1618652474.py\u001b[0m in \u001b[0;36mhuffman\u001b[1;34m(image)\u001b[0m\n\u001b[0;32m 18\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 19\u001b[0m \u001b[0mmask\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdiff\u001b[0m \u001b[1;33m<=\u001b[0m \u001b[1;36m25\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 20\u001b[1;33m \u001b[0mstring\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0merror\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mmask\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mint\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 21\u001b[0m \u001b[0mfreq\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mCounter\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstring\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 22\u001b[0m \u001b[0mfreq\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msorted\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfreq\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mreverse\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mIndexError\u001b[0m: boolean index did not match indexed array along dimension 0; dimension is 510 but corresponding boolean dimension is 512"
]
}
],
"source": [
"def huffman(image):\n",
" origin, predicty, diff, error, A = predict(image,0)\n",
" \n",
" image = Image.open(image[0])\n",
" image = np.array(image)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
" image = image.astype(int)\n",
" \n",
" boundary = np.hstack((image[0,:],image[-1,:],image[1:-1,0],image[1:-1,-1]))\n",
" boundary = boundary - image[0,0]\n",
" boundary[0] = image[0,0]\n",
"\n",
" string = [str(i) for i in boundary]\n",
" freq = dict(Counter(string))\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\n",
" node = make_tree(freq)\n",
" encode1 = huffman_code_tree(node)\n",
" \n",
" \n",
" mask = diff <= 25\n",
" string = [str(i) for i in error[mask].astype(int)]\n",
" freq = dict(Counter(string))\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\n",
" node = make_tree(freq)\n",
" encode2 = huffman_code_tree(node)\n",
"\n",
" \n",
" mask = diff > 25\n",
" new_error = error[mask]\n",
" mask2 = diff[mask] <= 40\n",
" string = [str(i) for i in new_error[mask2].astype(int)]\n",
" freq = dict(Counter(string))\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\n",
" node = make_tree(freq)\n",
" encode3 = huffman_code_tree(node)\n",
" \n",
"\n",
" mask = diff > 40\n",
" new_error = error[mask]\n",
" mask2 = diff[mask] <= 70\n",
" string = [str(i) for i in new_error[mask2].astype(int)]\n",
" freq = dict(Counter(string))\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\n",
" node = make_tree(freq)\n",
" encode4 = huffman_code_tree(node)\n",
" \n",
" \n",
" mask = diff > 70\n",
" string = [str(i) for i in error[mask].astype(int)]\n",
" freq = dict(Counter(string))\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\n",
" node = make_tree(freq)\n",
" encode5 = huffman_code_tree(node)\n",
"\n",
"\n",
" new_error = np.copy(image)\n",
" new_error[1:-1,1:-1] = np.reshape(error,(510, 638))\n",
" keep = new_error[0,0]\n",
" new_error[0,:] = new_error[0,:] - keep\n",
" new_error[-1,:] = new_error[-1,:] - keep\n",
" new_error[1:-1,0] = new_error[1:-1,0] - keep\n",
" new_error[1:-1,-1] = new_error[1:-1,-1] - keep\n",
" new_error[0,0] = keep\n",
" \n",
" \n",
" #new_error = np.ravel(new_error)\n",
" \n",
" bins = [25,40,70]\n",
" \n",
" # return the huffman dictionary\n",
" return encode1, encode2, encode3, encode4, encode5, np.ravel(image), error, new_error, diff, boundary, bins\n",
" \n",
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"encode1, encode2, encode3, encode4, encode5, image, error, new_error, diff, boundary, bins = huffman(images)"
]
},
{
"cell_type": "code",
"execution_count": 159,
"id": "e98fc3cf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[22541 -10 14 ... 62 151 208]\n"
]
}
],
"source": [
"print(boundary)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f5e71acc",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 127,
"id": "642b95a3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.4427516682942708"
]
},
"execution_count": 127,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def compress_rate(image, error, diff, bound, encode1, encode2, encode3, encode4, encode5):\n",
" #original = original.reshape(-1)\n",
" #error = error.reshape(-1)\n",
" o_len = 0\n",
" c_len = 0\n",
" im = np.reshape(image,(512, 640))\n",
" real_b = np.hstack((im[0,:],im[-1,:],im[1:-1,0],im[1:-1,-1]))\n",
" original = im[1:-1,1:-1].reshape(-1)\n",
"\n",
" for i in range(0,len(bound)):\n",
" o_len += len(bin(real_b[i])[2:])\n",
" c_len += len(encode1[str(bound[i])])\n",
" \n",
" for i in range(0, len(original)):\n",
" o_len += len(bin(original[i])[2:])\n",
" if diff[i] <= 10:\n",
" c_len += len(encode2[str(int(error[i]))])\n",
"\n",
" if diff[i] <= 25 and diff[i] > 10:\n",
" c_len += len(encode3[str(int(error[i]))])\n",
" \n",
" if diff[i] <= 45 and diff[i] > 25:\n",
" c_len += len(encode4[str(int(error[i]))])\n",
" \n",
" if diff[i] > 45:\n",
" c_len += len(encode5[str(int(error[i]))])\n",
" \n",
" return c_len/o_len\n",
"compress_rate(origin, error, diff, boundary, encode1, encode2, encode3, encode4, encode5)\n"
]
},
{
"cell_type": "code",
"execution_count": 209,
"id": "7d507cfb",
"metadata": {},
"outputs": [],
"source": [
"def encode_multiple(error, diff, bound, encode1, encode2, encode3, encode4, encode5):\n",
" #original = original.reshape(-1)\n",
" #error = error.reshape(-1)\n",
" original = len(np.ravel(error))\n",
" error = np.ravel(error)\n",
" encode_error = error.astype(str).astype(object).copy()\n",
" bound_error = bound.astype(str).astype(object).copy()\n",
" \n",
" \n",
" for i in range(0,len(bound_error)):\n",
" bound_error[i] = encode1[bound_error[i]] \n",
" \n",
" for i in range(0, original):\n",
" if diff[i] <= 10:\n",
" encode_error[i] = encode2[encode_error[i]]\n",
"\n",
" if diff[i] <= 25 and diff[i] > 10:\n",
" encode_error[i] = encode3[encode_error[i]]\n",
" \n",
" if diff[i] <= 45 and diff[i] > 25:\n",
" encode_error[i] = encode4[encode_error[i]]\n",
" \n",
" if diff[i] > 45:\n",
" encode_error[i] = encode5[encode_error[i]]\n",
" \n",
" encode_error = np.pad(encode_error.reshape(510,638), pad_width=1)\n",
" encode_error[0] = bound_error[:640]\n",
" encode_error[-1] = bound_error[640:640*2]\n",
" encode_error[1:-1,0] = bound_error[640*2:(640*2)+510]\n",
" encode_error[1:-1,-1] = bound_error[(640*2)+510:]\n",
" \n",
" return encode_error, bound_error\n",
"enc_mat, bound_e = encode_multiple(error, diff, boundary, encode1, encode2, encode3, encode4, encode5)"
]
},
{
"cell_type": "code",
"execution_count": 211,
"id": "2faf5cd9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1 1\n"
]
},
{
"ename": "ValueError",
"evalue": "'101011' is not in list",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_1700/1235154671.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 42\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0merror_matrix\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mint\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 43\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 44\u001b[1;33m \u001b[0mdec\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdecode_multi\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mA\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0menc_mat\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode4\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mencode5\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdiff\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_1700/1235154671.py\u001b[0m in \u001b[0;36mdecode_multi\u001b[1;34m(A, encoded_matrix, encode1, encode2, encode3, encode4, encode5, diff)\u001b[0m\n\u001b[0;32m 35\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0merror_matrix\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;34m'101011'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 36\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mj\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 37\u001b[1;33m \u001b[0merror_matrix\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mthe_keys4\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mthe_values4\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0merror_matrix\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 38\u001b[0m \u001b[1;32melif\u001b[0m \u001b[0mdiff\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m*\u001b[0m\u001b[1;36m640\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;36m45\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 39\u001b[0m \u001b[0merror_matrix\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mthe_keys5\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mthe_values5\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0merror_matrix\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: '101011' is not in list"
]
}
],
"source": [
"def decode_multi(A, encoded_matrix, encode1, encode2, encode3, encode4, encode5, diff):\n",
" \"\"\"\n",
" Function that accecpts the prediction matrix A for the linear system,\n",
" the encoded matrix of error values, and the encoding dicitonary.\n",
" \"\"\"\n",
" \n",
" \n",
" the_keys1 = list(encode1.keys())\n",
" the_values1 = list(encode1.values())\n",
" the_keys2 = list(encode2.keys())\n",
" the_values2 = list(encode2.values())\n",
" the_keys3 = list(encode3.keys())\n",
" the_values3 = list(encode3.values())\n",
" the_keys4 = list(encode4.keys())\n",
" the_values4 = list(encode4.values())\n",
" the_keys5 = list(encode5.keys())\n",
" the_values5 = list(encode5.values())\n",
" \n",
" error_matrix = encoded_matrix.copy()\n",
" \n",
" for i in range(error_matrix.shape[0]):\n",
" for j in range(error_matrix.shape[1]):\n",
" if i == 0 and j == 0:\n",
" error_matrix[i][j] = int(the_keys1[the_values1.index(encoded_matrix[i,j])])\n",
" \n",
" \n",
" elif i == 0 or i == error_matrix.shape[0]-1 or j == 0 or j == error_matrix.shape[1]-1:\n",
" error_matrix[i][j] = int(the_keys1[the_values1.index(error_matrix[i,j])]) + int(error_matrix[0][0])\n",
" else:\n",
" if diff[i*640 + j] <= 10:\n",
" error_matrix[i][j] = int(the_keys2[the_values2.index(error_matrix[i,j])])\n",
" elif diff[i*640 + j] > 10 and diff[i*640 + j] <= 25:\n",
" error_matrix[i,j] = int(the_keys3[the_values3.index(error_matrix[i,j])])\n",
" elif diff[i*640 + j] > 25 and diff[i*640 + j] <= 45:\n",
" if error_matrix[i,j] == '101011':\n",
" print(i,j)\n",
" \n",
" error_matrix[i,j] = int(the_keys4[the_values4.index(error_matrix[i,j])])\n",
" elif diff[i*640 + j] > 45:\n",
" error_matrix[i,j] = int(the_keys5[the_values5.index(error_matrix[i,j])])\n",
" \n",
" \n",
" return error_matrix.astype(int)\n",
"\n",
"dec = decode_multi(A, enc_mat, encode1, encode2, encode3, encode4, encode5, diff)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "64832ca7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[58 38 13 ... 65 97 32]\n"
]
},
{
"ename": "NameError",
"evalue": "name 'o' is not defined",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2620/2795330121.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[0mfreqs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcount\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mvalue\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mfreqs\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 9\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstats\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mentropy\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mrel_freq\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlist\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mo\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mentropy_check\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mNameError\u001b[0m: name 'o' is not defined"
]
}
],
"source": [
"\n",
"\"\"\"plt.hexbin(x,y,cmap=\"rocket\")\n",
"plt.colorbar()\n",
"plt.xlim(0,50)\n",
"plt.ylim(0,100)\"\"\"\n",
"\n",
"def rel_freq(x):\n",
" freqs = [x.count(value) / len(x) for value in set(x)] \n",
" return freqs\n",
"print(sp.stats.entropy(rel_freq(list(np.ravel(image)))))\n",
"\n",
"def entropy_check(x, y):\n",
" #freq = rel_freq(list(np.ravel(o)))\n",
" means = []\n",
" for i in range(len(images)):\n",
" p, d, o, e, A = predict(images,0)\n",
" d = d.reshape((510,638))\n",
" x = np.abs(np.ravel(e))\n",
" y = np.ravel(d)\n",
" \n",
" mask1 = y <= 25\n",
" x_masked1 = x[mask1]\n",
"\n",
" mask2 = y > 25\n",
" x_masked2 = x[mask2]\n",
" mask2 = y[mask2] <= 40\n",
" x_masked2 = x_masked2[mask2]\n",
"\n",
" mask3 = y > 40\n",
" x_masked3 = x[mask3]\n",
" mask3 = y[mask3] <= 75\n",
" x_masked3 = x_masked3[mask3]\n",
" \n",
" mask4 = y > 75\n",
" x_masked4 = x[mask4]\n",
"\n",
"\n",
" e_m1 = sp.stats.entropy(rel_freq(list(x_masked1)))\n",
" e_m2 = sp.stats.entropy(rel_freq(list(x_masked2)))\n",
" e_m3 = sp.stats.entropy(rel_freq(list(x_masked3)))\n",
" e_m4 = sp.stats.entropy(rel_freq(list(x_masked4)))\n",
" means.append([e_m1, e_m2, e_m3, e_m4])\n",
" return np.mean(np.array(means).reshape(len(images),4), axis=0)\n",
" \n",
"#print(entropy_check(x, y))"
]
}
],
"metadata": {
"colab": {
"collapsed_sections": [],
"name": "Wavelet_Huffman.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
File added
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"cells": [
{
"cell_type": "code",
"execution_count": 28,
"id": "dbef8759",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from matplotlib import pyplot as plt\n",
"from itertools import product\n",
"import os\n",
"import sys\n",
"from PIL import Image\n",
"from scipy.optimize import minimize\n",
"from time import time"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "b7a550e0",
"metadata": {},
"outputs": [],
"source": [
"def file_extractor(dirname=\"images\"):\n",
" files = os.listdir(dirname)\n",
" scenes = []\n",
" for file in files:\n",
" scenes.append(os.path.join(dirname, file))\n",
" return scenes\n",
"\n",
"def image_extractor(scenes):\n",
" image_folder = []\n",
" for scene in scenes:\n",
" files = os.listdir(scene)\n",
" for file in files:\n",
" image_folder.append(os.path.join(scene, file))\n",
" images = []\n",
" for folder in image_folder:\n",
" ims = os.listdir(folder)\n",
" for im in ims:\n",
" if im[-4:] == \".jp4\" or im[-7:] == \"_6.tiff\":\n",
" continue\n",
" else:\n",
" images.append(os.path.join(folder, im))\n",
" return images #returns a list of file paths to .tiff files in the specified directory given in file_extractor\n",
"\n",
"def im_distribution(images, num):\n",
" \"\"\"\n",
" Function that extracts tiff files from specific cameras and returns a list of all\n",
" the tiff files corresponding to that camera. i.e. all pictures labeled \"_7.tiff\" or otherwise\n",
" specified camera numbers.\n",
" \n",
" Parameters:\n",
" images (list): list of all tiff files, regardless of classification. This is NOT a list of directories but\n",
" of specific tiff files that can be opened right away. This is the list that we iterate through and \n",
" divide.\n",
" \n",
" num (str): a string designation for the camera number that we want to extract i.e. \"14\" for double digits\n",
" of \"_1\" for single digits.\n",
" \n",
" Returns:\n",
" tiff (list): A list of tiff files that have the specified designation from num. They are the files extracted\n",
" from the 'images' list that correspond to the given num.\n",
" \"\"\"\n",
" tiff = []\n",
" for im in images:\n",
" if im[-7:-5] == num:\n",
" tiff.append(im)\n",
" return tiff"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "9ed20f84",
"metadata": {},
"outputs": [],
"source": [
"def plot_hist(tiff_list,i):\n",
" \"\"\"\n",
" This function is the leftovers from the first attempt to plot histograms.\n",
" As it stands it needs some work in order to function again. We will\n",
" fix this later. 1/25/22\n",
" \"\"\"\n",
" \n",
"\n",
" image = tiff_list[i]\n",
" image = Image.open(image) #Open the image and read it as an Image object\n",
" image = np.array(image)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
" image = image.astype(int)\n",
" A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) # the matrix for system of equation\n",
" z0 = image[0:-2,0:-2] # get all the first pixel for the entire image\n",
" z1 = image[0:-2,1:-1] # get all the second pixel for the entire image\n",
" z2 = image[0:-2,2::] # get all the third pixel for the entire image\n",
" z3 = image[1:-1,0:-2] # get all the forth pixel for the entire image\n",
" # calculate the out put of the system of equation\n",
" y0 = np.ravel(-z0+z2-z3)\n",
" y1 = np.ravel(z0+z1+z2)\n",
" y2 = np.ravel(-z0-z1-z2-z3)\n",
" y = np.vstack((y0,y1,y2))\n",
" # use numpy solver to solve the system of equations all at once\n",
" predict = np.floor(np.linalg.solve(A,y)[-1])\n",
" # flatten the neighbor pixlels and stack them together\n",
" z0 = np.ravel(z0)\n",
" z1 = np.ravel(z1)\n",
" z2 = np.ravel(z2)\n",
" z3 = np.ravel(z3)\n",
" neighbor = np.vstack((z0,z1,z2,z3)).T\n",
" # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\n",
" # flatten the image to a vector\n",
" image = np.ravel(image[1:-1,1:-1])\n",
" return image, predict, diff\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "8e3ef654",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"120\n",
"8\n"
]
}
],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\n",
"print(len(images))\n",
"print(len(num_images))\n",
"error_mean = []\n",
"error_mean1 = []\n",
"diff_mean = []\n",
"times = []\n",
"times1 = []\n",
"all_error = []\n",
"for i in range(len(num_images)):\n",
" \"\"\"start1 = time()\n",
" image_1, predict_1, difference_1, x_s_1 = plot_hist(num_images, i, \"second\")\n",
" stop1 = time()\n",
" times1.append(stop1-start1)\n",
" error1 = np.abs(image_1-predict_1)\n",
" error_mean1.append(np.mean(np.ravel(error1)))\"\"\"\n",
" start = time()\n",
" image, predict, difference = plot_hist(num_images, i)\n",
" stop = time()\n",
" times.append(stop-start)\n",
" error = np.abs(image-predict)\n",
" all_error.append(np.ravel(error))\n",
" error_mean.append(np.mean(np.ravel(error)))\n",
" diff_mean.append(np.mean(np.ravel(difference)))"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "fa65dcd6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Average Error First and Second Added: 20.017415790767718\n",
"Standard Deviaiton of Mean Errors: 0.1611803882535028\n",
"Average Difference: 53.678648426455226\n",
"Average Time per Image for First: 0.07302114367485046\n"
]
}
],
"source": [
"print(f\"Average Error First and Second Added: {np.mean(error_mean)}\")\n",
"print(f\"Standard Deviaiton of Mean Errors: {np.sqrt(np.var(error_mean))}\")\n",
"print(f\"Average Difference: {np.mean(diff_mean)}\")\n",
"print(f\"Average Time per Image for First: {np.mean(times)}\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "b7e88aab",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([3.8620e+03, 2.0014e+04, 4.1788e+04, 4.4365e+04, 4.6890e+04,\n",
" 3.4932e+04, 3.0758e+04, 2.1131e+04, 1.8305e+04, 1.2642e+04,\n",
" 1.0859e+04, 7.4890e+03, 5.9740e+03, 5.3350e+03, 3.8500e+03,\n",
" 3.3960e+03, 2.3890e+03, 2.2130e+03, 1.5640e+03, 1.3960e+03,\n",
" 1.0520e+03, 9.5300e+02, 7.2300e+02, 6.6400e+02, 4.8700e+02,\n",
" 3.8800e+02, 3.5700e+02, 3.1300e+02, 2.5000e+02, 2.0000e+02,\n",
" 1.6800e+02, 1.2700e+02, 1.3000e+02, 6.9000e+01, 8.0000e+01,\n",
" 6.1000e+01, 6.2000e+01, 3.6000e+01, 2.4000e+01, 2.0000e+01,\n",
" 1.3000e+01, 1.3000e+01, 1.4000e+01, 1.0000e+01, 4.0000e+00,\n",
" 3.0000e+00, 3.0000e+00, 2.0000e+00, 0.0000e+00, 2.0000e+00]),\n",
" array([ 0. , 8.46, 16.92, 25.38, 33.84, 42.3 , 50.76, 59.22,\n",
" 67.68, 76.14, 84.6 , 93.06, 101.52, 109.98, 118.44, 126.9 ,\n",
" 135.36, 143.82, 152.28, 160.74, 169.2 , 177.66, 186.12, 194.58,\n",
" 203.04, 211.5 , 219.96, 228.42, 236.88, 245.34, 253.8 , 262.26,\n",
" 270.72, 279.18, 287.64, 296.1 , 304.56, 313.02, 321.48, 329.94,\n",
" 338.4 , 346.86, 355.32, 363.78, 372.24, 380.7 , 389.16, 397.62,\n",
" 406.08, 414.54, 423. ]),\n",
" <BarContainer object of 50 artists>)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.hist(difference,bins=50)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "aaf16d98",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.collections.PathCollection at 0x7fcf7a43fb80>"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"error = np.abs(image-predict)\n",
"plt.scatter(error,np.sqrt(difference),alpha =0.2)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "3b78c8d4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"numpy.ndarray"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(error)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2a081505",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment