1
Fork 0
solar-conflux/python/denoising/Main.ipynb

653 lines
3.4 MiB
Plaintext
Raw Normal View History

{
"cells": [
{
"cell_type": "markdown",
"id": "9785abf6",
"metadata": {},
"source": [
"We have:\n",
"$$\n",
"\\nabla f = (I + \\beta A) \\vec s - \\vec y\n",
" = \\vec s - \\vec y + \\beta A \\vec s\n",
"$$ \n",
"We can substitute in the partial derivatives:\n",
"$$ \n",
"\\left(\\begin{matrix}\n",
"s_0 - y_0 + \\beta (s_0 - s_1) \\\\\n",
"s_1 - y_1 + \\beta (2s_1 - s_0 - s_2) \\\\\n",
"\\vdots \\\\\n",
"s_N - y_N + \\beta (s_N - s_{N - 1})\n",
"\\end{matrix}\\right) \n",
"= \\vec s - \\vec y + \\beta A \\vec s\n",
"$$\n",
"\n",
"Adding $\\vec y - \\vec s$ to both sides and then dividing by $\\beta$ yields:\n",
"$$ \n",
"\\left(\\begin{matrix}\n",
"s_0 - s_1 \\\\\n",
"2s_1 - s_0 - s_2 \\\\\n",
"\\vdots \\\\\n",
"s_N - s_{N - 1}\n",
"\\end{matrix}\\right) \n",
"= A \\vec s\n",
"$$\n",
"\n",
"Solving for $A$ is trivial and yields:\n",
"$$ \n",
"A = \\left(\\begin{matrix}\n",
"1 & -1 & & & & & \\\\\n",
"-1 & 2 & -1 & & & & \\\\\n",
" & -1 & 2 & -1 & & & \\\\\n",
" & & \\ddots & \\ddots & \\ddots & & \\\\\n",
" & & & -1 & 2 & -1 & \\\\\n",
" & & & & -1 & 2 & -1\\\\\n",
" & & & & & -1 & 1\n",
"\\end{matrix}\\right) \n",
"$$"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "e7d69a97",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import scipy.sparse as sparse\n",
"import modules.tridiagonal as td\n",
"import matplotlib.pyplot as plot\n",
"import matplotlib.pyplot as plot\n",
"import modules.tridiagonal as td\n",
"import modules.image_tools as image_tools\n",
"from PIL import Image # PIL is an image processing module\n",
"\n",
"def sample_with_noise(points, vectorized_g):\n",
" \"\"\"\n",
" Sample a function at a given set of points,\n",
" introducing noise in the process.\n",
"\n",
" Returns a tuple of the real values of the function\n",
" and the values with introduced noise.\n",
"\n",
" For performance reasons, this function takes in\n",
" a vectorized version of `g`. If you want to pass\n",
" a non vectorized function use `np.vectorize`. Eg:\n",
" ```py\n",
" sample_with_noise(points, np.vectorize(g))\n",
" ```\n",
" \"\"\"\n",
" gs = vectorized_g(points)\n",
" ys = gs + 0.05 * np.random.randn(len(gs))\n",
"\n",
" return (gs, ys)\n",
"\n",
"def p5(x):\n",
" \"\"\"\n",
" Vectorized version of the function\n",
" described in the pdf.\n",
" \"\"\"\n",
" n = 5\n",
" result = 0\n",
"\n",
" for k in range(n + 1):\n",
" result += x**k\n",
"\n",
" return result/(n + 1)\n",
"\n",
"def create_A(n):\n",
" \"\"\"\n",
" Creates the (n+1) x (n + 1) A matrix.\n",
" (see the latex above for it's definition)\n",
" \"\"\"\n",
" a = 2*np.ones(n + 1)\n",
" a[0] = 1\n",
" a[-1] = 1\n",
"\n",
" c = -np.ones(n)\n",
" e = -np.ones(n)\n",
"\n",
" return td.create(a, c, e)\n",
"\n",
"def smooth(data, beta):\n",
" \"\"\"\n",
" Smooth noisy data (y) by means of solving \n",
" a minimization problem.\n",
"\n",
" Args:\n",
" data (numpy.array): noisy data to be smoothed (y)\n",
" beta (float): parameter >= 0 that balances fit and smoothing\n",
"\n",
" Returns:\n",
" numpy array of smoothed data (s)\n",
" \"\"\"\n",
" # We need to solve for s in:\n",
" # (I + βA)s - y = 0\n",
" # <=> (I + βA)s = y\n",
" #\n",
" # Because A and I are tridiagonal, I + βA\n",
" # is tridiagonal as well (linear combinations\n",
" # of tridiagonal matrices are themselves\n",
" # tridiagonal)\n",
" #\n",
" # This means we can use our existing implementation\n",
" # of tridiagonal linear equation system solving.\n",
" # \n",
" # We start by constructing \n",
" # iba := I + βA\n",
" n = len(data) - 1\n",
"\n",
" # I + βA\n",
" iba = td.add(\n",
" td.identity(n + 1),\n",
" td.scale(beta, create_A(n))\n",
" )\n",
"\n",
" data_smoothed = td.solve(*iba, data)\n",
"\n",
" return data_smoothed"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "2b9f2b79",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Reusable function to plot the data\n",
"def plot_denoise_results(beta, N, ax):\n",
" # Create the data\n",
" x = np.linspace(-1, 1, num=N+1)\n",
" g, y = sample_with_noise(x, p5)\n",
" s = smooth(y, beta)\n",
"\n",
" ax.set_title(f\"β={beta} and {N=}\")\n",
" ax.set_xlabel(\"x\")\n",
" ax.set_ylabel(\"y\")\n",
" ax.plot(x, y, \".\", label=\"raw data points\")\n",
" ax.plot(x, g, \"-\", label=\"original function\")\n",
" ax.plot(x, s, \"-\", label=\"denoised values\")\n",
" ax.legend()\n",
"\n",
"\n",
"N = 100\n",
"beta = 10\n",
"\n",
"fig, ax = plot.subplots()\n",
"fig.suptitle(\"Data denoising results\")\n",
"\n",
"# Plot the data\n",
"plot_denoise_results(beta, N, ax)"
]
},
{
"cell_type": "markdown",
"id": "f2e5c860",
"metadata": {},
"source": [
"We notice that finding a point where $\\nabla f(s) = 0$ is the same as\n",
"finding a point where $\\frac 1 \\beta \\nabla f(s) = \\nabla \\frac 1 \\beta f(s) = 0$.\n",
"We can use this to our advantage, by defining $h(s) = \\frac 1 \\beta f(s)$ and\n",
"finding the points where $\\nabla h(s) = 0$ instead. When $\\beta \\to \\infty$, we have:\n",
"$$\n",
"\\lim_{\\beta \\to \\inf} h _\\beta (s) =\n",
"\\lim_{\\beta \\to \\inf} \n",
" \\frac 1 {2\\beta} \\sum_{k=0}^n (y_k - s_k)^2\n",
" +\\frac 1 2 \\sum_{k=1}^n (s_k - s_{k - 1})^2\n",
" = \\frac 1 2 \\sum_{k=1}^n (s_k - s_{k - 1})^2\n",
"$$\n",
"\n",
"It now becomes trivial to verify that $\\nabla f(s) = As$.\n",
"Looking at the value of $A$ we notice that any vector with all values\n",
"equal to some constant are solutions for this equation.\n",
"This means the result will be a constant function\n",
"(which might differ based on the linear equation solver we are using)."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "d7f7dbdf",
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1280x960 with 9 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axs = plot.subplots(\n",
" 3,\n",
" 3,\n",
" layout=\"constrained\",\n",
" figsize=(12.8, 9.6)\n",
")\n",
"\n",
"fig.suptitle(r\"Data denoising results as $\\beta \\to \\infty$\")\n",
"\n",
"N = 100\n",
"\n",
"for i in range(len(axs.flat)):\n",
" ax = axs.flat[i]\n",
" plot_denoise_results(4**i, N, ax)"
]
},
{
"cell_type": "markdown",
"id": "3c9f50cc",
"metadata": {},
"source": [
"When $\\beta \\to 0$ we have:\n",
"$$\n",
"\\lim_{\\beta \\to 0} \\nabla f(s) =\n",
"\\lim_{\\beta \\to 0} (I + \\betaA)s - y = s - y\n",
"$$\n",
"\n",
"This means when solving for $\\nabla f(s) = 0$, we are solving\n",
"the equation $s - y = 0$, which has the solution $s = y$.\n",
"The resulting function will then be one equal to the data containing the noise."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "dfc485d5",
"metadata": {
"lines_to_next_cell": 1
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAPLCAYAAAD4+99NAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3gUZdfH8e+m9wAJJKGk0IN0AlKkiYCIqICC5RFR9FVREZAiViwPRVGxtwcEC8UCNpAiUgREutJUSkIogRBKEtKzO+8fS1aWFBIg2U3y+1xXLsjsPTNnxnUPc/YuJsMwDERERERERERERKTSc3F0ACIiIiIiIiIiIuIcVCwUERERERERERERQMVCEREREREREREROUfFQhEREREREREREQFULBQREREREREREZFzVCwUERERERERERERQMVCEREREREREREROUfFQhEREREREREREQFULBQREREREREREZFzVCwUERERERERERERQMVCEREREREREREROUfFQhERESnQrFmzMJlMth8vLy9CQ0Pp3r07kydPJjEx8ZKPvX79eiZOnMiZM2euXMBFmDhxIiaTqUzOdTF59zUuLq5U96nICrofZf2eulLS09N54YUXaNy4MV5eXgQFBXHHHXdw+vTpK3L8s2fPMnLkSGrWrImXlxctW7Zk3rx5V+TYIiIiUjGpWCgiIiJF+uSTT/jtt99Yvnw57777Li1btmTq1KlER0fz888/X9Ix169fzwsvvFDuCjtXQt++ffntt98ICwsr1X0qm/L4njIMgzvuuIPp06fz4IMP8tNPP/Hcc88xf/58XnvttStyjgEDBjB79myef/55fvrpJ9q2bcsdd9zBnDlzrsjxRUREpOJxc3QAIiIi4tyaNm1KTEyM7feBAwcyatQorrnmGgYMGMDevXsJCQlxYITlS/Xq1alevXqp71Pa0tPT8fHxcXQY5drq1av5/vvv+eqrr7j11lsBbD1309LSLvv4ixcvZvny5cyZM4c77rjDdvyDBw8yduxYBg8ejKur62WfR0RERCoW9SwUERGREgsPD+e1114jNTWVDz/8EIB9+/Zx77330qBBA3x8fKhVqxb9+vVjx44ddvtOnDiRsWPHAhAVFWUb5rxq1apiH6MoixYtomXLlnh6ehIVFcW0adMKbLd3717uvPNOatSogaenJ9HR0bz77rv5YjWZTOzatYs77riDwMBAQkJCuO+++0hOTs53zLVr19KjRw/8/f3x8fGhY8eOLFq0yK5NQUNoT5w4wf/93/9Rp04dPD09qV69Op06dbL13Cxon5LG9t1339G8eXM8PT2pW7cub775ZrGHZ+e127p1K7feeitVq1alXr16xb6PxbnGoUOHEhkZWei5LxZfYe+pi523MMV9L17q8QG++uorqlatSv/+/W3b1qxZw/Hjx7n22msvun+eN954g2+//Tbf9oULF+Ln58dtt91mt/3ee+/l6NGj/P7778U+h4iIiFQe6lkoIiIil+SGG27A1dWVNWvWAHD06FGCgoKYMmUK1atX59SpU8yePZurr76abdu20ahRIwDuv/9+Tp06xdtvv82CBQtsQ2ubNGnC9u3bi3WMwqxYsYKbb76ZDh06MG/ePMxmM6+88grHjx+3a7d79246duxoK3qGhoaydOlSRowYQVJSEs8//7xd+4EDBzJ48GCGDRvGjh07mDBhAgAzZ860tVm9ejU9e/akefPmzJgxA09PT9577z369evH3LlzGTx4cKFx33333WzdupX//ve/NGzYkDNnzrB161ZOnjx50f8OxYltyZIlDBgwgC5dujB//nxyc3OZNm1avvtyMQMGDOD222/noYceIi0trUT38XKu8WKKek8NGjToks5b3Pfz5VzX+vXrufrqq23nW7p0KePGjaNHjx7ceOONxb7+zZs3M378eL788ktuueUW2/adO3cSHR2Nm5v9P/mbN29ue71jx47FPo+IiIhUEoaIiIhIAT755BMDMDZt2lRom5CQECM6OrrA13Jzc43s7GyjQYMGxqhRo+xee/XVVw3AiI2NLTKGoo5RkKuvvtqoWbOmkZGRYduWkpJiVKtWzTj/nz29e/c2ateubSQnJ9vt/+ijjxpeXl7GqVOnDMMwjOeff94AjFdeecWu3fDhww0vLy/DYrHYtrVv396oUaOGkZqaahd/06ZNjdq1a9va5t3X86/dz8/PGDlyZKHXVdA+JYmtbdu2Rp06dYysrCzbttTUVCMoKMgozj8H88713HPP2W0v7n0szjXec889RkRERKHnPl9B96Ow99TFzltchb0XL/X4GRkZhpubm/H8888bL774ogEYgBEeHm4cOnSoxLHdeeedhru7u7Fw4ULb9gYNGhi9e/fO1/7o0aMGYEyaNKnEcYuIiEjFp2HIIiIicskMw7D9PTc3l0mTJtGkSRM8PDxwc3PDw8ODvXv3smfPnmId73KOkZaWxqZNmxgwYABeXl627f7+/vTr18/2e2ZmJitWrKB///74+PiQm5tr+7nhhhvIzMxkw4YNdse+6aab7H5v3rw5mZmZthWh09LS+P3337n11lvx8/OztXN1deXuu+/m8OHD/P3334XG3q5dO2bNmsXLL7/Mhg0byMnJufjNKkFsmzdv5pZbbsHDw8PWzs/Pz+6+FMfAgQNtfy/pfbyca7wcl3re4r4XL/X4W7duJTc3l3bt2nHXXXexdOlSXnjhBVJTU+nSpQtnz54FICkpyW5V8oJ+3NzcmDNnDjk5OQwaNMiux2hRQ7idZYVwERERcS4ahiwiIiKXJC0tjZMnT9KsWTMARo8ezbvvvsv48ePp2rUrVatWxcXFhfvvv5+MjIxiHfNyjnH69GksFguhoaH5Xjt/28mTJ8nNzeXtt9/m7bffLvBYSUlJdr8HBQXZ/e7p6Qlgi+n06dMYhlHgasU1a9a0nbcw8+fP5+WXX+Z///sfzz77LH5+fvTv359XXnmlwOu5lNgKWoSmpAvTnH99Jb2Pl3ONl+NSz1vc9+KlHn/jxo2AtdgYHBxM3bp16dWrFw0bNuSOO+5gw4YNXHfddfj7+/Pxxx9f9DqXLFnCN998w80332x7TwQFBRX4vjt16hQA1apVu+hxRUREpPJRsVBEREQuyaJFizCbzXTr1g2Azz//nCFDhjBp0iS7dklJSVSpUqVYx7ycY1StWhWTycSxY8fyvXb+tqpVq9p6/D3yyCMFHisqKqpY8Z5/TBcXFxISEvK9dvToUQCCg4ML3T84OJjp06czffp04uPj+f7773nyySdJTExkyZIlJYqloNhMJlOB8xMWdK+Kcn5PtJLex4tdo5eXF1lZWfmOcWHhtqQu9d4W9714qcffuHEjdevWLfR9kVdk9vT05P777y/yGhctWsSPP/7Irbfeyty5c21zFDZr1oy5c+eSm5trN29h3iItTZs2LfK4IiIiUjlpGLKIiIiUWHx8PGPGjCEwMJAHH3wQsBaS8nq15Vm0aBFHjhzJt/+Fvd/ylOQYF/L19aVdu3YsWLCAzMxM2/bU1FR++OEH2+8+Pj50796dbdu20bx5c2JiYvL9XNhbrzjnvvrqq1mwYIHdNVksFj7//HNq165Nw4YNi3Ws8PBwHn30UXr27MnWrVtLFEdhscXExPDtt9+SnZ1t23727Fl+/PHHSz7u5dzHgq4xMjKSxMREu6JmdnY2S5cuLVY8hb2nLnbewlzKe7Ekx9+4cWO+nqiGYfC///2Ppk2b0qRJkyL3P9+rr75qW0jn/KJg//79OXv2LN98841d+9mzZ1OzZk3b4ioiIiIi51PPQhERESnSzp07bXPRJSYm8uuvv/LJJ5/g6urKwoULqV69OgA33ngjs2bNonHjxjRv3pwtW7bw6quvUrt27XzHzBu6/Oabb3LPPffg7u5Oo0aNSnSMgrz00ktcf/319OzZkyeeeAKz2czUqVPx9fW1Db3MO+8111xD586defjhh4mMjCQ1NZV9+/bxww8/8Msvv5T4Pk2ePJmePXvSvXt3xowZg4eHB++99x47d+5k7ty5hc4Pl5ycTPfu3bnzzjt
"text/plain": [
"<Figure size 1280x960 with 6 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axs = plot.subplots(\n",
" 2,\n",
" 3,\n",
" layout=\"constrained\",\n",
" figsize=(12.8, 9.6)\n",
")\n",
"\n",
"fig.suptitle(r\"Data denoising results as $\\beta \\to 0$\")\n",
"\n",
"N = 100\n",
"\n",
"for i in range(len(axs.flat)):\n",
" ax = axs.flat[i]\n",
" plot_denoise_results(2**-i, N, ax)"
]
},
{
"cell_type": "markdown",
"id": "7cd79ba5",
"metadata": {
"lines_to_next_cell": 0
},
"source": [
"We know from the last lecture that picking any\n",
"$\\alpha$ which satisfies $\\alpha < \\frac 2 {\\lambda_H}$\n",
"leads to a converging sequence, where $\\lambda_H$ is\n",
"the largest eigenvalue of the hessian.\n",
"Let $\\lambda_A$ be the largest eigenvalue of $A$.\n",
"Our hessian is $I + \\beta A$, therefore we have $Ax = \\lambda_A x$ \n",
"(for some vector $x$, from the definition of the eigenvalue for $\\lambda_A$).\n",
"We can multiply by $\\beta$ and add $x$ to both sides to get\n",
"$(I + \\beta A)I = (1 + \\beta\\lambda_A) x$,\n",
"which means $1 + \\beta\\lambda_A$ is indeed an eigenvalue of the hessian.\n",
"\n",
"Is it the biggest one though? \n",
"Let's assume a bigger eigenvalue $\\lambda_M$ exists (for the hessian).\n",
"This means that $(I + \\beta A)y = \\lambda_M y$ (for some vector $y$).\n",
"By distributivity we then also have $y + \\beta A y = \\lambda_M y$,\n",
"which makes it easy to then notice that $\\frac {\\lambda_M-1} \\beta$\n",
"is an eigenvalue for $A$.\n",
"Earlier we have assumed that $\\lambda_M > \\lambda_H$,\n",
"therefore $\\frac {\\lambda_M - 1} \\beta > \\frac {\\lambda_H - 1} \\beta = \\lambda_A$,\n",
"which would imply $\\lambda_A$ is not the biggest eigenvalue for $A$,\n",
"hence a contradiction.\n",
"This let's us conclude that $\\lambda_H$ is the biggest eigenvalue for the hessian,\n",
"and therefore our sequence will converge given\n",
"$\\alpha < \\frac 2 {\\lambda _H} = \\frac 2 {1 + \\beta \\lambda_A}$."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "cef74c06",
"metadata": {
"lines_to_next_cell": 1,
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1280x960 with 6 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def smooth_iterative(data, beta, num_iterations):\n",
" \"\"\"\n",
" Smooth noisy data (y) by means of solving a minimization problem\n",
" iteratively with the gradient descent method.\n",
"\n",
" Args:\n",
" data (numpy.array): of the noisy data to be smoothed (y)\n",
" beta (float): parameter >= 0 that balances fit and smoothing\n",
" num_iterations (int): number of gradient descent iterations (>0)\n",
"\n",
" Returns:\n",
" numpy array of smoothed data (s)\n",
" \"\"\"\n",
"\n",
" n = len(data) - 1\n",
"\n",
" A = create_A(n)\n",
"\n",
" # Our initial eigenvalue guess\n",
" initial_guess = np.zeros(n + 1)\n",
" initial_guess[0] = 1\n",
"\n",
" max_eigenvalue = td.largest_eigenvalue(\n",
" *A, \n",
" initial_guess,\n",
" 30\n",
" )\n",
"\n",
" alpha = 1.5 / (1 + beta * max_eigenvalue)\n",
" x = np.zeros(n + 1)\n",
"\n",
" for _ in range(num_iterations):\n",
" gradient = td.multiply_vector(\n",
" *td.add(\n",
" td.identity(n + 1), \n",
" td.scale(beta, A)\n",
" ),\n",
" x\n",
" ) - data\n",
" # print(f\"{alpha=}\")\n",
" # print(f\"{gradient=}\")\n",
" # print(f\"{x=}\")\n",
" x = x - alpha * gradient\n",
"\n",
" return x\n",
"\n",
"fig, axs = plot.subplots(\n",
" 3,\n",
" 2,\n",
" # 1,\n",
" # 1,\n",
" layout=\"constrained\",\n",
" figsize=(12.8, 9.6)\n",
")\n",
"\n",
"N = 100\n",
"beta = 10\n",
"\n",
"fig.suptitle(f\"Iterative vs direct denoising comparison for β={beta} and {N=}\")\n",
"\n",
"for i in range(len(axs.flat)):\n",
"# for _ in range(1):\n",
" ax = axs.flat[i]\n",
" iterations = 3**(i + 1)\n",
" # ax = axs\n",
" # iterations = 3 ** 5\n",
"\n",
" # Create the data\n",
" x = np.linspace(-1, 1, num=N+1)\n",
" g, y = sample_with_noise(x, p5)\n",
" sd = smooth(y, beta) # Indirect\n",
" si = smooth_iterative(y, beta, iterations) # Direct\n",
"\n",
" # Plot the data\n",
" ax.set_title(f\"{iterations=}\")\n",
" ax.set_xlabel(\"x\")\n",
" ax.set_ylabel(\"y\")\n",
" ax.plot(x, y, \".\", label=\"raw data points\")\n",
" ax.plot(x, g, \"-\", label=\"original function\")\n",
" ax.plot(x, sd, \"-\", label=\"directly denoised values\")\n",
" ax.plot(x, si, \"-\", label=\"iteratively denoised values\")\n",
" ax.legend()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "8079a686",
"metadata": {
"lines_to_next_cell": 0
},
"outputs": [],
"source": [
"def hessian(beta, nx, ny):\n",
" \"\"\"\n",
" Compute the Hessian of the image denoising problem, given by\n",
" `H = I + beta C^T C`.\n",
"\n",
" Args:\n",
" beta (float): parameter >= 0 that balances fit and smoothing\n",
" nx (int): number of pixels in x-direction\n",
" ny (int): number of pixels in y-direction\n",
"\n",
" Returns:\n",
" H: sparse hessian matrix (scipy.sparse.csr_array)\n",
" \"\"\"\n",
" size = nx * ny\n",
"\n",
" b_upper_diagonal = np.ones(nx)\n",
" b_upper_diagonal[-1] = 0\n",
"\n",
" b_main_diagonal = -np.ones(nx)\n",
" b_main_diagonal[-1] = 0\n",
"\n",
" # We want to reuse the tridiagonal -> csr conversion code,\n",
" # so we first define C as a tridiagonal matrix.\n",
" tridiagonal_C = td.create(\n",
" np.resize(b_main_diagonal, size),\n",
" np.resize(b_upper_diagonal, size - 1),\n",
" np.zeros(size - 1)\n",
" )\n",
"\n",
" C = td.to_csr(*tridiagonal_C)\n",
" H = sparse.identity(size, format=\"csr\") + beta * (C.T @ C)\n",
"\n",
" return H"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "1775b494",
"metadata": {
"lines_to_next_cell": 0
},
"outputs": [
{
"data": {
"image/png": "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ER61ypGiuhpUWnDnnXcSDoeZP38+wWAw4rlgMMjvf/97wuEwd95552Htf/LkycCB1XwlH374IYFA4PAOuhU0Gg16vT5icHC73bz99tud9h5HihioTCZTxOOvvPJKxP99+vQhPT2df/zjHxGPFxUVsXr16ojHzjnnHGprawkGg4wcObLFT58+fY7Cmah0BNXiVWnBhAkTeOaZZ1iwYAETJ07khhtuICcnh6KiIl544QXWrFnDM888w/jx4w9r/wMGDOCSSy7hySefRKfTcfrpp5OXl8eTTz5JXFxchK/0SJg5cyZPPfUUl156Kddddx21tbUsXry4hcgdT8aPH09CQgK/+93vuPfeezEYDLzzzjts3rw5YjutVsuiRYu4/vrrmTNnDldffTUNDQ0sWrSIjIyMiGt28cUX884773D22Wfzxz/+kdGjR2MwGCgpKeGbb77hvPPO4/zzzz/Wp6qiQBVelVa58cYbGTVqFE8++SQ333wztbW1JCYmMnHiRP73v/8xbty4I9r/m2++SUZGBn/96195+umnGTp0KP/4xz/41a9+RXx8fKecw+mnn84bb7zBY489xrnnnkuXLl347W9/S2pqKtdcc02nvMeRkpSUxH//+19uvvlmLrvsMmJiYjjvvPP44IMPWmTrXXfddWg0Gh5//HHOP/98unXrxh133MG///3viMU6nU7Hp59+yrPPPsvbb7/NI488gl6vJysriylTpjBo0KBjfZoqUaiZayonDKtXr2bChAm88847XHrppcf7cE4KGhoa6N27N7Nnz+bVV1893oej0k5U4VU5LixdupQffviBESNGYLFY2Lx5M48++ihxcXFs2bKlRcSCyoFFtIceeojTTjuNpKQkCgsLefrpp9m5cyfr169nwIABx/sQVdqJ6mpQOS7Y7Xa+/vprnnnmGZxOJ8nJycyYMYNHHnlEFd02MJlMFBQUMH/+fOrq6rBarYwdO5aXX35ZFd2TDNXiVVFRUTnGHNdwshdffJHc3FzMZjMjRozgu+++O56Ho6KionJMOG7C+8EHH7BgwQL+/Oc/s3HjRiZNmsSMGTMiVmdVVFRUTkWOm6thzJgxDB8+nJdeekk+1q9fP2bPns0jjzxyPA5JRUVF5ZhwXBbXfD4fGzZs4I477oh4fPr06S2ycOBA7VZl6btQKERdXR1JSUmH3VJGRUVFpbMJh8M4nU4yMzMPmgh0XIS3pqaGYDDYouBHWlpai7xzOFCYe9GiRcfq8FRUVFSOiOLi4jbrWcNxDieLtlbD4XCrFuydd97JwoUL5f+NjY3k5ORQXFyM3W4/6sepoqKi0h4cDgfZ2dmHLER0XIQ3OTkZnU7XwrqtqqpqteydyWRqNb/ebrerwquionLCcSgX6HGJajAajYwYMYKlS5dGPL506dLDLryioqKicrJw3FwNCxcu5PLLL2fkyJGMGzeOV199laKiIn73u98dr0NSUVFROSYcN+GdN28etbW13H///ZSXlzNw4EA+//xzunbterwOSUVFReWYcFKmDDscDuLi4mhsbFR9vCoqKicM7dUmtUiOyimB0n4Qf4soGbHQIR7vrELrKiqHi/oNVDnpUQotHFhRFqIbCoUIhUIttlFROZ6owqty0qMU1dbazodCIflb/K2icjxRXQ0qpxyhUEg2zXS73RQ
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Here so we can experiment with different picutres\n",
"image_name = \"sonic\"\n",
"image_tools.create_noisy_image(\"./images/\", image_name + \".jpg\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "a5dbb0d2",
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1280x960 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"image = np.asarray(Image.open(f\"./images/{image_name}_gray_noisy.jpg\"))\n",
"\n",
"fig, axs = plot.subplots(\n",
" 2,\n",
" 4,\n",
" layout=\"constrained\",\n",
" figsize=(12.8, 9.6)\n",
")\n",
"\n",
"fig.suptitle(\"Image row denoising results\")\n",
"\n",
"ny, nx = image.shape\n",
"flat_image = image.flatten()\n",
"for i in range(len(axs.flat)):\n",
" beta = 3**i\n",
" ax = axs.flat[i]\n",
"\n",
" H = hessian(beta, nx, ny)\n",
"\n",
" smooth = sparse.linalg.spsolve(H, flat_image).reshape(image.shape)\n",
" smooth_image = Image.fromarray(smooth.astype(np.uint8), mode=\"L\")\n",
"\n",
" ax.set_title(f\"β={beta}\")\n",
" ax.imshow(smooth_image)"
]
},
{
"cell_type": "markdown",
"id": "40fbd1dd",
"metadata": {},
"source": [
"Finding the equation for $f$ when we want to denoise by column would simply require us to consider an image $p_c = p^T$:\n",
"$$\n",
"f(s) = \\frac 1 2 \\sum_{i = 1}^{N_x} \\sum_{j = 1}^{N_y} (y_{j, i} - s_{j, i})^2\n",
"+ \\beta \\frac 1 2 \\sum_{i = 1}^{N_x} \\sum_{j = 2}^{N_y} (s_{j, i} - s_{j - 1, i})^2\n",
"$$\n",
"\n",
"In this case, our hessian looks almost the same as the one in the original equation, with the difference being $B$ having the ones under the main diagonal instead of on top.\n",
"\n",
"For the actual python implementation, we can simply transpose the image before/after the denoising:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "d48e32df",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAOqCAYAAAA7UwOyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOy9d5ijZ3X3/1Ud9VEdSdPbzsxWb3HvawjGYEJ5kwAJxQkpBPhdGELooVcneYG8eRPehBonoYVAgFDjAga3XdvbZ2d3epE0mpFmpJE00qj9/hh/j59xARM3NpzPde1lr1blKfdz3+d8T7lNzWazCUVRFEVRFEVRFEVRFEVRfu0xP9MHoCiKoiiKoiiKoiiKoijKrwYqFiqKoiiKoiiKoiiKoiiKAkDFQkVRFEVRFEVRFEVRFEVRHkTFQkVRFEVRFEVRFEVRFEVRAKhYqCiKoiiKoiiKoiiKoijKg6hYqCiKoiiKoiiKoiiKoigKABULFUVRFEVRFEVRFEVRFEV5EBULFUVRFEVRFEVRFEVRFEUBoGKhoiiKoiiKoiiKoiiKoigPomKhoiiKovwa84UvfAEmkwmHDx9+pg/lnOHqq6/G1Vdf/UwfxpPKDTfcgN7e3mf6MAAA09PTMJlM+MIXvvBLfe5X6RyeaR7tWnzkIx/BN7/5zWfkeBRFURRFObdQsVBRFEVRFEX5lSEej+Ouu+7C85///F/qc3/xF3+Bb3zjG0/RUZ37qFioKIqiKMrjxfpMH4CiKIqiKIqikJaWFlx88cW/9OcGBgaegqP571MqleByuZ7pw1AURVEURfml0cxCRVEURVG2cMMNN8Dj8eD06dO49tpr4Xa7EY/H8bGPfQwAcPfdd+Pyyy+H2+3G0NAQvvjFL275/NLSEl73utdhx44d8Hg8aGtrwzXXXIM77rjjEb81Pz+P3/qt34LX64Xf78fv/d7v4dChQ49ahnr48GH85m/+JoLBIBwOB/bt24evfvWrj+ucKpUKPvCBD2D79u1wOBwIhUI4ePAg7rzzTnlPuVzGO97xDvT19cFut6OjowOvf/3rsbq6+nO/+/bbb4fJZMLtt9++5fVHK6d9oteWZeO33XYb/vRP/xThcBihUAgveclLkEgkHte1+MIXvoDh4WG0tLRg+/bt+Kd/+qdHfd/GxgY+9KEPYWRkBC0tLYhEIvj93/99LC0tbXlfb28vrr/+enz/+9/H/v374XQ6MTIygs997nOP+M4TJ07ghS98IQKBABwOB/bu3fuIc3y067a0tIQ//uM/RldXlxzLZZddhv/6r//acm0fXnprMpnwhje8ATfffDO2b98Ol8uF8847D9/5zncecWz/8R//gT179qClpQX9/f341Kc+hfe9730wmUy/6JLi6quvxq5du/CTn/wEl156KVwuF/7gD/4AAJDP5/GWt7xly7i68cYbUSwWt3zH1772NVx00UVobW2Fy+VCf3+/fAfw0L2fnp7e8rnHGn8Pvw7FYhFf/OIXYTKZYDKZpJS+VCrJ8TkcDgSDQZx//vn40pe+9AvPW1EURVGU/5loZqGiKIqiKI+gWq3iJS95CV772tfiz//8z/Gv//qveMc73oF8Po+vf/3reNvb3obOzk78n//zf3DDDTdg165dOHDgAAAgm80CAN773vciFouhUCjgG9/4Bq6++mrccsstIlIUi0UcPHgQ2WwWH//4xzE4OIjvf//7eOlLX/qI47ntttvw3Oc+FxdddBE+/elPo7W1FV/+8pfx0pe+FKVSCTfccMNjnkutVsN1112HO+64AzfeeCOuueYa1Go13H333ZidncWll16KZrOJF73oRbjlllvwjne8A1dccQWOHTuG9773vbjrrrtw1113oaWl5Rm/tuQP//AP8fznPx//+q//irm5Ofz5n/85XvGKV+DWW2/9ub/9hS98Ab//+7+PF77whfjrv/5r5HI5vO9970OlUoHZ/FAMudFo4IUvfCHuuOMOvPWtb8Wll16KmZkZvPe978XVV1+Nw4cPw+l0yvuPHj2KP/uzP8Pb3/52RKNRfOYzn8FrXvMaDA4O4sorrwQAjI2N4dJLL0VbWxv+5m/+BqFQCP/8z/+MG264AYuLi3jrW9/6mMf9yle+Evfffz8+/OEPY2hoCKurq7j//vuRyWR+4fX+z//8Txw6dAgf+MAH4PF4cNNNN+HFL34xxsbG0N/fDwD4/ve/j5e85CW48sor8ZWvfAW1Wg1/9Vd/hcXFxV/4/SSZTOIVr3gF3vrWt+IjH/kIzGYzSqUSrrrqKszPz+Od73wn9uzZg5MnT+I973kPjh8/jv/6r/+CyWTCXXfdhZe+9KV46Utfive9731wOByYmZn5hffz8XLXXXfhmmuuwcGDB/EXf/EXAACfzwcAePOb34ybb74ZH/rQh7Bv3z4Ui0WcOHHicV1bRVEURVH+h9JUFEVRFOXXls9//vNNAM1Dhw7Ja69+9aubAJpf//rX5bVqtdqMRCJNAM37779fXs9kMk2LxdJ885vf/Ji/UavVmtVqtfmsZz2r+eIXv1he/7//9/82ATS/973vbXn/n/zJnzQBND//+c/LayMjI819+/Y1q9Xqlvdef/31zXg83qzX64/5+//0T//UBND8x3/8x8d8z/e///0mgOZNN9205fWvfOUrTQDNf/iHf5DXrrrqquZVV10lf7/tttuaAJq33Xbbls9OTU094jye6LXl/Xrd61635bduuummJoBmMpl8zHOs1+vN9vb25v79+5uNRkNen56ebtpstmZPT4+89qUvfekRx9lsNpuHDh1qAmj+3d/9nbzW09PTdDgczZmZGXltfX29GQwGm3/yJ38ir73sZS9rtrS0NGdnZ7d853XXXdd0uVzN1dXVx7xuHo+neeONNz7muTWbm9fWeA7NZrMJoBmNRpv5fF5eS6VSTbPZ3PzoRz8qr11wwQXNrq6uZqVSkdfW1taaoVCo+XjM5auuuqoJoHnLLbdsef2jH/1o02w2b3m+ms1m89/+7d+aAJrf/e53m81ms/lXf/VXTQByDR4N3vupqaktrz/a+Hu0a+F2u5uvfvWrH/G9u3btar7oRS/6heeoKIqiKMqvD1qGrCiKoijKIzCZTHje854nf7darRgcHEQ8Hse+ffvk9WAwiLa2NszMzGz5/Kc//Wns378fDocDVqsVNpsNt9xyC0ZHR+U9P/7xj+H1evHc5z53y2df/vKXb/n7+Pg4Tp8+jd/7vd8DsJkpyD/Pe97zkEwmMTY29pjn8r3vfQ8Oh2NLSefDYQbXwzMUf/u3fxtutxu33HLLY372l+WJXlsA+M3f/M0tf9+zZw8APOp7ydjYGBKJBH73d393S2ltT08PLr300i3v/c53vgO/348XvOAFW6733r17EYvFHlHyunfvXnR3d8vfHQ4HhoaGthzPrbfeimc961no6ura8tkbbrgBpVIJd91112Me+4UXXogvfOEL+NCHPoS7774b1Wr1Md/7cA4ePAiv1yt/j0ajW65rsVjE4cOH8aIXvQh2u13e5/F48IIXvOBx/04gEMA111yz5bXvfOc72LVrF/bu3bvlOl577bVbSocvuOACAMDv/M7v4Ktf/SoWFhYe9+8+US688EJ873vfw9vf/nbcfvvtWF9ff9p+W1EURVGUX01ULFQURVEU5RG4XC44HI4tr9ntdgSDwUe81263o1wuy9//9//+3/jTP/1TXHTRRfj617+Ou+++G4cOHcJzn/vcLUJEJpNBNBp9xPc9/DWWgr7lLW+BzWbb8ud1r3sdAGB5efkxz2VpaQnt7e1bymwfTiaTgdVqRSQS2fK6yWRCLBZ7Uksyn8i1JaFQaMvfWSL984QenkMsFnvEvz38tcXFRayursJutz/imqdSqUdc74cfD4/p4fc7Ho8/4n3t7e1bju/R+MpXvoJXv/rV+MxnPoNLLrkEwWAQr3rVq5BKpR7zM4/32FZWVtBsNh/XWPx5PNq5LS4u4tixY4+4hl6vF81mU67jlVdeiW9+85uo1Wp41atehc7OTuzatetp6Rv4N3/zN3jb296Gb37zmzh48CC
"text/plain": [
"<Figure size 1280x960 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"image = np.asarray(Image.open(f\"./images/{image_name}_gray_noisy.jpg\")).T\n",
"\n",
"fig, axs = plot.subplots(\n",
" 2,\n",
" 4,\n",
" layout=\"constrained\",\n",
" figsize=(12.8, 9.6)\n",
")\n",
"\n",
"fig.suptitle(\"Image column denoising results\")\n",
"\n",
"ny, nx = image.shape\n",
"flat_image = image.flatten()\n",
"for i in range(len(axs.flat)):\n",
" beta = 3**i\n",
" ax = axs.flat[i]\n",
"\n",
" H = hessian(beta, nx, ny)\n",
"\n",
" smooth = sparse.linalg.spsolve(H, flat_image).reshape(image.shape).T\n",
" smooth_image = Image.fromarray(smooth.astype(np.uint8), mode=\"L\")\n",
"\n",
" ax.set_title(f\"β={beta}\")\n",
" ax.imshow(smooth_image)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}