Commit cbba7336 authored by Nathaniel Callens's avatar Nathaniel Callens

compression try

parent 0bc96f0e
......@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 76,
"execution_count": 72,
"id": "dbef8759",
"metadata": {},
"outputs": [],
......@@ -16,14 +16,16 @@
"from scipy.optimize import minimize\n",
"from time import time\n",
"from numpy import linalg as la\n",
"from scipy.stats import gaussian_kde\n",
"from scipy.stats import gaussian_kde, entropy\n",
"import seaborn as sns\n",
"import pywt"
"import pywt\n",
"import math\n",
"#import cv2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 15,
"id": "b7a550e0",
"metadata": {},
"outputs": [],
......@@ -78,7 +80,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 16,
"id": "9ed20f84",
"metadata": {},
"outputs": [],
......@@ -106,6 +108,7 @@
" y = np.vstack((y0,y1,y2))\n",
" # use numpy solver to solve the system of equations all at once\n",
" predict = np.linalg.solve(A,y)[-1]\n",
" #predict = []\n",
" # flatten the neighbor pixlels and stack them together\n",
" z0 = np.ravel(z0)\n",
" z1 = np.ravel(z1)\n",
......@@ -114,6 +117,15 @@
" neighbor = np.vstack((z0,z1,z2,z3)).T\n",
" # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\n",
" \n",
" \"\"\"for i in range(len(neighbor)):\n",
" if neighbor[i][0] >= max(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(min(neighbor[i][3], neighbor[i][1]))\n",
" elif neighbor[i][0] < min(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(max(neighbor[i][3], neighbor[i][1]))\n",
" else:\n",
" predict.append(neighbor[i][3] + neighbor[i][1] - neighbor[i][0])\"\"\"\n",
" \n",
" # flatten the image to a vector\n",
" image_ravel = np.ravel(image[1:-1,1:-1])\n",
" return image_ravel, predict, diff, image"
......@@ -121,14 +133,14 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 17,
"id": "8e3ef654",
"metadata": {},
"outputs": [],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\n",
"num_images = im_distribution(images, \"_1\")\n",
"error_mean = []\n",
"error_mean1 = []\n",
"diff_mean = []\n",
......@@ -156,7 +168,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 18,
"id": "fa65dcd6",
"metadata": {},
"outputs": [
......@@ -164,15 +176,15 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Average Error First and Second Added: 20.017164930235474\n",
"Standard Deviaiton of Mean Errors: 0.16101183692475135\n",
"Average Difference: 53.678648426455226\n",
"Average Time per Image for First: 0.10891032218933105\n"
"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.04917508363723755\n"
]
}
],
"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\"Average Difference: {np.mean(diff_mean)}\")\n",
"print(f\"Average Time per Image for First: {np.mean(times)}\")"
......@@ -180,7 +192,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 19,
"id": "4c05b947",
"metadata": {},
"outputs": [],
......@@ -190,13 +202,13 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 21,
"id": "dda442ae",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAZQAAAEGCAYAAABCa2PoAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAArGElEQVR4nO3de5xcZZ3v+8+3OhcIEHKHXDrpBDqByEViCyjqjBecgEgcLyOIL9gOW04U5mydcTSjHl+z58w+m+3McUZGhgzOZiujB2QUNW7jIOAFLwQId0LSSedGmtw6CSSEkEt3/c4fazUUneru6k6tXtXd3/frVa+qWut5Vv1qpTu/ftbzrOdRRGBmZnasCnkHYGZmQ4MTipmZVYUTipmZVYUTipmZVYUTipmZVcWIvAMYCJMmTYqGhoa8wzAzG1QeffTRXRExudLywyKhNDQ0sHLlyrzDMDMbVCRt7kt5X/IyM7OqcEIxM7OqcEIxM7OqyDShSFooqVlSi6QlZfZL0k3p/qckLSjZd5uknZKeKVPvz9LjrpL01Sy/g5mZVSazhCKpDrgZuASYD1wpaX6XYpcAjenjOuCWkn3fAhaWOe47gUXAORHxBuDvqx68mZn1WZYtlPOBlojYEBGHgTtJEkGpRcDtkVgBjJM0FSAiHgD2lDnup4AbI+JQWm5nZt/AzMwqlmVCmQ5sKXnfmm7ra5mu5gJvl/SQpF9LevMxR2pmZscsy/tQVGZb17nyKynT1QhgPHAh8GbgLklzoss8/JKuI7mMxsyZMysK2GzQKRah4LE1Vhuy/ElsBepL3s8AtvajTLnj3p1eJnsYKAKTuhaKiFsjoikimiZPrvhGT7PB4eA++N+fhb+dDF+bD7//Rt4RmWWaUB4BGiXNljQKuAJY1qXMMuDqdLTXhcDeiNjWy3F/BLwLQNJcYBSwq6qRm9WyQy/Bv74HHv0WnPNRGN8AP/8ybH4w78hsmMssoUREO3ADcA+wGrgrIlZJWixpcVpsObABaAG+CXy6s76kO4AHgXmSWiVdm+66DZiTDie+E7im6+UusyFt+edh9zq46vvwgX+Gj90F42bCjz4Fhw/kHZ0NYxoO/xc3NTWF5/KyIaH5P+COj8IffAHe+cXXtm/4Fdy+CC79ezj/k7mFZ0OLpEcjoqnS8u7NMxtMVt4GJ02Dd3z+9dtn/wFMfxM8tDTpqDfLgROK2WCxfye03AfnfhTqugzQlOCCT8HuFlh/fz7x2bDnhGI2WDz9fYgOOOeK8vvnL4KTpsLD3xzYuMxSTihmg8WTd8C082DKGeX3jxgFb/ggbPglHNo/sLGZ4YRiNji8tB22P5W0Qnoy973QcRg2/npg4jIr4YRiNhhs/E3yPOcPey43860w6iRYe0/mIZl15YRiNhhs/DUcdzKcek7P5UaMgtPemSSUYXBLgNUWJxSzwWDjA9DwdijU9V527kLYvx22PZl9XGYlnFDMat0Lm+DFzTD7HZWVP+2dyfPm32UWklk5Tihmta6z/6TShDJ2GoybBZt/n11MZmU4oZjVuudXJv0nk7sZLlzOrLfCcyvcj2IDygnFrNZtfQKmnpvcDV+pmRfCgV3JnfNmA8QJxayWtR+Gnc/C1Df2rd7MtybPvuxlAyjLFRvN7FjtfDa5UXHaG4/a1bDkpz1UDB4dfRK//NH3+dy/H7X+HJtufF/1YjRLuYViVsu2PZE897WFglhZnEeTmqsckFn3nFDMatnWJ2D0yTBhTp+rPl48nYbCDsazr/pxmZXhhGJWy7Y9CVPP6VuHfOqJOB2Acwvrqx2VWVlOKGa1quMI7FhVtv+kEk8V59AR4jwnFBsgmSYUSQslNUtqkbSkzH5Juind/5SkBSX7bpO0M107vtyxPycpJB3d42g2FOxaBx2H4NRz+1X9AMexNuo5T+uqHJhZeZklFEl1wM3AJcB84EpJ87sUuwRoTB/XAbeU7PsWsLCbY9cDFwPPVTdqsxqy/enk+dSz+n2Ix4unc25hPcLLAlv2smyhnA+0RMSGiDgM3Al0XcxhEXB7JFYA4yRNBYiIB4A93Rz7H4DPA74N2Iau7U9B3WiY2NjvQzwep3OyDjBH26oYmFl5WSaU6cCWkvet6ba+lnkdSZcDz0dEj1OpSrpO0kpJK9va2iqP2qxW7HgGTpl/9PrxffBEMe2Yl/tRLHtZJpRyw1K6tigqKfNaYWkM8CXgK719eETcGhFNEdE0efLk3oqb1ZaI5JLXKf2/3AWwPqbxSoziDYXNVQrMrHtZ3infCtSXvJ8BbO1HmVKnAbOBJ5UMo5wBPCbp/IjYfswRmw2w7u52P4U9PHTcbr7ycIHbH+zpjvieFSnwbMzirMLGfh/DrFJZtlAeARolzZY0CrgCWNalzDLg6nS014XA3ojo9mJvRDwdEVMioiEiGkgS0gInExtqzkxbFM8WZx3zsZ4pNjBfm90xb5nLLKFERDtwA3APsBq4KyJWSVosaXFabDmwAWgBvgl8urO+pDuAB4F5klolXZtVrGa1Zr6ShLImZh7zsZ6J2ZykV5ilHcd8LLOeZDo5ZEQsJ0kapduWlrwO4Ppu6l5ZwfEbjjFEs5o0v/Acm4tT2M+YYz7Ws8UGAM7SJjbF1GM+nll3fKe8WQ06U5t5No79chfA2pjB4ajjrMKmqhzPrDtOKGY15ngOMlvbWV2F/hOAI4ygOeqZr01VOZ5Zd5xQzGrMGdpCQVG1FgrAqmID8z102DLmhGJWYzr/419dPPYO+U7rYgaTtI+J7K3aMc26ckIxqzFnajN7YwzPU715T9fGDADmFlqrdkyzrpxQzGrM/MLmdGRW39dA6c7aYpJQGuWEYtlxQjGrIaLIGdrC6ircf1JqB+PZF2OY64RiGXJCMash07WLMTpEc9T3XrhPRHPMoLHwfJWPa/YaJxSzGtI5zfyGYvVvQFxXnJG2ULzqg2XDCcWshryaUDK4o31tzGC89jPZI70sI04oZjVktraxL8awm7FVP3bnSK9Gj/SyjDihmNWQOdqWtk6qN8Kr07p0pJc75i0rTihmNWR2YXsml7sA2jiZF+JE5mpL74XN+sEJxaxGHMchZmhXJh3yCbE2ZjDXI70sI04oZjWiIV2vZGOGU8yv7RzpFR7pZdXnhGJWI+YoWf06q0tekHTMj9UBeKnbhVHN+s0JxaxGdA4Z3hSnZPYZ69KRXuxcndln2PCVaUKRtFBSs6QWSUvK7Jekm9L9T0laULLvNkk7JT3Tpc7fSVqTlv+hpHFZfgezgTK7sI3nYyKvcFxmn9E5pxdtazL7DBu+MksokuqAm4FLgPnAlZLmdyl2CdCYPq4DbinZ9y1gYZlD3wucFRHnAGuBv6pu5Gb5OE3b2Fg8NdPP2MNYdsVYt1AsE1m2UM4HWiJiQ0QcBu4EFnUpswi4PRIrgHGSpgJExAPAnq4HjYifR0R7+nYFMCOzb2A2YILZ2saGmJb5J60rznBCsUxkmVCmA6UD3lvTbX0t05M/BX5Wboek6yStlLSyra2tD4c0G3gT2cfJOsDGyLaFArA2pkNbs0d6WdVlmVDK3erb9Se4kjLlDy59CWgHvltuf0TcGhFNEdE0efLkSg5plpvZaYd8lkOGO7XEdDj8Ery0PfPPsuEly4TSCpTOwT0D2NqPMkeRdA1wGXBVhP/MssFvTiFJKOsHIKGs77ystntd5p9lw0uWCeURoFHSbEmjgCuAZV3KLAOuTkd7XQjsjYgeB8hLWgh8Abg8Ig5kEbjZQJuj7RyKETwf2bem1xfThLJrbeafZcNLZgkl7Ti/AbgHWA3cFRGrJC2WtDgtthzYALQA3wQ+3Vlf0h3Ag8A8Sa2Srk13fQM4CbhX0hOSlmb1HcwGyhxtZXOcQnEAbg3bwXgYdSLscgvFqmtElgePiOUkSaN029KS1wFc303dK7vZfno1YzSrBbOV3aSQRxNMPN0tFKs63ylvlrM6Opg1oAkFmDTXLRSrOicUs5xN1y5GqWPgE8reLXD45YH7TBvynFDMcvbqpJCZTVtfxqTG5Hl3y8B9pg15TihmOZuj5H6QgbgH5VWT5ibPvuxlVeSEYpazOdrKi3ECezhp4D50whxQwR3zVlVOKGY5m63taeuk+uvId2vkcTBulhOKVZUTilnO5hS2DWyHfCeP9LIqc0Ixy9EYDjJVewa2Q77TpMakU77YMfCfbUOSE4pZjmanHfK5tVDaDybDh82qwAnFLEcDOcvwUV4d6eWhw1YdTihmOZrzakLJfh2Uo7yaUNwxb9XhhGKWo9mFbbTGJA4xauA//ISJcPwEJxSrGicUsxzN0bZ8OuQ7TWr0SC+rGicUs7xEso58Lpe7Ok1qdAvFqsYJxSwv+3cyVq+woXMFxTxMmgsv74RXXsgvBhsynFDM8pJOzJhvC8Ujvax6nFDM8pKu6Z57CwV82cuqItOEImmhpGZJLZKWlNkvSTel+5+StKBk322Sdkp6pkudCZLulbQufR6f5Xcwy8zuFg7FSLbGxPxiGDcLCiOdUKwqMksokuqAm4FLgPnAlZLmdyl2CdCYPq4DbinZ9y1gYZlDLwHuj4hG4P70vdngs6uFTQO0jny36kbAxNM80suqIsuf5POBlojYEBGHgTuBRV3KLAJuj8QKYJykqQAR8QCwp8xxFwHfTl9/G/hAFsGbZW53Sz5TrnTlkV5WJVkmlOlA6SRBrem2vpbp6pSI2AaQPk8pV0jSdZJWSlrZ1tbWp8DNMtdxBF7YmM+UK11NmgsvbExiMjsGWSaUcos7RD/K9EtE3BoRTRHRNHny5Goc0qx6XnwOiu010kKZC8V2eGFT3pHYIJdlQmkF6kvezwC29qNMVzs6L4ulzzuPMU6zgdfWDMD6Yo4jvDp1ri/vy152jLJMKI8AjZJmSxoFXAEs61JmGXB1OtrrQmBv5+WsHiwDrklfXwP8uJpBmw2IXWlCyXPIcKeJaUJJk5xZf2WWUCKiHbgBuAdYDdwVEaskLZa0OC22HNgAtADfBD7dWV/SHcCDwDxJrZKuTXfdCFwsaR1wcfrebHDZtQ5OPIV9nJB3JHDcWDhhCuzZkHckNsiNyPLgEbGcJGmUblta8jqA67upe2U323cD765imGYDr605XYI370BSE+bAno15R2GDXEUtFEk/kPQ+Sb6z3uxYRST9FZPn5R3JaybMcQvFjlmlCeIW4GPAOkk3Sjojw5jMhraXtsOhfTCplhLKbHhpKxx5Je9IbBCrKKFExH0RcRWwANgE3Cvp95I+IWlklgGaDTmdo6kmz803jlIT5iTPHjpsx6DiS1iSJgL/CfjPwOPA10kSzL2ZRGY2VHUmlEm1lFBmJ8++7GXHoKJOeUl3A2cA/wa8v2Ro7/ckrcwqOLMhqa0ZRp0EJ00l+dusBnS2UJxQ7BhUOsrrX9MRW6+SNDoiDkVEUwZxmQ1du5qTy10qN1FETo4fD8eN80gvOyaVXvL62zLbHqxmIGbDxq51tdUh38kjvewY9dhCkXQqyWSNx0s6j9fm3hoLjMk4NrOh5+BeeGlbbXXId5owB1ofyTsKG8R6u+T1RyQd8TOAr5Vsfwn4YkYxmQ1dneuO1FKHfKcJc2DV3dB+GEaMyjsaG4R6TCgR8W3g25I+FBE/GKCYzIauzvmyavKS12yIIuzdkiy6ZdZHvV3y+nhEfAdokPTnXfdHxNfKVDOz7uxaC3WjYHxD3pEcrXSklxOK9UNvl7w6Z647MetAzIaFXWthwmnJ0ru1xkOH7Rj1dsnrX9Ln/zow4ZgNcW3NcOpZeUdR3gmTYdSJHjps/Vbp5JBflTRW0khJ90vaJenjWQdnNqS0H0qW2q3FDnlI7osZP9stFOu3Su9DeW9E7AMuI1llcS7wl5lFZTYU7dmQdHrXYod8pwlOKNZ/lV7I7ZwA8lLgjojYo1q6y9dsMHh1Dq/GfOMAGpb8tOz2L4wIrq3bwBlLfkKxm783N934vixDs0Gs0hbKTyStAZqA+yVNBg5mF5bZENSZUCaenm8cPdgUpzJKHUxld96h2CBU6fT1S4C3AE0RcQR4GVjUWz1JCyU1S2qRtKTMfkm6Kd3/lKQFvdWV9EZJKyQ9IWmlpPMr+Q5mudvVAmOnw+jaHTT5XEwBYFZhR86R2GDUl7GLZ5Lcj1Ja5/buCkuqA24mWfe9FXhE0rKIeLak2CVAY/q4gGQhrwt6qftV4L9GxM8kXZq+/8M+fA+zfOxeVxOXu3qyqXgqAA3awe+p0dFoVrMqnb7+34DTgCeAjnRz0ENCAc4HWiJiQ3qMO0laNaUJZRFwe7q2/ApJ4yRNBRp6qBskc4kBnAxsreQ7mOUqIpl25ZyP5h1Jj7YznkMxkgZtzzsUG4QqbaE0AfPT//grNR3YUvK+laQV0luZ6b3U/Qxwj6S/J7lk99ZyHy7pOuA6gJkzZ/YhbLMM7N+ZLvtb2y2UoMD6mEajWvMOxQahSjvlnwFO7eOxyw0D65qQuivTU91PAZ+NiHrgs8D/LPfhEXFrRDRFRNPkyZMrDNksI7s7J4Ws7YQCsCbqmVfY0ntBsy4qTSiTgGcl3SNpWeejlzqtQH3J+xkcfXmquzI91b0GuDt9/e8kl9bMaturI7xqP6GsLc5gmvYwlpfzDsUGmUovef11P479CNAoaTbwPHAF8LEuZZYBN6R9JBcAeyNim6S2HupuBf4A+BXwLmBdP2IzG1i7WmDE8ckorxq3JpK/5eZqCyvjjJyjscGkooQSEb+WNAtojIj7JI0B6nqp0y7pBuCetOxtEbFK0uJ0/1JgOcnNki3AAeATPdVND/1J4OvpaLODpP0kZjVt11qYdDoUKr0okJ+1xSShzCu0srLDCcUqV+kor0+S/Mc9gWS013RgKfDunuql69Av77JtacnrAK6vtG66/bfAmyqJ26xm7F4H0xb0Xq4GbGUi++J45sn9KNY3lf65dD1wEbAPICLWAVOyCspsSDlyEF58blB0yCfEWnfMWz9UmlAORcThzjfp5aa+DCE2G75enRSyRmcZLqO5WJ+2UPxrbpWrNKH8WtIXgeMlXUwyuuon2YVlNoR0Dhmu4Tm8umqOGYzTy0zhxbxDsUGk0oSyBGgDngb+D5K+jS9nFZTZkDIIJoXsqrmY3Ax8RuG5nCOxwaTSUV5FST8CfhQRbdmGZDbEDIJJIbtqjhkAzFUrD3BuztHYYNFjCyWdDfivJe0C1gDNktokfWVgwjMbAnavG1StE4AXOYkdMY4z3DFvfdDbJa/PkIzuenNETIyICSQ3IF4k6bNZB2c26HVOCjmIOuQ7NRfrmeuhw9YHvSWUq4ErI2Jj54Z0BuCPp/vMrCeDZFLIcpqjnrlqpUAx71BskOgtoYyMiF1dN6b9KCPLlDezUoNwhFentTGD43SEmfJiW1aZ3hLK4X7uMzMoWUd+8F3yWpOO9PId81ap3hLKuZL2lXm8BJw9EAGaDWqDaFLIrtbFdIohznBCsQr1OGw4InqcANLMEg1Lflp2+/8a+VtO0RQu/eLPBjiiY3eQ0WyOKcwtbHltnVazHtT+1Kdmg9gcbWN9TM07jH5rjpluoVjFnFDMMjKaw8xQGxtiWt6h9FtzzKBB2xntLlOrgBOKWUZmaQd1CtYXB3FCKdZTp+B0dV1s1exoTihmGZmjbQCD/JLXa6s3mvXGCcUsI6elf9VvHMQJZVOcyqEY4bVRrCKZJhRJCyU1S2qRtKTMfkm6Kd3/lKQFldSV9GfpvlWSvprldzDrrzmFrWyNCRzguLxD6bcO6lgf030vilWkotmG+0NSHXAzcDHQCjwiaVlEPFtS7BKgMX1cANwCXNBTXUnvBBYB50TEIUleOdJq0mnayobi4G2ddFoT9VxYeLb3gjbsZdlCOR9oiYgN6WqPd5IkglKLgNsjsQIYJ2lqL3U/BdwYEYcAImJnht/BrF9EkUY9z7p0GvjBbG1xBtO0h7G8nHcoVuOyTCjTgdJ2cmu6rZIyPdWdC7xd0kOSfi3pzeU+XNJ1klZKWtnW5iVcbGDNUBsn6BBrYmbeoRyzNe6YtwplmVBUZlvXBaq7K9NT3RHAeOBC4C+BuyQdVT4ibo2Ipohomjx5cuVRm1VB582Aa4tDoYWSJJR5hdacI7Fal1kfCkmror7k/Qyg62D27sqM6qFuK3B3RATwsKQiMIlkiWKzmjBXyX++a4fAJa+tTGRfHO+OeetVli2UR4BGSbMljQKuAJZ1KbMMuDod7XUhsDcitvVS90fAuwAkzSVJPkdNsW+WpzMKz/FccTIvc3zeoVSBWBv1HjpsvcqshRIR7ZJuAO4B6oDbImKVpMXp/qXAcuBSoAU4AHyip7rpoW8DbpP0DMkU+tekrRWzmjFPW2geAv0nnZqL9byvbgVHX7U2e02Wl7yIiOUkSaN029KS1wFcX2nddPthkhUjzWrSKI4wW9v5ebEp71CqZk3Uc5Xu5xReyDsUq2G+U96syuZoGyPVQXOxvvfCg8RrHfO+7GXdc0Ixq7Iz9BzAkBgy3Kk5HVzgjnnriROKWZWdXdjIKzGKDYN4Dq+uXuQkdsQ4Dx22HjmhmFXZWYWNPBuz6GBoLXjaXKxnXtr6MivHCcWsikSRN2gTTxdn5x1K1TVHPY16HopeD9jKc0Ixq6I52saJOsiqaMg7lKprjnqO0xHYszHvUKxGOaGYVdFZSv6zfbo4J+dIqu/VUWs7PfOwleeEYlZFZxc2cjBGsi66zoM6+K2L6RRDTijWLScUsyo6u7CR1UOwQx7gIKPZHFOcUKxbTihmVVJIO+SfGoId8p2aYybscEKx8pxQzKqkUa2cqIM8XmzMO5TMNMcM2LMejhzMOxSrQU4oZlVyXqEFgMfj9JwjyU5zsR6iCG1r8g7FapATilmVnKcW9sSJbI5T8g4lM89Eejlv6+P5BmI1yQnFrErOK6zjieLplF9wdGh4LqbA8eNh62N5h2I1yAnFrArG8jJzC8/zeHHoXu5KCKadB8+7hWJHc0Ixq4JzChsAeDyGbof8q6a/KRk6fPhA3pFYjXFCMauCNxeaKYZ4snha3qFkb9oCiA7Y/lTekViNyTShSFooqVlSi6QlZfZL0k3p/qckLehD3c9JCkmTsvwOZpW4oLCaVTGLlxiTdyjZm57+mj7/aL5xWM3JLKFIqgNuBi4B5gNXSprfpdglQGP6uA64pZK6kuqBiwHPpW35O3KQ89TCQ8Uz845kYJx0KoydDs+7Y95eL8sWyvlAS0RsSNeBvxNY1KXMIuD2SKwAxkmaWkHdfwA+D0SG8ZtV5vlHGa0jwyehAMxogi0P5R2F1ZgsE8p0oHS90NZ0WyVluq0r6XLg+Yh4stoBm/XL5t9RDPFw8Yy8Ixk4sy6CvVvghc15R2I1JMuEUm4wftcWRXdlym6XNAb4EvCVXj9cuk7SSkkr29raeg3WrN82/ZbmqGcvJ+YdycCZdVHyvPn3+cZhNSXLhNIK1Je8nwFsrbBMd9tPA2YDT0ralG5/TNKpXT88Im6NiKaIaJo8efIxfhWzbrQfhi0Ps2I4Xe4CmDI/ucFx82/zjsRqSJYJ5RGgUdJsSaOAK4BlXcosA65OR3tdCOyNiG3d1Y2IpyNiSkQ0REQDSeJZEBHbM/weZt3b+ji0vzL8EkqhADPfCpt+l3ckVkNGZHXgiGiXdANwD1AH3BYRqyQtTvcvBZYDlwItwAHgEz3VzSpWs35L/0IfVv0nnRouguafwr6tMHZa3tFYDcgsoQBExHKSpFG6bWnJ6wCur7RumTINxx6l2THY9DuYfCYvbBmbdyQDr+FtyfPGB+DcK/KNxWqC75Q366+O9mTobMNFeUeSj1POhhMmQ8t9eUdiNcIJxay/tj0Jh/e/NuJpuCkU4PT3QMv9UOzIOxqrAU4oZv216TfJ83BNKJAklFf2wNYn8o7EaoATill/bfglTHkDnDR0F9Tq1WnvAgQt9+YdidUAJxSz/jh8ADY/CKe9M+9I8jVmQjKdvftRDCcUs/557vfQccgJBaDxYmhdCQf25B2J5cwJxaw/1v8S6kYnN/cNd6e/BwhY/4u8I7GcOaGY9cf6X8Kst8CoYbD+SW+mnQfHT/BlL3NCMeuzF5+DnavgtHfnHUltKNQlnfMt90OxmHc0liMnFLO+WpNO4HDG+/KNo5Y0Xgwv7/SywMNcplOvmA1Ja/43TD4TJg6D9ePLaFjy06O2TaTII6PFP978T9zU8cGy9Tbd6AQ81LmFYtYXB/bA5t+5ddLFbk7msWjk4rqVeYdiOXJCMeuL5p9BFJ1QyrivYwFnFzZxKrvzDsVy4oRi1herfggn1ycjm+x17i2+CYD31D2WcySWFycUs0q9vDuZbuWsD4LKrVI9vK2PaWwonsrFhUfzDsVy4oRiVqnVP4ZiO5z14bwjqVHinuKbeWthFRPYl3cwlgMnFLNKPf0DmDQXTj0770hq1g873sZIdfD+ugfzDsVykGlCkbRQUrOkFklLyuyXpJvS/U9JWtBbXUl/J2lNWv6HksZl+R3MANjbmozuOuvDvtzVg7VRz6riLP647jd5h2I5yCyhSKoDbgYuAeYDV0qa36XYJUBj+rgOuKWCuvcCZ0XEOcBa4K+y+g5mr3riDiDg3I/mHUnNu7vjbbyxsIHT9HzeodgAy7KFcj7QEhEbIuIwcCewqEuZRcDtkVgBjJM0tae6EfHziGhP668AZmT4HcyS6USe+A40vB3GN+QdTc1b1nERR6KOj9d5bq/hJss75acDW0retwIXVFBmeoV1Af4U+N4xR2pG+TvAAS7Qar43ehOf2XEpP+qmjL2mjXH8uHgRH637FV9v/yAvclLeIdkAybKFUu5Cc1RYpte6kr4EtAPfLfvh0nWSVkpa2dbWVkG4ZuVdMeIX7Ivj+Y/im/MOZdD4l/bLGKNDXF3nlRyHkywTSitQX/J+BrC1wjI91pV0DXAZcFVEdE1SAETErRHRFBFNkydP7veXsOFtMi/yvsIKftDxDg4yOu9wBo11MYP7Os7jmhH3cByH8g7HBkiWCeURoFHSbEmjgCuAZV3KLAOuTkd7XQjsjYhtPdWVtBD4AnB5RBzIMH4zPlZ3P6PUwe0d7807lEFnafv7maiX+JO6X+Udig2QzBJK2nF+A3APsBq4KyJWSVosaXFabDmwAWgBvgl8uqe6aZ1vACcB90p6QtLSrL6DDW+jOMJVI+7nlx3nsjGm5h3OoLMy5vFosZFP1i2njo68w7EBkOn09RGxnCRplG5bWvI6gOsrrZtuP73KYZqV9ZG6XzNFL/IXHYt7L2xliKXt7+ebo77GZYUHgcvzDsgy5jvlzcoYxRE+PeLHPFps5DdF3xnfX/cVF7CmWM//OeKH0NHeewUb1JxQzMr4k7pfMV27+cf2D1F+0KFVIijwD+0f5rTCNnj6rrzDsYw5oZh1MYF9/MWIf+eh4hlunVTBPcUmni42wK/+Oxw5mHc4liEnFLMuvjzyO5zAK3zpyJ/i1kk1iBvbr4QXn4MH/ynvYCxDTihmJd5ZeJwP1v2WpR3vpyU8q0+1/K54Npx5OTzw/yaJxYYkJxSz1Hj28dWRt7K6WM832v8473CGnj/6f5KZmn/yX5L50WzIcUIxA4jgv428jZPZz58f+TSHGZl3REPPuHp47/8N638BD9+adzSWAScUM4CnvseldQ/ztfaPsDpm5R3N0NV0LcxdCPd+BTZ7Ea6hxgnFbM9GWP6XPFycx60dl+UdzdAmwQduSVord14Ju9blHZFVkROKDW+vvAD/359AoY6/OLKYon8lsjdmAlz1fSiMgO98CPbvzDsiqxL/9tjw1X4Y7ro6aaF89LtsiVPyjmj4mDAbPvY9eLkNvvsROPRS3hFZFTih2PAUAT/9LGx8AC7/J2i4KO+Ihp/pb4IP/y/Y/jTccSUceSXviOwYZTo5pFlNKhbhni/C49+Bd3we3nhl3hENC92tiHl5YTH/uPGf+f3fvJvFRz7LfsYcVWbTje/LOjyrArdQbHg5sAd+cC08dAtc8Cl45xfzjmjYW1a8iL84spgLC6u5c9TfMh2vsDpYOaHY8LB/J/z67+AbTbB6Gbzr/4KF/z0ZdWS5+2Hx7fznI59jlnbw09Ff5H2FFRy9YrjVOnWzgu6Q0tTUFCtXrsw7DBsAr7+sEizQOq4e8XMuLTzEKHXwQMfZ/Lf2q2iOmbnFaN2bqR18Y+RNnFPYyAMdZ/OP7R/isWhk040ezp0HSY9GRFOl5d2HYkPOGA5yWd2DXF13L2cVNrEvjuc7HRfznY73sCGm5R2e9eC5OIU/Pvw3fLzuPj474vvcPfqvWV2sh188AfMugannQcEXVmqVWyg2NLzyIqz/Bcu/dwvvKjzOcTrC6mI9/9bxXn7UcREHOC7vCK2PjucgH6r7De+ve5AL6tZCFOHEU2HeQpj9BzDrIjjJQ72z1NcWSqYJRdJC4OtAHfCvEXFjl/1K918KHAD+U0Q81lNdSROA7wENwCbgTyLihZ7icEIZItoPJX0h+3fC/u2wbyvsXA3PrYCdzwLBzhjH8o7z+UnHW3g05uLp54eGTV95C6z7OTQvh5b74fD+ZMfE02HWW6H+ApgyH8ZOg+PHw4jR+QY8RNRMQpFUB6wFLgZagUeAKyPi2ZIylwJ/RpJQLgC+HhEX9FRX0leBPRFxo6QlwPiI+EJPsQzahFL6b/Pq6z5ue92/70BsKxN7sR3aX0kWVzpyANrT5yMHk3sPut13AA6/DHtbkynP928/+nNGnQj158PMt0DD25hzy27f7T7EjaCdN2gT5xfWvPo4WQdeV+ZAjOZFTmBvnMiZc2YlSabcY9SY5I79wsjkuW5Ez+8LdclADhUAdXldKL9vEA/8qKU+lPOBlojYACDpTmAR8GxJmUXA7ZFktRWSxkmaStL66K7uIuAP0/rfBn4F9JhQ+u0/vgiPfos+/yd+rNuGuUMxkoOM5BVGcyBGsy0m0hpn8Hy8jR2Mpy1Opi3GsT0msOvgWGJVAVYBvIAHLg597YzgyTidJztO55sdlyGKzNZ2GtXKJO3jZPYzTi8zjv2M0372bWhjPBsYp5c5mf2MVh5r26cJpvT5dbu7Jp0q7r/iO3Dau/oUbX9lmVCmA1tK3reStEJ6KzO9l7qnRMQ2gIjYJmlKuQ+XdB1wXfp2v6Tm/nyJDE0CduUdRI3zOarMsD9Pm4Bf9lxk+J6jL7+7L6W7nqc+Tb2dZUIp187r+md4d2UqqdujiLgVqNlFFySt7EtTcjjyOaqMz1PvfI4qc6znKcvrA61Afcn7GcDWCsv0VHdHelmM9NlTlZqZ1YAsE8ojQKOk2ZJGAVcAy7qUWQZcrcSFwN70clZPdZcB16SvrwF+nOF3MDOzCmV2ySsi2iXdANxDMvT3tohYJWlxun8psJxkhFcLybDhT/RUNz30jcBdkq4FngM+ktV3yFjNXo6rIT5HlfF56p3PUWWO6TwNixsbzcwsex5jaWZmVeGEYmZmVeGEkjFJfydpjaSnJP1Q0riSfX8lqUVSs6Q/Ktn+JklPp/tuSqeoGdIkfUTSKklFSU1d9vk8lSFpYXpOWtJZI4YtSbdJ2inpmZJtEyTdK2ld+jy+ZF/Zn6mhTFK9pF9KWp3+rv2XdHv1zlNE+JHhA3gvMCJ9/T+A/5G+ng88CYwGZgPrgbp038PAW0jux/kZcEne32MAztOZwDySmQ+aSrb7PJU/X3XpuZgDjErP0fy848rxfLwDWAA8U7Ltq8CS9PWSSn73hvIDmAosSF+fRDK91fxqnie3UDIWET+PiM65HlaQ3FMDyRQyd0bEoYjYSDLS7fz03pqxEfFgJP+qtwMfGOi4B1pErI6IcrMZ+DyV9+rURhFxGOicnmhYiogHgD1dNi8imZ6J9PkDJduP+pkaiDjzFBHbIp18NyJeAlaTzEpStfPkhDKw/pTkL2noedqZ1jLbhyufp/K6Oy/2mtdN0wR0TtM07M+dpAbgPOAhqnievMBWFUi6Dzi1zK4vRcSP0zJfAtqB73ZWK1O+KtPO1KpKzlO5amW2DenzVKHh/v2PxbA+d5JOBH4AfCYi9vXQ9djn8+SEUgUR8Z6e9ku6BrgMeHd6eQZ6nnZmRpntg15v56kbw+48VaiSqY2Gux2SpkYyiWzpNE3D9txJGkmSTL4bEXenm6t2nnzJK2PpQmFfAC6PiNJFG5YBV0gaLWk20Ag8nDY5X5J0YTpq6WqG9/QyPk/lVTK10XDX3TRNZX+mcohvQKW/J/8TWB0RXyvZVb3zlPfIg6H+IOnI2gI8kT6Wluz7EsnIiWZKRigBTcAz6b5vkM5oMJQfwB+T/EV0CNgB3OPz1Os5u5RkpM56ksuGuceU47m4A9gGHEl/jq4FJgL3A+vS5wm9/UwN5QfwNpJLVk+V/H90aTXPk6deMTOzqvAlLzMzqwonFDMzqwonFDMzqwonFDMzqwonFDMzqwonFDMzqwonFLMcSKrr6X03dSTJv7NWs/zDaZYBSR+X9LCkJyT9i6Q6Sfsl/Y2kh4C3lHn/55KeSR+fSY/TkK5f8c/AY7x+KgyzmuKEYlZlks4EPgpcFBFvBDqAq4ATSNbruCAiflv6HngF+ARwAXAh8ElJ56WHnAfcHhHnRcTmgf02ZpXz5JBm1fdu4E3AI+lMrseTTLjXQTIxX6fS928DfhgRLwNIuht4O8l8SpsjYsXAhG7Wf04oZtUn4NsR8Vev2yh9LiI6SjYdLHnf0/LFL1c7QLMs+JKXWfXdD3xY0hR4dc3uWb3UeQD4gKQxkk4gmSzzNxnHaVZVbqGYVVlEPCvpy8DP01FZR4Dre6nzmKRv8dr04P8aEY+nK+uZDQqebdjMzKrCl7zMzKwqnFDMzKwqnFDMzKwqnFDMzKwqnFDMzKwqnFDMzKwqnFDMzKwq/n9a38AEPPLXOgAAAABJRU5ErkJggg==\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
......@@ -208,7 +220,7 @@
}
],
"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",
"sns.kdeplot(new_error)\n",
"plt.xlabel(\"error\")\n",
......@@ -217,58 +229,63 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 41,
"id": "58da6063",
"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": [
"Std Deviation of E: 26.627504708827136\n",
"Normal bits: 15\n",
"Encoded Bits: 6.677845333316752\n"
]
}
],
"source": [
"plt.hist(new_image, bins=25, density=True)\n",
"sns.kdeplot(new_image)\n",
"plt.xlabel(\"Actual Pixel Value\")\n",
"plt.show()"
"image = Image.open(images[0]) #Open the image and read it as an Image object\n",
"image = np.array(image)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
"image = image.astype(np.int64)\n",
"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",
"execution_count": 79,
"id": "2562feeb",
"metadata": {
"scrolled": false
},
"execution_count": 47,
"id": "ec4db902",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(512, 640)\n",
"1310832\n",
"9\n"
"8192\n"
]
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2562feeb",
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"f_r = no_ravel[0]\n",
"print(no_ravel.shape)\n",
"print(sys.getsizeof(no_ravel))\n",
"print((256).bit_length())"
"pred = new_pred.reshape((510,638))\n",
"real_pred = no_ravel.copy()\n",
"real_pred[1:-1, 1:-1] = pred"
]
},
{
"cell_type": "code",
"execution_count": 99,
"execution_count": 10,
"id": "470cc137",
"metadata": {},
"outputs": [
......@@ -285,7 +302,7 @@
"'print(decompress)\\nprint(np.mean(np.abs(decompress-no_ravel)))'"
]
},
"execution_count": 99,
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
......@@ -301,112 +318,201 @@
},
{
"cell_type": "code",
"execution_count": 59,
"execution_count": null,
"id": "3292b395",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 97, 109, 101, 32, 105, 115, 32, 83, 99, 111, 117, 116]\n",
"256\n",
"71\n"
]
}
],
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "f9687830",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 13,
"id": "e98eed4b",
"metadata": {},
"outputs": [],
"source": [
"def compress(uncompressed):\n",
" \"\"\"Compress a string to a list of output symbols.\"\"\"\n",
" \n",
" # 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\"))"
"f = open(\"test.craw\", \"wb\")\n",
"f.write(real_pred.tobytes())\n",
"f.close()"
]
},
{
"cell_type": "code",
"execution_count": 101,
"id": "f9687830",
"execution_count": 12,
"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": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "too many values to unpack (expected 2)",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_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",
"\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",
"\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)"
]
"data": {
"text/plain": [
"'change = Image.open(\"test.tiff\")\\nchange = np.array(change)\\nprint(change.shape)'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def wavelet(num_images, i): \n",
"\n",
" image = Image.open(num_images[i]) #Open the image and read it as an Image object\n",
" 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))"
"\"\"\"change = Image.open(\"test.tiff\")\n",
"change = np.array(change)\n",
"print(change.shape)\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e98eed4b",
"execution_count": 114,
"id": "82c20d94",
"metadata": {},
"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",
"execution_count": null,
"id": "b7e88aab",
"execution_count": 123,
"id": "9190b5a8",
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"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": {
......
#
# 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 @@
"cells": [
{
"cell_type": "code",
"execution_count": 76,
"execution_count": 72,
"id": "dbef8759",
"metadata": {},
"outputs": [],
......@@ -16,14 +16,16 @@
"from scipy.optimize import minimize\n",
"from time import time\n",
"from numpy import linalg as la\n",
"from scipy.stats import gaussian_kde\n",
"from scipy.stats import gaussian_kde, entropy\n",
"import seaborn as sns\n",
"import pywt"
"import pywt\n",
"import math\n",
"#import cv2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 15,
"id": "b7a550e0",
"metadata": {},
"outputs": [],
......@@ -78,7 +80,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 16,
"id": "9ed20f84",
"metadata": {},
"outputs": [],
......@@ -106,6 +108,7 @@
" y = np.vstack((y0,y1,y2))\n",
" # use numpy solver to solve the system of equations all at once\n",
" predict = np.linalg.solve(A,y)[-1]\n",
" #predict = []\n",
" # flatten the neighbor pixlels and stack them together\n",
" z0 = np.ravel(z0)\n",
" z1 = np.ravel(z1)\n",
......@@ -114,6 +117,15 @@
" neighbor = np.vstack((z0,z1,z2,z3)).T\n",
" # calculate the difference\n",
" diff = np.max(neighbor,axis = 1) - np.min(neighbor, axis=1)\n",
" \n",
" \"\"\"for i in range(len(neighbor)):\n",
" if neighbor[i][0] >= max(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(min(neighbor[i][3], neighbor[i][1]))\n",
" elif neighbor[i][0] < min(neighbor[i][3], neighbor[i][1]):\n",
" predict.append(max(neighbor[i][3], neighbor[i][1]))\n",
" else:\n",
" predict.append(neighbor[i][3] + neighbor[i][1] - neighbor[i][0])\"\"\"\n",
" \n",
" # flatten the image to a vector\n",
" image_ravel = np.ravel(image[1:-1,1:-1])\n",
" return image_ravel, predict, diff, image"
......@@ -121,14 +133,14 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 17,
"id": "8e3ef654",
"metadata": {},
"outputs": [],
"source": [
"scenes = file_extractor()\n",
"images = image_extractor(scenes)\n",
"num_images = im_distribution(images, \"_9\")\n",
"num_images = im_distribution(images, \"_1\")\n",
"error_mean = []\n",
"error_mean1 = []\n",
"diff_mean = []\n",
......@@ -156,7 +168,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 18,
"id": "fa65dcd6",
"metadata": {},
"outputs": [
......@@ -164,15 +176,15 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Average Error First and Second Added: 20.017164930235474\n",
"Standard Deviaiton of Mean Errors: 0.16101183692475135\n",
"Average Difference: 53.678648426455226\n",
"Average Time per Image for First: 0.10891032218933105\n"
"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.04917508363723755\n"
]
}
],
"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\"Average Difference: {np.mean(diff_mean)}\")\n",
"print(f\"Average Time per Image for First: {np.mean(times)}\")"
......@@ -180,7 +192,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 19,
"id": "4c05b947",
"metadata": {},
"outputs": [],
......@@ -190,13 +202,13 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 21,
"id": "dda442ae",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAZQAAAEGCAYAAABCa2PoAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAArGElEQVR4nO3de5xcZZ3v+8+3OhcIEHKHXDrpBDqByEViCyjqjBecgEgcLyOIL9gOW04U5mydcTSjHl+z58w+m+3McUZGhgzOZiujB2QUNW7jIOAFLwQId0LSSedGmtw6CSSEkEt3/c4fazUUneru6k6tXtXd3/frVa+qWut5Vv1qpTu/ftbzrOdRRGBmZnasCnkHYGZmQ4MTipmZVYUTipmZVYUTipmZVYUTipmZVcWIvAMYCJMmTYqGhoa8wzAzG1QeffTRXRExudLywyKhNDQ0sHLlyrzDMDMbVCRt7kt5X/IyM7OqcEIxM7OqcEIxM7OqyDShSFooqVlSi6QlZfZL0k3p/qckLSjZd5uknZKeKVPvz9LjrpL01Sy/g5mZVSazhCKpDrgZuASYD1wpaX6XYpcAjenjOuCWkn3fAhaWOe47gUXAORHxBuDvqx68mZn1WZYtlPOBlojYEBGHgTtJEkGpRcDtkVgBjJM0FSAiHgD2lDnup4AbI+JQWm5nZt/AzMwqlmVCmQ5sKXnfmm7ra5mu5gJvl/SQpF9LevMxR2pmZscsy/tQVGZb17nyKynT1QhgPHAh8GbgLklzoss8/JKuI7mMxsyZMysK2GzQKRah4LE1Vhuy/ElsBepL3s8AtvajTLnj3p1eJnsYKAKTuhaKiFsjoikimiZPrvhGT7PB4eA++N+fhb+dDF+bD7//Rt4RmWWaUB4BGiXNljQKuAJY1qXMMuDqdLTXhcDeiNjWy3F/BLwLQNJcYBSwq6qRm9WyQy/Bv74HHv0WnPNRGN8AP/8ybH4w78hsmMssoUREO3ADcA+wGrgrIlZJWixpcVpsObABaAG+CXy6s76kO4AHgXmSWiVdm+66DZiTDie+E7im6+UusyFt+edh9zq46vvwgX+Gj90F42bCjz4Fhw/kHZ0NYxoO/xc3NTWF5/KyIaH5P+COj8IffAHe+cXXtm/4Fdy+CC79ezj/k7mFZ0OLpEcjoqnS8u7NMxtMVt4GJ02Dd3z+9dtn/wFMfxM8tDTpqDfLgROK2WCxfye03AfnfhTqugzQlOCCT8HuFlh/fz7x2bDnhGI2WDz9fYgOOOeK8vvnL4KTpsLD3xzYuMxSTihmg8WTd8C082DKGeX3jxgFb/ggbPglHNo/sLGZ4YRiNji8tB22P5W0Qnoy973QcRg2/npg4jIr4YRiNhhs/E3yPOcPey43860w6iRYe0/mIZl15YRiNhhs/DUcdzKcek7P5UaMgtPemSSUYXBLgNUWJxSzwWDjA9DwdijU9V527kLYvx22PZl9XGYlnFDMat0Lm+DFzTD7HZWVP+2dyfPm32UWklk5Tihmta6z/6TShDJ2GoybBZt/n11MZmU4oZjVuudXJv0nk7sZLlzOrLfCcyvcj2IDygnFrNZtfQKmnpvcDV+pmRfCgV3JnfNmA8QJxayWtR+Gnc/C1Df2rd7MtybPvuxlAyjLFRvN7FjtfDa5UXHaG4/a1bDkpz1UDB4dfRK//NH3+dy/H7X+HJtufF/1YjRLuYViVsu2PZE897WFglhZnEeTmqsckFn3nFDMatnWJ2D0yTBhTp+rPl48nYbCDsazr/pxmZXhhGJWy7Y9CVPP6VuHfOqJOB2Acwvrqx2VWVlOKGa1quMI7FhVtv+kEk8V59AR4jwnFBsgmSYUSQslNUtqkbSkzH5Juind/5SkBSX7bpO0M107vtyxPycpJB3d42g2FOxaBx2H4NRz+1X9AMexNuo5T+uqHJhZeZklFEl1wM3AJcB84EpJ87sUuwRoTB/XAbeU7PsWsLCbY9cDFwPPVTdqsxqy/enk+dSz+n2Ix4unc25hPcLLAlv2smyhnA+0RMSGiDgM3Al0XcxhEXB7JFYA4yRNBYiIB4A93Rz7H4DPA74N2Iau7U9B3WiY2NjvQzwep3OyDjBH26oYmFl5WSaU6cCWkvet6ba+lnkdSZcDz0dEj1OpSrpO0kpJK9va2iqP2qxW7HgGTpl/9PrxffBEMe2Yl/tRLHtZJpRyw1K6tigqKfNaYWkM8CXgK719eETcGhFNEdE0efLk3oqb1ZaI5JLXKf2/3AWwPqbxSoziDYXNVQrMrHtZ3infCtSXvJ8BbO1HmVKnAbOBJ5UMo5wBPCbp/IjYfswRmw2w7u52P4U9PHTcbr7ycIHbH+zpjvieFSnwbMzirMLGfh/DrFJZtlAeARolzZY0CrgCWNalzDLg6nS014XA3ojo9mJvRDwdEVMioiEiGkgS0gInExtqzkxbFM8WZx3zsZ4pNjBfm90xb5nLLKFERDtwA3APsBq4KyJWSVosaXFabDmwAWgBvgl8urO+pDuAB4F5klolXZtVrGa1Zr6ShLImZh7zsZ6J2ZykV5ilHcd8LLOeZDo5ZEQsJ0kapduWlrwO4Ppu6l5ZwfEbjjFEs5o0v/Acm4tT2M+YYz7Ws8UGAM7SJjbF1GM+nll3fKe8WQ06U5t5No79chfA2pjB4ajjrMKmqhzPrDtOKGY15ngOMlvbWV2F/hOAI4ygOeqZr01VOZ5Zd5xQzGrMGdpCQVG1FgrAqmID8z102DLmhGJWYzr/419dPPYO+U7rYgaTtI+J7K3aMc26ckIxqzFnajN7YwzPU715T9fGDADmFlqrdkyzrpxQzGrM/MLmdGRW39dA6c7aYpJQGuWEYtlxQjGrIaLIGdrC6ircf1JqB+PZF2OY64RiGXJCMash07WLMTpEc9T3XrhPRHPMoLHwfJWPa/YaJxSzGtI5zfyGYvVvQFxXnJG2ULzqg2XDCcWshryaUDK4o31tzGC89jPZI70sI04oZjVktraxL8awm7FVP3bnSK9Gj/SyjDihmNWQOdqWtk6qN8Kr07p0pJc75i0rTihmNWR2YXsml7sA2jiZF+JE5mpL74XN+sEJxaxGHMchZmhXJh3yCbE2ZjDXI70sI04oZjWiIV2vZGOGU8yv7RzpFR7pZdXnhGJWI+YoWf06q0tekHTMj9UBeKnbhVHN+s0JxaxGdA4Z3hSnZPYZ69KRXuxcndln2PCVaUKRtFBSs6QWSUvK7Jekm9L9T0laULLvNkk7JT3Tpc7fSVqTlv+hpHFZfgezgTK7sI3nYyKvcFxmn9E5pxdtazL7DBu+MksokuqAm4FLgPnAlZLmdyl2CdCYPq4DbinZ9y1gYZlD3wucFRHnAGuBv6pu5Gb5OE3b2Fg8NdPP2MNYdsVYt1AsE1m2UM4HWiJiQ0QcBu4EFnUpswi4PRIrgHGSpgJExAPAnq4HjYifR0R7+nYFMCOzb2A2YILZ2saGmJb5J60rznBCsUxkmVCmA6UD3lvTbX0t05M/BX5Wboek6yStlLSyra2tD4c0G3gT2cfJOsDGyLaFArA2pkNbs0d6WdVlmVDK3erb9Se4kjLlDy59CWgHvltuf0TcGhFNEdE0efLkSg5plpvZaYd8lkOGO7XEdDj8Ery0PfPPsuEly4TSCpTOwT0D2NqPMkeRdA1wGXBVhP/MssFvTiFJKOsHIKGs77ystntd5p9lw0uWCeURoFHSbEmjgCuAZV3KLAOuTkd7XQjsjYgeB8hLWgh8Abg8Ig5kEbjZQJuj7RyKETwf2bem1xfThLJrbeafZcNLZgkl7Ti/AbgHWA3cFRGrJC2WtDgtthzYALQA3wQ+3Vlf0h3Ag8A8Sa2Srk13fQM4CbhX0hOSlmb1HcwGyhxtZXOcQnEAbg3bwXgYdSLscgvFqmtElgePiOUkSaN029KS1wFc303dK7vZfno1YzSrBbOV3aSQRxNMPN0tFKs63ylvlrM6Opg1oAkFmDTXLRSrOicUs5xN1y5GqWPgE8reLXD45YH7TBvynFDMcvbqpJCZTVtfxqTG5Hl3y8B9pg15TihmOZuj5H6QgbgH5VWT5ibPvuxlVeSEYpazOdrKi3ECezhp4D50whxQwR3zVlVOKGY5m63taeuk+uvId2vkcTBulhOKVZUTilnO5hS2DWyHfCeP9LIqc0Ixy9EYDjJVewa2Q77TpMakU77YMfCfbUOSE4pZjmanHfK5tVDaDybDh82qwAnFLEcDOcvwUV4d6eWhw1YdTihmOZrzakLJfh2Uo7yaUNwxb9XhhGKWo9mFbbTGJA4xauA//ISJcPwEJxSrGicUsxzN0bZ8OuQ7TWr0SC+rGicUs7xEso58Lpe7Ok1qdAvFqsYJxSwv+3cyVq+woXMFxTxMmgsv74RXXsgvBhsynFDM8pJOzJhvC8Ujvax6nFDM8pKu6Z57CwV82cuqItOEImmhpGZJLZKWlNkvSTel+5+StKBk322Sdkp6pkudCZLulbQufR6f5Xcwy8zuFg7FSLbGxPxiGDcLCiOdUKwqMksokuqAm4FLgPnAlZLmdyl2CdCYPq4DbinZ9y1gYZlDLwHuj4hG4P70vdngs6uFTQO0jny36kbAxNM80suqIsuf5POBlojYEBGHgTuBRV3KLAJuj8QKYJykqQAR8QCwp8xxFwHfTl9/G/hAFsGbZW53Sz5TrnTlkV5WJVkmlOlA6SRBrem2vpbp6pSI2AaQPk8pV0jSdZJWSlrZ1tbWp8DNMtdxBF7YmM+UK11NmgsvbExiMjsGWSaUcos7RD/K9EtE3BoRTRHRNHny5Goc0qx6XnwOiu010kKZC8V2eGFT3pHYIJdlQmkF6kvezwC29qNMVzs6L4ulzzuPMU6zgdfWDMD6Yo4jvDp1ri/vy152jLJMKI8AjZJmSxoFXAEs61JmGXB1OtrrQmBv5+WsHiwDrklfXwP8uJpBmw2IXWlCyXPIcKeJaUJJk5xZf2WWUCKiHbgBuAdYDdwVEaskLZa0OC22HNgAtADfBD7dWV/SHcCDwDxJrZKuTXfdCFwsaR1wcfrebHDZtQ5OPIV9nJB3JHDcWDhhCuzZkHckNsiNyPLgEbGcJGmUblta8jqA67upe2U323cD765imGYDr605XYI370BSE+bAno15R2GDXEUtFEk/kPQ+Sb6z3uxYRST9FZPn5R3JaybMcQvFjlmlCeIW4GPAOkk3Sjojw5jMhraXtsOhfTCplhLKbHhpKxx5Je9IbBCrKKFExH0RcRWwANgE3Cvp95I+IWlklgGaDTmdo6kmz803jlIT5iTPHjpsx6DiS1iSJgL/CfjPwOPA10kSzL2ZRGY2VHUmlEm1lFBmJ8++7GXHoKJOeUl3A2cA/wa8v2Ro7/ckrcwqOLMhqa0ZRp0EJ00l+dusBnS2UJxQ7BhUOsrrX9MRW6+SNDoiDkVEUwZxmQ1du5qTy10qN1FETo4fD8eN80gvOyaVXvL62zLbHqxmIGbDxq51tdUh38kjvewY9dhCkXQqyWSNx0s6j9fm3hoLjMk4NrOh5+BeeGlbbXXId5owB1ofyTsKG8R6u+T1RyQd8TOAr5Vsfwn4YkYxmQ1dneuO1FKHfKcJc2DV3dB+GEaMyjsaG4R6TCgR8W3g25I+FBE/GKCYzIauzvmyavKS12yIIuzdkiy6ZdZHvV3y+nhEfAdokPTnXfdHxNfKVDOz7uxaC3WjYHxD3pEcrXSklxOK9UNvl7w6Z647MetAzIaFXWthwmnJ0ru1xkOH7Rj1dsnrX9Ln/zow4ZgNcW3NcOpZeUdR3gmTYdSJHjps/Vbp5JBflTRW0khJ90vaJenjWQdnNqS0H0qW2q3FDnlI7osZP9stFOu3Su9DeW9E7AMuI1llcS7wl5lFZTYU7dmQdHrXYod8pwlOKNZ/lV7I7ZwA8lLgjojYo1q6y9dsMHh1Dq/GfOMAGpb8tOz2L4wIrq3bwBlLfkKxm783N934vixDs0Gs0hbKTyStAZqA+yVNBg5mF5bZENSZUCaenm8cPdgUpzJKHUxld96h2CBU6fT1S4C3AE0RcQR4GVjUWz1JCyU1S2qRtKTMfkm6Kd3/lKQFvdWV9EZJKyQ9IWmlpPMr+Q5mudvVAmOnw+jaHTT5XEwBYFZhR86R2GDUl7GLZ5Lcj1Ja5/buCkuqA24mWfe9FXhE0rKIeLak2CVAY/q4gGQhrwt6qftV4L9GxM8kXZq+/8M+fA+zfOxeVxOXu3qyqXgqAA3awe+p0dFoVrMqnb7+34DTgCeAjnRz0ENCAc4HWiJiQ3qMO0laNaUJZRFwe7q2/ApJ4yRNBRp6qBskc4kBnAxsreQ7mOUqIpl25ZyP5h1Jj7YznkMxkgZtzzsUG4QqbaE0AfPT//grNR3YUvK+laQV0luZ6b3U/Qxwj6S/J7lk99ZyHy7pOuA6gJkzZ/YhbLMM7N+ZLvtb2y2UoMD6mEajWvMOxQahSjvlnwFO7eOxyw0D65qQuivTU91PAZ+NiHrgs8D/LPfhEXFrRDRFRNPkyZMrDNksI7s7J4Ws7YQCsCbqmVfY0ntBsy4qTSiTgGcl3SNpWeejlzqtQH3J+xkcfXmquzI91b0GuDt9/e8kl9bMaturI7xqP6GsLc5gmvYwlpfzDsUGmUovef11P479CNAoaTbwPHAF8LEuZZYBN6R9JBcAeyNim6S2HupuBf4A+BXwLmBdP2IzG1i7WmDE8ckorxq3JpK/5eZqCyvjjJyjscGkooQSEb+WNAtojIj7JI0B6nqp0y7pBuCetOxtEbFK0uJ0/1JgOcnNki3AAeATPdVND/1J4OvpaLODpP0kZjVt11qYdDoUKr0okJ+1xSShzCu0srLDCcUqV+kor0+S/Mc9gWS013RgKfDunuql69Av77JtacnrAK6vtG66/bfAmyqJ26xm7F4H0xb0Xq4GbGUi++J45sn9KNY3lf65dD1wEbAPICLWAVOyCspsSDlyEF58blB0yCfEWnfMWz9UmlAORcThzjfp5aa+DCE2G75enRSyRmcZLqO5WJ+2UPxrbpWrNKH8WtIXgeMlXUwyuuon2YVlNoR0Dhmu4Tm8umqOGYzTy0zhxbxDsUGk0oSyBGgDngb+D5K+jS9nFZTZkDIIJoXsqrmY3Ax8RuG5nCOxwaTSUV5FST8CfhQRbdmGZDbEDIJJIbtqjhkAzFUrD3BuztHYYNFjCyWdDfivJe0C1gDNktokfWVgwjMbAnavG1StE4AXOYkdMY4z3DFvfdDbJa/PkIzuenNETIyICSQ3IF4k6bNZB2c26HVOCjmIOuQ7NRfrmeuhw9YHvSWUq4ErI2Jj54Z0BuCPp/vMrCeDZFLIcpqjnrlqpUAx71BskOgtoYyMiF1dN6b9KCPLlDezUoNwhFentTGD43SEmfJiW1aZ3hLK4X7uMzMoWUd+8F3yWpOO9PId81ap3hLKuZL2lXm8BJw9EAGaDWqDaFLIrtbFdIohznBCsQr1OGw4InqcANLMEg1Lflp2+/8a+VtO0RQu/eLPBjiiY3eQ0WyOKcwtbHltnVazHtT+1Kdmg9gcbWN9TM07jH5rjpluoVjFnFDMMjKaw8xQGxtiWt6h9FtzzKBB2xntLlOrgBOKWUZmaQd1CtYXB3FCKdZTp+B0dV1s1exoTihmGZmjbQCD/JLXa6s3mvXGCcUsI6elf9VvHMQJZVOcyqEY4bVRrCKZJhRJCyU1S2qRtKTMfkm6Kd3/lKQFldSV9GfpvlWSvprldzDrrzmFrWyNCRzguLxD6bcO6lgf030vilWkotmG+0NSHXAzcDHQCjwiaVlEPFtS7BKgMX1cANwCXNBTXUnvBBYB50TEIUleOdJq0mnayobi4G2ddFoT9VxYeLb3gjbsZdlCOR9oiYgN6WqPd5IkglKLgNsjsQIYJ2lqL3U/BdwYEYcAImJnht/BrF9EkUY9z7p0GvjBbG1xBtO0h7G8nHcoVuOyTCjTgdJ2cmu6rZIyPdWdC7xd0kOSfi3pzeU+XNJ1klZKWtnW5iVcbGDNUBsn6BBrYmbeoRyzNe6YtwplmVBUZlvXBaq7K9NT3RHAeOBC4C+BuyQdVT4ibo2Ipohomjx5cuVRm1VB582Aa4tDoYWSJJR5hdacI7Fal1kfCkmror7k/Qyg62D27sqM6qFuK3B3RATwsKQiMIlkiWKzmjBXyX++a4fAJa+tTGRfHO+OeetVli2UR4BGSbMljQKuAJZ1KbMMuDod7XUhsDcitvVS90fAuwAkzSVJPkdNsW+WpzMKz/FccTIvc3zeoVSBWBv1HjpsvcqshRIR7ZJuAO4B6oDbImKVpMXp/qXAcuBSoAU4AHyip7rpoW8DbpP0DMkU+tekrRWzmjFPW2geAv0nnZqL9byvbgVHX7U2e02Wl7yIiOUkSaN029KS1wFcX2nddPthkhUjzWrSKI4wW9v5ebEp71CqZk3Uc5Xu5xReyDsUq2G+U96syuZoGyPVQXOxvvfCg8RrHfO+7GXdc0Ixq7Iz9BzAkBgy3Kk5HVzgjnnriROKWZWdXdjIKzGKDYN4Dq+uXuQkdsQ4Dx22HjmhmFXZWYWNPBuz6GBoLXjaXKxnXtr6MivHCcWsikSRN2gTTxdn5x1K1TVHPY16HopeD9jKc0Ixq6I52saJOsiqaMg7lKprjnqO0xHYszHvUKxGOaGYVdFZSv6zfbo4J+dIqu/VUWs7PfOwleeEYlZFZxc2cjBGsi66zoM6+K2L6RRDTijWLScUsyo6u7CR1UOwQx7gIKPZHFOcUKxbTihmVVJIO+SfGoId8p2aYybscEKx8pxQzKqkUa2cqIM8XmzMO5TMNMcM2LMejhzMOxSrQU4oZlVyXqEFgMfj9JwjyU5zsR6iCG1r8g7FapATilmVnKcW9sSJbI5T8g4lM89Eejlv6+P5BmI1yQnFrErOK6zjieLplF9wdGh4LqbA8eNh62N5h2I1yAnFrArG8jJzC8/zeHHoXu5KCKadB8+7hWJHc0Ixq4JzChsAeDyGbof8q6a/KRk6fPhA3pFYjXFCMauCNxeaKYZ4snha3qFkb9oCiA7Y/lTekViNyTShSFooqVlSi6QlZfZL0k3p/qckLehD3c9JCkmTsvwOZpW4oLCaVTGLlxiTdyjZm57+mj7/aL5xWM3JLKFIqgNuBi4B5gNXSprfpdglQGP6uA64pZK6kuqBiwHPpW35O3KQ89TCQ8Uz845kYJx0KoydDs+7Y95eL8sWyvlAS0RsSNeBvxNY1KXMIuD2SKwAxkmaWkHdfwA+D0SG8ZtV5vlHGa0jwyehAMxogi0P5R2F1ZgsE8p0oHS90NZ0WyVluq0r6XLg+Yh4stoBm/XL5t9RDPFw8Yy8Ixk4sy6CvVvghc15R2I1JMuEUm4wftcWRXdlym6XNAb4EvCVXj9cuk7SSkkr29raeg3WrN82/ZbmqGcvJ+YdycCZdVHyvPn3+cZhNSXLhNIK1Je8nwFsrbBMd9tPA2YDT0ralG5/TNKpXT88Im6NiKaIaJo8efIxfhWzbrQfhi0Ps2I4Xe4CmDI/ucFx82/zjsRqSJYJ5RGgUdJsSaOAK4BlXcosA65OR3tdCOyNiG3d1Y2IpyNiSkQ0REQDSeJZEBHbM/weZt3b+ji0vzL8EkqhADPfCpt+l3ckVkNGZHXgiGiXdANwD1AH3BYRqyQtTvcvBZYDlwItwAHgEz3VzSpWs35L/0IfVv0nnRouguafwr6tMHZa3tFYDcgsoQBExHKSpFG6bWnJ6wCur7RumTINxx6l2THY9DuYfCYvbBmbdyQDr+FtyfPGB+DcK/KNxWqC75Q366+O9mTobMNFeUeSj1POhhMmQ8t9eUdiNcIJxay/tj0Jh/e/NuJpuCkU4PT3QMv9UOzIOxqrAU4oZv216TfJ83BNKJAklFf2wNYn8o7EaoATill/bfglTHkDnDR0F9Tq1WnvAgQt9+YdidUAJxSz/jh8ADY/CKe9M+9I8jVmQjKdvftRDCcUs/557vfQccgJBaDxYmhdCQf25B2J5cwJxaw/1v8S6kYnN/cNd6e/BwhY/4u8I7GcOaGY9cf6X8Kst8CoYbD+SW+mnQfHT/BlL3NCMeuzF5+DnavgtHfnHUltKNQlnfMt90OxmHc0liMnFLO+WpNO4HDG+/KNo5Y0Xgwv7/SywMNcplOvmA1Ja/43TD4TJg6D9ePLaFjy06O2TaTII6PFP978T9zU8cGy9Tbd6AQ81LmFYtYXB/bA5t+5ddLFbk7msWjk4rqVeYdiOXJCMeuL5p9BFJ1QyrivYwFnFzZxKrvzDsVy4oRi1herfggn1ycjm+x17i2+CYD31D2WcySWFycUs0q9vDuZbuWsD4LKrVI9vK2PaWwonsrFhUfzDsVy4oRiVqnVP4ZiO5z14bwjqVHinuKbeWthFRPYl3cwlgMnFLNKPf0DmDQXTj0770hq1g873sZIdfD+ugfzDsVykGlCkbRQUrOkFklLyuyXpJvS/U9JWtBbXUl/J2lNWv6HksZl+R3MANjbmozuOuvDvtzVg7VRz6riLP647jd5h2I5yCyhSKoDbgYuAeYDV0qa36XYJUBj+rgOuKWCuvcCZ0XEOcBa4K+y+g5mr3riDiDg3I/mHUnNu7vjbbyxsIHT9HzeodgAy7KFcj7QEhEbIuIwcCewqEuZRcDtkVgBjJM0tae6EfHziGhP668AZmT4HcyS6USe+A40vB3GN+QdTc1b1nERR6KOj9d5bq/hJss75acDW0retwIXVFBmeoV1Af4U+N4xR2pG+TvAAS7Qar43ehOf2XEpP+qmjL2mjXH8uHgRH637FV9v/yAvclLeIdkAybKFUu5Cc1RYpte6kr4EtAPfLfvh0nWSVkpa2dbWVkG4ZuVdMeIX7Ivj+Y/im/MOZdD4l/bLGKNDXF3nlRyHkywTSitQX/J+BrC1wjI91pV0DXAZcFVEdE1SAETErRHRFBFNkydP7veXsOFtMi/yvsIKftDxDg4yOu9wBo11MYP7Os7jmhH3cByH8g7HBkiWCeURoFHSbEmjgCuAZV3KLAOuTkd7XQjsjYhtPdWVtBD4AnB5RBzIMH4zPlZ3P6PUwe0d7807lEFnafv7maiX+JO6X+Udig2QzBJK2nF+A3APsBq4KyJWSVosaXFabDmwAWgBvgl8uqe6aZ1vACcB90p6QtLSrL6DDW+jOMJVI+7nlx3nsjGm5h3OoLMy5vFosZFP1i2njo68w7EBkOn09RGxnCRplG5bWvI6gOsrrZtuP73KYZqV9ZG6XzNFL/IXHYt7L2xliKXt7+ebo77GZYUHgcvzDsgy5jvlzcoYxRE+PeLHPFps5DdF3xnfX/cVF7CmWM//OeKH0NHeewUb1JxQzMr4k7pfMV27+cf2D1F+0KFVIijwD+0f5rTCNnj6rrzDsYw5oZh1MYF9/MWIf+eh4hlunVTBPcUmni42wK/+Oxw5mHc4liEnFLMuvjzyO5zAK3zpyJ/i1kk1iBvbr4QXn4MH/ynvYCxDTihmJd5ZeJwP1v2WpR3vpyU8q0+1/K54Npx5OTzw/yaJxYYkJxSz1Hj28dWRt7K6WM832v8473CGnj/6f5KZmn/yX5L50WzIcUIxA4jgv428jZPZz58f+TSHGZl3REPPuHp47/8N638BD9+adzSWAScUM4CnvseldQ/ztfaPsDpm5R3N0NV0LcxdCPd+BTZ7Ea6hxgnFbM9GWP6XPFycx60dl+UdzdAmwQduSVord14Ju9blHZFVkROKDW+vvAD/359AoY6/OLKYon8lsjdmAlz1fSiMgO98CPbvzDsiqxL/9tjw1X4Y7ro6aaF89LtsiVPyjmj4mDAbPvY9eLkNvvsROPRS3hFZFTih2PAUAT/9LGx8AC7/J2i4KO+Ihp/pb4IP/y/Y/jTccSUceSXviOwYZTo5pFlNKhbhni/C49+Bd3we3nhl3hENC92tiHl5YTH/uPGf+f3fvJvFRz7LfsYcVWbTje/LOjyrArdQbHg5sAd+cC08dAtc8Cl45xfzjmjYW1a8iL84spgLC6u5c9TfMh2vsDpYOaHY8LB/J/z67+AbTbB6Gbzr/4KF/z0ZdWS5+2Hx7fznI59jlnbw09Ff5H2FFRy9YrjVOnWzgu6Q0tTUFCtXrsw7DBsAr7+sEizQOq4e8XMuLTzEKHXwQMfZ/Lf2q2iOmbnFaN2bqR18Y+RNnFPYyAMdZ/OP7R/isWhk040ezp0HSY9GRFOl5d2HYkPOGA5yWd2DXF13L2cVNrEvjuc7HRfznY73sCGm5R2e9eC5OIU/Pvw3fLzuPj474vvcPfqvWV2sh188AfMugannQcEXVmqVWyg2NLzyIqz/Bcu/dwvvKjzOcTrC6mI9/9bxXn7UcREHOC7vCK2PjucgH6r7De+ve5AL6tZCFOHEU2HeQpj9BzDrIjjJQ72z1NcWSqYJRdJC4OtAHfCvEXFjl/1K918KHAD+U0Q81lNdSROA7wENwCbgTyLihZ7icEIZItoPJX0h+3fC/u2wbyvsXA3PrYCdzwLBzhjH8o7z+UnHW3g05uLp54eGTV95C6z7OTQvh5b74fD+ZMfE02HWW6H+ApgyH8ZOg+PHw4jR+QY8RNRMQpFUB6wFLgZagUeAKyPi2ZIylwJ/RpJQLgC+HhEX9FRX0leBPRFxo6QlwPiI+EJPsQzahFL6b/Pq6z5ue92/70BsKxN7sR3aX0kWVzpyANrT5yMHk3sPut13AA6/DHtbkynP928/+nNGnQj158PMt0DD25hzy27f7T7EjaCdN2gT5xfWvPo4WQdeV+ZAjOZFTmBvnMiZc2YlSabcY9SY5I79wsjkuW5Ez+8LdclADhUAdXldKL9vEA/8qKU+lPOBlojYACDpTmAR8GxJmUXA7ZFktRWSxkmaStL66K7uIuAP0/rfBn4F9JhQ+u0/vgiPfos+/yd+rNuGuUMxkoOM5BVGcyBGsy0m0hpn8Hy8jR2Mpy1Opi3GsT0msOvgWGJVAVYBvIAHLg597YzgyTidJztO55sdlyGKzNZ2GtXKJO3jZPYzTi8zjv2M0372bWhjPBsYp5c5mf2MVh5r26cJpvT5dbu7Jp0q7r/iO3Dau/oUbX9lmVCmA1tK3reStEJ6KzO9l7qnRMQ2gIjYJmlKuQ+XdB1wXfp2v6Tm/nyJDE0CduUdRI3zOarMsD9Pm4Bf9lxk+J6jL7+7L6W7nqc+Tb2dZUIp187r+md4d2UqqdujiLgVqNlFFySt7EtTcjjyOaqMz1PvfI4qc6znKcvrA61Afcn7GcDWCsv0VHdHelmM9NlTlZqZ1YAsE8ojQKOk2ZJGAVcAy7qUWQZcrcSFwN70clZPdZcB16SvrwF+nOF3MDOzCmV2ySsi2iXdANxDMvT3tohYJWlxun8psJxkhFcLybDhT/RUNz30jcBdkq4FngM+ktV3yFjNXo6rIT5HlfF56p3PUWWO6TwNixsbzcwsex5jaWZmVeGEYmZmVeGEkjFJfydpjaSnJP1Q0riSfX8lqUVSs6Q/Ktn+JklPp/tuSqeoGdIkfUTSKklFSU1d9vk8lSFpYXpOWtJZI4YtSbdJ2inpmZJtEyTdK2ld+jy+ZF/Zn6mhTFK9pF9KWp3+rv2XdHv1zlNE+JHhA3gvMCJ9/T+A/5G+ng88CYwGZgPrgbp038PAW0jux/kZcEne32MAztOZwDySmQ+aSrb7PJU/X3XpuZgDjErP0fy848rxfLwDWAA8U7Ltq8CS9PWSSn73hvIDmAosSF+fRDK91fxqnie3UDIWET+PiM65HlaQ3FMDyRQyd0bEoYjYSDLS7fz03pqxEfFgJP+qtwMfGOi4B1pErI6IcrMZ+DyV9+rURhFxGOicnmhYiogHgD1dNi8imZ6J9PkDJduP+pkaiDjzFBHbIp18NyJeAlaTzEpStfPkhDKw/pTkL2noedqZ1jLbhyufp/K6Oy/2mtdN0wR0TtM07M+dpAbgPOAhqnievMBWFUi6Dzi1zK4vRcSP0zJfAtqB73ZWK1O+KtPO1KpKzlO5amW2DenzVKHh/v2PxbA+d5JOBH4AfCYi9vXQ9djn8+SEUgUR8Z6e9ku6BrgMeHd6eQZ6nnZmRpntg15v56kbw+48VaiSqY2Gux2SpkYyiWzpNE3D9txJGkmSTL4bEXenm6t2nnzJK2PpQmFfAC6PiNJFG5YBV0gaLWk20Ag8nDY5X5J0YTpq6WqG9/QyPk/lVTK10XDX3TRNZX+mcohvQKW/J/8TWB0RXyvZVb3zlPfIg6H+IOnI2gI8kT6Wluz7EsnIiWZKRigBTcAz6b5vkM5oMJQfwB+T/EV0CNgB3OPz1Os5u5RkpM56ksuGuceU47m4A9gGHEl/jq4FJgL3A+vS5wm9/UwN5QfwNpJLVk+V/H90aTXPk6deMTOzqvAlLzMzqwonFDMzqwonFDMzqwonFDMzqwonFDMzqwonFDMzqwonFLMcSKrr6X03dSTJv7NWs/zDaZYBSR+X9LCkJyT9i6Q6Sfsl/Y2kh4C3lHn/55KeSR+fSY/TkK5f8c/AY7x+KgyzmuKEYlZlks4EPgpcFBFvBDqAq4ATSNbruCAiflv6HngF+ARwAXAh8ElJ56WHnAfcHhHnRcTmgf02ZpXz5JBm1fdu4E3AI+lMrseTTLjXQTIxX6fS928DfhgRLwNIuht4O8l8SpsjYsXAhG7Wf04oZtUn4NsR8Vev2yh9LiI6SjYdLHnf0/LFL1c7QLMs+JKXWfXdD3xY0hR4dc3uWb3UeQD4gKQxkk4gmSzzNxnHaVZVbqGYVVlEPCvpy8DP01FZR4Dre6nzmKRv8dr04P8aEY+nK+uZDQqebdjMzKrCl7zMzKwqnFDMzKwqnFDMzKwqnFDMzKwqnFDMzKwqnFDMzKwqnFDMzKwq/n9a38AEPPLXOgAAAABJRU5ErkJggg==\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
......@@ -208,7 +220,7 @@
}
],
"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",
"sns.kdeplot(new_error)\n",
"plt.xlabel(\"error\")\n",
......@@ -217,58 +229,63 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 41,
"id": "58da6063",
"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": [
"Std Deviation of E: 26.627504708827136\n",
"Normal bits: 15\n",
"Encoded Bits: 6.677845333316752\n"
]
}
],
"source": [
"plt.hist(new_image, bins=25, density=True)\n",
"sns.kdeplot(new_image)\n",
"plt.xlabel(\"Actual Pixel Value\")\n",
"plt.show()"
"image = Image.open(images[0]) #Open the image and read it as an Image object\n",
"image = np.array(image)[1:,:] #Convert to an array, leaving out the first row because the first row is just housekeeping data\n",
"image = image.astype(np.int64)\n",
"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",
"execution_count": 79,
"id": "2562feeb",
"metadata": {
"scrolled": false
},
"execution_count": 47,
"id": "ec4db902",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(512, 640)\n",
"1310832\n",
"9\n"
"8192\n"
]
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2562feeb",
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"f_r = no_ravel[0]\n",
"print(no_ravel.shape)\n",
"print(sys.getsizeof(no_ravel))\n",
"print((256).bit_length())"
"pred = new_pred.reshape((510,638))\n",
"real_pred = no_ravel.copy()\n",
"real_pred[1:-1, 1:-1] = pred"
]
},
{
"cell_type": "code",
"execution_count": 99,
"execution_count": 10,
"id": "470cc137",
"metadata": {},
"outputs": [
......@@ -285,7 +302,7 @@
"'print(decompress)\\nprint(np.mean(np.abs(decompress-no_ravel)))'"
]
},
"execution_count": 99,
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
......@@ -301,112 +318,201 @@
},
{
"cell_type": "code",
"execution_count": 59,
"execution_count": null,
"id": "3292b395",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 97, 109, 101, 32, 105, 115, 32, 83, 99, 111, 117, 116]\n",
"256\n",
"71\n"
]
}
],
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "f9687830",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 13,
"id": "e98eed4b",
"metadata": {},
"outputs": [],
"source": [
"def compress(uncompressed):\n",
" \"\"\"Compress a string to a list of output symbols.\"\"\"\n",
" \n",
" # 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\"))"
"f = open(\"test.craw\", \"wb\")\n",
"f.write(real_pred.tobytes())\n",
"f.close()"
]
},
{
"cell_type": "code",
"execution_count": 101,
"id": "f9687830",
"execution_count": 12,
"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": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "too many values to unpack (expected 2)",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_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",
"\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",
"\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)"
]
"data": {
"text/plain": [
"'change = Image.open(\"test.tiff\")\\nchange = np.array(change)\\nprint(change.shape)'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def wavelet(num_images, i): \n",
"\n",
" image = Image.open(num_images[i]) #Open the image and read it as an Image object\n",
" 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))"
"\"\"\"change = Image.open(\"test.tiff\")\n",
"change = np.array(change)\n",
"print(change.shape)\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e98eed4b",
"execution_count": 114,
"id": "82c20d94",
"metadata": {},
"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",
"execution_count": null,
"id": "b7e88aab",
"execution_count": 123,
"id": "9190b5a8",
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"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": {
......
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