Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
image-compression
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Elphel
image-compression
Commits
f9f43c1a
Commit
f9f43c1a
authored
Mar 17, 2022
by
Nathaniel Callens
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
updates-this needs to be updated with Kelly's changes as well
parent
2e28b2f4
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
314 additions
and
490 deletions
+314
-490
Error_to_Image-checkpoint.ipynb
.ipynb_checkpoints/Error_to_Image-checkpoint.ipynb
+157
-245
Error_to_Image.ipynb
Error_to_Image.ipynb
+157
-245
No files found.
.ipynb_checkpoints/Error_to_Image-checkpoint.ipynb
View file @
f9f43c1a
...
@@ -2,45 +2,12 @@
...
@@ -2,45 +2,12 @@
"cells": [
"cells": [
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1,
"execution_count": 1
34
,
"id": "dbef8759",
"id": "dbef8759",
"metadata": {
"metadata": {
"id": "dbef8759"
"id": "dbef8759"
},
},
"outputs": [
"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.058679431676864624\n"
]
},
{
"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": [
"Std Deviation of E: 26.627504708827136\n",
"Normal bits: 15\n",
"Encoded Bits: 6.677845333316752\n",
"(258, 322)\n"
]
}
],
"source": [
"source": [
"import numpy as np\n",
"import numpy as np\n",
"from prediction_MSE_Scout import file_extractor, image_extractor, im_distribution\n",
"from prediction_MSE_Scout import file_extractor, image_extractor, im_distribution\n",
...
@@ -54,24 +21,48 @@
...
@@ -54,24 +21,48 @@
"from numpy import linalg as la\n",
"from numpy import linalg as la\n",
"from scipy.stats import gaussian_kde\n",
"from scipy.stats import gaussian_kde\n",
"import seaborn as sns\n",
"import seaborn as sns\n",
"import pywt\n",
"from collections import Counter\n",
"from collections import Counter"
"import pandas as pd\n",
"import scipy as sp"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count":
2
,
"execution_count":
126
,
"id": "9ed20f84",
"id": "9ed20f84",
"metadata": {
"metadata": {
"id": "9ed20f84"
"id": "9ed20f84"
},
},
"outputs": [],
"outputs": [],
"source": [
"source": [
"def p
lot_his
t(tiff_list, i=0):\n",
"def p
redic
t(tiff_list, i=0):\n",
" \"\"\"\n",
" \"\"\"\n",
" This function is the leftovers from the first attempt to plot histograms.\n",
" This function predicts the pixel values based on a linear combination\n",
" As it stands it needs some work in order to function again. We will\n",
" of the MSE from the three pixels above it and the one to the left. It\n",
" fix this later. 1/25/22\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",
" \n",
" \n",
" image = tiff_list[i]\n",
" image = tiff_list[i]\n",
...
@@ -94,7 +85,7 @@
...
@@ -94,7 +85,7 @@
" \n",
" \n",
" # use numpy solver to solve the system of equations all at once\n",
" # use numpy solver to solve the system of equations all at once\n",
" #predict = np.linalg.solve(A,y)[-1]\n",
" #predict = np.linalg.solve(A,y)[-1]\n",
" predict = np.floor(np.linalg.solve(A,y)[-1]).astype(int)\n",
" predict
ion
= np.floor(np.linalg.solve(A,y)[-1]).astype(int)\n",
" #predict = []\n",
" #predict = []\n",
" \n",
" \n",
" # flatten the neighbor pixels and stack them together\n",
" # flatten the neighbor pixels and stack them together\n",
...
@@ -112,11 +103,7 @@
...
@@ -112,11 +103,7 @@
" small_image = image_int[1:-1,1:-1]\n",
" small_image = image_int[1:-1,1:-1]\n",
" \n",
" \n",
" #Reshape the predictions to be a 2D array\n",
" #Reshape the predictions to be a 2D array\n",
" predict = np.pad(predict.reshape(510,638), pad_width=1)\n",
" prediction = np.pad(prediction.reshape(510,638), pad_width=1)\n",
" \"\"\"predict[0,:] = image[0,:]\n",
" predict[:,0] = image[:,0]\n",
" predict[:,-1] = image[:,-1]\n",
" predict[-1,:] = image[-1,:]\"\"\"\n",
" \n",
" \n",
" \n",
" \n",
" #Calculate the error between the original image and our predictions\n",
" #Calculate the error between the original image and our predictions\n",
...
@@ -125,15 +112,15 @@
...
@@ -125,15 +112,15 @@
" #error = (image_int - predict).astype(int) #Experiment\n",
" #error = (image_int - predict).astype(int) #Experiment\n",
" \n",
" \n",
" #this one works\n",
" #this one works\n",
" error = image_int - predict\n",
" error = image_int - predict
ion
\n",
"\n",
"\n",
" \n",
" \n",
" return predict, diff, image_int, error, A"
" return predict
ion
, diff, image_int, error, A"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 3,
"execution_count":
5
3,
"id": "ba2881d9",
"id": "ba2881d9",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -145,17 +132,17 @@
...
@@ -145,17 +132,17 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 4,
"execution_count":
5
4,
"id": "11e95c34",
"id": "11e95c34",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": [
"source": [
"predict
, diff, im, err, A = plot_his
t(images, 2)"
"predict
ion, diff, im, err, A = predic
t(images, 2)"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 5,
"execution_count": 5
5
,
"id": "434e4d2f",
"id": "434e4d2f",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -176,20 +163,23 @@
...
@@ -176,20 +163,23 @@
" new_e = error.copy()\n",
" new_e = error.copy()\n",
" rows, columns = new_e.shape\n",
" rows, columns = new_e.shape\n",
"\n",
"\n",
" for r in range(1, rows-1):\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",
" 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",
" 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))\n",
" y = np.vstack((-z0+z2-z3, z0+z1+z2, -z0-z1-z2-z3)) #Create a vector of the linear combinations for the\n",
" \n",
" #solution to be solved\n",
" new_e[r][c] = np.round(new_e[r][c] + np.linalg.solve(A,y)[-1], 1)\n",
" \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",
" return new_e.astype(int)\n",
" "
" "
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 6,
"execution_count":
5
6,
"id": "3cc609dc",
"id": "3cc609dc",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -199,7 +189,7 @@
...
@@ -199,7 +189,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 7,
"execution_count":
5
7,
"id": "5d290a0c",
"id": "5d290a0c",
"metadata": {},
"metadata": {},
"outputs": [
"outputs": [
...
@@ -215,7 +205,7 @@
...
@@ -215,7 +205,7 @@
" [ True, True, True, ..., True, True, True]])"
" [ True, True, True, ..., True, True, True]])"
]
]
},
},
"execution_count": 7,
"execution_count":
5
7,
"metadata": {},
"metadata": {},
"output_type": "execute_result"
"output_type": "execute_result"
}
}
...
@@ -226,130 +216,7 @@
...
@@ -226,130 +216,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 8,
"execution_count": 60,
"id": "706f2816",
"metadata": {},
"outputs": [],
"source": [
"first = []\n",
"second = []\n",
"third = []\n",
"fourth = []\n",
"\n",
"for i in range(1,diff.shape[0]-1):\n",
" for j in range(1,diff.shape[1]-1):\n",
" if diff[i][j] <= 50:\n",
" first.append(np.abs(err[i][j]))\n",
" elif diff[i][j] > 50 and diff[i][j] <= 100:\n",
" second.append(np.abs(err[i][j]))\n",
" elif diff[i][j] > 100 and diff[i][j] <= 200:\n",
" third.append(np.abs(err[i][j]))\n",
" else:\n",
" fourth.append(np.abs(err[i][j]))\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "530d2cab",
"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": [
"142\n"
]
},
{
"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": [
"154\n"
]
},
{
"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": [
"217\n"
]
},
{
"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": [
"176\n"
]
}
],
"source": [
"\n",
"plt.hist(first)\n",
"plt.show()\n",
"print(np.max(first))\n",
"plt.hist(second)\n",
"plt.show()\n",
"print(np.max(second))\n",
"plt.hist(third)\n",
"plt.show()\n",
"print(np.max(third))\n",
"plt.hist(fourth)\n",
"plt.show()\n",
"print(np.max(fourth))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "bb11dcd0",
"id": "bb11dcd0",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -397,51 +264,68 @@
...
@@ -397,51 +264,68 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1
1
,
"execution_count": 1
27
,
"id": "c01fda28",
"id": "c01fda28",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": [
"source": [
"def enc_experiment(images, plot=True):\n",
"def encoder(images, i, plot=True):\n",
" origin, predict, diff, error, A = plot_hist(images, 2)\n",
" \"\"\"\n",
" image = Image.open(images[2]) #Open the image and read it as an Image object\n",
" Function that creates Huffman encodings out of the error values\n",
" image = np.array(image)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
" for a given image. The encodings are more efficient ways to store \n",
" image = image.astype(int)\n",
" large integer values that the original image contains.\n",
" new_error = np.copy(image)\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] = np.reshape(error[1:-1,1:-1],(510, 638))\n",
" new_error[1:-1, 1:-1] = error[1:-1, 1:-1]\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",
" keep = new_error[0,0]\n",
" #error matrix retreived from predicting\n",
" new_error[0,:] = new_error[0,:] - keep\n",
" keep = new_error[0,0] #The top left entry stays the same\n",
" new_error[-1,:] = new_error[-1,:] - keep\n",
" new_error[0,:] = new_error[0,:] - keep #All edge pixels are set to be the difference between themselves and\n",
" new_error[1:-1,0] = new_error[1:-1,0] - keep\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[1:-1,-1] = new_error[1:-1,-1] - keep\n",
" new_error[0,0] = keep\n",
" new_error[0,0] = keep\n",
" new_error = np.ravel(new_error)\n",
" \n",
" new_error = np.ravel(new_error) #Unravel it to plot it\n",
" if plot:\n",
" if plot:\n",
" plt.hist(new_error[1:],bins=100)\n",
" plt.hist(new_error[1:],bins=100)\n",
" plt.show()\n",
" plt.show()\n",
" \n",
" \n",
" #ab_error = np.abs(new_error)\n",
"\n",
" #string = [str(i) for i in ab_error]\n",
" string = [str(i) for i in new_error] #Create strings out of the integers in the new_error matrix\n",
" string = [str(i) for i in new_error]\n",
" \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)) #Initialize a dictionary that maps integers to the string values\n",
" freq = dict(Counter(string))\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) #Create a frequency mapping of how often the string\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\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",
" \n",
" node = make_tree(freq)\n",
" encoding_dict = huffman_code_tree(node)\n",
" #encoded = [\"1\"+encoding[str(-i)] if i < 0 else \"0\"+encoding[str(i)] for i in error]\n",
" #encoded = [\"1\"+encoding[str(-i)] if i < 0 else \"0\"+encoding[str(i)] for i in error]\n",
" #print(time.time()-start)\n",
" encoded = new_error.reshape((512,640)).copy().astype(str).astype(object)\n",
"\n",
"\n",
" for i in range(encoded.shape[0]):\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",
" for j in range(encoded.shape[1]):\n",
" if i == 0 and j == 0:\n",
" if i == 0 and j == 0:\n",
" encoded[i][j] = encoded[i][j]\n",
" encoded[i][j] = encoded[i][j]
#Replace each value in the dictionary with its encoding from the dictionary
\n",
" else:\n",
" else:\n",
" #print(encoding_dict[encoded[i][j]])\n",
" encoded[i][j] = encoding_dict[encoded[i][j]]\n",
" encoded[i][j] = encoding_dict[encoded[i][j]]\n",
" #print(encoded[i][j])\n",
" \n",
" \n",
" return encoding_dict, encoded, new_error.reshape((512,640)), image\n",
" return encoding_dict, encoded, new_error.reshape((512,640)), image\n",
" #print(encoding)"
" #print(encoding)"
...
@@ -449,38 +333,17 @@
...
@@ -449,38 +333,17 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count":
1
2,
"execution_count":
6
2,
"id": "ffa858e8",
"id": "ffa858e8",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": [
"source": [
"encode_dict, encoding, error, orig_image = enc
_experiment(images
, plot=False)"
"encode_dict, encoding, error, orig_image = enc
oder(images, 2
, plot=False)"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 13,
"execution_count": 121,
"id": "8dfdedc6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"error[1,6]"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "825cc48c",
"id": "825cc48c",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -490,8 +353,8 @@
...
@@ -490,8 +353,8 @@
" Function that accecpts the prediction matrix A for the linear system,\n",
" Function that accecpts the prediction matrix A for the linear system,\n",
" the encoded matrix of error values, and the encoding dicitonary.\n",
" the encoded matrix of error values, and the encoding dicitonary.\n",
" \"\"\"\n",
" \"\"\"\n",
" the_keys = list(encod
e
_dict.keys())\n",
" the_keys = list(encod
ing
_dict.keys())\n",
" the_values = list(encod
e
_dict.values())\n",
" the_values = list(encod
ing
_dict.values())\n",
" error_matrix = encoded_matrix.copy()\n",
" error_matrix = encoded_matrix.copy()\n",
" \n",
" \n",
" for i in range(error_matrix.shape[0]):\n",
" for i in range(error_matrix.shape[0]):\n",
...
@@ -513,7 +376,7 @@
...
@@ -513,7 +376,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1
5
,
"execution_count": 1
22
,
"id": "ba1d2c2c",
"id": "ba1d2c2c",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -523,7 +386,7 @@
...
@@ -523,7 +386,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1
6
,
"execution_count": 1
23
,
"id": "b2cdce6d",
"id": "b2cdce6d",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -534,11 +397,60 @@
...
@@ -534,11 +397,60 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count":
null
,
"execution_count":
124
,
"id": "a
42c21b1
",
"id": "a
686a66e
",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": []
"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": 137,
"id": "76374cc0",
"metadata": {},
"outputs": [],
"source": [
"def entropy_func(images):\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)"
]
},
{
"cell_type": "code",
"execution_count": 139,
"id": "f62bc952",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6.7830123821108295\n"
]
}
],
"source": [
"print(np.mean(e))"
]
}
}
],
],
"metadata": {
"metadata": {
...
...
Error_to_Image.ipynb
View file @
f9f43c1a
...
@@ -2,45 +2,12 @@
...
@@ -2,45 +2,12 @@
"cells": [
"cells": [
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1,
"execution_count": 1
34
,
"id": "dbef8759",
"id": "dbef8759",
"metadata": {
"metadata": {
"id": "dbef8759"
"id": "dbef8759"
},
},
"outputs": [
"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.058679431676864624\n"
]
},
{
"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": [
"Std Deviation of E: 26.627504708827136\n",
"Normal bits: 15\n",
"Encoded Bits: 6.677845333316752\n",
"(258, 322)\n"
]
}
],
"source": [
"source": [
"import numpy as np\n",
"import numpy as np\n",
"from prediction_MSE_Scout import file_extractor, image_extractor, im_distribution\n",
"from prediction_MSE_Scout import file_extractor, image_extractor, im_distribution\n",
...
@@ -54,24 +21,48 @@
...
@@ -54,24 +21,48 @@
"from numpy import linalg as la\n",
"from numpy import linalg as la\n",
"from scipy.stats import gaussian_kde\n",
"from scipy.stats import gaussian_kde\n",
"import seaborn as sns\n",
"import seaborn as sns\n",
"import pywt\n",
"from collections import Counter\n",
"from collections import Counter"
"import pandas as pd\n",
"import scipy as sp"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count":
2
,
"execution_count":
126
,
"id": "9ed20f84",
"id": "9ed20f84",
"metadata": {
"metadata": {
"id": "9ed20f84"
"id": "9ed20f84"
},
},
"outputs": [],
"outputs": [],
"source": [
"source": [
"def p
lot_his
t(tiff_list, i=0):\n",
"def p
redic
t(tiff_list, i=0):\n",
" \"\"\"\n",
" \"\"\"\n",
" This function is the leftovers from the first attempt to plot histograms.\n",
" This function predicts the pixel values based on a linear combination\n",
" As it stands it needs some work in order to function again. We will\n",
" of the MSE from the three pixels above it and the one to the left. It\n",
" fix this later. 1/25/22\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",
" \n",
" \n",
" image = tiff_list[i]\n",
" image = tiff_list[i]\n",
...
@@ -94,7 +85,7 @@
...
@@ -94,7 +85,7 @@
" \n",
" \n",
" # use numpy solver to solve the system of equations all at once\n",
" # use numpy solver to solve the system of equations all at once\n",
" #predict = np.linalg.solve(A,y)[-1]\n",
" #predict = np.linalg.solve(A,y)[-1]\n",
" predict = np.floor(np.linalg.solve(A,y)[-1]).astype(int)\n",
" predict
ion
= np.floor(np.linalg.solve(A,y)[-1]).astype(int)\n",
" #predict = []\n",
" #predict = []\n",
" \n",
" \n",
" # flatten the neighbor pixels and stack them together\n",
" # flatten the neighbor pixels and stack them together\n",
...
@@ -112,11 +103,7 @@
...
@@ -112,11 +103,7 @@
" small_image = image_int[1:-1,1:-1]\n",
" small_image = image_int[1:-1,1:-1]\n",
" \n",
" \n",
" #Reshape the predictions to be a 2D array\n",
" #Reshape the predictions to be a 2D array\n",
" predict = np.pad(predict.reshape(510,638), pad_width=1)\n",
" prediction = np.pad(prediction.reshape(510,638), pad_width=1)\n",
" \"\"\"predict[0,:] = image[0,:]\n",
" predict[:,0] = image[:,0]\n",
" predict[:,-1] = image[:,-1]\n",
" predict[-1,:] = image[-1,:]\"\"\"\n",
" \n",
" \n",
" \n",
" \n",
" #Calculate the error between the original image and our predictions\n",
" #Calculate the error between the original image and our predictions\n",
...
@@ -125,15 +112,15 @@
...
@@ -125,15 +112,15 @@
" #error = (image_int - predict).astype(int) #Experiment\n",
" #error = (image_int - predict).astype(int) #Experiment\n",
" \n",
" \n",
" #this one works\n",
" #this one works\n",
" error = image_int - predict\n",
" error = image_int - predict
ion
\n",
"\n",
"\n",
" \n",
" \n",
" return predict, diff, image_int, error, A"
" return predict
ion
, diff, image_int, error, A"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 3,
"execution_count":
5
3,
"id": "ba2881d9",
"id": "ba2881d9",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -145,17 +132,17 @@
...
@@ -145,17 +132,17 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 4,
"execution_count":
5
4,
"id": "11e95c34",
"id": "11e95c34",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": [
"source": [
"predict
, diff, im, err, A = plot_his
t(images, 2)"
"predict
ion, diff, im, err, A = predic
t(images, 2)"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 5,
"execution_count": 5
5
,
"id": "434e4d2f",
"id": "434e4d2f",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -176,20 +163,23 @@
...
@@ -176,20 +163,23 @@
" new_e = error.copy()\n",
" new_e = error.copy()\n",
" rows, columns = new_e.shape\n",
" rows, columns = new_e.shape\n",
"\n",
"\n",
" for r in range(1, rows-1):\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",
" 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",
" 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))\n",
" y = np.vstack((-z0+z2-z3, z0+z1+z2, -z0-z1-z2-z3)) #Create a vector of the linear combinations for the\n",
" \n",
" #solution to be solved\n",
" new_e[r][c] = np.round(new_e[r][c] + np.linalg.solve(A,y)[-1], 1)\n",
" \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",
" return new_e.astype(int)\n",
" "
" "
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 6,
"execution_count":
5
6,
"id": "3cc609dc",
"id": "3cc609dc",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -199,7 +189,7 @@
...
@@ -199,7 +189,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 7,
"execution_count":
5
7,
"id": "5d290a0c",
"id": "5d290a0c",
"metadata": {},
"metadata": {},
"outputs": [
"outputs": [
...
@@ -215,7 +205,7 @@
...
@@ -215,7 +205,7 @@
" [ True, True, True, ..., True, True, True]])"
" [ True, True, True, ..., True, True, True]])"
]
]
},
},
"execution_count": 7,
"execution_count":
5
7,
"metadata": {},
"metadata": {},
"output_type": "execute_result"
"output_type": "execute_result"
}
}
...
@@ -226,130 +216,7 @@
...
@@ -226,130 +216,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 8,
"execution_count": 60,
"id": "706f2816",
"metadata": {},
"outputs": [],
"source": [
"first = []\n",
"second = []\n",
"third = []\n",
"fourth = []\n",
"\n",
"for i in range(1,diff.shape[0]-1):\n",
" for j in range(1,diff.shape[1]-1):\n",
" if diff[i][j] <= 50:\n",
" first.append(np.abs(err[i][j]))\n",
" elif diff[i][j] > 50 and diff[i][j] <= 100:\n",
" second.append(np.abs(err[i][j]))\n",
" elif diff[i][j] > 100 and diff[i][j] <= 200:\n",
" third.append(np.abs(err[i][j]))\n",
" else:\n",
" fourth.append(np.abs(err[i][j]))\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "530d2cab",
"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": [
"142\n"
]
},
{
"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": [
"154\n"
]
},
{
"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": [
"217\n"
]
},
{
"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": [
"176\n"
]
}
],
"source": [
"\n",
"plt.hist(first)\n",
"plt.show()\n",
"print(np.max(first))\n",
"plt.hist(second)\n",
"plt.show()\n",
"print(np.max(second))\n",
"plt.hist(third)\n",
"plt.show()\n",
"print(np.max(third))\n",
"plt.hist(fourth)\n",
"plt.show()\n",
"print(np.max(fourth))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "bb11dcd0",
"id": "bb11dcd0",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -397,51 +264,68 @@
...
@@ -397,51 +264,68 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1
1
,
"execution_count": 1
27
,
"id": "c01fda28",
"id": "c01fda28",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": [
"source": [
"def enc_experiment(images, plot=True):\n",
"def encoder(images, i, plot=True):\n",
" origin, predict, diff, error, A = plot_hist(images, 2)\n",
" \"\"\"\n",
" image = Image.open(images[2]) #Open the image and read it as an Image object\n",
" Function that creates Huffman encodings out of the error values\n",
" image = np.array(image)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
" for a given image. The encodings are more efficient ways to store \n",
" image = image.astype(int)\n",
" large integer values that the original image contains.\n",
" new_error = np.copy(image)\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] = np.reshape(error[1:-1,1:-1],(510, 638))\n",
" new_error[1:-1, 1:-1] = error[1:-1, 1:-1]\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",
" keep = new_error[0,0]\n",
" #error matrix retreived from predicting\n",
" new_error[0,:] = new_error[0,:] - keep\n",
" keep = new_error[0,0] #The top left entry stays the same\n",
" new_error[-1,:] = new_error[-1,:] - keep\n",
" new_error[0,:] = new_error[0,:] - keep #All edge pixels are set to be the difference between themselves and\n",
" new_error[1:-1,0] = new_error[1:-1,0] - keep\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[1:-1,-1] = new_error[1:-1,-1] - keep\n",
" new_error[0,0] = keep\n",
" new_error[0,0] = keep\n",
" new_error = np.ravel(new_error)\n",
" \n",
" new_error = np.ravel(new_error) #Unravel it to plot it\n",
" if plot:\n",
" if plot:\n",
" plt.hist(new_error[1:],bins=100)\n",
" plt.hist(new_error[1:],bins=100)\n",
" plt.show()\n",
" plt.show()\n",
" \n",
" \n",
" #ab_error = np.abs(new_error)\n",
"\n",
" #string = [str(i) for i in ab_error]\n",
" string = [str(i) for i in new_error] #Create strings out of the integers in the new_error matrix\n",
" string = [str(i) for i in new_error]\n",
" \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)) #Initialize a dictionary that maps integers to the string values\n",
" freq = dict(Counter(string))\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True) #Create a frequency mapping of how often the string\n",
" freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)\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",
" \n",
" node = make_tree(freq)\n",
" encoding_dict = huffman_code_tree(node)\n",
" #encoded = [\"1\"+encoding[str(-i)] if i < 0 else \"0\"+encoding[str(i)] for i in error]\n",
" #encoded = [\"1\"+encoding[str(-i)] if i < 0 else \"0\"+encoding[str(i)] for i in error]\n",
" #print(time.time()-start)\n",
" encoded = new_error.reshape((512,640)).copy().astype(str).astype(object)\n",
"\n",
"\n",
" for i in range(encoded.shape[0]):\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",
" for j in range(encoded.shape[1]):\n",
" if i == 0 and j == 0:\n",
" if i == 0 and j == 0:\n",
" encoded[i][j] = encoded[i][j]\n",
" encoded[i][j] = encoded[i][j]
#Replace each value in the dictionary with its encoding from the dictionary
\n",
" else:\n",
" else:\n",
" #print(encoding_dict[encoded[i][j]])\n",
" encoded[i][j] = encoding_dict[encoded[i][j]]\n",
" encoded[i][j] = encoding_dict[encoded[i][j]]\n",
" #print(encoded[i][j])\n",
" \n",
" \n",
" return encoding_dict, encoded, new_error.reshape((512,640)), image\n",
" return encoding_dict, encoded, new_error.reshape((512,640)), image\n",
" #print(encoding)"
" #print(encoding)"
...
@@ -449,38 +333,17 @@
...
@@ -449,38 +333,17 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count":
1
2,
"execution_count":
6
2,
"id": "ffa858e8",
"id": "ffa858e8",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": [
"source": [
"encode_dict, encoding, error, orig_image = enc
_experiment(images
, plot=False)"
"encode_dict, encoding, error, orig_image = enc
oder(images, 2
, plot=False)"
]
]
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 13,
"execution_count": 121,
"id": "8dfdedc6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"error[1,6]"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "825cc48c",
"id": "825cc48c",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -490,8 +353,8 @@
...
@@ -490,8 +353,8 @@
" Function that accecpts the prediction matrix A for the linear system,\n",
" Function that accecpts the prediction matrix A for the linear system,\n",
" the encoded matrix of error values, and the encoding dicitonary.\n",
" the encoded matrix of error values, and the encoding dicitonary.\n",
" \"\"\"\n",
" \"\"\"\n",
" the_keys = list(encod
e
_dict.keys())\n",
" the_keys = list(encod
ing
_dict.keys())\n",
" the_values = list(encod
e
_dict.values())\n",
" the_values = list(encod
ing
_dict.values())\n",
" error_matrix = encoded_matrix.copy()\n",
" error_matrix = encoded_matrix.copy()\n",
" \n",
" \n",
" for i in range(error_matrix.shape[0]):\n",
" for i in range(error_matrix.shape[0]):\n",
...
@@ -513,7 +376,7 @@
...
@@ -513,7 +376,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1
5
,
"execution_count": 1
22
,
"id": "ba1d2c2c",
"id": "ba1d2c2c",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -523,7 +386,7 @@
...
@@ -523,7 +386,7 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count": 1
6
,
"execution_count": 1
23
,
"id": "b2cdce6d",
"id": "b2cdce6d",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
...
@@ -534,11 +397,60 @@
...
@@ -534,11 +397,60 @@
},
},
{
{
"cell_type": "code",
"cell_type": "code",
"execution_count":
null
,
"execution_count":
124
,
"id": "a
42c21b1
",
"id": "a
686a66e
",
"metadata": {},
"metadata": {},
"outputs": [],
"outputs": [],
"source": []
"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": 137,
"id": "76374cc0",
"metadata": {},
"outputs": [],
"source": [
"def entropy_func(images):\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)"
]
},
{
"cell_type": "code",
"execution_count": 139,
"id": "f62bc952",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6.7830123821108295\n"
]
}
],
"source": [
"print(np.mean(e))"
]
}
}
],
],
"metadata": {
"metadata": {
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment