{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "from tqdm.notebook import tqdm\n",
    "import os\n",
    "from datetime import datetime\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "from py.Dataset import Dataset\n",
    "from py.DatasetStatistics import DatasetStatistics\n",
    "from py.Session import Session, MotionImage, LapseImage\n",
    "from py.FileUtils import list_folders, list_jpegs_recursive\n",
    "from py.ImageUtils import display_images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 32 sessions\n",
      "Session 'Beaver_01' at folder: /home/AMMOD_data/camera_traps/BayerWald/Vielkadaver-Projekt/VIELAAS_Spring_Session01-VIELAAS_Beaver_01\n",
      "Loaded scans.\n"
     ]
    }
   ],
   "source": [
    "DIR = '/home/AMMOD_data/camera_traps/BayerWald/Vielkadaver-Projekt/'\n",
    "\n",
    "ds = Dataset(DIR)\n",
    "session = ds.create_session(\"beaver_01\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = session.get_random_motion_image(day_only=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.24944444444444444\n"
     ]
    }
   ],
   "source": [
    "previous_img, next_img, rel = img.get_closest_lapse_images()\n",
    "print(rel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "scale = 0.5\n",
    "gray = True\n",
    "img1 = previous_img.read(gray=gray, scale=scale)\n",
    "img2 = img.read(gray=gray, scale=scale)\n",
    "img3 = next_img.read(gray=gray, scale=scale)\n",
    "# previous_img.open()\n",
    "# img.open()\n",
    "# next_img.open()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 1127028 characters]",
      "text/plain": [
       "<Figure size 1728x576 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "kwargs = { \"cmap\": \"gray\" } if gray else {}\n",
    "display_images([img1, img2, img3], [\"Lapse before\", \"Motion\", \"Lapse after\"], **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 331520 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "interpol = rel * img3 + (1 - rel) * img1\n",
    "display_images([interpol], [\"Interpolated\"], **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 1451784 characters]",
      "text/plain": [
       "<Figure size 1728x576 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.29880033334438955\n",
      "0.2788665254237288\n",
      "0.3943098237089124\n"
     ]
    }
   ],
   "source": [
    "from skimage.metrics import structural_similarity\n",
    "from skimage.transform import rescale\n",
    "from skimage.color import rgb2gray\n",
    "from skimage.feature import canny\n",
    "cinterpol = canny(interpol)\n",
    "cimg2 = canny(img2)\n",
    "display_images([cinterpol, cimg2, cimg2 ^ cinterpol], [\"Interpolated\", \"Motion image\", \"diff\"])\n",
    "print(np.average(cinterpol))\n",
    "print(np.average(cimg2))\n",
    "print(np.average(cimg2 ^ cinterpol))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def normalize(img):\n",
    "    return (img - np.mean(img)) / np.std(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 296792 characters]",
      "text/plain": [
       "<Figure size 576x576 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.016139167999069934\n"
     ]
    }
   ],
   "source": [
    "if gray:\n",
    "    mssim, S = structural_similarity(normalize(interpol), normalize(img2), full=True)\n",
    "    display_images([-S], [\"channel 1\"], colorbar=True)\n",
    "    print(mssim)\n",
    "else:\n",
    "    mssim, S = structural_similarity(normalize(interpol), normalize(img2), full=True, multichannel=True)\n",
    "    display_images([-S[:,:,0], -S[:,:,0], -S[:,:,0]], [\"channel 1\", \"channel 2\", \"channel 3\"], colorbar=True)\n",
    "    print(mssim)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def threshold(img, thr):\n",
    "    return img * (img >= thr)\n",
    "\n",
    "def mask(img, thr):\n",
    "    return img >= thr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.08065312657807827\n",
      "0.005569134421361333\n"
     ]
    }
   ],
   "source": [
    "diff = (img2 - img1) ** 2\n",
    "diff_test = (img1 - interpol) ** 2\n",
    "print(np.average(diff))\n",
    "print(np.average(diff_test))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.8183910536004511\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 231948 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "S_ = mask(-S, -0.2)\n",
    "plt.imshow(S_)\n",
    "print(np.average(S_))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.ndimage.morphology import binary_closing, binary_erosion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f5b7aa35b38>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 6564 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "S_er = binary_closing(S_, structure=np.ones((9,9)), iterations=3)\n",
    "plt.imshow(S_er)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "from py.ImageClassifier import AbstractImageClassifier\n",
    "\n",
    "class AbsDiffClassifier(AbstractImageClassifier):\n",
    "    def evaluate(self, motion_img: MotionImage, display=False):\n",
    "        before_img, after_img, rel = motion_img.get_closest_lapse_images()\n",
    "        comp_img = before_img if rel <= 0.5 else after_img\n",
    "        motion_arr = motion_img.read(scale=0.5, gray=True)\n",
    "        comp_arr = comp_img.read(scale=0.5, gray=True)\n",
    "\n",
    "        diff = (motion_arr - comp_arr) ** 2\n",
    "        val = np.average(diff)\n",
    "\n",
    "        if display:\n",
    "            display_images([motion_arr, comp_arr, diff], [\"Motion image\", \"Closest lapse image\", f\"avg sq diff = {val}\"], cmap=\"gray\")\n",
    "\n",
    "        return val"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 767432 characters]",
      "text/plain": [
       "<Figure size 1728x576 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "0.028698550835298233"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "img = session.get_random_motion_image(day_only=True)\n",
    "classifier = AbsDiffClassifier()\n",
    "classifier.evaluate(img, display=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ipywidgets as widgets\n",
    "from IPython.display import display\n",
    "\n",
    "class ImageAnnotator():\n",
    "    def __init__(self, classifier: AbstractImageClassifier, session: Session, initial_scores = [], initial_annotations = []):\n",
    "        self.scores = initial_scores\n",
    "        self.annotations = initial_annotations\n",
    "        self.score = -1\n",
    "        self.classifier = classifier\n",
    "        self.session = session\n",
    "        normal_btn = widgets.Button(description = \"Normal\")\n",
    "        anomalous_btn = widgets.Button(description = \"Anomalous\")\n",
    "        self.button_box = widgets.HBox([normal_btn, anomalous_btn])\n",
    "        self.output = widgets.Output(layout={\"height\": \"400px\"})\n",
    "        display(self.button_box, self.output)\n",
    "        normal_btn.on_click(self.mark_as_normal)\n",
    "        anomalous_btn.on_click(self.mark_as_anomalous)\n",
    "        self.next_image()\n",
    "    \n",
    "    def mark_as_normal(self, _):\n",
    "        with self.output:\n",
    "            print(\"Marking as normal...\")\n",
    "        self.annotations.append(True)\n",
    "        self.scores.append(self.score)\n",
    "        self.next_image()\n",
    "    \n",
    "    def mark_as_anomalous(self, _):\n",
    "        with self.output:\n",
    "            print(\"Marking as anomalous...\")\n",
    "        self.annotations.append(False)\n",
    "        self.scores.append(self.score)\n",
    "        self.next_image()\n",
    "    \n",
    "    def next_image(self):\n",
    "        img = self.session.get_random_motion_image(day_only=True)\n",
    "        self.score = self.classifier.evaluate(img)\n",
    "        self.output.clear_output()\n",
    "        with self.output:\n",
    "            display(img.to_ipython_image())\n",
    "            print(f\"score = {self.score}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "516e5bc37e7742e5a736f7a9dff606d4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(Button(description='Normal', style=ButtonStyle()), Button(description='Anomalous', style=Button…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "542f31c165394928b68f249f614bfcfc",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output(layout=Layout(height='400px'))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "annotator = ImageAnnotator(AbsDiffClassifier(), session, initial_scores=annotator.scores, initial_annotations=annotator.annotations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.save(\"annotations.npy\", [annotator.annotations, annotator.scores])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.        , 0.        , 0.        , 0.        , 0.        ,\n",
       "        0.        , 0.        , 0.        , 0.        , 0.        ,\n",
       "        0.        , 0.        , 0.        , 0.        , 0.        ,\n",
       "        0.        , 0.        , 0.        , 1.        , 0.        ,\n",
       "        0.        , 1.        , 1.        , 0.        , 0.        ,\n",
       "        0.        , 0.        , 0.        , 0.        , 0.        ,\n",
       "        0.        , 0.        , 0.        , 1.        , 0.        ,\n",
       "        0.        , 0.        , 0.        , 0.        , 0.        ,\n",
       "        0.        , 0.        , 0.        , 0.        , 0.        ,\n",
       "        0.        ],\n",
       "       [0.04106169, 0.07320884, 0.06721638, 0.02182765, 0.0340965 ,\n",
       "        0.02000366, 0.02940218, 0.03074892, 0.04367824, 0.03088665,\n",
       "        0.03074892, 0.078383  , 0.02000366, 0.01949857, 0.02916867,\n",
       "        0.07510512, 0.07904947, 0.04788776, 0.00349494, 0.03657243,\n",
       "        0.00766623, 0.03088665, 0.00654453, 0.05281735, 0.0430545 ,\n",
       "        0.03838451, 0.02773041, 0.0430545 , 0.07850142, 0.06700845,\n",
       "        0.09001972, 0.04367824, 0.05336722, 0.05701452, 0.05040492,\n",
       "        0.07904947, 0.03204007, 0.04367824, 0.05790128, 0.07793063,\n",
       "        0.07139326, 0.00766623, 0.0430545 , 0.01843753, 0.06337109,\n",
       "        0.02905117]])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = np.load(\"annotations.npy\")\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x7f14f5ecbc88>"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 7208 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(data[0], data[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
  },
  "kernelspec": {
   "display_name": "Python 3.6.9 64-bit",
   "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.6.9"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
