Commit cbba7336 authored by Nathaniel Callens's avatar Nathaniel Callens

compression try

parent 0bc96f0e
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 76, "execution_count": 72,
"id": "dbef8759", "id": "dbef8759",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -16,14 +16,16 @@ ...@@ -16,14 +16,16 @@
"from scipy.optimize import minimize\n", "from scipy.optimize import minimize\n",
"from time import time\n", "from time import time\n",
"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, entropy\n",
"import seaborn as sns\n", "import seaborn as sns\n",
"import pywt" "import pywt\n",
"import math\n",
"#import cv2"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 15,
"id": "b7a550e0", "id": "b7a550e0",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -78,7 +80,7 @@ ...@@ -78,7 +80,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 16,
"id": "9ed20f84", "id": "9ed20f84",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -106,6 +108,7 @@ ...@@ -106,6 +108,7 @@
" y = np.vstack((y0,y1,y2))\n", " y = np.vstack((y0,y1,y2))\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 = []\n",
" # flatten the neighbor pixlels and stack them together\n", " # flatten the neighbor pixlels and stack them together\n",
" z0 = np.ravel(z0)\n", " z0 = np.ravel(z0)\n",
" z1 = np.ravel(z1)\n", " z1 = np.ravel(z1)\n",
...@@ -114,6 +117,15 @@ ...@@ -114,6 +117,15 @@
" neighbor = np.vstack((z0,z1,z2,z3)).T\n", " neighbor = np.vstack((z0,z1,z2,z3)).T\n",
" # calculate the difference\n", " # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\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", " # flatten the image to a vector\n",
" image_ravel = np.ravel(image[1:-1,1:-1])\n", " image_ravel = np.ravel(image[1:-1,1:-1])\n",
" return image_ravel, predict, diff, image" " return image_ravel, predict, diff, image"
...@@ -121,14 +133,14 @@ ...@@ -121,14 +133,14 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 17,
"id": "8e3ef654", "id": "8e3ef654",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"scenes = file_extractor()\n", "scenes = file_extractor()\n",
"images = image_extractor(scenes)\n", "images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\n", "num_images = im_distribution(images, \"_1\")\n",
"error_mean = []\n", "error_mean = []\n",
"error_mean1 = []\n", "error_mean1 = []\n",
"diff_mean = []\n", "diff_mean = []\n",
...@@ -156,7 +168,7 @@ ...@@ -156,7 +168,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 18,
"id": "fa65dcd6", "id": "fa65dcd6",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
...@@ -164,15 +176,15 @@ ...@@ -164,15 +176,15 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Average Error First and Second Added: 20.017164930235474\n", "Average Error: 19.44221679267325\n",
"Standard Deviaiton of Mean Errors: 0.16101183692475135\n", "Standard Deviaiton of Mean Errors: 0.17734010606906342\n",
"Average Difference: 53.678648426455226\n", "Average Difference: 51.95430150900486\n",
"Average Time per Image for First: 0.10891032218933105\n" "Average Time per Image for First: 0.04917508363723755\n"
] ]
} }
], ],
"source": [ "source": [
"print(f\"Average Error First and Second Added: {np.mean(error_mean)}\")\n", "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\"Standard Deviaiton of Mean Errors: {np.sqrt(np.var(error_mean))}\")\n",
"print(f\"Average Difference: {np.mean(diff_mean)}\")\n", "print(f\"Average Difference: {np.mean(diff_mean)}\")\n",
"print(f\"Average Time per Image for First: {np.mean(times)}\")" "print(f\"Average Time per Image for First: {np.mean(times)}\")"
...@@ -180,7 +192,7 @@ ...@@ -180,7 +192,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 19,
"id": "4c05b947", "id": "4c05b947",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -190,13 +202,13 @@ ...@@ -190,13 +202,13 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 21,
"id": "dda442ae", "id": "dda442ae",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"image/png": "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\n", "image/png": "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\n",
"text/plain": [ "text/plain": [
"<Figure size 432x288 with 1 Axes>" "<Figure size 432x288 with 1 Axes>"
] ]
...@@ -208,7 +220,7 @@ ...@@ -208,7 +220,7 @@
} }
], ],
"source": [ "source": [
"new_error = np.abs(new_image-new_pred)\n", "new_error = new_image-new_pred\n",
"plt.hist(new_error, bins=20, density=True)\n", "plt.hist(new_error, bins=20, density=True)\n",
"sns.kdeplot(new_error)\n", "sns.kdeplot(new_error)\n",
"plt.xlabel(\"error\")\n", "plt.xlabel(\"error\")\n",
...@@ -217,58 +229,63 @@ ...@@ -217,58 +229,63 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 41,
"id": "58da6063", "id": "58da6063",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "name": "stdout",
"image/png": "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\n", "output_type": "stream",
"text/plain": [ "text": [
"<Figure size 432x288 with 1 Axes>" "Std Deviation of E: 26.627504708827136\n",
] "Normal bits: 15\n",
}, "Encoded Bits: 6.677845333316752\n"
"metadata": { ]
"needs_background": "light"
},
"output_type": "display_data"
} }
], ],
"source": [ "source": [
"plt.hist(new_image, bins=25, density=True)\n", "image = Image.open(images[0]) #Open the image and read it as an Image object\n",
"sns.kdeplot(new_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",
"plt.xlabel(\"Actual Pixel Value\")\n", "image = image.astype(np.int64)\n",
"plt.show()" "print(\"Std Deviation of E: \", np.std(new_error))\n",
"print(\"Normal bits: \", int(image[0][0]).bit_length())\n",
"H = np.log2(np.std(new_error)) + 1.943\n",
"print(\"Encoded Bits: \", H)"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 79, "execution_count": 47,
"id": "2562feeb", "id": "ec4db902",
"metadata": { "metadata": {},
"scrolled": false
},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"(512, 640)\n", "8192\n"
"1310832\n",
"9\n"
] ]
} }
], ],
"source": []
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2562feeb",
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [ "source": [
"f_r = no_ravel[0]\n", "pred = new_pred.reshape((510,638))\n",
"print(no_ravel.shape)\n", "real_pred = no_ravel.copy()\n",
"print(sys.getsizeof(no_ravel))\n", "real_pred[1:-1, 1:-1] = pred"
"print((256).bit_length())"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 99, "execution_count": 10,
"id": "470cc137", "id": "470cc137",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
...@@ -285,7 +302,7 @@ ...@@ -285,7 +302,7 @@
"'print(decompress)\\nprint(np.mean(np.abs(decompress-no_ravel)))'" "'print(decompress)\\nprint(np.mean(np.abs(decompress-no_ravel)))'"
] ]
}, },
"execution_count": 99, "execution_count": 10,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
...@@ -301,112 +318,201 @@ ...@@ -301,112 +318,201 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 59, "execution_count": null,
"id": "3292b395", "id": "3292b395",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [],
{ "source": []
"name": "stdout", },
"output_type": "stream", {
"text": [ "cell_type": "code",
"[72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 97, 109, 101, 32, 105, 115, 32, 83, 99, 111, 117, 116]\n", "execution_count": null,
"256\n", "id": "f9687830",
"71\n" "metadata": {},
] "outputs": [],
} "source": []
], },
{
"cell_type": "code",
"execution_count": 13,
"id": "e98eed4b",
"metadata": {},
"outputs": [],
"source": [ "source": [
"def compress(uncompressed):\n", "f = open(\"test.craw\", \"wb\")\n",
" \"\"\"Compress a string to a list of output symbols.\"\"\"\n", "f.write(real_pred.tobytes())\n",
" \n", "f.close()"
" # Build the dictionary.\n",
" dict_size = 256\n",
" dictionary = dict((chr(i), i) for i in range(dict_size))\n",
" # in Python 3: dictionary = {chr(i): i for i in range(dict_size)}\n",
"\n",
" w = \"\"\n",
" result = []\n",
" for c in uncompressed:\n",
" wc = w + c\n",
" if wc in dictionary:\n",
" w = wc\n",
" else:\n",
" result.append(dictionary[w])\n",
" # Add wc to the dictionary.\n",
" dictionary[wc] = dict_size\n",
" dict_size += 1\n",
" w = c\n",
" \n",
" # Output the code for w.\n",
" if w:\n",
" result.append(dictionary[w])\n",
" return result\n",
"\n",
"store = compress(\"Hello my name is Scout\")\n",
"print(store)\n",
"print(sys.getsizeof(store))\n",
"print(sys.getsizeof(\"Hello my name is Scout\"))"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 101, "execution_count": 12,
"id": "f9687830", "id": "b7e88aab",
"metadata": {},
"outputs": [],
"source": [
"# Apply arithmetic coding to compress it\n",
"import adaptive_arithmetic_compress\n",
"adaptive_arithmetic_compress.main([\"test.craw\", \"test.tiff\"])"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "7c8abaee",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "ValueError", "data": {
"evalue": "too many values to unpack (expected 2)", "text/plain": [
"output_type": "error", "'change = Image.open(\"test.tiff\")\\nchange = np.array(change)\\nprint(change.shape)'"
"traceback": [ ]
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", },
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "execution_count": 11,
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_22104/2202774112.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 18\u001b[0m \u001b[0mtimes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstop\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mstart\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 19\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mtimes\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 20\u001b[1;33m \u001b[0mti\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mwave_decompress\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcoef\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[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmean\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mti\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", "metadata": {},
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_22104/2202774112.py\u001b[0m in \u001b[0;36mwave_decompress\u001b[1;34m(coeffs)\u001b[0m\n\u001b[0;32m 14\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcoeffs\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[0;32m 15\u001b[0m \u001b[0mstart\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtime\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;32m---> 16\u001b[1;33m \u001b[0mdecompress\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpywt\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0midwt2\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcoeffs\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'bior1.3'\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 17\u001b[0m \u001b[0mstop\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtime\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 18\u001b[0m \u001b[0mtimes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstop\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mstart\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "output_type": "execute_result"
"\u001b[1;32m~\\anaconda3\\lib\\site-packages\\pywt\\_multidim.py\u001b[0m in \u001b[0;36midwt2\u001b[1;34m(coeffs, wavelet, mode, axes)\u001b[0m\n\u001b[0;32m 110\u001b[0m \"\"\"\n\u001b[0;32m 111\u001b[0m \u001b[1;31m# L -low-pass data, H - high-pass data\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 112\u001b[1;33m \u001b[0mLL\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mHL\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mLH\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mHH\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcoeffs\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 113\u001b[0m \u001b[0maxes\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maxes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 114\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maxes\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[1;36m2\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: too many values to unpack (expected 2)"
]
} }
], ],
"source": [ "source": [
"def wavelet(num_images, i): \n", "\"\"\"change = Image.open(\"test.tiff\")\n",
"\n", "change = np.array(change)\n",
" image = Image.open(num_images[i]) #Open the image and read it as an Image object\n", "print(change.shape)\"\"\""
" image = np.array(im)[1:,:]\n",
" coeffs = pywt.dwt2(image, 'bior1.3')\n",
" return coeffs\n",
"\n",
" \n",
"\n",
"coef, t = wavelet(num_images,0)\n",
"\n",
"def wave_decompress(coeffs):\n",
" times = []\n",
" for i in range(len(coeffs)):\n",
" start = time()\n",
" decompress = pywt.idwt2(coeffs[i], 'bior1.3')\n",
" stop = time()\n",
" times.append(stop-start)\n",
" return times\n",
"ti = wave_decompress(coef)\n",
"print(np.mean(ti))"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 114,
"id": "e98eed4b", "id": "82c20d94",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [] "source": [
"def compress(inputFile):#, outputFile):\n",
" twoBytes = 256*256\n",
" # Read the input file into a numpy array of 8-bit values\n",
" #\n",
" # The img.shape is a 3-type with rows,columns,channels, where\n",
" # channels is the number of components in each pixel. The img.dtype\n",
" # is 'uint8', meaning that each component is an 8-bit unsigned\n",
" # integer.\n",
"\n",
" #img = netpbm.imread(inputFile).astype('uint8')\n",
" img = Image.open(inputFile) #Open the image and read it as an Image object\n",
" img = np.array(img)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
" img = img.astype('uint8')\n",
"\n",
"\n",
" # Compress the image\n",
" #\n",
" #\n",
" # Note that single-channel images will have a 'shape' with only two\n",
" # components: the y dimensions and the x dimension. So you will\n",
" # have to detect this and set the number of channels accordingly.\n",
" # Furthermore, single-channel images must be indexed as img[y,x]\n",
" # instead of img[y,x,1]. You'll need two pieces of similar code:\n",
" # one piece for the single-channel case and one piece for the\n",
" # multi-channel case.\n",
"\n",
" #startTime = time.time()\n",
"\n",
" outputBytes = bytearray()\n",
"\n",
" # initialize dictionary\n",
" d = {}\n",
" counter = 256\n",
" for i in range(-counter, counter):\n",
" d[str(i)] = i\n",
" # Set Dictionary limit\n",
"\n",
" # Make a list to hold bytes\n",
" tempBytes = []\n",
" # A counter for the number of bytes\n",
" numBytes = 0\n",
" multichannel = False\n",
" \n",
" # for a single channel image\n",
" if (len(img.shape) == 2) :\n",
" multichannel = False\n",
" \n",
" # Go through whole image\n",
" for y in range(img.shape[0]):\n",
" for x in range(img.shape[1]):\n",
" # Initialize prediction to image value\n",
" prediction = img[y][x]\n",
" #\"\"\" \n",
" # Modify prediction to show the difference between prior pixels and current pixel\n",
" if(x != 0):\n",
" prediction = prediction - img[y][x-1]\n",
" elif(y != 0):\n",
" prediction = prediction - img[y-1][x]\n",
" else:\n",
" prediction = prediction - (img[y][x-1]/3 + img[y-1][x]/3 + img[y-1][x-1]/3)\n",
" #\"\"\"\n",
" # Add the predicted value to the bytestream\n",
" tempBytes.append(prediction)\n",
" numBytes += 1\n",
" # Using a string variable as it allows for concatenation\n",
" s = \"\"\n",
" # Set s to the first value of the bytestream \n",
" s = str(int(tempBytes[0]))\n",
" # Go through all bytes\n",
" for i in range(1, numBytes):\n",
" # Do LZW encoding\n",
" # If trying to add entry larger than max size of the dictionary reinitialize the dictionary\n",
" if(counter >= twoBytes):\n",
" counter = 256\n",
" d = {}\n",
" for i in range(-counter, counter):\n",
" d[str(i)] = i\n",
"\n",
" # Add the next byte to the current string. Uses a delimeter to distinguish numbers\n",
" w = s +\"|\"+str(int(tempBytes[i]))\n",
" # Checking if it has been seen before\n",
" if w in d:\n",
" s = w\n",
" else:\n",
" # Output bytes by splitting integer into two bytes, this allows for a larger dictionary\n",
" outputBytes.append((int(d[s]) >> 8) & 0xFF)\n",
" outputBytes.append(int(d[s]) & 0xFF)\n",
" # Add to dictionarry\n",
" d[w] = counter\n",
" counter += 1\n",
" s = str(int(tempBytes[i]))\n",
" # Check if the last byte was added or not \n",
" if s in d: \n",
" outputBytes.append((int(d[s]) >> 8) & 0xFF)\n",
" outputBytes.append(int(d[s]) & 0xFF) \n",
" return numBytes, outputBytes, tempBytes"
]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 123,
"id": "b7e88aab", "id": "9190b5a8",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
"source": [] {
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\calle\\AppData\\Local\\Temp/ipykernel_1700/265550185.py:56: RuntimeWarning: overflow encountered in ubyte_scalars\n",
" prediction = prediction - img[y][x-1]\n",
"C:\\Users\\calle\\AppData\\Local\\Temp/ipykernel_1700/265550185.py:58: RuntimeWarning: overflow encountered in ubyte_scalars\n",
" prediction = prediction - img[y-1][x]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"245\n"
]
}
],
"source": [
"test = images[0]\n",
"comp, out, temp = compress(test)\n",
"print(out[19])"
]
} }
], ],
"metadata": { "metadata": {
......
#
# Compression application using adaptive arithmetic coding
#
# Usage: python adaptive-arithmetic-compress.py InputFile OutputFile
# Then use the corresponding adaptive-arithmetic-decompress.py application to recreate the original input file.
# Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1),
# and updates it after each byte encoded. The corresponding decompressor program also starts with a flat
# frequency table and updates it after each byte decoded. It is by design that the compressor and
# decompressor have synchronized states, so that the data can be decompressed properly.
#
# Copyright (c) Project Nayuki
#
# https://www.nayuki.io/page/reference-arithmetic-coding
# https://github.com/nayuki/Reference-arithmetic-coding
#
import sys
import arithmeticcoding
python3 = sys.version_info.major >= 3
# Command line main application function.
def main(args):
# Handle command line arguments
if len(args) != 2:
sys.exit("Usage: python adaptive-arithmetic-compress.py InputFile OutputFile")
inputfile = args[0]
outputfile = args[1]
# Perform file compression
with open(inputfile, "rb") as inp:
bitout = arithmeticcoding.BitOutputStream(open(outputfile, "wb"))
try:
compress(inp, bitout)
finally:
bitout.close()
def compress(inp, bitout):
initfreqs = arithmeticcoding.FlatFrequencyTable(257)
freqs = arithmeticcoding.SimpleFrequencyTable(initfreqs)
enc = arithmeticcoding.ArithmeticEncoder(bitout)
while True:
# Read and encode one byte
symbol = inp.read(1)
if len(symbol) == 0:
break
symbol = symbol[0] if python3 else ord(symbol)
enc.write(freqs, symbol)
freqs.increment(symbol)
enc.write(freqs, 256) # EOF
enc.finish() # Flush remaining code bits
# Main launcher
if __name__ == "__main__":
main(sys.argv[1 : ])
# Example implementation of simple arithmetic coding in Python (2.7+).
#
# USAGE
#
# python -i arithmetic.py
# >>> m = {'a': 1, 'b': 1, 'c': 1}
# >>> model = dirichlet(m)
# >>> encode(model, "aabbaacc")
# '00011110011110010'
#
# NOTES
#
# This implementation has many shortcomings, e.g.,
# - There are several inefficient tests, loops, and conversions
# - There are a few places where code is uncessarily duplicated
# - It does not output the coded message as a stream
# - It can only code short messages due to machine precision
# - The is no defensive coding against errors (e.g., out-of-model symbols)
# - I've not implemented a decoder!
#
# The aim was to make the implementation here as close as possible to
# the algorithm described in lectures while giving some extra detail about
# routines such as finding extensions to binary intervals.
#
# For a more sophisticated implementation, please refer to:
#
# "Arithmetic Coding for Data Compression"
# I. H. Witten, R. M. Neal, and J. G. Cleary
# Communications of the ACM, Col. 30 (6), 1987
#
# AUTHOR: Mark Reid
# CREATED: 2014-09-30
def encode(G, stream):
'''
Arithmetically encodes the given stream using the guesser function G
which returns probabilities over symbols P(x|xs) given a sequence xs.
'''
u, v = 0.0, 1.0 # The interval [u, v) for the message
xs, bs = "", "" # The message xs, and binary code bs
p = G(xs) # Compute the initial distribution over symbols
# Iterate through stream, repeatedly finding the longest binary code
# that surrounds the interval for the message so far
for x in stream:
# Record the new symbol
xs += x
# Find the interval for the message so far
F_lo, F_hi = cdf_interval(p, x)
u, v = u + (v-u)*F_lo, u + (v-u)*F_hi
# Find a binary code whose interval surrounds [u,v)
bs = extend_around(bs, u, v)
# Update the symbol probabilities
p = G(xs)
# Stream finished so find shortest extension of the code that sits inside
# the top half of [u, v)
bs = extend_inside(bs, u + (v-u)/2, v)
return bs
##############################################################################
# Models
def dirichlet(m):
'''
Returns a Dirichlet model (as a function) for probabilities with
prior counts given by the symbol to count dictionary m.
Probabilities returned by the returned functions are (symbol, prob)
dictionaries.
'''
# Build a function that returns P(x|xs) based on the priors in m
# and the counts of the symbols in xs
def p(xs):
counts = m.copy()
for x in xs:
counts[x] += 1
total = sum(counts.values())
return { a: float(c)/total for a, c in counts.items() }
# Return the constructed function
return p
##############################################################################
# Interval methods
def cdf_interval(p, a):
'''
Compute the cumulative distribution interval [F(a'), F(a)) for the
probabilities p (represented as a (symbol,prob) dict) where
F(a) = P(x <= a) and a' is the symbol preceeding a.
'''
F_lo, F_hi = 0, 0
A = sorted(p)
for x in A:
F_lo, F_hi = F_hi, F_hi + p[x]
if x == a:
break
return F_lo, F_hi
def binary_interval(bs):
'''
Returns an interval [n, m) for n and m integers, and denominator d
representing the interval [n/d, m/d) for the binary string bs.
'''
n, d = to_rational(bs)
return n, n + 1, d
def to_rational(bs):
'''Return numerator and denominator for ratio of 0.bs.'''
n = 0
for b in bs:
n *= 2
n += int(b)
return n, 2**len(bs)
def around(bs, u, v):
'''Tests whether [0.bs, 0.bs111...) contains [u, v).'''
n, m, d = binary_interval(bs)
return (n <= u*d) and (v*d <= m)
def extend_around(bs, u, v):
'''Find the longest extension of the given binary string so its interval
wraps around the interval [u, v).'''
contained = True
while contained:
if around(bs + "0", u, v):
bs += "0"
elif around(bs + "1", u, v):
bs += "1"
else:
contained = False
return bs
def inside(bs, u, v):
'''Tests whether [0.bs, 0.bs111...) is contained by [u, v).'''
n, m, d = binary_interval(bs)
return (u*d <= n) and (m <= v*d)
def extend_inside(bs, u, v):
'''Find the shortest extension of the given binary string so its interval
sits inside the interval [u, v).'''
while not inside(bs, u, v):
# Test whether gap between binary interval and [u,v) is bigger at the
# bottom than at the top
n, m, d = binary_interval(bs)
if u*d - n > m - v*d:
bs += "1" # If so, move bottom up by halving
else:
bs += "0" # If not, move top down by halving
return bs
#
# Reference arithmetic coding
# Copyright (c) Project Nayuki
#
# https://www.nayuki.io/page/reference-arithmetic-coding
# https://github.com/nayuki/Reference-arithmetic-coding
#
import sys
python3 = sys.version_info.major >= 3
# ---- Arithmetic coding core classes ----
# Provides the state and behaviors that arithmetic coding encoders and decoders share.
class ArithmeticCoderBase(object):
# Number of bits for 'low' and 'high'. Configurable and must be at least 1.
STATE_SIZE = 32
# Maximum range during coding (trivial), i.e. 1000...000.
MAX_RANGE = 1 << STATE_SIZE
# Minimum range during coding (non-trivial), i.e. 010...010.
MIN_RANGE = (MAX_RANGE >> 2) + 2
# Maximum allowed total frequency at all times during coding.
MAX_TOTAL = MIN_RANGE
# Mask of STATE_SIZE ones, i.e. 111...111.
MASK = MAX_RANGE - 1
# Mask of the top bit at width STATE_SIZE, i.e. 100...000.
TOP_MASK = MAX_RANGE >> 1
# Mask of the second highest bit at width STATE_SIZE, i.e. 010...000.
SECOND_MASK = TOP_MASK >> 1
# Constructs an arithmetic coder, which initializes the code range.
def __init__(self):
# Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
self.low = 0
# High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
self.high = ArithmeticCoderBase.MASK
# Updates the code range (low and high) of this arithmetic coder as a result
# of processing the given symbol with the given frequency table.
# Invariants that are true before and after encoding/decoding each symbol:
# - 0 <= low <= code <= high < 2^STATE_SIZE. ('code' exists only in the decoder.)
# Therefore these variables are unsigned integers of STATE_SIZE bits.
# - (low < 1/2 * 2^STATE_SIZE) && (high >= 1/2 * 2^STATE_SIZE).
# In other words, they are in different halves of the full range.
# - (low < 1/4 * 2^STATE_SIZE) || (high >= 3/4 * 2^STATE_SIZE).
# In other words, they are not both in the middle two quarters.
# - Let range = high - low + 1, then MAX_RANGE/4 < MIN_RANGE <= range
# <= MAX_RANGE = 2^STATE_SIZE. These invariants for 'range' essentially
# dictate the maximum total that the incoming frequency table can have.
def update(self, freqs, symbol):
# State check
low = self.low
high = self.high
if low >= high or (low & ArithmeticCoderBase.MASK) != low or (high & ArithmeticCoderBase.MASK) != high:
raise AssertionError("Low or high out of range")
range = high - low + 1
if not (ArithmeticCoderBase.MIN_RANGE <= range <= ArithmeticCoderBase.MAX_RANGE):
raise AssertionError("Range out of range")
# Frequency table values check
total = freqs.get_total()
symlow = freqs.get_low(symbol)
symhigh = freqs.get_high(symbol)
if symlow == symhigh:
raise ValueError("Symbol has zero frequency")
if total > ArithmeticCoderBase.MAX_TOTAL:
raise ValueError("Cannot code symbol because total is too large")
# Update range
newlow = low + symlow * range // total
newhigh = low + symhigh * range // total - 1
self.low = newlow
self.high = newhigh
# While the highest bits are equal
while ((self.low ^ self.high) & ArithmeticCoderBase.TOP_MASK) == 0:
self.shift()
self.low = (self.low << 1) & ArithmeticCoderBase.MASK
self.high = ((self.high << 1) & ArithmeticCoderBase.MASK) | 1
# While the second highest bit of low is 1 and the second highest bit of high is 0
while (self.low & ~self.high & ArithmeticCoderBase.SECOND_MASK) != 0:
self.underflow()
self.low = (self.low << 1) & (ArithmeticCoderBase.MASK >> 1)
self.high = ((self.high << 1) & (ArithmeticCoderBase.MASK >> 1)) | ArithmeticCoderBase.TOP_MASK | 1
# Called to handle the situation when the top bit of 'low' and 'high' are equal.
def shift(self):
raise NotImplementedError()
# Called to handle the situation when low=01(...) and high=10(...).
def underflow(self):
raise NotImplementedError()
# Encodes symbols and writes to an arithmetic-coded bit stream.
class ArithmeticEncoder(ArithmeticCoderBase):
# Constructs an arithmetic coding encoder based on the given bit output stream.
def __init__(self, bitout):
super(ArithmeticEncoder, self).__init__()
# The underlying bit output stream.
self.output = bitout
# Number of saved underflow bits. This value can grow without bound.
self.num_underflow = 0
# Encodes the given symbol based on the given frequency table.
# This updates this arithmetic coder's state and may write out some bits.
def write(self, freqs, symbol):
if not isinstance(freqs, CheckedFrequencyTable):
freqs = CheckedFrequencyTable(freqs)
self.update(freqs, symbol)
# Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly.
# It is important that this method must be called at the end of the each encoding process.
# Note that this method merely writes data to the underlying output stream but does not close it.
def finish(self):
self.output.write(1)
def shift(self):
bit = self.low >> (ArithmeticCoderBase.STATE_SIZE - 1)
self.output.write(bit)
# Write out the saved underflow bits
for i in range(self.num_underflow):
self.output.write(bit ^ 1)
self.num_underflow = 0
def underflow(self):
self.num_underflow += 1
# Reads from an arithmetic-coded bit stream and decodes symbols.
class ArithmeticDecoder(ArithmeticCoderBase):
# Constructs an arithmetic coding decoder based on the
# given bit input stream, and fills the code bits.
def __init__(self, bitin):
super(ArithmeticDecoder, self).__init__()
# The underlying bit input stream.
self.input = bitin
# The current raw code bits being buffered, which is always in the range [low, high].
self.code = 0
for i in range(ArithmeticCoderBase.STATE_SIZE):
self.code = self.code << 1 | self.read_code_bit()
# Decodes the next symbol based on the given frequency table and returns it.
# Also updates this arithmetic coder's state and may read in some bits.
def read(self, freqs):
if not isinstance(freqs, CheckedFrequencyTable):
freqs = CheckedFrequencyTable(freqs)
# Translate from coding range scale to frequency table scale
total = freqs.get_total()
if total > ArithmeticCoderBase.MAX_TOTAL:
raise ValueError("Cannot decode symbol because total is too large")
range = self.high - self.low + 1
offset = self.code - self.low
value = ((offset + 1) * total - 1) // range
assert value * range // total <= offset
assert 0 <= value < total
# A kind of binary search. Find highest symbol such that freqs.get_low(symbol) <= value.
start = 0
end = freqs.get_symbol_limit()
while end - start > 1:
middle = (start + end) >> 1
if freqs.get_low(middle) > value:
end = middle
else:
start = middle
assert start + 1 == end
symbol = start
assert freqs.get_low(symbol) * range // total <= offset < freqs.get_high(symbol) * range // total
self.update(freqs, symbol)
if not (self.low <= self.code <= self.high):
raise AssertionError("Code out of range")
return symbol
def shift(self):
self.code = ((self.code << 1) & ArithmeticCoderBase.MASK) | self.read_code_bit()
def underflow(self):
self.code = (self.code & ArithmeticCoderBase.TOP_MASK) | ((self.code << 1) & (ArithmeticCoderBase.MASK >> 1)) | self.read_code_bit()
# Returns the next bit (0 or 1) from the input stream. The end
# of stream is treated as an infinite number of trailing zeros.
def read_code_bit(self):
temp = self.input.read()
if temp == -1:
temp = 0
return temp
# ---- Frequency table classes ----
# A table of symbol frequencies. The table holds data for symbols numbered from 0
# to get_symbol_limit()-1. Each symbol has a frequency, which is a non-negative integer.
# Frequency table objects are primarily used for getting cumulative symbol
# frequencies. These objects can be mutable depending on the implementation.
class FrequencyTable(object):
# Returns the number of symbols in this frequency table, which is a positive number.
def get_symbol_limit(self):
raise NotImplementedError()
# Returns the frequency of the given symbol. The returned value is at least 0.
def get(self, symbol):
raise NotImplementedError()
# Sets the frequency of the given symbol to the given value.
# The frequency value must be at least 0.
def set(self, symbol, freq):
raise NotImplementedError()
# Increments the frequency of the given symbol.
def increment(self, symbol):
raise NotImplementedError()
# Returns the total of all symbol frequencies. The returned value is at
# least 0 and is always equal to get_high(get_symbol_limit() - 1).
def get_total(self):
raise NotImplementedError()
# Returns the sum of the frequencies of all the symbols strictly
# below the given symbol value. The returned value is at least 0.
def get_low(self, symbol):
raise NotImplementedError()
# Returns the sum of the frequencies of the given symbol
# and all the symbols below. The returned value is at least 0.
def get_high(self, symbol):
raise NotImplementedError()
# An immutable frequency table where every symbol has the same frequency of 1.
# Useful as a fallback model when no statistics are available.
class FlatFrequencyTable(FrequencyTable):
# Constructs a flat frequency table with the given number of symbols.
def __init__(self, numsyms):
if numsyms < 1:
raise ValueError("Number of symbols must be positive")
self.numsymbols = numsyms # Total number of symbols, which is at least 1
# Returns the number of symbols in this table, which is at least 1.
def get_symbol_limit(self):
return self.numsymbols
# Returns the frequency of the given symbol, which is always 1.
def get(self, symbol):
self._check_symbol(symbol)
return 1
# Returns the total of all symbol frequencies, which is
# always equal to the number of symbols in this table.
def get_total(self):
return self.numsymbols
# Returns the sum of the frequencies of all the symbols strictly below
# the given symbol value. The returned value is equal to 'symbol'.
def get_low(self, symbol):
self._check_symbol(symbol)
return symbol
# Returns the sum of the frequencies of the given symbol and all
# the symbols below. The returned value is equal to 'symbol' + 1.
def get_high(self, symbol):
self._check_symbol(symbol)
return symbol + 1
# Returns silently if 0 <= symbol < numsymbols, otherwise raises an exception.
def _check_symbol(self, symbol):
if 0 <= symbol < self.numsymbols:
return
else:
raise ValueError("Symbol out of range")
# Returns a string representation of this frequency table. The format is subject to change.
def __str__(self):
return "FlatFrequencyTable={}".format(self.numsymbols)
# Unsupported operation, because this frequency table is immutable.
def set(self, symbol, freq):
raise NotImplementedError()
# Unsupported operation, because this frequency table is immutable.
def increment(self, symbol):
raise NotImplementedError()
# A mutable table of symbol frequencies. The number of symbols cannot be changed
# after construction. The current algorithm for calculating cumulative frequencies
# takes linear time, but there exist faster algorithms such as Fenwick trees.
class SimpleFrequencyTable(FrequencyTable):
# Constructs a simple frequency table in one of two ways:
# - SimpleFrequencyTable(sequence):
# Builds a frequency table from the given sequence of symbol frequencies.
# There must be at least 1 symbol, and no symbol has a negative frequency.
# - SimpleFrequencyTable(freqtable):
# Builds a frequency table by copying the given frequency table.
def __init__(self, freqs):
if isinstance(freqs, FrequencyTable):
numsym = freqs.get_symbol_limit()
self.frequencies = [freqs.get(i) for i in range(numsym)]
else: # Assume it is a sequence type
self.frequencies = list(freqs) # Make copy
# 'frequencies' is a list of the frequency for each symbol.
# Its length is at least 1, and each element is non-negative.
if len(self.frequencies) < 1:
raise ValueError("At least 1 symbol needed")
for freq in self.frequencies:
if freq < 0:
raise ValueError("Negative frequency")
# Always equal to the sum of 'frequencies'
self.total = sum(self.frequencies)
# cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive).
# Initialized lazily. When it is not None, the data is valid.
self.cumulative = None
# Returns the number of symbols in this frequency table, which is at least 1.
def get_symbol_limit(self):
return len(self.frequencies)
# Returns the frequency of the given symbol. The returned value is at least 0.
def get(self, symbol):
self._check_symbol(symbol)
return self.frequencies[symbol]
# Sets the frequency of the given symbol to the given value. The frequency value
# must be at least 0. If an exception is raised, then the state is left unchanged.
def set(self, symbol, freq):
self._check_symbol(symbol)
if freq < 0:
raise ValueError("Negative frequency")
temp = self.total - self.frequencies[symbol]
assert temp >= 0
self.total = temp + freq
self.frequencies[symbol] = freq
self.cumulative = None
# Increments the frequency of the given symbol.
def increment(self, symbol):
self._check_symbol(symbol)
self.total += 1
self.frequencies[symbol] += 1
self.cumulative = None
# Returns the total of all symbol frequencies. The returned value is at
# least 0 and is always equal to get_high(get_symbol_limit() - 1).
def get_total(self):
return self.total
# Returns the sum of the frequencies of all the symbols strictly
# below the given symbol value. The returned value is at least 0.
def get_low(self, symbol):
self._check_symbol(symbol)
if self.cumulative is None:
self._init_cumulative()
return self.cumulative[symbol]
# Returns the sum of the frequencies of the given symbol
# and all the symbols below. The returned value is at least 0.
def get_high(self, symbol):
self._check_symbol(symbol)
if self.cumulative is None:
self._init_cumulative()
return self.cumulative[symbol + 1]
# Recomputes the array of cumulative symbol frequencies.
def _init_cumulative(self):
cumul = [0]
sum = 0
for freq in self.frequencies:
sum += freq
cumul.append(sum)
assert sum == self.total
self.cumulative = cumul
# Returns silently if 0 <= symbol < len(frequencies), otherwise raises an exception.
def _check_symbol(self, symbol):
if 0 <= symbol < len(self.frequencies):
return
else:
raise ValueError("Symbol out of range")
# Returns a string representation of this frequency table,
# useful for debugging only, and the format is subject to change.
def __str__(self):
result = ""
for (i, freq) in enumerate(self.frequencies):
result += "{}\t{}\n".format(i, freq)
return result
# A wrapper that checks the preconditions (arguments) and postconditions (return value) of all
# the frequency table methods. Useful for finding faults in a frequency table implementation.
class CheckedFrequencyTable(FrequencyTable):
def __init__(self, freqtab):
# The underlying frequency table that holds the data
self.freqtable = freqtab
def get_symbol_limit(self):
result = self.freqtable.get_symbol_limit()
if result <= 0:
raise AssertionError("Non-positive symbol limit")
return result
def get(self, symbol):
result = self.freqtable.get(symbol)
if not self._is_symbol_in_range(symbol):
raise AssertionError("ValueError expected")
if result < 0:
raise AssertionError("Negative symbol frequency")
return result
def get_total(self):
result = self.freqtable.get_total()
if result < 0:
raise AssertionError("Negative total frequency")
return result
def get_low(self, symbol):
if self._is_symbol_in_range(symbol):
low = self.freqtable.get_low (symbol)
high = self.freqtable.get_high(symbol)
if not (0 <= low <= high <= self.freqtable.get_total()):
raise AssertionError("Symbol low cumulative frequency out of range")
return low
else:
self.freqtable.get_low(symbol)
raise AssertionError("ValueError expected")
def get_high(self, symbol):
if self._is_symbol_in_range(symbol):
low = self.freqtable.get_low (symbol)
high = self.freqtable.get_high(symbol)
if not (0 <= low <= high <= self.freqtable.get_total()):
raise AssertionError("Symbol high cumulative frequency out of range")
return high
else:
self.freqtable.get_high(symbol)
raise AssertionError("ValueError expected")
def __str__(self):
return "CheckFrequencyTable (" + str(self.freqtable) + ")"
def set(self, symbol, freq):
self.freqtable.set(symbol, freq)
if not self._is_symbol_in_range(symbol) or freq < 0:
raise AssertionError("ValueError expected")
def increment(self, symbol):
self.freqtable.increment(symbol)
if not self._is_symbol_in_range(symbol):
raise AssertionError("ValueError expected")
def _is_symbol_in_range(self, symbol):
return 0 <= symbol < self.get_symbol_limit()
# ---- Bit-oriented I/O streams ----
# A stream of bits that can be read. Because they come from an underlying byte stream,
# the total number of bits is always a multiple of 8. The bits are read in big endian.
class BitInputStream(object):
# Constructs a bit input stream based on the given byte input stream.
def __init__(self, inp):
# The underlying byte stream to read from
self.input = inp
# Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached
self.currentbyte = 0
# Number of remaining bits in the current byte, always between 0 and 7 (inclusive)
self.numbitsremaining = 0
# Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if
# the end of stream is reached. The end of stream always occurs on a byte boundary.
def read(self):
if self.currentbyte == -1:
return -1
if self.numbitsremaining == 0:
temp = self.input.read(1)
if len(temp) == 0:
self.currentbyte = -1
return -1
self.currentbyte = temp[0] if python3 else ord(temp)
self.numbitsremaining = 8
assert self.numbitsremaining > 0
self.numbitsremaining -= 1
return (self.currentbyte >> self.numbitsremaining) & 1
# Reads a bit from this stream. Returns 0 or 1 if a bit is available, or raises an EOFError
# if the end of stream is reached. The end of stream always occurs on a byte boundary.
def read_no_eof(self):
result = self.read()
if result != -1:
return result
else:
raise EOFError()
# Closes this stream and the underlying input stream.
def close(self):
self.input.close()
self.currentbyte = -1
self.numbitsremaining = 0
# A stream where bits can be written to. Because they are written to an underlying
# byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits.
# The bits are written in big endian.
class BitOutputStream(object):
# Constructs a bit output stream based on the given byte output stream.
def __init__(self, out):
self.output = out # The underlying byte stream to write to
self.currentbyte = 0 # The accumulated bits for the current byte, always in the range [0x00, 0xFF]
self.numbitsfilled = 0 # Number of accumulated bits in the current byte, always between 0 and 7 (inclusive)
# Writes a bit to the stream. The given bit must be 0 or 1.
def write(self, b):
if b not in (0, 1):
raise ValueError("Argument must be 0 or 1")
self.currentbyte = (self.currentbyte << 1) | b
self.numbitsfilled += 1
if self.numbitsfilled == 8:
towrite = bytes((self.currentbyte,)) if python3 else chr(self.currentbyte)
self.output.write(towrite)
self.currentbyte = 0
self.numbitsfilled = 0
# Closes this stream and the underlying output stream. If called when this
# bit stream is not at a byte boundary, then the minimum number of "0" bits
# (between 0 and 7 of them) are written as padding to reach the next byte boundary.
def close(self):
while self.numbitsfilled != 0:
self.write(0)
self.output.close()
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 76, "execution_count": 72,
"id": "dbef8759", "id": "dbef8759",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -16,14 +16,16 @@ ...@@ -16,14 +16,16 @@
"from scipy.optimize import minimize\n", "from scipy.optimize import minimize\n",
"from time import time\n", "from time import time\n",
"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, entropy\n",
"import seaborn as sns\n", "import seaborn as sns\n",
"import pywt" "import pywt\n",
"import math\n",
"#import cv2"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 15,
"id": "b7a550e0", "id": "b7a550e0",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -78,7 +80,7 @@ ...@@ -78,7 +80,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 16,
"id": "9ed20f84", "id": "9ed20f84",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -106,6 +108,7 @@ ...@@ -106,6 +108,7 @@
" y = np.vstack((y0,y1,y2))\n", " y = np.vstack((y0,y1,y2))\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 = []\n",
" # flatten the neighbor pixlels and stack them together\n", " # flatten the neighbor pixlels and stack them together\n",
" z0 = np.ravel(z0)\n", " z0 = np.ravel(z0)\n",
" z1 = np.ravel(z1)\n", " z1 = np.ravel(z1)\n",
...@@ -114,6 +117,15 @@ ...@@ -114,6 +117,15 @@
" neighbor = np.vstack((z0,z1,z2,z3)).T\n", " neighbor = np.vstack((z0,z1,z2,z3)).T\n",
" # calculate the difference\n", " # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\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", " # flatten the image to a vector\n",
" image_ravel = np.ravel(image[1:-1,1:-1])\n", " image_ravel = np.ravel(image[1:-1,1:-1])\n",
" return image_ravel, predict, diff, image" " return image_ravel, predict, diff, image"
...@@ -121,14 +133,14 @@ ...@@ -121,14 +133,14 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 17,
"id": "8e3ef654", "id": "8e3ef654",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"scenes = file_extractor()\n", "scenes = file_extractor()\n",
"images = image_extractor(scenes)\n", "images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\n", "num_images = im_distribution(images, \"_1\")\n",
"error_mean = []\n", "error_mean = []\n",
"error_mean1 = []\n", "error_mean1 = []\n",
"diff_mean = []\n", "diff_mean = []\n",
...@@ -156,7 +168,7 @@ ...@@ -156,7 +168,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 18,
"id": "fa65dcd6", "id": "fa65dcd6",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
...@@ -164,15 +176,15 @@ ...@@ -164,15 +176,15 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Average Error First and Second Added: 20.017164930235474\n", "Average Error: 19.44221679267325\n",
"Standard Deviaiton of Mean Errors: 0.16101183692475135\n", "Standard Deviaiton of Mean Errors: 0.17734010606906342\n",
"Average Difference: 53.678648426455226\n", "Average Difference: 51.95430150900486\n",
"Average Time per Image for First: 0.10891032218933105\n" "Average Time per Image for First: 0.04917508363723755\n"
] ]
} }
], ],
"source": [ "source": [
"print(f\"Average Error First and Second Added: {np.mean(error_mean)}\")\n", "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\"Standard Deviaiton of Mean Errors: {np.sqrt(np.var(error_mean))}\")\n",
"print(f\"Average Difference: {np.mean(diff_mean)}\")\n", "print(f\"Average Difference: {np.mean(diff_mean)}\")\n",
"print(f\"Average Time per Image for First: {np.mean(times)}\")" "print(f\"Average Time per Image for First: {np.mean(times)}\")"
...@@ -180,7 +192,7 @@ ...@@ -180,7 +192,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 19,
"id": "4c05b947", "id": "4c05b947",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
...@@ -190,13 +202,13 @@ ...@@ -190,13 +202,13 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 21,
"id": "dda442ae", "id": "dda442ae",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"image/png": "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\n", "image/png": "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\n",
"text/plain": [ "text/plain": [
"<Figure size 432x288 with 1 Axes>" "<Figure size 432x288 with 1 Axes>"
] ]
...@@ -208,7 +220,7 @@ ...@@ -208,7 +220,7 @@
} }
], ],
"source": [ "source": [
"new_error = np.abs(new_image-new_pred)\n", "new_error = new_image-new_pred\n",
"plt.hist(new_error, bins=20, density=True)\n", "plt.hist(new_error, bins=20, density=True)\n",
"sns.kdeplot(new_error)\n", "sns.kdeplot(new_error)\n",
"plt.xlabel(\"error\")\n", "plt.xlabel(\"error\")\n",
...@@ -217,58 +229,63 @@ ...@@ -217,58 +229,63 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 41,
"id": "58da6063", "id": "58da6063",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "name": "stdout",
"image/png": "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\n", "output_type": "stream",
"text/plain": [ "text": [
"<Figure size 432x288 with 1 Axes>" "Std Deviation of E: 26.627504708827136\n",
] "Normal bits: 15\n",
}, "Encoded Bits: 6.677845333316752\n"
"metadata": { ]
"needs_background": "light"
},
"output_type": "display_data"
} }
], ],
"source": [ "source": [
"plt.hist(new_image, bins=25, density=True)\n", "image = Image.open(images[0]) #Open the image and read it as an Image object\n",
"sns.kdeplot(new_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",
"plt.xlabel(\"Actual Pixel Value\")\n", "image = image.astype(np.int64)\n",
"plt.show()" "print(\"Std Deviation of E: \", np.std(new_error))\n",
"print(\"Normal bits: \", int(image[0][0]).bit_length())\n",
"H = np.log2(np.std(new_error)) + 1.943\n",
"print(\"Encoded Bits: \", H)"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 79, "execution_count": 47,
"id": "2562feeb", "id": "ec4db902",
"metadata": { "metadata": {},
"scrolled": false
},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"(512, 640)\n", "8192\n"
"1310832\n",
"9\n"
] ]
} }
], ],
"source": []
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2562feeb",
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [ "source": [
"f_r = no_ravel[0]\n", "pred = new_pred.reshape((510,638))\n",
"print(no_ravel.shape)\n", "real_pred = no_ravel.copy()\n",
"print(sys.getsizeof(no_ravel))\n", "real_pred[1:-1, 1:-1] = pred"
"print((256).bit_length())"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 99, "execution_count": 10,
"id": "470cc137", "id": "470cc137",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
...@@ -285,7 +302,7 @@ ...@@ -285,7 +302,7 @@
"'print(decompress)\\nprint(np.mean(np.abs(decompress-no_ravel)))'" "'print(decompress)\\nprint(np.mean(np.abs(decompress-no_ravel)))'"
] ]
}, },
"execution_count": 99, "execution_count": 10,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
...@@ -301,112 +318,201 @@ ...@@ -301,112 +318,201 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 59, "execution_count": null,
"id": "3292b395", "id": "3292b395",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [],
{ "source": []
"name": "stdout", },
"output_type": "stream", {
"text": [ "cell_type": "code",
"[72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 97, 109, 101, 32, 105, 115, 32, 83, 99, 111, 117, 116]\n", "execution_count": null,
"256\n", "id": "f9687830",
"71\n" "metadata": {},
] "outputs": [],
} "source": []
], },
{
"cell_type": "code",
"execution_count": 13,
"id": "e98eed4b",
"metadata": {},
"outputs": [],
"source": [ "source": [
"def compress(uncompressed):\n", "f = open(\"test.craw\", \"wb\")\n",
" \"\"\"Compress a string to a list of output symbols.\"\"\"\n", "f.write(real_pred.tobytes())\n",
" \n", "f.close()"
" # Build the dictionary.\n",
" dict_size = 256\n",
" dictionary = dict((chr(i), i) for i in range(dict_size))\n",
" # in Python 3: dictionary = {chr(i): i for i in range(dict_size)}\n",
"\n",
" w = \"\"\n",
" result = []\n",
" for c in uncompressed:\n",
" wc = w + c\n",
" if wc in dictionary:\n",
" w = wc\n",
" else:\n",
" result.append(dictionary[w])\n",
" # Add wc to the dictionary.\n",
" dictionary[wc] = dict_size\n",
" dict_size += 1\n",
" w = c\n",
" \n",
" # Output the code for w.\n",
" if w:\n",
" result.append(dictionary[w])\n",
" return result\n",
"\n",
"store = compress(\"Hello my name is Scout\")\n",
"print(store)\n",
"print(sys.getsizeof(store))\n",
"print(sys.getsizeof(\"Hello my name is Scout\"))"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 101, "execution_count": 12,
"id": "f9687830", "id": "b7e88aab",
"metadata": {},
"outputs": [],
"source": [
"# Apply arithmetic coding to compress it\n",
"import adaptive_arithmetic_compress\n",
"adaptive_arithmetic_compress.main([\"test.craw\", \"test.tiff\"])"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "7c8abaee",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "ValueError", "data": {
"evalue": "too many values to unpack (expected 2)", "text/plain": [
"output_type": "error", "'change = Image.open(\"test.tiff\")\\nchange = np.array(change)\\nprint(change.shape)'"
"traceback": [ ]
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", },
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "execution_count": 11,
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_22104/2202774112.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 18\u001b[0m \u001b[0mtimes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstop\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mstart\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 19\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mtimes\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 20\u001b[1;33m \u001b[0mti\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mwave_decompress\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcoef\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[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmean\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mti\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", "metadata": {},
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_22104/2202774112.py\u001b[0m in \u001b[0;36mwave_decompress\u001b[1;34m(coeffs)\u001b[0m\n\u001b[0;32m 14\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcoeffs\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[0;32m 15\u001b[0m \u001b[0mstart\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtime\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;32m---> 16\u001b[1;33m \u001b[0mdecompress\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpywt\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0midwt2\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcoeffs\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'bior1.3'\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 17\u001b[0m \u001b[0mstop\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtime\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 18\u001b[0m \u001b[0mtimes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstop\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mstart\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "output_type": "execute_result"
"\u001b[1;32m~\\anaconda3\\lib\\site-packages\\pywt\\_multidim.py\u001b[0m in \u001b[0;36midwt2\u001b[1;34m(coeffs, wavelet, mode, axes)\u001b[0m\n\u001b[0;32m 110\u001b[0m \"\"\"\n\u001b[0;32m 111\u001b[0m \u001b[1;31m# L -low-pass data, H - high-pass data\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 112\u001b[1;33m \u001b[0mLL\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mHL\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mLH\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mHH\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcoeffs\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 113\u001b[0m \u001b[0maxes\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maxes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 114\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maxes\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[1;36m2\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: too many values to unpack (expected 2)"
]
} }
], ],
"source": [ "source": [
"def wavelet(num_images, i): \n", "\"\"\"change = Image.open(\"test.tiff\")\n",
"\n", "change = np.array(change)\n",
" image = Image.open(num_images[i]) #Open the image and read it as an Image object\n", "print(change.shape)\"\"\""
" image = np.array(im)[1:,:]\n",
" coeffs = pywt.dwt2(image, 'bior1.3')\n",
" return coeffs\n",
"\n",
" \n",
"\n",
"coef, t = wavelet(num_images,0)\n",
"\n",
"def wave_decompress(coeffs):\n",
" times = []\n",
" for i in range(len(coeffs)):\n",
" start = time()\n",
" decompress = pywt.idwt2(coeffs[i], 'bior1.3')\n",
" stop = time()\n",
" times.append(stop-start)\n",
" return times\n",
"ti = wave_decompress(coef)\n",
"print(np.mean(ti))"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 114,
"id": "e98eed4b", "id": "82c20d94",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [] "source": [
"def compress(inputFile):#, outputFile):\n",
" twoBytes = 256*256\n",
" # Read the input file into a numpy array of 8-bit values\n",
" #\n",
" # The img.shape is a 3-type with rows,columns,channels, where\n",
" # channels is the number of components in each pixel. The img.dtype\n",
" # is 'uint8', meaning that each component is an 8-bit unsigned\n",
" # integer.\n",
"\n",
" #img = netpbm.imread(inputFile).astype('uint8')\n",
" img = Image.open(inputFile) #Open the image and read it as an Image object\n",
" img = np.array(img)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
" img = img.astype('uint8')\n",
"\n",
"\n",
" # Compress the image\n",
" #\n",
" #\n",
" # Note that single-channel images will have a 'shape' with only two\n",
" # components: the y dimensions and the x dimension. So you will\n",
" # have to detect this and set the number of channels accordingly.\n",
" # Furthermore, single-channel images must be indexed as img[y,x]\n",
" # instead of img[y,x,1]. You'll need two pieces of similar code:\n",
" # one piece for the single-channel case and one piece for the\n",
" # multi-channel case.\n",
"\n",
" #startTime = time.time()\n",
"\n",
" outputBytes = bytearray()\n",
"\n",
" # initialize dictionary\n",
" d = {}\n",
" counter = 256\n",
" for i in range(-counter, counter):\n",
" d[str(i)] = i\n",
" # Set Dictionary limit\n",
"\n",
" # Make a list to hold bytes\n",
" tempBytes = []\n",
" # A counter for the number of bytes\n",
" numBytes = 0\n",
" multichannel = False\n",
" \n",
" # for a single channel image\n",
" if (len(img.shape) == 2) :\n",
" multichannel = False\n",
" \n",
" # Go through whole image\n",
" for y in range(img.shape[0]):\n",
" for x in range(img.shape[1]):\n",
" # Initialize prediction to image value\n",
" prediction = img[y][x]\n",
" #\"\"\" \n",
" # Modify prediction to show the difference between prior pixels and current pixel\n",
" if(x != 0):\n",
" prediction = prediction - img[y][x-1]\n",
" elif(y != 0):\n",
" prediction = prediction - img[y-1][x]\n",
" else:\n",
" prediction = prediction - (img[y][x-1]/3 + img[y-1][x]/3 + img[y-1][x-1]/3)\n",
" #\"\"\"\n",
" # Add the predicted value to the bytestream\n",
" tempBytes.append(prediction)\n",
" numBytes += 1\n",
" # Using a string variable as it allows for concatenation\n",
" s = \"\"\n",
" # Set s to the first value of the bytestream \n",
" s = str(int(tempBytes[0]))\n",
" # Go through all bytes\n",
" for i in range(1, numBytes):\n",
" # Do LZW encoding\n",
" # If trying to add entry larger than max size of the dictionary reinitialize the dictionary\n",
" if(counter >= twoBytes):\n",
" counter = 256\n",
" d = {}\n",
" for i in range(-counter, counter):\n",
" d[str(i)] = i\n",
"\n",
" # Add the next byte to the current string. Uses a delimeter to distinguish numbers\n",
" w = s +\"|\"+str(int(tempBytes[i]))\n",
" # Checking if it has been seen before\n",
" if w in d:\n",
" s = w\n",
" else:\n",
" # Output bytes by splitting integer into two bytes, this allows for a larger dictionary\n",
" outputBytes.append((int(d[s]) >> 8) & 0xFF)\n",
" outputBytes.append(int(d[s]) & 0xFF)\n",
" # Add to dictionarry\n",
" d[w] = counter\n",
" counter += 1\n",
" s = str(int(tempBytes[i]))\n",
" # Check if the last byte was added or not \n",
" if s in d: \n",
" outputBytes.append((int(d[s]) >> 8) & 0xFF)\n",
" outputBytes.append(int(d[s]) & 0xFF) \n",
" return numBytes, outputBytes, tempBytes"
]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 123,
"id": "b7e88aab", "id": "9190b5a8",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
"source": [] {
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\calle\\AppData\\Local\\Temp/ipykernel_1700/265550185.py:56: RuntimeWarning: overflow encountered in ubyte_scalars\n",
" prediction = prediction - img[y][x-1]\n",
"C:\\Users\\calle\\AppData\\Local\\Temp/ipykernel_1700/265550185.py:58: RuntimeWarning: overflow encountered in ubyte_scalars\n",
" prediction = prediction - img[y-1][x]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"245\n"
]
}
],
"source": [
"test = images[0]\n",
"comp, out, temp = compress(test)\n",
"print(out[19])"
]
} }
], ],
"metadata": { "metadata": {
......
File added
test.tiff

635 KB

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