svd_mpsic/jupyter.ipynb

820 lines
26 KiB
Plaintext
Raw Normal View History

{
"cells": [
{
"cell_type": "code",
2022-05-18 12:44:39 +02:00
"execution_count": 1,
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
2022-05-17 22:28:19 +02:00
"is_executing": true,
2022-05-11 13:49:01 +02:00
"name": "#%%\n"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
2022-05-18 14:12:24 +02:00
"/var/folders/8w/3c34c7kd2n144tvm764_pdbw0000gq/T/ipykernel_3019/1657712203.py:16: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display\n",
2022-05-11 13:49:01 +02:00
" from IPython.core.display import display, HTML\n"
]
},
{
"data": {
2022-05-17 22:28:19 +02:00
"text/html": [
"<style>.container { width:80% !important; }</style>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
2022-05-11 13:49:01 +02:00
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
2022-05-18 14:09:41 +02:00
"import pandas as pd\n",
"import numpy as np\n",
2022-05-09 14:30:12 +02:00
"import matplotlib.pyplot as plt\n",
"from skimage import data\n",
"from skimage.color import rgb2gray\n",
"from skimage import img_as_ubyte,img_as_float\n",
"from numpy.linalg import svd\n",
2022-05-18 00:08:40 +02:00
"import scipy.linalg as la\n",
2022-05-09 14:30:12 +02:00
"from PIL import Image\n",
2022-05-11 13:49:01 +02:00
"from ipywidgets import interact\n",
2022-05-18 11:54:15 +02:00
"from numpy.linalg import eig\n",
"from math import isclose\n",
"import pprint\n",
2022-05-17 21:36:32 +02:00
"\n",
"# zmień szerokość komórki\n",
2022-05-09 14:30:12 +02:00
"from IPython.core.display import display, HTML\n",
"display(HTML(\"<style>.container { width:80% !important; }</style>\"))\n"
2022-05-11 13:49:01 +02:00
]
},
{
"cell_type": "code",
2022-05-18 12:44:39 +02:00
"execution_count": 2,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
2022-05-11 13:49:01 +02:00
},
"outputs": [],
"source": [
2022-05-17 21:36:32 +02:00
"#Ta linia jest wymagana do wyświetlania wizualizacji w przeglądarce\n",
"%matplotlib inline"
2022-05-11 13:49:01 +02:00
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
2022-05-11 13:49:01 +02:00
},
"source": [
"# Kompresja obrazów z wykorzystaniem rozkładu SVD"
]
},
{
"cell_type": "markdown",
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
2022-05-11 13:49:01 +02:00
"Metodę SVD zastosujemy do kompresji obrazów. SVD dokonuje dekompozycji macierzy prostokątnej $M$ na trzy części.\n",
"$M=U\\Sigma V^T$ -\n",
2022-05-14 22:51:06 +02:00
"- $U$ - macierz, w której kolumny są wektorami własnymi macierzy $MM^T$ (lewe wektory osobliwe - 'left singular vectors'). Wektory te tworzą układ ortonormalny.\n",
"- $\\Sigma$ - macierz diagonalna, która na swojej diagonalii ma nieujemne wartości osobliwe (szczególne), czyli pierwiastki wartości własnych macierzy $M^TM$ uporządkowane nierosnąco\n",
"- $V$ - macierz, w której kolumny są wektorami własnymi macierzy $M^TM$ (prawe wektory osobliwe - 'right singular vectors'). Wektory te tworzą układ ortonormalny.\n",
"\n",
2022-05-11 13:49:01 +02:00
"SVD polega na rekonstrukcji oryginalnej macierzy jako kombinacji liniowej kilku macierzy rangi jeden. Macierz rangi jeden można wyrazić jako iloczyn zewnętrzny dwóch wektorów kolumnowych. \n",
"\n",
2022-05-17 21:11:07 +02:00
"$M=\\sigma_1u_1v_1^T+\\sigma_2u_2v_2^T+\\sigma_3u_3v_3^T+\\sigma_4u_4v_4^T+....$ .\n",
2022-05-14 22:51:06 +02:00
"\n",
"$rank M=r$ .\n",
"$M=\\sum_{i=1}^{r} \\sigma_iu_iv_i^T$\n",
"\n",
2022-05-11 13:49:01 +02:00
"Macierz o randze r będzie miała r takich wyrazów.\n",
"\n",
2022-05-11 13:49:01 +02:00
"Tutaj $\\sigma_1,\\sigma_2,\\sigma_3 ...$ są wartościami osobliwymi. $u_1,u_2,u_3 ...$ i $v_1,v_2,v_3 ...$ są kolejnymi kolumnami (wektorami własnymi) z macierzy U i V.\n",
"\n",
2022-05-11 13:49:01 +02:00
"Kompresja obrazu przy użyciu SVD polega na wykorzystaniu faktu, że tylko nieliczne wartości osobliwe są duże. Chociaż obrazy ze świata rzeczywistego mają pełną rangę, to ich efektywna ranga jest niska, co oznacza, że tylko kilka wartości osobliwych rozkładu SVD obrazów będzie dużych."
]
2022-05-09 14:30:12 +02:00
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
2022-05-09 14:30:12 +02:00
"name": "#%% md\n"
}
2022-05-11 13:49:01 +02:00
},
"source": [
"### skimage - biblioteka do przetwarzania obrazów\n",
"\n",
"Do pracy z obrazami w Pythonie używamy biblioteki do przetwarzania obrazów ```skimage``` (z rodziny pakietów ```sci-kit```). Ma ona moduł o nazwie data, który udostępnia zestaw obrazów. Wczytujemy kilka obrazów i konwertujemy je do formatu skali szarości. Obrazy te są przechowywane w słowniku ```gray_images```."
]
},
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 20,
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"gray_images = {\n",
2022-05-18 12:44:39 +02:00
" \"cat\":rgb2gray(img_as_float(data.chelsea())),\n",
" \"astro\":rgb2gray(img_as_float(data.astronaut())),\n",
" \"camera\":data.camera(),\n",
" \"coin\": data.coins(),\n",
" \"clock\":data.clock(),\n",
2022-05-17 10:43:41 +02:00
" \"text\":data.text(),\n",
" \"page\":data.page(),\n",
" \"blobs\":data.binary_blobs(),\n",
" \"coffee\":rgb2gray(img_as_float(data.coffee()))\n",
"}"
2022-05-11 13:49:01 +02:00
]
2022-05-09 14:30:12 +02:00
},
{
"cell_type": "markdown",
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
2022-05-11 13:49:01 +02:00
"### SVD w python'ie\n",
"Używamy funkcji ```svd``` z biblioteki ```numpy.linalg``` do obliczenia rozkładu SVD naszej macierzy. Funkcja svd zwraca U,s,V .\n",
" - U macierz, w której kolumny są wektorami własnymi macierzy $MM^T$\n",
" - s jest tablicą numpy rangi 1 z wartościami osobliwymi\n",
" - V macierz, w której wiersze są wektorami własnymi macierzy $M^TM$ - odpowiednik $V^T$ w tradycyjnej literaturze algebry liniowej\n",
" \n",
2022-05-11 13:49:01 +02:00
"Zrekonstruowana aproksymacja oryginalnej macierzy jest wykonywana przy użyciu podzbioru wektorów osobliwych, jak poniżej w funkcji ``compress_svd``. Używamy ```NumPy Array Slicing```, aby wybrać k wektorów osobliwych i wartości osobliwych. Zamiast przechowywać $m\\times n$ wartości dla oryginalnego obrazu, możemy teraz przechowywać $k(m+n)+k$ wartości\n",
"\n",
" reconst_matrix = np.dot(U[:,:k],np.dot(np.diag(s[:k]),V[:k,:]))\n",
" "
2022-05-11 13:49:01 +02:00
]
},
{
"cell_type": "code",
2022-05-18 12:44:39 +02:00
"execution_count": 4,
2022-05-18 14:09:41 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
2022-05-18 11:54:15 +02:00
}
2022-05-18 14:09:41 +02:00
},
"outputs": [],
2022-05-18 00:08:40 +02:00
"source": [
"def calculate(A):\n",
2022-05-18 11:54:15 +02:00
" n = A.shape[0]\n",
" m = A.shape[1]\n",
2022-05-18 00:08:40 +02:00
" S = np.zeros(n)\n",
"\n",
" helper = np.matmul(A, np.transpose(A))\n",
2022-05-18 11:54:15 +02:00
" eigenvalues, eigenvectors = eig(helper)\n",
2022-05-18 12:44:39 +02:00
" \n",
2022-05-18 00:08:40 +02:00
" index = eigenvalues.argsort()[::-1]\n",
2022-05-18 11:54:15 +02:00
" eigenvalues = np.real(eigenvalues)\n",
" eigenvectors = np.real(eigenvectors)\n",
2022-05-18 00:08:40 +02:00
" eigenvalues = eigenvalues[index]\n",
" eigenvectors = eigenvectors[:, index]\n",
" U = eigenvectors\n",
"\n",
2022-05-18 11:54:15 +02:00
" helper2 = np.matmul(np.transpose(A), A)\n",
" eigenvalues2, eigenvectors2 = eig(helper2)\n",
" index2 = eigenvalues2.argsort()[::-1]\n",
" eigenvalues2 = np.real(eigenvalues2)\n",
" eigenvectors2 = np.real(eigenvectors2)\n",
" eigenvalues2 = eigenvalues2[index2]\n",
" eigenvectors2 = eigenvectors2[:, index2]\n",
" V = np.transpose(eigenvectors2)\n",
" \n",
2022-05-18 00:08:40 +02:00
" j = 0\n",
2022-05-18 11:54:15 +02:00
" for i in eigenvalues2:\n",
2022-05-18 00:08:40 +02:00
" if j == S.size:\n",
" break\n",
" elif i >= 0:\n",
" S[j] = np.sqrt(i)\n",
" j += 1\n",
"\n",
" S[::-1].sort()\n",
"\n",
2022-05-18 14:09:41 +02:00
" return U, S, V"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
2022-05-18 11:54:15 +02:00
"def check_sign_V(V, builtin):\n",
2022-05-18 12:44:39 +02:00
" if builtin.shape[0] < builtin.shape[1]:\n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[j][i] < 0.0 and V[j][i] > 0.0:\n",
" V[j][i] *= -1\n",
" elif builtin[j][i] > 0.0 and V[j][i] < 0.0:\n",
" V[j][i] *= -1\n",
" else:\n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[i][j] < 0.0 and V[i][j] > 0.0:\n",
" V[i][j] *= -1\n",
" elif builtin[i][j] > 0.0 and V[i][j] < 0.0:\n",
" V[i][j] *= -1\n",
2022-05-18 11:54:15 +02:00
" return V\n",
"\n",
"def check_sign_U(U, builtin):\n",
2022-05-18 12:44:39 +02:00
" if builtin.shape[0] < builtin.shape[1]: \n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[j][i] < 0.0 and U[j][i] > 0.0:\n",
" U[j][i] *= -1\n",
" elif builtin[j][i] > 0.0 and U[j][i] < 0.0:\n",
" U[j][i] *= -1\n",
" else:\n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[i][j] < 0.0 and U[i][j] > 0.0:\n",
" U[i][j] *= -1\n",
" elif builtin[j][j] > 0.0 and U[i][j] < 0.0:\n",
" U[i][j] *= -1\n",
2022-05-18 14:09:41 +02:00
" return U"
2022-05-18 00:08:40 +02:00
]
},
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 6,
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def compress_svd(image,k):\n",
" \"\"\"\n",
2022-05-17 21:11:07 +02:00
" Wykonaj dekompozycję SVD, a następnie okrojoną rekonstrukcję (przy użyciu k wartości/wektorów osobliwych)\n",
" \"\"\"\n",
2022-05-18 11:54:15 +02:00
" image = np.real(image)\n",
" U,s,V = svd(image,full_matrices=False)\n",
" reconst_matrix = np.dot(U[:,:k],np.dot(np.diag(s[:k]),V[:k,:]))\n",
2022-05-09 14:18:40 +02:00
"\n",
2022-05-18 12:44:39 +02:00
" return reconst_matrix,s"
2022-05-11 13:49:01 +02:00
]
},
2022-05-18 14:09:41 +02:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Przykładowa macierz"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Matrix U:\n",
" 0 1 2 3\n",
"0 0.0 0.0 1.0 0.0\n",
"1 0.0 1.0 0.0 0.0\n",
"2 0.0 0.0 0.0 -1.0\n",
"3 1.0 0.0 0.0 0.0\n",
"\n",
"Matrix V:\n",
" 0 1 2 3 4\n",
"0 0.000000 1.0 0.0 0.0 0.000000\n",
"1 0.000000 0.0 1.0 0.0 0.000000\n",
"2 0.447214 0.0 0.0 0.0 0.894427\n",
"3 0.000000 0.0 0.0 1.0 0.000000\n",
"4 -0.894427 0.0 0.0 0.0 0.447214\n",
"\n",
"Matrix s:\n",
" 0\n",
"0 4.000000\n",
"1 3.000000\n",
"2 2.236068\n",
"3 0.000000\n",
"\n",
"--------------------------------------\n",
"\n",
"Reconstructed matrix: \n",
"\n",
" 0 1 2 3 4\n",
"0 1.0 0.0 0.0 0.0 2.0\n",
"1 0.0 0.0 3.0 0.0 0.0\n",
"2 0.0 0.0 0.0 0.0 0.0\n",
"3 0.0 4.0 0.0 0.0 0.0\n"
]
}
],
"source": [
"a = np.array([[1, 0, 0, 0, 2], \n",
" [0, 0, 3, 0, 0],\n",
" [0, 0, 0, 0, 0],\n",
" [0, 4, 0, 0, 0]])\n",
"\n",
"U,s,V = calculate(a)\n",
"U1,s1,V1 = svd(a)\n",
"U = check_sign_U(U, U1)\n",
"V = check_sign_V(V, V1)\n",
"\n",
"U_dataframe = pd.DataFrame(U)\n",
"s_dataframe = pd.DataFrame(s)\n",
"V_dataframe = pd.DataFrame(V)\n",
"\n",
"print(\"Matrix U:\")\n",
"print(U_dataframe)\n",
"\n",
"print(\"\\nMatrix V:\")\n",
"print(V_dataframe)\n",
"\n",
"print(\"\\nMatrix s:\")\n",
"print(s_dataframe)\n",
"\n",
"print('\\n--------------------------------------\\n')\n",
"k = 4\n",
"reconst_matrix4 = np.dot(U[:,:k],np.dot(np.diag(s[:k]),V[:k,:]))\n",
"\n",
"recon_dataframe_matrix = pd.DataFrame(reconst_matrix4)\n",
"print('Reconstructed matrix: \\n')\n",
"print(recon_dataframe_matrix)"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
2022-05-11 13:49:01 +02:00
},
"source": [
"### Kompresja obrazów w skali szarości\n",
"Poniższa funkcja ``compress_show_gray_images`` przyjmuje nazwę obrazu (img_name) i liczbę wartości/wektorów osobliwych (k), które mają być użyte w skompresowanej rekonstrukcji. Na wykresie są wartości osobliwe oraz obraz."
]
},
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 8,
2022-05-17 21:11:07 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def compress_show_gray_images(img_name,k):\n",
" \"\"\"\n",
2022-05-17 21:11:07 +02:00
" Kompresuje obrazy w skali szarości i wyświetla zrekonstruowany obraz.\n",
" Wyświetla również wykres wartości singularnych\n",
" \"\"\"\n",
" image=gray_images[img_name]\n",
" original_shape = image.shape\n",
" reconst_img,s = compress_svd(image,k)\n",
" fig,axes = plt.subplots(1,2,figsize=(8,5))\n",
" axes[0].plot(s)\n",
" compression_ratio =100.0* (k*(original_shape[0] + original_shape[1])+k)/(original_shape[0]*original_shape[1])\n",
2022-05-17 21:11:07 +02:00
" axes[1].set_title(\"compression ratio={:.2f}\".format(100 - compression_ratio)+\"%\")\n",
" axes[1].imshow(reconst_img,cmap='gray')\n",
" axes[1].axis('off')\n",
2022-05-17 18:18:53 +02:00
" fig.tight_layout()\n",
" # compression rate = 100% * (k * (height + width + k)) / (height + width)"
2022-05-17 21:11:07 +02:00
]
},
{
"cell_type": "code",
2022-05-18 14:12:24 +02:00
"execution_count": 9,
2022-05-18 14:09:41 +02:00
"metadata": {},
"outputs": [],
"source": [
"def compute_k_max(img_name):\n",
" \"\"\"\n",
2022-05-17 21:11:07 +02:00
" Funkcja do obliczania maksymalnej wartości zakresu suwaka \"k\"\n",
" \"\"\"\n",
" img = gray_images[img_name]\n",
" m,n = img.shape\n",
" return m*n/(m+n+1)\n",
"\n",
"import ipywidgets as widgets\n",
"\n",
"list_widget = widgets.Dropdown(options=list(gray_images.keys()))\n",
"int_slider_widget = widgets.IntSlider(min=1,max=compute_k_max('cat'))\n",
2022-05-14 22:51:06 +02:00
"\n",
"def update_k_max(*args):\n",
" img_name=list_widget.value\n",
" int_slider_widget.max = compute_k_max(img_name)\n",
2022-05-14 22:51:06 +02:00
"\n",
2022-05-17 21:11:07 +02:00
"list_widget.observe(update_k_max,'value')"
]
},
2022-05-18 14:09:41 +02:00
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"W celu zbadania, jak jakość zrekonstruowanego obrazu zmienia się wraz z $k$ należy użyć poniższego interaktywnego widżetu."
]
},
2022-05-17 21:11:07 +02:00
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 10,
2022-05-09 14:18:40 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
2022-05-17 21:11:07 +02:00
},
2022-05-09 14:18:40 +02:00
"outputs": [],
"source": [
"def print_matrices(img_name, k):\n",
2022-05-17 21:18:02 +02:00
" \"\"\"\n",
" Wyświetlanie macierzy U V S wraz z wymiarami.\n",
" \"\"\"\n",
"\n",
2022-05-17 21:11:07 +02:00
" if img_name not in gray_images.keys():\n",
2022-05-17 18:18:53 +02:00
" return\n",
" \n",
2022-05-09 14:18:40 +02:00
" image=gray_images[img_name]\n",
" original_shape = image.shape\n",
2022-05-18 14:09:41 +02:00
" print(f\"Input image dimensions. Width:{original_shape[1]} Height:{original_shape[0]}\\n\")\n",
2022-05-09 14:18:40 +02:00
"\n",
2022-05-18 11:54:15 +02:00
" U,s,V = svd(image,full_matrices=False)\n",
2022-05-18 14:09:41 +02:00
"\n",
" U_dataframe = pd.DataFrame(U[:,:k])\n",
" print(f\"U MATRIX:\\n {U_dataframe}\\n\")\n",
" print('\\n', '*' * 100, '\\n')\n",
" print(f\"\\nShape of S matrix: {s[:k].shape[0]}\\n\")\n",
" s_dataframe = pd.DataFrame(np.diag(s[:k]))\n",
" print(f\"S MATRIX:\\n {s_dataframe}\")\n",
" print('\\n', '*' * 100, '\\n')\n",
" V_dataframe = pd.DataFrame(V[:k,:].T)\n",
" print(f\"V MATRIX:\\n {V_dataframe}\")\n"
2022-05-17 21:11:07 +02:00
]
2022-05-09 14:18:40 +02:00
},
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 11,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
2022-05-17 21:11:07 +02:00
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
2022-05-18 14:12:24 +02:00
"model_id": "40f7f6318beb4d248fc1b3aa82096324",
2022-05-17 21:11:07 +02:00
"version_major": 2,
2022-05-17 22:28:19 +02:00
"version_minor": 0
},
"text/plain": [
2022-05-18 12:44:39 +02:00
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'line', 'camera', 'coin', 'clo…"
2022-05-17 22:28:19 +02:00
]
2022-05-17 21:11:07 +02:00
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
2022-05-17 22:28:19 +02:00
"text/plain": [
"<function __main__.print_matrices(img_name, k)>"
]
2022-05-17 21:11:07 +02:00
},
2022-05-18 14:09:41 +02:00
"execution_count": 11,
2022-05-17 21:11:07 +02:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"interact(print_matrices, img_name=list_widget, k=int_slider_widget)"
]
2022-05-09 14:18:40 +02:00
},
{
"cell_type": "code",
2022-05-18 14:12:24 +02:00
"execution_count": 12,
2022-05-09 14:18:40 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
2022-05-18 14:09:41 +02:00
}
2022-05-17 21:11:07 +02:00
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
2022-05-18 14:12:24 +02:00
"model_id": "3ec2852728b145a0b405eb6c24ef4e9b",
2022-05-17 21:11:07 +02:00
"version_major": 2,
2022-05-17 22:28:19 +02:00
"version_minor": 0
},
"text/plain": [
2022-05-18 12:44:39 +02:00
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'line', 'camera', 'coin', 'clo…"
2022-05-17 22:28:19 +02:00
]
2022-05-17 21:11:07 +02:00
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"interact(compress_show_gray_images,img_name=list_widget,k=int_slider_widget);"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
2022-05-17 21:11:07 +02:00
},
"source": [
"### Ładowanie kolorowych obrazów"
]
},
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 13,
2022-05-17 21:11:07 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"color_images = {\n",
" \"cat\":img_as_float(data.chelsea()),\n",
" \"astro\":img_as_float(data.astronaut()),\n",
2022-05-09 14:30:12 +02:00
" \"coffee\":img_as_float(data.coffee()),\n",
2022-05-17 10:43:41 +02:00
" \"rocket\":img_as_float(data.rocket()),\n",
2022-05-09 14:30:12 +02:00
" \"koala\": img_as_float(Image.open('koala.jpeg')),\n",
2022-05-17 18:18:53 +02:00
" \"orange\": img_as_float(Image.open('orange.jpeg')),\n",
" \"teacher\": img_as_float(Image.open('teacher.jpeg'))\n",
2022-05-18 14:09:41 +02:00
"}"
2022-05-17 21:11:07 +02:00
]
2022-05-09 14:30:12 +02:00
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
2022-05-11 13:49:01 +02:00
},
"source": [
"### Kompresja kolorowych obrazów\n",
"\n",
"Obrazy kolorowe są reprezentowane w Pythonie jako trójwymiarowe tablice numpy - trzeci wymiar reprezentuje wartości kolorów (czerwony, zielony, niebieski). Jednak metoda svd ma zastosowanie do macierzy dwuwymiarowych. W tym celu musimy przekonwertować tablicę trójwymiarową na tablicę dwuwymiarową, zastosować svd i zrekonstruować ją z powrotem jako tablicę trójwymiarową. Istnieją dwa sposoby, aby to zrobić: \n",
" - Metoda reshape\n",
" - Metoda layers (warstwowa)\n",
"\n",
"Obie te metody pokażemy poniżej.\n"
]
2022-05-09 14:30:12 +02:00
},
{
"cell_type": "markdown",
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
2022-05-11 13:49:01 +02:00
"#### Metoda reshape do kompresji kolorowych obrazów\n",
" \n",
"Metoda ta polega na spłaszczeniu trzeciego wymiaru tablicy obrazów do drugiego wymiaru przy użyciu metody ```reshape``` z biblioteki ```numpy```.\n",
" \n",
" ``` image_reshaped = image.reshape((original_shape[0],original_shape[1]*3))```\n",
"\n",
2022-05-11 13:49:01 +02:00
"Dekompozycja svd jest stosowana do wynikowej, przekształconej tablicy i rekonstruowana z żądaną liczbą wartości/wektorów osobliwych. Tablica obrazów jest przekształcana z powrotem do trzech wymiarów przez kolejne wywołanie metody reshape.\n",
" \n",
2022-05-11 13:49:01 +02:00
" ```image_reconst = image_reconst.reshape(original_shape)```"
]
2022-05-09 14:30:12 +02:00
},
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 14,
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def compress_show_color_images_reshape(img_name,k):\n",
" \"\"\"\n",
2022-05-17 21:11:07 +02:00
" Kompresowanie i wyświetlanie zrekonstruowanego obrazu kolorowego przy użyciu metody reshape.\n",
" \"\"\"\n",
" image = color_images[img_name]\n",
" original_shape = image.shape\n",
" image_reshaped = image.reshape((original_shape[0],original_shape[1]*3))\n",
" image_reconst,_ = compress_svd(image_reshaped,k)\n",
" image_reconst = image_reconst.reshape(original_shape)\n",
" compression_ratio =100.0* (k*(original_shape[0] + 3*original_shape[1])+k)/(original_shape[0]*original_shape[1]*original_shape[2])\n",
2022-05-17 21:11:07 +02:00
" plt.title(\"compression ratio={:.2f}\".format(100 - compression_ratio)+\"%\")\n",
" plt.imshow(image_reconst)"
2022-05-11 13:49:01 +02:00
]
},
{
"cell_type": "code",
2022-05-18 14:09:41 +02:00
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"def compute_k_max_color_images(img_name):\n",
" image = color_images[img_name]\n",
" original_shape = image.shape\n",
" return (original_shape[0]*original_shape[1]*original_shape[2])//(original_shape[0] + 3*original_shape[1] + 1)\n",
"\n",
"\n",
2022-05-18 14:12:24 +02:00
"list_widget_color = widgets.Dropdown(options=list(color_images.keys()))\n",
"int_slider_widget = widgets.IntSlider(min=1,max=compute_k_max_color_images('cat'))\n",
"def update_k_max_color(*args):\n",
2022-05-18 14:12:24 +02:00
" img_name=list_widget_color.value\n",
" int_slider_widget.max = compute_k_max_color_images(img_name)\n",
2022-05-18 14:12:24 +02:00
"list_widget_color.observe(update_k_max_color,'value')"
2022-05-11 13:49:01 +02:00
]
},
{
2022-05-18 14:09:41 +02:00
"cell_type": "markdown",
2022-05-09 14:18:40 +02:00
"metadata": {
"pycharm": {
2022-05-18 14:09:41 +02:00
"name": "#%% md\n"
2022-05-18 12:44:39 +02:00
}
2022-05-11 13:49:01 +02:00
},
"source": [
2022-05-18 14:09:41 +02:00
"Oto interaktywny widżet do badania kompresji obrazów kolorowych metodą reshape. Przeciągając suwak w celu zmiany wartości $k$, można zaobserwować, jak zmienia się jakość obrazu. Można także badać różne obrazy, wybierając je za pomocą rozwijanego widżetu."
2022-05-11 13:49:01 +02:00
]
2022-05-09 14:18:40 +02:00
},
{
"cell_type": "code",
2022-05-18 00:08:40 +02:00
"execution_count": 16,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
2022-05-11 13:49:01 +02:00
},
2022-05-17 10:43:41 +02:00
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
2022-05-18 14:12:24 +02:00
"model_id": "eaba6da4395e43d4ab429b4cca24ad3f",
2022-05-17 10:43:41 +02:00
"version_major": 2,
2022-05-17 22:28:19 +02:00
"version_minor": 0
},
"text/plain": [
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'coffee', 'rocket', 'koala', '…"
]
2022-05-17 10:43:41 +02:00
},
"metadata": {},
"output_type": "display_data"
}
],
2022-05-11 13:49:01 +02:00
"source": [
2022-05-18 14:12:24 +02:00
"interact(compress_show_color_images_reshape,img_name=list_widget_color,k=int_slider_widget);"
2022-05-11 13:49:01 +02:00
]
},
{
"cell_type": "markdown",
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
2022-05-11 13:49:01 +02:00
"### Metoda layers (warstwowa) do kompresji kolorowych obrazów\n",
"W funkcji ``compress_show_color_images_layer``, traktujemy kolorowy obraz jako stos 3 oddzielnych dwuwymiarowych obrazów (warstwy czerwona, niebieska i zielona). Stosujemy okrojoną rekonstrukcję svd na każdej dwuwymiarowej warstwie osobno.\n",
"\n",
2022-05-11 13:49:01 +02:00
"``image_reconst_layers = [compress_svd(image[:,:,i],k)[0] for i in range(3)]``.\n",
"\n",
2022-05-11 13:49:01 +02:00
"I ponownie łączymy zrekonstruowane warstwy razem.\n",
"\n",
"```\n",
"image_reconst = np.zeros(image.shape)\n",
"for i in range(3):\n",
2022-05-11 13:49:01 +02:00
" image_reconst[:,:,,i] = image_reconst_layers[i]\n",
"``` "
]
2022-05-09 14:30:12 +02:00
},
{
"cell_type": "code",
2022-05-18 00:08:40 +02:00
"execution_count": 17,
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def compress_show_color_images_layer(img_name,k):\n",
" \"\"\"\n",
2022-05-17 21:11:07 +02:00
" Kompresowanie i wyświetlanie zrekonstruowanego obrazu kolorowego przy użyciu metody warstwowej.\n",
" \"\"\"\n",
" image = color_images[img_name]\n",
" original_shape = image.shape\n",
" image_reconst_layers = [compress_svd(image[:,:,i],k)[0] for i in range(3)]\n",
" image_reconst = np.zeros(image.shape)\n",
" for i in range(3):\n",
" image_reconst[:,:,i] = image_reconst_layers[i]\n",
" \n",
" compression_ratio =100.0*3* (k*(original_shape[0] + original_shape[1])+k)/(original_shape[0]*original_shape[1]*original_shape[2])\n",
2022-05-17 21:11:07 +02:00
" plt.title(\"compression ratio={:.2f}\".format(100- compression_ratio)+\"%\")\n",
2022-05-09 14:18:40 +02:00
" plt.imshow(image_reconst, vmin=0, vmax=255)\n"
2022-05-11 13:49:01 +02:00
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
2022-05-11 13:49:01 +02:00
},
"source": [
"Oto widżet do badania metody layers (warstwowej) kompresji obrazów kolorowych."
]
},
{
"cell_type": "code",
2022-05-18 00:08:40 +02:00
"execution_count": 18,
2022-05-11 13:49:01 +02:00
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def compute_k_max_color_images_layers(img_name):\n",
" image = color_images[img_name]\n",
" original_shape = image.shape\n",
" return (original_shape[0]*original_shape[1]*original_shape[2])// (3*(original_shape[0] + original_shape[1] + 1))\n",
"\n",
"\n",
2022-05-18 14:12:24 +02:00
"list_widget_color = widgets.Dropdown(options=list(color_images.keys()))\n",
"int_slider_widget = widgets.IntSlider(min=1,max=compute_k_max_color_images_layers('cat'))\n",
"def update_k_max_color_layers(*args):\n",
2022-05-18 14:12:24 +02:00
" img_name=list_widget_color.value\n",
" int_slider_widget.max = compute_k_max_color_images_layers(img_name)\n",
2022-05-18 14:12:24 +02:00
"list_widget_color.observe(update_k_max_color_layers,'value')"
2022-05-11 13:49:01 +02:00
]
},
{
"cell_type": "code",
2022-05-18 00:08:40 +02:00
"execution_count": 19,
"metadata": {
2022-05-09 12:39:29 +02:00
"pycharm": {
"name": "#%%\n"
}
2022-05-11 13:49:01 +02:00
},
2022-05-17 10:43:41 +02:00
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
2022-05-18 14:12:24 +02:00
"model_id": "5089ca8c1cb845478b279185787ad156",
2022-05-17 10:43:41 +02:00
"version_major": 2,
2022-05-17 22:28:19 +02:00
"version_minor": 0
},
"text/plain": [
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'coffee', 'rocket', 'koala', '…"
]
2022-05-17 10:43:41 +02:00
},
"metadata": {},
"output_type": "display_data"
}
],
2022-05-11 13:49:01 +02:00
"source": [
2022-05-18 14:12:24 +02:00
"interact(compress_show_color_images_layer,img_name=list_widget_color,k=int_slider_widget);"
2022-05-11 13:49:01 +02:00
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
2022-05-18 14:09:41 +02:00
"version": "3.8.9"
}
},
"nbformat": 4,
"nbformat_minor": 1
2022-05-17 22:28:19 +02:00
}