Commit 174904aa authored by Nathaniel Callens's avatar Nathaniel Callens

deletions

parent 3ee02b10
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "8868bc30",
"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,linprog\n",
"import time\n",
"import seaborn as sns\n",
"from sklearn.neighbors import KernelDensity\n",
"import pandas as pd\n",
"from collections import Counter\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "76317b02",
"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:-6] == num:\n",
" tiff.append(im)\n",
" return tiff"
]
},
{
"cell_type": "code",
"execution_count": 62,
"id": "be1ff8a1",
"metadata": {},
"outputs": [],
"source": [
"def plot_hist(tiff_list):\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",
" image = tiff_list\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",
" \n",
" # flatten the image to a vector\n",
" image = np.ravel(image[1:-1,1:-1])\n",
" error = image-predict\n",
" \n",
" return image, predict, diff, error, A"
]
},
{
"cell_type": "code",
"execution_count": 63,
"id": "8483903e",
"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": 86,
"id": "64a3a193",
"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):\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]\n",
" y = np.vstack((-z0+z2-z3, z0+z1+z2, -z0-z1-z2-z3))\n",
"\n",
" '''if r == 345 and c == 421:\n",
" print(new_e[r][c])\n",
" print(np.linalg.solve(A,y)[-1])\n",
" print(new_e[r][c] + np.linalg.solve(A,y)[-1])\n",
" print(np.ceil(new_e[r][c]) + np.floor(np.linalg.solve(A,y)[-1]))\n",
" \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",
" \n",
" #Real solution that works, DO NOT DELETE\n",
" print(new_e[r][c]+ np.floor(np.linalg.solve(A,y)[-1]))\n",
" new_e[r][c] = new_e[r][c] + np.floor(np.linalg.solve(A,y)[-1])\n",
" print(new_e[r][c])\n",
" #new_e[r][c] = np.ceil(new_e[r][c]) + np.floor(np.linalg.solve(A,y)[-1])\n",
" \n",
" return new_e"
]
},
{
"cell_type": "code",
"execution_count": 132,
"id": "91879f19",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"257\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAYMAAAD4CAYAAAAO9oqkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAQCklEQVR4nO3df6zdd13H8efLwQjhR9bRS23azg6txkHi2JqtiWhQtOu2mI6oZPxhG1yoCVsCiSYW90cJk2SYgLERZ4Y0dAaZi4BrYFhKgxL/6OgdlHY/GL2MLmvTtYXODYMZTt/+cT53+VrO6b29v865vc9HcnK+5/39nu95n2+/97z6/XG+J1WFJGlp+5lhNyBJGj7DQJJkGEiSDANJEoaBJAl4xbAbmKnly5fX2rVrh92GJC0qjzzyyA+qauzc+qINg7Vr1zI+Pj7sNiRpUUnydL+6u4kkSYaBJMkwkCRhGEiSMAwkSRgGkiQMA0kShoEkCcNAksQi/gayNBfWbv/Sy8PH7r55iJ1Iw+WWgSTJMJAkGQaSJAwDSRKGgSQJzyaS+vIsIy01bhlIkgwDSZJhIEnCMJAkYRhIkjAMJEkYBpIkDANJEoaBJAnDQJKEYSBJwmsTaYnwWkPS+bllIEkyDCRJhoEkCcNAksQ0wiDJmiRfS/J4kseSvL/VL0+yL8nRdr+s1ZNkZ5KJJIeTXNOZ19Y2/dEkWzv1a5Mcac/ZmSTz8WYlSf1NZ8vgJeCPq+oqYANwe5KrgO3A/qpaB+xvjwFuBNa12zbgHuiFB7ADuB64DtgxGSBtmvd2nrdp9m9NkjRdU4ZBVZ2sqm+24R8BTwCrgM3A7jbZbuCWNrwZuK96DgCXJVkJ3ADsq6qzVfUcsA/Y1Ma9vqoOVFUB93XmJUlaABd0zCDJWuCtwMPAiqo62UY9C6xow6uAZzpPO95q56sf71Pv9/rbkownGT9z5syFtC5JOo9ph0GS1wKfAz5QVS90x7X/0dcc9/ZTqureqlpfVevHxsbm++UkacmYVhgkeSW9IPhMVX2+lU+1XTy0+9OtfgJY03n66lY7X311n7okaYFM52yiAJ8Cnqiqj3dG7QEmzwjaCjzYqW9pZxVtAJ5vu5P2AhuTLGsHjjcCe9u4F5JsaK+1pTMvSdICmM61iX4V+APgSJJDrfZnwN3AA0luA54G3tXGPQTcBEwAPwbeA1BVZ5PcBRxs0324qs624fcBnwZeDXy53SRJC2TKMKiqfwcGnff/jj7TF3D7gHntAnb1qY8Db5mqF2nYvOCdLlZ+A1mSZBhIkgwDSRKGgSQJw0CShGEgScIwkCRhGEiSMAwkSRgGkiQMA0kShoEkCcNAkoRhIEnCMJAkMb0ft5EWDX9vQJoZtwwkSYaBJMkwkCRhGEiS8ACylqDuQWZJPYaB1BgSWsrcTSRJMgwkSYaBJAnDQJKEYSBJwjCQJGEYSJIwDCRJ+KUzaUp+GU1LgVsGkiTDQJJkGEiSMAwkSXgAWZoT/vayFrsptwyS7EpyOsmjndqHkpxIcqjdbuqM+2CSiSRPJrmhU9/UahNJtnfqVyZ5uNX/Mcmlc/kGJUlTm85uok8Dm/rU/7Kqrm63hwCSXAXcCry5PedvklyS5BLgE8CNwFXAu9u0AB9t8/oF4Dngttm8IUnShZsyDKrq68DZac5vM3B/Vb1YVd8HJoDr2m2iqp6qqp8A9wObkwT4TeCf2vN3A7dc2FuQJM3WbA4g35HkcNuNtKzVVgHPdKY53mqD6m8A/qOqXjqn3leSbUnGk4yfOXNmFq1LkrpmGgb3AD8PXA2cBD42Vw2dT1XdW1Xrq2r92NjYQrykJC0JMzqbqKpOTQ4n+STwxfbwBLCmM+nqVmNA/YfAZUle0bYOutNLkhbIjLYMkqzsPHwnMHmm0R7g1iSvSnIlsA74BnAQWNfOHLqU3kHmPVVVwNeA32vP3wo8OJOeJEkzN+WWQZLPAm8Hlic5DuwA3p7kaqCAY8AfAVTVY0keAB4HXgJur6r/afO5A9gLXALsqqrH2kv8KXB/kj8HvgV8aq7enCRpeqYMg6p6d5/ywA/sqvoI8JE+9YeAh/rUn6J3tpEkaUj8BrIuWl56Wpo+r00kSTIMJEmGgSQJw0CShGEgScIwkCRhGEiSMAwkSfilMy1S/sykNLcMA2mG/IazLibuJpIkuWUgzTV3YWkxcstAkmQYSJIMA0kShoEkCcNAkoRhIEnCMJAkYRhIkjAMJEkYBpIkvByFLgJeME6aPbcMJEmGgSTJMJAkYRhIkjAMJEkYBpIkDANJEoaBJAnDQJKEYSBJwjCQJGEYSJKYRhgk2ZXkdJJHO7XLk+xLcrTdL2v1JNmZZCLJ4STXdJ6ztU1/NMnWTv3aJEfac3YmyVy/SUnS+U1ny+DTwKZzatuB/VW1DtjfHgPcCKxrt23APdALD2AHcD1wHbBjMkDaNO/tPO/c15IkzbMpw6Cqvg6cPae8GdjdhncDt3Tq91XPAeCyJCuBG4B9VXW2qp4D9gGb2rjXV9WBqirgvs68JEkLZKbHDFZU1ck2/Cywog2vAp7pTHe81c5XP96n3leSbUnGk4yfOXNmhq1Lks416wPI7X/0NQe9TOe17q2q9VW1fmxsbCFeUpKWhJmGwam2i4d2f7rVTwBrOtOtbrXz1Vf3qUuSFtBMw2APMHlG0FbgwU59SzuraAPwfNudtBfYmGRZO3C8Edjbxr2QZEM7i2hLZ16SpAUy5W8gJ/ks8HZgeZLj9M4Kuht4IMltwNPAu9rkDwE3ARPAj4H3AFTV2SR3AQfbdB+uqsmD0u+jd8bSq4Evt5skaQFNGQZV9e4Bo97RZ9oCbh8wn13Arj71ceAtU/UhSZo/U4aBNCxrt3/p5eFjd988xE6ki5+Xo5AkuWUgLRS3dDTK3DKQJBkGkiTDQJKEYSBJwjCQJGEYSJLw1FItEt3TMiXNPcNAmkeGmBYLdxNJkgwDSZJhIEnCMJAkYRhIkjAMJEkYBpIkDANJEoaBJAnDQJKEYSBJwjCQJGEYSJIwDCRJGAaSJAwDSRKGgSQJw0CShD97qRHQ/WnIY3ffPMROpKXLLQNJkmEgSXI3kTR07ibTKDAMNFK6H4ySFo67iSRJbhlIw+AWkEbNrLYMkhxLciTJoSTjrXZ5kn1Jjrb7Za2eJDuTTCQ5nOSazny2tumPJtk6u7ckSbpQc7Gb6Deq6uqqWt8ebwf2V9U6YH97DHAjsK7dtgH3QC88gB3A9cB1wI7JAJEkLYz5OGawGdjdhncDt3Tq91XPAeCyJCuBG4B9VXW2qp4D9gGb5qEvSdIAsw2DAr6S5JEk21ptRVWdbMPPAiva8Crgmc5zj7faoLokaYHM9gDy26rqRJI3AvuSfKc7sqoqSc3yNV7WAmcbwBVXXDFXs5WkJW9WWwZVdaLdnwa+QG+f/6m2+4d2f7pNfgJY03n66lYbVO/3evdW1fqqWj82Njab1iVJHTMOgySvSfK6yWFgI/AosAeYPCNoK/BgG94DbGlnFW0Anm+7k/YCG5MsaweON7aaJGmBzGY30QrgC0km5/MPVfUvSQ4CDyS5DXgaeFeb/iHgJmAC+DHwHoCqOpvkLuBgm+7DVXV2Fn1Jki7QjMOgqp4CfqVP/YfAO/rUC7h9wLx2Abtm2oskaXa8HIUkyTCQJBkGkiQMA0kShoEkCcNAkoS/Z6AF5M87SqPLMNBQ+OMu0mgxDKQRMigk3ZLSfPOYgSTJMJAkGQaSJAwDSRKGgSQJw0CShGEgScIwkCRhGEiSMAwkSRgGkiS8NpHmgVcnnV8uX80Hw0DzyquTSouDYSAtAoaq5pvHDCRJhoEkyTCQJGEYSJIwDCRJGAaSJDy1VLPg6Y7Dd75/A7+QpgvhloEkyTCQJBkGkiQMA0kSHkDWNHigePHzSqeaimEgXaQMcV0IdxNJkkZnyyDJJuCvgEuAv6uqu4fc0pLj/ySXhkH/zu4+WtpGIgySXAJ8Avht4DhwMMmeqnp8uJ1dnPzQVz+GxNI2EmEAXAdMVNVTAEnuBzYDhsE0+OGu+XSh65fhsTiNShisAp7pPD4OXH/uREm2Advaw/9M8uQcvPZy4AdzMJ+Fspj6tdf5M7L95qM/VRrZXgdYTP3OpNef61cclTCYlqq6F7h3LueZZLyq1s/lPOfTYurXXufPYup3MfUKi6vfuex1VM4mOgGs6Txe3WqSpAUwKmFwEFiX5MoklwK3AnuG3JMkLRkjsZuoql5Kcgewl96ppbuq6rEFevk53e20ABZTv/Y6fxZTv4upV1hc/c5Zr6mquZqXJGmRGpXdRJKkITIMJElLKwyS/H6Sx5L8b5L1nfraJP+V5FC7/W1n3LVJjiSZSLIzSYbZaxv3wdbPk0lu6NQ3tdpEku0L0Wc/ST6U5ERned7UGde392EaleU2SJJjbR08lGS81S5Psi/J0Xa/bIj97UpyOsmjnVrf/tKzsy3rw0muGYFeR3J9TbImydeSPN4+C97f6vOzbKtqydyAXwZ+CfhXYH2nvhZ4dMBzvgFsAAJ8GbhxyL1eBXwbeBVwJfA9egfdL2nDbwIubdNcNaTl/CHgT/rU+/Y+5HViZJbbeXo8Biw/p/YXwPY2vB346BD7+3Xgmu7f0KD+gJva31Ha39XDI9DrSK6vwErgmjb8OuC7rad5WbZLasugqp6oqml/aznJSuD1VXWgekv7PuCW+eqv6zy9bgbur6oXq+r7wAS9y3m8fEmPqvoJMHlJj1EyqPdhWgzLrZ/NwO42vJsFWi/7qaqvA2fPKQ/qbzNwX/UcAC5rf2cLYkCvgwx1fa2qk1X1zTb8I+AJeldrmJdlu6TCYApXJvlWkn9L8muttorepTEmHW+1Yep36Y5V56kPyx1tU3VXZxfGqPUIo9nTuQr4SpJH2iVZAFZU1ck2/CywYjitDTSov1Fd3iO9viZZC7wVeJh5WrYj8T2DuZTkq8DP9hl1Z1U9OOBpJ4ErquqHSa4F/jnJm+etyWaGvY6E8/UO3APcRe9D7C7gY8AfLlx3F523VdWJJG8E9iX5TndkVVWSkT1HfNT7Y8TX1ySvBT4HfKCqXugetpzLZXvRhUFV/dYMnvMi8GIbfiTJ94BfpHdJjNWdSef0Mhkz6ZXzX7pjwS7pMd3ek3wS+GJ7OIqXHRnFnv6fqjrR7k8n+QK9XRWnkqysqpNtV8DpoTb50wb1N3LLu6pOTQ6P2vqa5JX0guAzVfX5Vp6XZetuIiDJWHq/qUCSNwHrgKfaptgLSTa0s4i2AMP+H/se4NYkr0pyJb1ev8EIXdLjnP2U7wQmz9wY1Pswjcxy6yfJa5K8bnIY2Ehvee4BtrbJtjL89fJcg/rbA2xpZ75sAJ7v7PIYilFdX9tnzqeAJ6rq451R87NsF+rI+Cjc6P1DH6e3FXAK2Nvqvws8BhwCvgn8Tuc56+mtHN8D/pr2re1h9drG3dn6eZLO2U30zib4bht35xCX898DR4DDbQVdOVXvQ14vRmK5DejtTfTOaPl2W0fvbPU3APuBo8BXgcuH2ONn6e1q/e+2zt42qD96Z7p8oi3rI3TOlBtiryO5vgJvo7fr6nD7bDrU1tV5WbZejkKS5G4iSZJhIEnCMJAkYRhIkjAMJEkYBpIkDANJEvB/DrQFsWZUkGEAAAAASUVORK5CYII=\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"-154.0\n",
"197.0\n"
]
}
],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"origin, predict, diff, error, A = plot_hist(images[0])\n",
"image = Image.open(images[0]) #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",
"print(len(set(list(error))))\n",
"plt.hist(error,100)\n",
"plt.show()\n",
"print(min(error))\n",
"print(max(error))"
]
},
{
"cell_type": "code",
"execution_count": 145,
"id": "207b0bd2",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"458\n",
"{'61': '000000000', '87': '000000001000', '140': '000000001001000', '142': '000000001001001', '250': '000000001001010', '179': '000000001001011', '151': '000000001001100', '207': '0000000010011010', '141': '0000000010011011', '101': '00000000100111', '77': '00000000101', '69': '0000000011', '53': '00000001', '44': '0000001', '33': '000001', '20': '00001', '19': '00010', '18': '00011', '43': '0010000', '75': '00100010000', '84': '001000100010', '104': '00100010001100', '122': '001000100011010', '120': '001000100011011', '94': '0010001000111', '83': '001000100100', '153': '001000100101000', '130': '001000100101001', '143': '001000100101010', '127': '001000100101011', '93': '0010001001011', '115': '0010001001100000', '375': '0010001001100001', '366': '0010001001100010', '373': '0010001001100011', '377': '0010001001100100', '314': '0010001001100101', '402': '0010001001100110', '367': '0010001001100111', '133': '0010001001101000', '210': '0010001001101001', '334': '0010001001101010', '298': '0010001001101011', '176': '0010001001101100', '332': '0010001001101101', '335': '0010001001101110', '362': '0010001001101111', '371': '0010001001110000', '333': '0010001001110001', '251': '0010001001110010', '226': '0010001001110011', '247': '0010001001110100', '315': '0010001001110101', '304': '0010001001110110', '258': '0010001001110111', '306': '0010001001111000', '261': '0010001001111001', '289': '0010001001111010', '372': '0010001001111011', '239': '0010001001111100', '252': '0010001001111101', '224': '0010001001111110', '205': '0010001001111111', '60': '001000101', '52': '00100011', '32': '001001', '17': '00101', '51': '00110000', '139': '001100010000000', '149': '001100010000001', '132': '001100010000010', '154': '001100010000011', '163': '001100010000100', '162': '001100010000101', '281': '001100010000110', '346': '001100010000111', '384': '00110001000100000', '331': '00110001000100001', '383': '00110001000100010', '155': '00110001000100011', '354': '00110001000100100', '456': '00110001000100101', '229': '00110001000100110', '388': '00110001000100111', '294': '00110001000101000', '413': '00110001000101001', '211': '00110001000101010', '292': '00110001000101011', '376': '00110001000101100', '382': '00110001000101101', '387': '00110001000101110', '309': '00110001000101111', '158': '001100010001100', '159': '001100010001101', '313': '00110001000111000', '126': '00110001000111001', '327': '00110001000111010', '319': '00110001000111011', '302': '00110001000111100', '330': '00110001000111101', '385': '00110001000111110', '573': '00110001000111111', '76': '00110001001', '214': '0011000101000000', '259': '0011000101000001', '243': '0011000101000010', '255': '0011000101000011', '410': '0011000101000100', '399': '0011000101000101', '134': '0011000101000110', '270': '0011000101000111', '216': '0011000101001000', '236': '0011000101001001', '213': '0011000101001010', '196': '0011000101001011', '290': '0011000101001100', '231': '0011000101001101', '128': '0011000101001110', '193': '0011000101001111', '169': '0011000101010000', '178': '0011000101010001', '328': '0011000101010010', '160': '0011000101010011', '394': '0011000101010100', '336': '0011000101010101', '204': '0011000101010110', '227': '0011000101010111', '200': '0011000101011000', '212': '0011000101011001', '352': '0011000101011010', '147': '0011000101011011', '342': '0011000101011100', '308': '0011000101011101', '329': '0011000101011110', '379': '0011000101011111', '221': '00110001011000000', '267': '00110001011000001', '269': '001100010110000100', '177': '001100010110000101', '220': '001100010110000110', '202': '001100010110000111', '225': '00110001011000100', '185': '00110001011000101', '170': '00110001011000110', '198': '00110001011000111', '429': '001100010110010000', '206': '001100010110010001', '426': '001100010110010010', '438': '001100010110010011', '403': '001100010110010100', '424': '001100010110010101', '299': '001100010110010110', '325': '001100010110010111', '237': '001100010110011000', '152': '001100010110011001', '145': '001100010110011010', '230': '001100010110011011', '411': '001100010110011100', '286': '001100010110011101', '374': '001100010110011110', '469': '001100010110011111', '293': '00110001011010000', '406': '00110001011010001', '407': '00110001011010010', '421': '00110001011010011', '301': '00110001011010100', '275': '00110001011010101', '423': '00110001011010110', '395': '00110001011010111', '244': '00110001011011000', '337': '00110001011011001', '300': '00110001011011010', '233': '00110001011011011', '322': '00110001011011100', '400': '00110001011011101', '253': '00110001011011110', '361': '00110001011011111', '297': '001100010111000000', '390': '001100010111000001', '444': '001100010111000010', '242': '001100010111000011', '606': '001100010111000100', '498': '001100010111000101', '397': '001100010111000110', '532': '001100010111000111', '209': '001100010111001000', '283': '001100010111001001', '430': '001100010111001010', '351': '001100010111001011', '539': '001100010111001100', '530': '001100010111001101', '256': '001100010111001110', '491': '001100010111001111', '511': '001100010111010000', '570': '001100010111010001', '559': '001100010111010010', '478': '001100010111010011', '359': '001100010111010100', '22554': '001100010111010101', '512': '001100010111010110', '503': '001100010111010111', '474': '001100010111011000', '489': '001100010111011001', '404': '001100010111011010', '380': '001100010111011011', '519': '001100010111011100', '568': '001100010111011101', '515': '001100010111011110', '543': '001100010111011111', '439': '001100010111100000', '418': '001100010111100001', '419': '001100010111100010', '425': '001100010111100011', '454': '001100010111100100', '228': '001100010111100101', '447': '001100010111100110', '452': '001100010111100111', '414': '001100010111101000', '435': '001100010111101001', '416': '001100010111101010', '345': '001100010111101011', '401': '001100010111101100', '440': '001100010111101101', '409': '001100010111101110', '350': '001100010111101111', '494': '001100010111110000', '482': '001100010111110001', '502': '001100010111110010', '393': '001100010111110011', '422': '001100010111110100', '370': '001100010111110101', '461': '001100010111110110', '369': '001100010111110111', '398': '001100010111111000', '445': '001100010111111001', '203': '001100010111111010', '249': '001100010111111011', '405': '001100010111111100', '486': '001100010111111101', '467': '001100010111111110', '470': '001100010111111111', '68': '0011000110', '74': '00110001110', '91': '0011000111100', '114': '001100011110100', '307': '001100011110101', '199': '001100011110110', '110': '001100011110111', '89': '0011000111110', '109': '00110001111110', '105': '001100011111110', '150': '0011000111111110', '129': '0011000111111111', '42': '0011001', '31': '001101', '16': '00111', '15': '01000', '67': '0100100000', '66': '0100100001', '59': '010010001', '50': '01001001', '41': '0100101', '30': '010011', '14': '01010', '13': '01011', '12': '01100', '29': '011010', '49': '01101100', '73': '01101101000', '82': '011011010010', '88': '0110110100110', '90': '0110110100111', '264': '0110110101000000', '272': '0110110101000001', '181': '0110110101000010', '218': '0110110101000011', '368': '0110110101000100', '347': '0110110101000101', '186': '0110110101000110', '248': '0110110101000111', '365': '0110110101001000', '187': '0110110101001001', '165': '0110110101001010', '164': '0110110101001011', '305': '0110110101001100', '161': '0110110101001101', '271': '0110110101001110', '340': '0110110101001111', '386': '0110110101010000', '280': '0110110101010001', '112': '0110110101010010', '137': '0110110101010011', '100': '01101101010101', '326': '0110110101011000', '277': '0110110101011001', '288': '0110110101011010', '316': '0110110101011011', '148': '0110110101011100', '287': '0110110101011101', '131': '0110110101011110', '183': '0110110101011111', '81': '011011010110', '188': '011011010111000', '125': '011011010111001', '171': '0110110101110100', '166': '0110110101110101', '167': '011011010111011', '116': '011011010111100', '174': '011011010111101', '108': '011011010111110', '107': '011011010111111', '58': '011011011', '40': '0110111', '11': '01110', '10': '01111', '28': '100000', '39': '1000010', '57': '100001100', '65': '1000011010', '72': '10000110110', '70': '10000110111', '48': '10000111', '9': '10001', '7': '10010', '8': '10011', '27': '101000', '38': '1010010', '47': '10100110', '63': '1010011100', '71': '10100111010', '79': '101001110110', '97': '10100111011100', '103': '10100111011101', '96': '10100111011110', '138': '10100111011111000', '146': '10100111011111001', '282': '10100111011111010', '222': '10100111011111011', '118': '101001110111111', '56': '101001111', '6': '10101', '5': '10110', '0': '101110', '26': '101111', '3': '11000', '2': '11001', '1': '11010', '4': '11011', '25': '111000', '37': '1110010', '64': '1110011000', '119': '11100110010000000', '349': '11100110010000001', '364': '11100110010000010', '392': '11100110010000011', '358': '11100110010000100', '378': '11100110010000101', '197': '11100110010000110', '279': '11100110010000111', '323': '11100110010001000', '318': '11100110010001001', '360': '11100110010001010', '436': '11100110010001011', '217': '11100110010001100', '124': '11100110010001101', '311': '11100110010001110', '324': '11100110010001111', '274': '11100110010010000', '278': '11100110010010001', '310': '11100110010010010', '296': '11100110010010011', '353': '11100110010010100', '357': '11100110010010101', '262': '11100110010010110', '223': '11100110010010111', '303': '11100110010011000', '284': '11100110010011001', '396': '11100110010011010', '338': '11100110010011011', '135': '11100110010011100', '355': '11100110010011101', '234': '11100110010011110', '441': '11100110010011111', '195': '1110011001010000', '320': '1110011001010001', '257': '11100110010100100', '215': '11100110010100101', '254': '11100110010100110', '263': '11100110010100111', '157': '1110011001010100', '285': '1110011001010101', '172': '1110011001010110', '192': '1110011001010111', '381': '11100110010110000', '389': '11100110010110001', '321': '11100110010110010', '189': '11100110010110011', '415': '11100110010110100', '190': '11100110010110101', '232': '11100110010110110', '245': '11100110010110111', '180': '11100110010111000', '235': '11100110010111001', '273': '11100110010111010', '317': '11100110010111011', '240': '11100110010111100', '219': '11100110010111101', '182': '11100110010111110', '246': '11100110010111111', '113': '1110011001100000', '276': '1110011001100001', '265': '1110011001100010', '175': '1110011001100011', '121': '1110011001100100', '123': '1110011001100101', '144': '1110011001100110', '156': '1110011001100111', '184': '1110011001101000', '344': '1110011001101001', '266': '1110011001101010', '173': '1110011001101011', '348': '1110011001101100', '268': '1110011001101101', '363': '1110011001101110', '312': '1110011001101111', '80': '111001100111', '55': '111001101', '46': '11100111', '24': '111010', '36': '1110110', '54': '111011100', '62': '1110111010', '92': '11101110110000', '98': '11101110110001', '86': '1110111011001', '95': '11101110110100', '99': '11101110110101', '106': '111011101101100', '117': '111011101101101', '136': '1110111011011100', '241': '1110111011011101', '102': '111011101101111', '85': '1110111011100', '201': '1110111011101000', '238': '1110111011101001', '191': '1110111011101010', '208': '1110111011101011', '343': '1110111011101100', '111': '1110111011101101', '168': '1110111011101110', '339': '1110111011101111', '78': '111011101111', '45': '11101111', '23': '111100', '35': '1111010', '34': '1111011', '22': '111110', '21': '111111'}\n"
]
}
],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"start = time.time()\n",
"origin, predict, diff, error, A = plot_hist(images[0])\n",
"image = Image.open(images[0]) #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",
"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",
"new_error = np.ravel(new_error)\n",
"plt.hist(new_error[1:],bins=100)\n",
"plt.show()\n",
"ab_error = np.abs(new_error)\n",
"string = [str(i) for i in ab_error]\n",
"#string = [str(i) for i in new_error]\n",
"#string = [str(i) for i in np.arange(0,5)] + [str(i) for i in np.arange(0,5)] + [str(i) for i in np.arange(0,2)]*2\n",
"freq = dict(Counter(string))\n",
"#print(freq)\n",
"freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\n",
"node = make_tree(freq)\n",
"encoding = huffman_code_tree(node)\n",
"#encoded = [\"1\"+encoding[str(-i)] if i < 0 else \"0\"+encoding[str(i)] for i in error]\n",
"#print(time.time()-start)\n",
"print(len(encoding))\n",
"print(encoding)"
]
},
{
"cell_type": "code",
"execution_count": 154,
"id": "14075c94",
"metadata": {},
"outputs": [],
"source": [
"def compress_rate(original, error, encoding):\n",
" original = original.reshape(-1)\n",
" error = error.reshape(-1)\n",
" o_len = 0\n",
" c_len = 0\n",
" for i in range(0, len(original)):\n",
" o_len += len(bin(original[i])[2:])\n",
" c_len += len(encoding[str(abs(error[i]))])\n",
" c_len += 1\n",
" \n",
" return c_len/o_len"
]
},
{
"cell_type": "code",
"execution_count": 155,
"id": "b93c068b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.4473590087890625"
]
},
"execution_count": 155,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"compress_rate(image,new_error,encoding)"
]
},
{
"cell_type": "code",
"execution_count": 140,
"id": "a8dc8674",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 140,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"int('0100',2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "992dd8bb",
"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
}
{
"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
}
......@@ -156,7 +156,7 @@
{
"cell_type": "code",
"execution_count": 16,
"id": "f62c1af6",
"id": "48abcf1e",
"metadata": {},
"outputs": [],
"source": [
......@@ -308,7 +308,7 @@
{
"cell_type": "code",
"execution_count": 35,
"id": "9e91c81d",
"id": "0afd3bef",
"metadata": {},
"outputs": [],
"source": [
......@@ -480,7 +480,7 @@
{
"cell_type": "code",
"execution_count": 38,
"id": "d342f424",
"id": "329cc11b",
"metadata": {},
"outputs": [
{
......@@ -596,7 +596,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "c0bb307b",
"id": "a2582804",
"metadata": {},
"outputs": [],
"source": [
......@@ -662,7 +662,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "671f7847",
"id": "487fc2f2",
"metadata": {},
"outputs": [],
"source": [
......@@ -693,7 +693,7 @@
{
"cell_type": "code",
"execution_count": 39,
"id": "eec0746a",
"id": "b4998aef",
"metadata": {},
"outputs": [
{
......@@ -720,7 +720,7 @@
}
],
"source": [
"def plot_hist_lstsq(tiff_list):\n",
"def predict_pix_lstsq(tiff_list):\n",
"\n",
" image = tiff_list\n",
" image = Image.open(image) #Open the image and read it as an Image object\n",
......@@ -775,7 +775,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "700f6e7f",
"id": "db376cb9",
"metadata": {},
"outputs": [],
"source": [
......@@ -798,7 +798,7 @@
{
"cell_type": "code",
"execution_count": 43,
"id": "0c297da9",
"id": "7575133b",
"metadata": {},
"outputs": [
{
......@@ -829,7 +829,7 @@
{
"cell_type": "code",
"execution_count": 44,
"id": "d7fc288d",
"id": "dcc26973",
"metadata": {},
"outputs": [
{
......@@ -842,9 +842,72 @@
}
],
"source": [
"fre = rel_freq(list(res))\n",
"print(np.array(fre)@np.array(entropy))\n",
"print(3.93012/15)"
"def predict_pix(tiff_image, difference = True):\n",
" \"\"\"\n",
" This function predict the pixel values excluding the boundary.\n",
" Using the 4 neighbor pixel values and MSE to predict the next pixel value\n",
" (-1,1) (0,1) (1,1) => relative position of the 4 other given values\n",
" (-1,0) (0,0) => (0,0) is the one we want to predict\n",
" take the derivative of mean square error to solve for the system of equation \n",
" A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]])\n",
" 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)\n",
" and the predicted pixel value is c.\n",
" \n",
" Input:\n",
" tiff_image (string): path to the tiff file\n",
" \n",
" Return:\n",
" image (512 X 640): original image \n",
" predict (325380,): predicted image excluding the boundary\n",
" diff. (325380,): IF difference = TRUE, difference between the min and max of four neighbors exclude the boundary\n",
" ELSE: the residuals of the four nearest pixels to a fitted hyperplane\n",
" error (325380,): difference between the original image and predicted image\n",
" A (3 X 3): system of equation\n",
" \"\"\"\n",
" image = Image.open(tiff_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",
" print(image.shape)\n",
" # use \n",
" A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) # the matrix for system of equation\n",
" # where z0 = (-1,1), z1 = (0,1), z2 = (1,1), z3 = (-1,0)\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",
" predict = np.round(np.round((np.linalg.solve(A,y)[-1]),1))\n",
" \n",
" #Matrix system of points that will be used to solve the least squares fitting hyperplane\n",
" points = np.array([[-1,-1,1], [-1,0,1], [-1,1,1], [0,-1,1]])\n",
" \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",
" \n",
" if difference:\n",
" # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\n",
" \n",
" else:\n",
" #Compute the best fitting hyperplane using least squares\n",
" #The res is the residuals of the four points used to fit the hyperplane (summed distance of each of the \n",
" #points to the hyperplane), it is a measure of gradient\n",
" f, diff, rank, s = la.lstsq(points, neighbor.T, rcond=None) \n",
" \n",
" # calculate the error\n",
" error = np.ravel(image[1:-1,1:-1])-predict\n",
" \n",
" return image, predict, diff, error, A\n"
]
}
],
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"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\n",
"from numpy import linalg as la\n",
"from scipy.stats import gaussian_kde, entropy\n",
"import seaborn as sns\n",
"import pywt\n",
"import math\n",
"#import cv2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"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": 32,
"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",
" 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.linalg.solve(A,y)[-1]\n",
" #predict = []\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",
" \n",
" \"\"\"for i in range(len(neighbor)):\n",
" if neighbor[i][0] >= max(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(min(neighbor[i][3], neighbor[i][1]))\n",
" elif neighbor[i][0] < min(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(max(neighbor[i][3], neighbor[i][1]))\n",
" else:\n",
" predict.append(neighbor[i][3] + neighbor[i][1] - neighbor[i][0])\"\"\"\n",
" \n",
" # flatten the image to a vector\n",
" image_ravel = np.ravel(image[1:-1,1:-1])\n",
" return image_ravel, predict, diff, image"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "8e3ef654",
"metadata": {},
"outputs": [],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_1\")\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, non_ravel = 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)))\n",
" \n",
"#image, predict, difference = plot_hist(images, 0)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "fa65dcd6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Average Error: 19.44221679267325\n",
"Standard Deviaiton of Mean Errors: 0.17734010606906342\n",
"Average Difference: 51.95430150900486\n",
"Average Time per Image for First: 0.050624340772628784\n"
]
}
],
"source": [
"print(f\"Average Error: {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": 6,
"id": "4c05b947",
"metadata": {},
"outputs": [],
"source": [
"new_image, new_pred, new_diff, no_ravel = plot_hist(images, 10)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "dda442ae",
"metadata": {},
"outputs": [
{
"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": [
"new_error = (new_image-new_pred).astype(np.int32)\n",
"plt.hist(new_error, bins=20, density=True)\n",
"sns.kdeplot(new_error)\n",
"plt.xlabel(\"error\")\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "58da6063",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0. , 0. , 0. , ..., 0. , 0. , 0. ],\n",
" [ 0. , 22327. , 22323. , ..., 22406.5, 22446. , 0. ],\n",
" [ 0. , 22350.5, 22335.5, ..., 22429. , 22390. , 0. ],\n",
" ...,\n",
" [ 0. , 22099. , 22125. , ..., 22823.5, 22817. , 0. ],\n",
" [ 0. , 22140. , 22172.5, ..., 22774. , 22771. , 0. ],\n",
" [ 0. , 0. , 0. , ..., 0. , 0. , 0. ]])"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prediction = new_pred.reshape((510,638))\n",
"prediction = np.pad(prediction, pad_width=1)"
]
}
],
"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.8.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"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": 44,
"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": 51,
"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.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": 49,
"id": "8e3ef654",
"metadata": {},
"outputs": [],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\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": 52,
"id": "fa65dcd6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Average Error First and Second Added: 20.017164930235474\n",
"Standard Deviaiton of Mean Errors: 0.16101183692475135\n",
"Average Difference: 53.678648426455226\n",
"Average Time per Image for First: 0.04535740613937378\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": null,
"id": "b7e88aab",
"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
}
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"id": "8868bc30",
"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,linprog\n",
"import time\n",
"import seaborn as sns\n",
"from sklearn.neighbors import KernelDensity\n",
"import pandas as pd\n",
"from collections import Counter\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "76317b02",
"metadata": {},
"outputs": [],
"source": [
"def file_extractor(dirname=\"images\"):\n",
" files = os.listdir(dirname)\n",
" scenes = []\n",
" for file in files:\n",
" if file == '.DS_Store':\n",
" continue\n",
" else:\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",
"\n",
"def image_extractor(scenes):\n",
" image_folder = []\n",
" for scene in scenes:\n",
" files = os.listdir(scene)\n",
" for file in files:\n",
" #if file[-4:] == \".jp4\" or file[-7:] == \"_6.tiff\":\n",
" if file[-5:] != \".tiff\" or file[-7:] == \"_6.tiff\":\n",
" print(file)\n",
" continue\n",
" else:\n",
" image_folder.append(os.path.join(scene, file))\n",
" return image_folder\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": 5,
"id": "be1ff8a1",
"metadata": {},
"outputs": [],
"source": [
"def plot_hist(tiff_list):\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",
" image = tiff_list\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",
" \n",
" # flatten the image to a vector\n",
" image = np.ravel(image[1:-1,1:-1])\n",
" error = image-predict\n",
" \n",
" return image, predict, diff, error, A"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "8483903e",
"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": "markdown",
"id": "c7104fbf",
"metadata": {},
"source": [
"### Huffman without dividing into bins"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "a43f3f1c",
"metadata": {},
"outputs": [],
"source": [
"def huffman_nb(image):\n",
" origin, predict, diff, error, A = plot_hist(image)\n",
" image = Image.open(image)\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",
" 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",
" new_error = np.ravel(new_error)\n",
" \n",
" \n",
" \n",
" #ab_error = np.abs(new_error)\n",
" #string = [str(i) for i in ab_error]\n",
" string = [str(i) for i in new_error.astype(int)]\n",
" freq = dict(Counter(string))\n",
" \n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\n",
" node = make_tree(freq)\n",
" encoding = huffman_code_tree(node)\n",
" #encoded = [\"1\"+encoding[str(-i)] if i < 0 else \"0\"+encoding[str(i)] for i in error]\n",
" \n",
" # return the huffman dictionary\n",
" return encoding, new_error, image.reshape(-1)\n",
" \n",
" \n",
"def compress_rate_nb(image, error, encoding):\n",
" original = image.reshape(-1)\n",
" error = error.reshape(-1)\n",
" o_len = 0\n",
" c_len = 0\n",
" for i in range(0, len(original)):\n",
" o_len += len(bin(original[i])[2:])\n",
" c_len += len(encoding[str(int(error[i]))])\n",
"\n",
" return c_len/o_len\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "eac2f456",
"metadata": {},
"source": [
"### Huffman with dividing into non-uniform bins"
]
},
{
"cell_type": "code",
"execution_count": 407,
"id": "207b0bd2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.44205322265625"
]
},
"execution_count": 407,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def huffman(image):\n",
" origin, predict, diff, error, A = plot_hist(image)\n",
" image = Image.open(image)\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",
" \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",
" \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",
" new_error = np.ravel(new_error)\n",
" \n",
" # return the huffman dictionary\n",
" return encode1, encode2, encode3, encode4, encode5, np.ravel(image), error, diff, boundary\n",
"\n",
"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] <= 25:\n",
" c_len += len(encode2[str(int(error[i]))])\n",
"\n",
" if diff[i] <= 40 and diff[i] > 25:\n",
" c_len += len(encode3[str(int(error[i]))])\n",
" \n",
" if diff[i] <= 70 and diff[i] > 40:\n",
" c_len += len(encode4[str(int(error[i]))])\n",
" \n",
" if diff[i] > 70:\n",
" c_len += len(encode5[str(int(error[i]))])\n",
" \n",
" return c_len/o_len\n",
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"encode1, encode2, encode3, encode4, encode5, image, error, diff, boundary = huffman(images[0])\n",
"compress_rate(image, error, diff, boundary, encode1, encode2, encode3, encode4, encode5)\n"
]
},
{
"cell_type": "markdown",
"id": "3a3f06a5",
"metadata": {},
"source": [
"### Huffman with dividing into uniform bins"
]
},
{
"cell_type": "code",
"execution_count": 415,
"id": "14075c94",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.4432273356119792"
]
},
"execution_count": 415,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def huffman_u(image):\n",
" origin, predict, diff, error, A = plot_hist(image)\n",
" image = Image.open(image)\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",
" bins = np.linspace(min(diff),max(diff),5)[1:-1]\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 <= bins[0]\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 > bins[0]\n",
" new_error = error[mask]\n",
" mask2 = diff[mask] <= bins[1]\n",
" string = [str(i) for i in new_error[mask2].astype(int)]\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",
" encode3 = huffman_code_tree(node)\n",
" \n",
"\n",
" mask = diff > bins[1]\n",
" new_error = error[mask]\n",
" mask2 = diff[mask] <= bins[2]\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 > bins[2]\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",
" \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",
" new_error = np.ravel(new_error)\n",
" \n",
" # return the huffman dictionary\n",
" #return encode1, encode2, encode3, encode4, encode5, np.ravel(image), error, diff, boundary\n",
" return [encode1, encode2, encode3, encode4, encode5], np.ravel(image), error, diff, boundary, bins\n",
"\n",
"#def compress_rate_u(image, error, diff, bound, encode1, encode2, encode3, encode4, encode5):\n",
"def compress_rate_u(image, error, diff, bound, list_dic, bins):\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(list_dic[0][str(bound[i])])\n",
" \n",
" for i in range(0, len(original)):\n",
" o_len += len(bin(original[i])[2:])\n",
" if diff[i] <= bins[0]:\n",
" c_len += len(list_dic[1][str(int(error[i]))])\n",
" \n",
" if diff[i] <= bins[1] and diff[i] > bins[0]:\n",
" c_len += len(list_dic[2][str(int(error[i]))])\n",
" \n",
" if diff[i] <= bins[2] and diff[i] > bins[1]:\n",
" c_len += len(list_dic[3][str(int(error[i]))])\n",
" \n",
" if diff[i] > bins[2]:\n",
" c_len += len(list_dic[4][str(int(error[i]))])\n",
" \n",
" return c_len/o_len\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f8b93cc5",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 417,
"id": "6abed5da",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Compression rate of huffman with different bins: 0.44946919759114584\n",
"Compression rate of huffman without bins: 0.4513634314749933\n",
"Compression rate of huffman with uniform bins: 0.44956921895345053\n"
]
}
],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\n",
"rate = []\n",
"rate_nb = []\n",
"rate_u = []\n",
"for i in range(len(num_images)):\n",
" encode1, encode2, encode3, encode4, encode5, image, error, diff, bound = huffman(num_images[i])\n",
" r = compress_rate(image, error, diff, bound, encode1, encode2, encode3, encode4, encode5)\n",
" rate.append(r)\n",
" encoding, error, image = huffman_nb(num_images[i])\n",
" r = compress_rate_nb(image, error, encoding)\n",
" rate_nb.append(r)\n",
" encode1, encode2, encode3, image, error, diff, bound = huffman_u(num_images[i])\n",
" r = compress_rate_u(image, error, diff, bound, encode1, encode2, encode3)\n",
" rate_u.append(r)\n",
" \n",
"print(f\"Compression rate of huffman with different bins: {np.mean(rate)}\")\n",
"print(f\"Compression rate of huffman without bins: {np.mean(rate_nb)}\")\n",
"print(f\"Compression rate of huffman with uniform bins: {np.mean(rate_u)}\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "15eecad3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.4427516682942708"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def huffman(image):\n",
" origin, predict, diff, error, A = plot_hist(image)\n",
" image = Image.open(image)\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 <= 10\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 > 10\n",
" new_error = error[mask]\n",
" mask2 = diff[mask] <= 25\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 > 25\n",
" new_error = error[mask]\n",
" mask2 = diff[mask] <= 45\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 > 45\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",
" \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",
" new_error = np.ravel(new_error)\n",
" \n",
" # return the huffman dictionary\n",
" return encode1, encode2, encode3, encode4, encode5, np.ravel(image), error, diff, boundary\n",
"\n",
"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",
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"encode1, encode2, encode3, encode4, encode5, image, error, diff, boundary = huffman(images[0])\n",
"compress_rate(image, error, diff, boundary, encode1, encode2, encode3, encode4, encode5)\n"
]
},
{
"cell_type": "code",
"execution_count": 428,
"id": "f8a8c717",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Compression rate of huffman with different bins: 0.4488415273030599\n"
]
}
],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\n",
"rate = []\n",
"\n",
"for i in range(len(num_images)):\n",
" encode1, encode2, encode3, encode4, encode5, image, error, diff, bound = huffman(num_images[i])\n",
" r = compress_rate(image, error, diff, bound, encode1, encode2, encode3, encode4, encode5)\n",
" rate.append(r)\n",
" \n",
" \n",
"print(f\"Compression rate of huffman with different bins: {np.mean(rate)}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 238,
"id": "992dd8bb",
"metadata": {},
"outputs": [],
"source": [
"origin, predict, diff, error, A = plot_hist(images[0])"
]
},
{
"cell_type": "code",
"execution_count": 418,
"id": "904ba7b1",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"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(error,bins=50)\n",
"plt.show()\n",
"mask = diff <= 20\n",
"plt.hist(error[mask],bins=50)\n",
"plt.show()\n",
"\n",
"mask = diff > 20\n",
"new_error = error[mask]\n",
"mask2 = diff[mask] <= 35\n",
"plt.hist(new_error[mask2],bins=50)\n",
"plt.show()\n",
"\n",
"mask = diff > 35\n",
"new_error = error[mask]\n",
"mask2 = diff[mask] <= 50\n",
"plt.hist(new_error[mask2],bins=50)\n",
"plt.show()\n",
"\n",
"mask = diff > 50\n",
"#new_error = error[mask]\n",
"#mask2 = diff[mask] <= 400\n",
"plt.hist(error[mask],bins=50)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 236,
"id": "2f5ef010",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(512, 640)\n"
]
}
],
"source": [
"image = Image.open(images[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",
"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",
"print(image.shape)"
]
},
{
"cell_type": "code",
"execution_count": 228,
"id": "4860903b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[22554 -2 -35 ... -16 40 19]\n"
]
}
],
"source": [
"print(boundary)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f145c221",
"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
}
......@@ -512,7 +512,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
"version": "3.8.11"
}
},
"nbformat": 4,
......
{
"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
}
......@@ -156,7 +156,7 @@
{
"cell_type": "code",
"execution_count": 16,
"id": "962f1139",
"id": "48abcf1e",
"metadata": {},
"outputs": [],
"source": [
......@@ -308,7 +308,7 @@
{
"cell_type": "code",
"execution_count": 35,
"id": "489f0def",
"id": "0afd3bef",
"metadata": {},
"outputs": [],
"source": [
......@@ -480,7 +480,7 @@
{
"cell_type": "code",
"execution_count": 38,
"id": "4fd1482b",
"id": "329cc11b",
"metadata": {},
"outputs": [
{
......@@ -596,7 +596,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "63ba5ba1",
"id": "a2582804",
"metadata": {},
"outputs": [],
"source": [
......@@ -662,7 +662,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "e5f6e2d4",
"id": "487fc2f2",
"metadata": {},
"outputs": [],
"source": [
......@@ -693,7 +693,7 @@
{
"cell_type": "code",
"execution_count": 39,
"id": "db1a1c1f",
"id": "b4998aef",
"metadata": {},
"outputs": [
{
......@@ -775,7 +775,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "926bac7c",
"id": "db376cb9",
"metadata": {},
"outputs": [],
"source": [
......@@ -798,7 +798,7 @@
{
"cell_type": "code",
"execution_count": 43,
"id": "aef3da82",
"id": "7575133b",
"metadata": {},
"outputs": [
{
......@@ -829,7 +829,7 @@
{
"cell_type": "code",
"execution_count": 44,
"id": "87e480ca",
"id": "dcc26973",
"metadata": {},
"outputs": [
{
......@@ -842,9 +842,72 @@
}
],
"source": [
"fre = rel_freq(list(res))\n",
"print(np.array(fre)@np.array(entropy))\n",
"print(3.93012/15)"
"def predict_pix(tiff_image, difference = True):\n",
" \"\"\"\n",
" This function predict the pixel values excluding the boundary.\n",
" Using the 4 neighbor pixel values and MSE to predict the next pixel value\n",
" (-1,1) (0,1) (1,1) => relative position of the 4 other given values\n",
" (-1,0) (0,0) => (0,0) is the one we want to predict\n",
" take the derivative of mean square error to solve for the system of equation \n",
" A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]])\n",
" 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)\n",
" and the predicted pixel value is c.\n",
" \n",
" Input:\n",
" tiff_image (string): path to the tiff file\n",
" \n",
" Return:\n",
" image (512 X 640): original image \n",
" predict (325380,): predicted image excluding the boundary\n",
" diff. (325380,): IF difference = TRUE, difference between the min and max of four neighbors exclude the boundary\n",
" ELSE: the residuals of the four nearest pixels to a fitted hyperplane\n",
" error (325380,): difference between the original image and predicted image\n",
" A (3 X 3): system of equation\n",
" \"\"\"\n",
" image = Image.open(tiff_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",
" print(image.shape)\n",
" # use \n",
" A = np.array([[3,0,-1],[0,3,3],[1,-3,-4]]) # the matrix for system of equation\n",
" # where z0 = (-1,1), z1 = (0,1), z2 = (1,1), z3 = (-1,0)\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",
" predict = np.round(np.round((np.linalg.solve(A,y)[-1]),1))\n",
" \n",
" #Matrix system of points that will be used to solve the least squares fitting hyperplane\n",
" points = np.array([[-1,-1,1], [-1,0,1], [-1,1,1], [0,-1,1]])\n",
" \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",
" \n",
" if difference:\n",
" # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\n",
" \n",
" else:\n",
" #Compute the best fitting hyperplane using least squares\n",
" #The res is the residuals of the four points used to fit the hyperplane (summed distance of each of the \n",
" #points to the hyperplane), it is a measure of gradient\n",
" f, diff, rank, s = la.lstsq(points, neighbor.T, rcond=None) \n",
" \n",
" # calculate the error\n",
" error = np.ravel(image[1:-1,1:-1])-predict\n",
" \n",
" return image, predict, diff, error, A\n"
]
}
],
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"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\n",
"from numpy import linalg as la\n",
"from scipy.stats import gaussian_kde, entropy\n",
"import seaborn as sns\n",
"import pywt\n",
"import math\n",
"#import cv2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"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": 32,
"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",
" 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.linalg.solve(A,y)[-1]\n",
" #predict = []\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",
" \n",
" \"\"\"for i in range(len(neighbor)):\n",
" if neighbor[i][0] >= max(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(min(neighbor[i][3], neighbor[i][1]))\n",
" elif neighbor[i][0] < min(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(max(neighbor[i][3], neighbor[i][1]))\n",
" else:\n",
" predict.append(neighbor[i][3] + neighbor[i][1] - neighbor[i][0])\"\"\"\n",
" \n",
" # flatten the image to a vector\n",
" image_ravel = np.ravel(image[1:-1,1:-1])\n",
" return image_ravel, predict, diff, image"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "8e3ef654",
"metadata": {},
"outputs": [],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_1\")\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, non_ravel = 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)))\n",
" \n",
"#image, predict, difference = plot_hist(images, 0)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "fa65dcd6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Average Error: 19.44221679267325\n",
"Standard Deviaiton of Mean Errors: 0.17734010606906342\n",
"Average Difference: 51.95430150900486\n",
"Average Time per Image for First: 0.050624340772628784\n"
]
}
],
"source": [
"print(f\"Average Error: {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": 6,
"id": "4c05b947",
"metadata": {},
"outputs": [],
"source": [
"new_image, new_pred, new_diff, no_ravel = plot_hist(images, 10)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "dda442ae",
"metadata": {},
"outputs": [
{
"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": [
"new_error = (new_image-new_pred).astype(np.int32)\n",
"plt.hist(new_error, bins=20, density=True)\n",
"sns.kdeplot(new_error)\n",
"plt.xlabel(\"error\")\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "58da6063",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0. , 0. , 0. , ..., 0. , 0. , 0. ],\n",
" [ 0. , 22327. , 22323. , ..., 22406.5, 22446. , 0. ],\n",
" [ 0. , 22350.5, 22335.5, ..., 22429. , 22390. , 0. ],\n",
" ...,\n",
" [ 0. , 22099. , 22125. , ..., 22823.5, 22817. , 0. ],\n",
" [ 0. , 22140. , 22172.5, ..., 22774. , 22771. , 0. ],\n",
" [ 0. , 0. , 0. , ..., 0. , 0. , 0. ]])"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prediction = new_pred.reshape((510,638))\n",
"prediction = np.pad(prediction, pad_width=1)"
]
}
],
"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
}
{
"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