{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center>\n",
    "<img src=\"../ontario-tech-univ-logo.png\" width=\"22%\">\n",
    "</center>\n",
    "\n",
    "# CSCI 3240U --- Computer Vision I\n",
    "\n",
    "## Lab 8 --- Homography and Image Stitching\n",
    "\n",
    "Faisal Z. Qureshi  \n",
    "Faculty of Science, Ontario Tech University  \n",
    "Oshawa ON Canada  \n",
    "<http://vclab.science.ontariotechu.ca>\n",
    "\n",
    "*Fall 2026*\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Copyright information\n",
    "\n",
    "&copy; Faisal Qureshi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## License\n",
    "\n",
    "<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc/4.0/\"><img alt=\"Creative Commons Licence\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-nc/4.0/88x31.png\" /></a><br />This work is licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc/4.0/\">Creative Commons Attribution-NonCommercial 4.0 International License</a>."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Outline\n",
    "\n",
    "Consider the following image pair\n",
    "\n",
    "<center>\n",
    "    <tr>\n",
    "        <td><img src=\"1-left.jpeg\" width=\"30%\"></td>\n",
    "    </tr>\n",
    "    <tr>\n",
    "        <td><img src=\"1-right.jpeg\" width=\"30%\"></td>\n",
    "    </tr>\n",
    "</center>\n",
    "\n",
    "You are asked to pick at least four correspondences in both images.  E.g., you can pick four points $(x^l_i,y^l_i)$ in the left image and then you can pick the corresponding locations $(x^r_i,y^r_i)$ in the right image in the same order.  Here $i > 3$.  Given these correspondences, estimate the homography matrix between the two set of images, and use this matrix to stitch the two images into a single image."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Picking locations in an image\n",
    "\n",
    "Use the following code to pick locations on an image as seen below\n",
    "\n",
    "<center>\n",
    "    <tr>\n",
    "        <td><img src=\"point-picker.png\" width=\"50%\"></td>\n",
    "    </tr>\n",
    "</center>\n",
    "\n",
    "Modify the code as needed to record the $(x,y)$ locations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib tk\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.image as mpimg\n",
    "import cv2 as cv\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PointPicker:\n",
    "    def __init__(self, imgplot, img, color=(255,0,0), radius=20, thickness=20):\n",
    "        self.imgplot = imgplot\n",
    "        self.img = img\n",
    "        self.color = color\n",
    "        self.radius = radius\n",
    "        self.thickness = thickness\n",
    "        self.cid = imgplot.figure.canvas.mpl_connect('button_press_event', self)\n",
    "    \n",
    "    def __call__(self, event):\n",
    "        if event.inaxes != self.imgplot.axes: \n",
    "            return\n",
    "        ix = event.xdata\n",
    "        iy = event.ydata\n",
    "        print(f'x={ix}, y={iy}')\n",
    "        self.img = cv.circle(self.img, (int(ix), int(iy)), self.radius, self.color, self.thickness)\n",
    "        \n",
    "        imgplot.set_array(self.img)\n",
    "        self.imgplot.figure.canvas.draw()\n",
    "\n",
    "img=cv.imread('1-left.jpeg')        \n",
    "        \n",
    "fig = plt.figure(figsize=(10,10))\n",
    "ax = fig.add_subplot(111)\n",
    "imgplot = plt.imshow(img)\n",
    "point_picker = PointPicker(imgplot, img)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Task\n",
    "\n",
    "- Load left image (`1-left.jpeg`) and pick at least four points in order.\n",
    "- Load right image (`1-right.jpeg`) and pick the corresponding locations.\n",
    "- Use the correspondences to estimate *homography*.\n",
    "- Use the homography to stitch the images together.\n",
    "\n",
    "### Some outdoor photography\n",
    "\n",
    "- The above image exhibits strong parallex.  You may consider going for a walk and taking an image pair of your favorite neighbourhood landscape.  Try not to translate the camera, just rotate in place.\n",
    "\n",
    "### Useful information\n",
    "\n",
    "- [Least squares fitting](http://csundergrad.science.uoit.ca/courses/cv-notes/notebooks/15-least-squares.html)\n",
    "- [RANSAC](http://csundergrad.science.uoit.ca/courses/cv-notes/notebooks/17-ransac.html)\n",
    "- [Homography](http://csundergrad.science.uoit.ca/courses/cv-notes/notebooks/19-homography.html)\n",
    "- [Image sampling](http://csundergrad.science.uoit.ca/courses/cv-notes/notebooks/10-image-sampling.html)\n",
    "\n",
    "### Bonus\n",
    "\n",
    "- Try stitching on different image pairs.\n",
    "- Can you stich more than one images to create a panorama?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Submission\n",
    "\n",
    "Include code and stiched image single jupyter notebook. *Submit via canvas.*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center>\n",
    "    <tr>\n",
    "    <td><img src=\"../ontario-tech-univ-logo.png\" width=\"25%\"></img></td>\n",
    "    </tr>\n",
    "</center>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}