{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# Image Processing SS 18 - Assignment - 02\n",
    "\n",
    "### Deadline is 2.5.2016 at 8:00\n",
    "\n",
    "Please solve the assignments together with a partner.\n",
    "I will run every notebook. Make sure the code runs through. Select `Kernel` -> `Restart & Run All` to test it.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Exercise 1 - 10 Points\n",
    "\n",
    "Implement affine transformation with [bicubic interpolation](https://en.wikipedia.org/wiki/Bicubic_interpolation)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# display the plots inside the notebook\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pylab\n",
    "pylab.rcParams['figure.figsize'] = (12, 12)   # This makes the plot bigger"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The [skimage](http://scikit-image.org/) library comes with multiple useful test images.  Let's start with an image of an astronaut. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from skimage.data import astronaut\n",
    "from skimage.color import rgb2gray"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We use a gray image. All the algorithms should work with color images too.\n",
    "img = rgb2gray(astronaut() / 255.)\n",
    "plt.imshow(img, cmap='gray')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def derive_y(image):\n",
    "    \"\"\"Computes the derivative of the image w.r.t the y coordinate\"\"\"\n",
    "    derived_image = np.zeros_like(image)\n",
    "    for x in range(image.shape[0]):\n",
    "        for y in range(image.shape[1]):\n",
    "            if y + 1 < image.shape[1] and y - 1 > 0:\n",
    "                derived_image[x,y] = image[x, y - 1] - image[x, y + 1]\n",
    "    return derived_image\n",
    "\n",
    "def derive_x(image):\n",
    "    \"\"\"Computes the derivative of the image w.r.t the x coordinate\"\"\"\n",
    "    derived_image = np.zeros_like(image)\n",
    "    for x in range(image.shape[0]):\n",
    "        for y in range(image.shape[1]):\n",
    "            if x + 1 < image.shape[1] and x - 1 > 0:\n",
    "                derived_image[x,y] = image[x - 1, y] - image[x + 1, y]\n",
    "    return derived_image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "dx_img = derive_x(img)\n",
    "dy_img = derive_y(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 388316 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10dd6470>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(18, 12))\n",
    "plt.subplot(131)\n",
    "plt.imshow(img, cmap='gray')\n",
    "plt.subplot(132)\n",
    "plt.imshow(dx_img, cmap='gray')\n",
    "plt.subplot(133)\n",
    "plt.imshow(dy_img, cmap='gray')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "min: -0.9896796078431372, max: 0.8965913725490197\n"
     ]
    }
   ],
   "source": [
    "# The derivatives are no longer in the range [0,1].\n",
    "print(\"min: {}, max: {}\".format(dx_img.min(), dx_img.max()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(512, 512)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indicies = np.indices(img.shape).reshape(2, -1)\n",
    "img.shape\n",
    "#indicies.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "262144"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pick some random index\n",
    "indicies.shape[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 0])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indicies[:, 512]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3, 262144)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indicies_hg = np.concatenate([\n",
    "        indicies, np.ones((1, indicies.shape[1]))], axis=0)\n",
    "indicies_hg.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 241.,   64.,    1.])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indicies_hg[:, 123456]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3, 262144)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "T_scale = np.array([\n",
    "    [0.75, 0, 0],\n",
    "    [0, 0.75, 0],\n",
    "    [0, 0, 1],\n",
    "])\n",
    "# np.dot(T_affine, indicies_hg).shape, for python < 3.5\n",
    "(T_scale @ indicies_hg).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "T_affine = np.array([\n",
    "    [1, 0.3, 0],\n",
    "    [0, 1, 0],\n",
    "    [0, 0, 1],\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.33333333,  0.        ,  0.        ],\n       [ 0.        ,  1.33333333,  0.        ],\n       [ 0.        ,  0.        ,  1.        ]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# you can use this function to invert the matricies\n",
    "np.linalg.inv(T_scale)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "def bicubic_interpolation(img, indicies):\n",
    "    dx_img = derive_x(img)\n",
    "    dy_img = derive_y(img)\n",
    "    dxy_img = derive_x(dy_img)\n",
    "    mat_a = np.array([[1, 0, 0, 0],\n",
    "                      [0, 0, 1, 0],\n",
    "                      [-3, 3, -2, -1],\n",
    "                      [2, -2, 1, 1]])\n",
    "    mat_b = np.transpose(mat_a)\n",
    "    print(mat_b)\n",
    "    \n",
    "    def calc_color(abs_x, abs_y):\n",
    "        floor_x = math.floor(abs_x)\n",
    "        floor_y = math.floor(abs_y)\n",
    "        ceil_x = math.ceil(abs_x)\n",
    "        ceil_y = math.ceil(abs_y)\n",
    "        x = abs_x-floor_x\n",
    "        y = abs_y-floor_y\n",
    "        f = np.array([[   img[floor_x, floor_y],    img[floor_x, ceil_y],  dy_img[floor_x, floor_y],  dy_img[floor_x, ceil_y]],\n",
    "                      [   img[ceil_x, floor_y] ,    img[ceil_x, ceil_y] ,  dy_img[ceil_x, floor_y] ,  dy_img[ceil_x, ceil_y] ],\n",
    "                      [dx_img[floor_x, floor_y], dx_img[floor_x, ceil_y], dxy_img[floor_x, floor_y], dxy_img[floor_x, ceil_y]],\n",
    "                      [dx_img[ceil_x, floor_y] , dx_img[ceil_x, ceil_y] , dxy_img[ceil_x, floor_y] , dxy_img[ceil_x, ceil_y] ]])\n",
    "        a = mat_a.dot(f).dot(mat_b)\n",
    "        p = np.array([[1, x, x**2, x**3]]).dot(a).dot(np.array([[1], [y], [y**2], [y**3]]))\n",
    "        return p[0, 0]#img[floor_x][floor_y]\n",
    "        \n",
    "    return np.array([(calc_color(x, y) if x != -1 else 0) for x, y in indicies])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "def affine_transformation(img, matrix):\n",
    "# your code here\n",
    "    matrix=np.linalg.inv(matrix)\n",
    "    Timg = np.zeros(img.shape)\n",
    "    #a=np.array([])\n",
    "    a=[]\n",
    "    i=0\n",
    "    for x in range(len(Timg)):\n",
    "        for y in range(len(Timg[0])): \n",
    "            (nx, ny, nz) = matrix.dot(np.array([x, y, 1]))\n",
    "            if 0 <= nx < (len(Timg)) and 0 <= ny < (len(Timg[0])):\n",
    "                #a.append(img[int(nx)][int(ny)])\n",
    "                a.append([nx, ny])\n",
    "            else:\n",
    "                #a.append(0)\n",
    "                a.append([-1, -1])\n",
    "    a = np.array(a)\n",
    "    a = bicubic_interpolation(img, a)\n",
    "    return a.reshape((len(Timg),len(Timg[0])))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  0 -3  2]\n [ 0  0  3 -2]\n [ 0  1 -2  1]\n [ 0  0 -1  1]]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  0 -3  2]\n [ 0  0  3 -2]\n [ 0  1 -2  1]\n [ 0  0 -1  1]]\n"
     ]
    }
   ],
   "source": [
    "img_scale = affine_transformation(img, T_scale)\n",
    "img_affine = affine_transformation(img, T_affine)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 233996 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10d87970>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(img_scale, cmap='gray')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 353052 characters]\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10da63b0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(img_affine, cmap='gray')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n"
   ]
  }
 ],
 "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.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
