{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "| Credentials |                                  |\n",
    "|----|----------------------------------|\n",
    "|Host | Montanuniversitaet Leoben        |\n",
    "|Web | https://cps.unileoben.ac.at      |\n",
    "|Mail | cps@unileoben.ac.at              |\n",
    "|Author | Fotios Lygerakis                 |\n",
    "|Corresponding Authors | fotios.lygerakis@unileoben.ac.at |\n",
    "|Last edited | 28.09.2023                       |"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "e94a99fbf273dd6e"
  },
  {
   "cell_type": "markdown",
   "source": [
    "This notebook contains code for visualizing the convolution operation."
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "ffa147d97adb2a8"
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 1500x500 with 3 Axes>",
      "image/png": "[encoded data, 53756 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.patches as patches\n",
    "from matplotlib.animation import FuncAnimation, PillowWriter\n",
    "\n",
    "# Sample image (5x5)\n",
    "image = np.array([\n",
    "    [1, 2, 3, 4, 5],\n",
    "    [5, 4, 3, 2, 1],\n",
    "    [1, 2, 3, 4, 5],\n",
    "    [5, 4, 3, 2, 1],\n",
    "    [1, 2, 3, 4, 5]\n",
    "])\n",
    "\n",
    "# Kernel (3x3)\n",
    "kernel = np.array([\n",
    "    [1, 0, -1],\n",
    "    [1, 0, -1],\n",
    "    [1, 0, -1]\n",
    "])\n",
    "# # kernel (2x2)\n",
    "# kernel = np.array([\n",
    "#     [1, 0],\n",
    "#     [1, 0]\n",
    "# ])\n",
    "\n",
    "# Stride and Padding\n",
    "stride = 1\n",
    "padding = 1\n",
    "\n",
    "# Create padded image\n",
    "padded_image = np.pad(image, ((padding, padding), (padding, padding)))\n",
    "\n",
    "# Calculate output dimensions\n",
    "output_dim = ((image.shape[0] - kernel.shape[0] + 2*padding) // stride) + 1\n",
    "\n",
    "# Initialize the convolution output\n",
    "conv_output = np.zeros((output_dim, output_dim))\n",
    "\n",
    "# Calculate all possible top-left positions for the kernel\n",
    "positions = [(y, x) for y in range(0, padded_image.shape[0] - kernel.shape[0] + 1, stride)\n",
    "                   for x in range(0, padded_image.shape[1] - kernel.shape[1] + 1, stride)]\n",
    "\n",
    "# Set up the plotting with three subplots for the image, kernel, and convolution output\n",
    "fig, (ax1, ax_kernel, ax2) = plt.subplots(1, 3, figsize=(15, 5))\n",
    "ax1.imshow(padded_image, cmap='viridis', aspect='equal')  # Use equal aspect for square pixels\n",
    "ax_kernel.imshow(kernel, cmap='viridis', aspect='equal')  # Display the kernel\n",
    "ax2.imshow(conv_output, cmap='viridis', aspect='equal', vmin=-15, vmax=15)  # Use equal aspect and set vmin, vmax for consistent color scaling\n",
    "\n",
    "# Add subplot titles\n",
    "ax1.set_title(\"Input Image with Kernel Overlay\")\n",
    "ax_kernel.set_title(\"Kernel\")\n",
    "ax2.set_title(\"Convolution Output\")\n",
    "\n",
    "# Display numbers on the matrix for the padded image\n",
    "for i in range(padded_image.shape[0]):\n",
    "    for j in range(padded_image.shape[1]):\n",
    "        ax1.text(j, i, str(padded_image[i, j]), ha='center', va='center', color='red')\n",
    "\n",
    "# Display numbers on the kernel\n",
    "for i in range(kernel.shape[0]):\n",
    "    for j in range(kernel.shape[1]):\n",
    "        ax_kernel.text(j, i, str(kernel[i, j]), ha='center', va='center', color='red')\n",
    "\n",
    "# Kernel rectangle overlay on ax1\n",
    "rect = patches.Rectangle((-0.5, -0.5), kernel.shape[1], kernel.shape[0], \n",
    "                         linewidth=3, edgecolor='blue', facecolor='none')\n",
    "ax1.add_patch(rect)\n",
    "\n",
    "# Animation function\n",
    "def animate(i):\n",
    "    y, x = positions[i]\n",
    "    rect.set_xy((x-0.5, y-0.5))\n",
    "\n",
    "    # Compute the convolution for the current position\n",
    "    region = padded_image[y:y+kernel.shape[0], x:x+kernel.shape[1]]\n",
    "    conv_value = np.sum(region * kernel)\n",
    "    \n",
    "    # Correctly compute the position in the output matrix\n",
    "    out_y = y // stride\n",
    "    out_x = x // stride\n",
    "    conv_output[out_y, out_x] = conv_value\n",
    "\n",
    "    # Update the convolution output display\n",
    "    ax2.imshow(conv_output, cmap='viridis', aspect='equal', vmin=-15, vmax=15)  # Adjusted colormap and vmin, vmax for better visualization\n",
    "\n",
    "    # Display numbers on the matrix for the convolution output\n",
    "    for i in range(conv_output.shape[0]):\n",
    "        for j in range(conv_output.shape[1]):\n",
    "            ax2.text(j, i, f\"{conv_output[i, j]:.1f}\", ha='center', va='center', color='red')\n",
    "\n",
    "    return rect,\n",
    "\n",
    "\n",
    "# Create animation with increased interval for slower movement\n",
    "ani = FuncAnimation(fig, animate, frames=len(positions), interval=2000, blit=True, repeat_delay=10000)  # interval set to 5000 for slower movement\n",
    "\n",
    "# Title and layout\n",
    "# title_text = f\"Kernel Size: {kernel.shape[0]}x{kernel.shape[1]}, Stride: {stride}, Padding: {padding}\"\n",
    "# fig.suptitle(title_text, fontsize=16)\n",
    "\n",
    "# Adjust subplot spacing and layout\n",
    "plt.subplots_adjust(wspace=0.5)\n",
    "plt.tight_layout()\n",
    "\n",
    "# Save and show\n",
    "writer = PillowWriter(fps=2)\n",
    "ani.save(f\"convolution_animation_with_output_k{kernel.shape[0]}_s{stride}_p{padding}.gif\", writer=writer)\n",
    "plt.show()\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-09-26T11:48:00.679662904Z",
     "start_time": "2023-09-26T11:47:47.667621921Z"
    }
   },
   "id": "7e43a9eac318f3c3"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   },
   "id": "bce4c6c7bb659beb"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
