{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Populating the interactive namespace from numpy and matplotlib\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "sys.path.insert(0, os.path.abspath('..'))\n",
    "\n",
    "from autocnet.examples import get_path\n",
    "from autocnet.graph.network import CandidateGraph\n",
    "from autocnet.matcher.feature import FlannMatcher\n",
    "from autocnet.matcher.suppression_funcs import distance\n",
    "\n",
    "from IPython.display import display\n",
    "\n",
    "%pylab inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#Point to the adjacency Graph\n",
    "adjacency = get_path('two_image_adjacency.json')\n",
    "basepath = get_path('Apollo15')\n",
    "cg = CandidateGraph.from_adjacency(adjacency, basepath=basepath)\n",
    "\n",
    "#Apply SIFT to extract features\n",
    "cg.extract_features(method='sift')\n",
    "\n",
    "#Match\n",
    "cg.match_features()\n",
    "    \n",
    "#Apply outlier detection\n",
    "cg.symmetry_checks()\n",
    "cg.ratio_checks()\n",
    "\n",
    "m = cg.edge[0][1].masks\n",
    "\n",
    "#Compute a fundamental matrix\n",
    "cg.compute_fundamental_matrices(clean_keys=['ratio', 'symmetry'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Suppression\n",
    "Create a suppression object using a default error tolerance and count.  Supply a custom function that suppresses based upon the distance between matches."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "#figsize(12,12)\n",
    "#cg.edge[0][1].suppress(clean_keys=['fundamental'], func=distance)\n",
    "\n",
    "# Plot, in blue the points that passed all outlier detectors so far\n",
    "#cg.edge[0][1].plot(clean_keys=['fundamental'], line_kwargs={'linewidth':0})\n",
    "# Overlay, in red, the points that remain after suppression\n",
    "#cg.edge[0][1].plot(clean_keys=['suppression'], line_kwargs={'linewidth':0}, scatter_kwargs={'color':'red'})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Suppression and Do/Undo\n",
    "The suppression object, associated with each edge is a stateful observable.  This means that other objects can observe the suppression object.  If the suppression object changes, all of the observers are notified and can take whatever action they have registered.  In addition to being observable, the suppression object keeps a history of itself.  This supports do/undo functionality (that alerts observers).  \n",
    "\n",
    "The cell above created that object with a custom distance function.  The cells below alter $k$, the desired number of points, and $k_{error}$, the acceptable percentage of error in $k$.  These changes are then rolled back and forth.\n",
    "\n",
    "The plotting calls remain the same for all of these example, only the first line of each is altered.\n",
    "\n",
    "--------"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$k=10$ and $k_{error}$ defaults to 10%  \n",
    "\n",
    "*Take note of the bad point, in the left image, that has made it through the ratio, symmetry, and fundamental matrix computation tests.*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#cg.edge[0][1].suppress(clean_keys=['fundamental'], func=distance, k=10)\n",
    "\n",
    "# Plot, in blue the points that passed all outlier detectors so far\n",
    "#cg.edge[0][1].plot(clean_keys=['fundamental'], line_kwargs={'linewidth':0})\n",
    "# Overlay, in red, the points that remain after suppression\n",
    "#cg.edge[0][1].plot(clean_keys=['suppression'], line_kwargs={'linewidth':0}, scatter_kwargs={'color':'red'})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$k = 50$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#cg.edge[0][1].suppress(clean_keys=['fundamental'], func=distance, k=50)\n",
    "\n",
    "# Plot, in blue the points that passed all outlier detectors so far\n",
    "#cg.edge[0][1].plot(clean_keys=['fundamental'], line_kwargs={'linewidth':0})\n",
    "# Overlay, in red, the points that remain after suppression\n",
    "#cg.edge[0][1].plot(clean_keys=['suppression'], line_kwargs={'linewidth':0}, scatter_kwargs={'color':'red'})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$k=100$ and $k_{error} = 25%$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#cg.edge[0][1].suppress(clean_keys=['fundamental'], func=distance, k=100, k_error=0.25)\n",
    "\n",
    "# Plot, in blue the points that passed all outlier detectors so far\n",
    "#cg.edge[0][1].plot(clean_keys=['fundamental'], line_kwargs={'linewidth':0})\n",
    "# Overlay, in red, the points that remain after suppression\n",
    "#cg.edge[0][1].plot(clean_keys=['suppression'], line_kwargs={'linewidth':0}, scatter_kwargs={'color':'red'})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using the suppression object we can access some attributes to see how many valid points."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#cg.edge[0][1].suppression.nvalid"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rollback\n",
    "Now we will undo that last change.  Perhaps the error was just too high (it was not near 25% in this case, but imagine it was)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#cg.edge[0][1].suppression.rollback()\n",
    "\n",
    "# Plot, in blue the points that passed all outlier detectors so far\n",
    "#cg.edge[0][1].plot(clean_keys=['fundamental'], line_kwargs={'linewidth':0})\n",
    "# Overlay, in red, the points that remain after suppression\n",
    "#cg.edge[0][1].plot(clean_keys=['suppression'], line_kwargs={'linewidth':0}, scatter_kwargs={'color':'red'})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "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.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
