{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Approach 1a: Basic frame differencing\n",
    "For this most basic approach, we compare each motion image $M$ to the closest lapse image $L$ and take the\n",
    "1. mean absolute pixel-wise difference $ \\frac{1}{xy} \\sum_{x,y} | M_{x,y} - L_{x,y} | $\n",
    "2. mean squared pixel-wise difference $ \\frac{1}{xy} \\sum_{x,y} (M_{x,y} - L_{x,y})^2 $\n",
    "M and L are both grayscale.\n",
    "\n",
    "**Reasoning:** We assume that anomalous images highly differ from the closest lapse image in a significant amount of pixels while normal images only have low pixel differences.\n",
    "\n",
    "### Suspected problems\n",
    "- **Noise** (we scale the images down for performance reasons which also reduces noise a bit)\n",
    "- **Small object movements** that are not of interest (such as leaves, dust particles, etc.)\n",
    "- Very sensitive to **camera movement** (which seems to happen a lot in the dataset)\n",
    "- Since we eliminate the **color information**, a deer might look very much like a forest."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 3 sessions\n",
      "Session 'Marten_01' at folder: ./ResizedSessions_NoBackup/VIELAAS_Spring_Session01-VIELAAS_Marten_01\n",
      "Loaded scans.\n"
     ]
    }
   ],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "from tqdm.notebook import tqdm\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from skimage.color import rgb2gray\n",
    "from tqdm import tqdm\n",
    "import warnings\n",
    "\n",
    "from py.PlotUtils import plot_roc_curve, get_percentiles\n",
    "from py.Dataset import Dataset\n",
    "from py.Session import MotionImage\n",
    "from py.ImageUtils import display_images, is_daytime, save_image\n",
    "from py.Labels import LABELS\n",
    "from py.ImageClassifier import AbstractImageClassifier\n",
    "\n",
    "DIR = './ResizedSessions_NoBackup' # dataset directory\n",
    "\n",
    "ds = Dataset(DIR)\n",
    "session = ds.create_session(\"marten_01\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Experiment 1: Basic classifier\n",
    "The proposed classifier computes the following features\n",
    "- mean of absolute pixel-wise difference _absmean_\n",
    "- variance of absolute pixel-wise difference _absvar_\n",
    "- mean of squared pixel-wise difference _sqmean_\n",
    "- var of squared pixel-wise difference _sqvar_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def normalize(comp_arr, motion_arr):\n",
    "    # normalize comp_arr and transform motion_arr identically\n",
    "    mean, std = np.mean(comp_arr), np.std(comp_arr)\n",
    "    motion_arr = (motion_arr - mean) / std\n",
    "    comp_arr = (comp_arr - mean) / std\n",
    "    return comp_arr, motion_arr\n",
    "\n",
    "def normalize_img(img):\n",
    "    return (img - np.mean(img)) / np.std(img)\n",
    "\n",
    "class FrameDiffClassifier(AbstractImageClassifier):\n",
    "    def evaluate(self, motion_img: MotionImage, display=False, save=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(gray=False)\n",
    "        comp_arr = comp_img.read(gray=False)\n",
    "        motion_daytime = is_daytime(motion_arr)\n",
    "\n",
    "        # don't compare daytime with nighttime images\n",
    "        if motion_daytime != is_daytime(comp_arr):\n",
    "            # choose the other closest lapse image\n",
    "            comp_img = after_img if rel <= 0.5 else before_img\n",
    "            comp_arr = comp_img.read(gray=False)\n",
    "            assert motion_daytime == is_daytime(comp_arr)\n",
    "            # if this assertion fails, a motion image was captured at daytime between two nighttime lapse images or the other way around\n",
    "\n",
    "        # convert to gray\n",
    "        motion_arr = rgb2gray(motion_arr)\n",
    "        comp_arr = rgb2gray(comp_arr)\n",
    "\n",
    "        # comp_arr, motion_arr = normalize(comp_arr, motion_arr)\n",
    "        comp_arr, motion_arr = normalize_img(comp_arr), normalize_img(motion_arr)\n",
    "\n",
    "        absdiff = abs(motion_arr - comp_arr)\n",
    "        sqdiff = (motion_arr - comp_arr) ** 2\n",
    "        absmean = np.average(absdiff)\n",
    "        absvar = np.var(absdiff)\n",
    "        sqmean = np.average(sqdiff)\n",
    "        sqvar = np.var(sqdiff)\n",
    "\n",
    "        if display:\n",
    "            # display_images([motion_arr, comp_arr, absdiff, sqdiff], [\"Motion image\", \"Closest lapse image\", f\"abs mean = {absmean}, std = {absstd}\", f\"sq mean = {sqmean}, std = {sqstd}\"], cmap=\"gray\")\n",
    "            display_images([motion_arr, comp_arr, sqdiff], [f\"Motion {motion_img.date}\", f\"Closest Lapse {comp_img.date}\", f\"Squared pixel-wise difference (mean={sqmean:.3f}, var={sqvar:.3f})\"], row_size=3, cmap=\"gray\")\n",
    "        if save:\n",
    "            save_image(motion_arr, \"imgs/approach1a_motion.pdf\", None, cmap=\"gray\")\n",
    "            save_image(comp_arr, \"imgs/approach1a_lapse.pdf\", None, cmap=\"gray\")\n",
    "            save_image(sqdiff, \"imgs/approach1a_sqdiff.pdf\", None, cmap=\"gray\")\n",
    "\n",
    "        return absmean, absvar, sqmean, sqvar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualize difference image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/kleinsteuber/vscode/py/Session.py:278: UserWarning: There are multiple lapse images for date 2021-04-24 11:00:00! Choosing the first one.\n",
      "  warn(f\"There are multiple lapse images for date {previous_date}! Choosing the first one.\")\n",
      "/home/kleinsteuber/vscode/py/Session.py:280: UserWarning: There are multiple lapse images for date 2021-04-24 12:00:00! Choosing the first one.\n",
      "  warn(f\"There are multiple lapse images for date {next_date}! Choosing the first one.\")\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 921612 characters]",
      "text/plain": [
       "<Figure size 1728x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "img = session.get_random_motion_image() # session.get_motion_image_from_filename(\"Beaver_01_00509.jpg\")\n",
    "classifier = FrameDiffClassifier()\n",
    "output = classifier.evaluate(img, display=True, save=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The anomalous object is usually clearly visible in the difference image but there are still a lot of unwanted artefacts around it (possibly because of small object movement and noise)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluate on all Motion images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_test_scores(classifier):\n",
    "    normal_scores = []\n",
    "    anomalous_scores = []\n",
    "\n",
    "    for img in tqdm(list(session.generate_motion_images())):\n",
    "        img_nr = int(img.filename[-9:-4])\n",
    "        if img_nr > LABELS[session.name][\"max\"] or img_nr in LABELS[session.name][\"not_annotated\"]:\n",
    "            continue\n",
    "        score = classifier.evaluate(img)\n",
    "        if img_nr in LABELS[session.name][\"normal\"]:\n",
    "            normal_scores.append(score)\n",
    "        else:\n",
    "            anomalous_scores.append(score)\n",
    "    return normal_scores, anomalous_scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 3105/3105 [04:24<00:00, 11.75it/s]\n"
     ]
    }
   ],
   "source": [
    "classifier = FrameDiffClassifier()\n",
    "with warnings.catch_warnings():\n",
    "    warnings.simplefilter(\"ignore\")\n",
    "    normal_scores, anomalous_scores = generate_test_scores(classifier)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualize data points\n",
    "By plotting the scores produced by frame differencing, we can see if the normal and anomalous classes are linearly separable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 58168 characters]",
      "text/plain": [
       "<Figure size 1080x576 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot(i1, i2, normal_scores, anomalous_scores, scale=\"log\"):\n",
    "    titles = [\"abs mean\", \"abs var\", \"sq mean\", \"sq var\"]\n",
    "    plt.scatter([ar[i1] for ar in anomalous_scores], [ar[i2] for ar in anomalous_scores], color=\"red\", label=\"anomalous\", marker=\".\")\n",
    "    plt.scatter([ar[i1] for ar in normal_scores], [ar[i2] for ar in normal_scores], color=\"blue\", label=\"normal\", marker=\".\")\n",
    "    plt.xlabel(titles[i1])\n",
    "    plt.ylabel(titles[i2])\n",
    "    plt.xscale(scale)\n",
    "    plt.yscale(scale)\n",
    "    plt.legend()\n",
    "    \n",
    "plt.figure(figsize=(15, 8))\n",
    "plt.subplot(1, 2, 1)\n",
    "plot(0, 1, normal_scores, anomalous_scores)\n",
    "plt.subplot(1, 2, 2)\n",
    "plot(2, 3, normal_scores, anomalous_scores)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Unfortunately, there is not a clear separating line between the two classes but normal samples tend to have lower variance and mean values than anomalies.\n",
    "\n",
    "### Scoring (AUC and elimination rates)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3105, 4)\n",
      "(3105,)\n"
     ]
    }
   ],
   "source": [
    "y_anom = np.array(anomalous_scores)\n",
    "assert y_anom.shape[1] == 4\n",
    "\n",
    "y_norm = np.array(normal_scores)\n",
    "assert y_norm.shape[1] == 4\n",
    "\n",
    "X = np.concatenate([y_norm, y_anom])\n",
    "print(X.shape)\n",
    "y = np.concatenate([-np.ones((y_norm.shape[0])), np.ones((y_anom.shape[0]))])\n",
    "print(y.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "absmean auc=0.6355777888310892\n",
      "0.9 percentile : TPR = 0.9071, FPR = 0.9768 <-> TNR = 0.0232 @ thresh 0.10961586920510108\n",
      "0.95 percentile : TPR = 0.9604, FPR = 0.9768 <-> TNR = 0.0232 @ thresh 0.09733281438072432\n",
      "0.99 percentile : TPR = 0.9918, FPR = 0.9958 <-> TNR = 0.0042 @ thresh 0.0835324211615366\n",
      "absvar auc=0.6136761126424554\n",
      "0.9 percentile : TPR = 0.9003, FPR = 0.9756 <-> TNR = 0.0244 @ thresh 0.021398314256101496\n",
      "0.95 percentile : TPR = 0.9768, FPR = 0.9785 <-> TNR = 0.0215 @ thresh 0.01243139288576224\n",
      "0.99 percentile : TPR = 0.9904, FPR = 0.9853 <-> TNR = 0.0147 @ thresh 0.00925403959223749\n",
      "sqmean auc=0.6279026456561636\n",
      "0.9 percentile : TPR = 0.9208, FPR = 0.9756 <-> TNR = 0.0244 @ thresh 0.030851647496162603\n",
      "0.95 percentile : TPR = 0.9590, FPR = 0.9756 <-> TNR = 0.0244 @ thresh 0.0264403832629429\n",
      "0.99 percentile : TPR = 0.9904, FPR = 0.9848 <-> TNR = 0.0152 @ thresh 0.016927961736901812\n",
      "sqvar auc=0.636314100571318\n",
      "0.9 percentile : TPR = 0.9221, FPR = 0.9756 <-> TNR = 0.0244 @ thresh 0.030067409342358558\n",
      "0.95 percentile : TPR = 0.9795, FPR = 0.9785 <-> TNR = 0.0215 @ thresh 0.009388315120142139\n",
      "0.99 percentile : TPR = 0.9904, FPR = 0.9840 <-> TNR = 0.0160 @ thresh 0.004871081161217191\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 27572 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 27612 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 27380 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 26868 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "vals = [\"absmean\", \"absvar\", \"sqmean\", \"sqvar\"]\n",
    "for i in range(4):\n",
    "    fpr, tpr, thresholds, auc_score = plot_roc_curve(y, X[:,i], f\"Basic frame differencing ({vals[i]})\", savefile=f\"plots/approach1a/roc_curves/{session.name}_{vals[i]}\", show=False)\n",
    "    print(f\"{vals[i]} auc={auc_score}\")\n",
    "    get_percentiles(fpr, tpr, thresholds, percentiles=[0.9, 0.95, 0.99])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Experiment 2: Add a Gaussian filter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "from py.ImageClassifier import AbstractImageClassifier\n",
    "from scipy import ndimage\n",
    "\n",
    "class GaussianFrameDiffClassifier(AbstractImageClassifier):\n",
    "    def __init__(self, sigma: int):\n",
    "        self.sigma = sigma\n",
    "    \n",
    "    def evaluate(self, motion_img: MotionImage, display=False, save=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(gray=False)\n",
    "        comp_arr = comp_img.read(gray=False)\n",
    "        motion_daytime = is_daytime(motion_arr)\n",
    "\n",
    "        # don't compare daytime with nighttime images\n",
    "        if motion_daytime != is_daytime(comp_arr):\n",
    "            # choose the other closest lapse image\n",
    "            comp_img = after_img if rel <= 0.5 else before_img\n",
    "            comp_arr = comp_img.read(gray=False)\n",
    "            assert motion_daytime == is_daytime(comp_arr)\n",
    "            # if this assertion fails, a motion image was captured at daytime between two nighttime lapse images or the other way around\n",
    "\n",
    "        # convert to gray\n",
    "        motion_arr = rgb2gray(motion_arr)\n",
    "        comp_arr = rgb2gray(comp_arr)\n",
    "\n",
    "        comp_arr, motion_arr = normalize_img(comp_arr), normalize_img(motion_arr)\n",
    "\n",
    "        motion_arrg = ndimage.gaussian_filter(motion_arr, sigma=self.sigma)\n",
    "        comp_arrg = ndimage.gaussian_filter(comp_arr, sigma=self.sigma)\n",
    "\n",
    "        absdiff = abs(motion_arrg - comp_arrg)\n",
    "        sqdiff = (motion_arrg - comp_arrg) ** 2\n",
    "        absmean = np.average(absdiff)\n",
    "        absvar = np.var(absdiff)\n",
    "        sqmean = np.average(sqdiff)\n",
    "        sqvar = np.var(sqdiff)\n",
    "\n",
    "        if display:\n",
    "            #display_images([motion_arr, comp_arr, absdiff, sqdiff], [\"Motion image\", \"Closest lapse image\", f\"abs mean = {absmean}, var = {absvar}\", f\"sq mean = {sqmean}, var = {sqvar}\"], cmap=\"gray\")\n",
    "            display_images([motion_arrg, comp_arrg, sqdiff], [f\"Motion {motion_img.date} (sigma={self.sigma})\", f\"Closest Lapse {comp_img.date} (sigma={self.sigma})\", f\"Squared pixel-wise difference (mean={sqmean:.3f}, var={sqvar:.3f})\"], row_size=3, cmap=\"gray\")\n",
    "        if save:\n",
    "            save_image(motion_arrg, f\"imgs/approach1a_sigma{self.sigma}_motion.pdf\", None, cmap=\"gray\")\n",
    "            save_image(comp_arrg, f\"imgs/approach1a_sigma{self.sigma}_lapse.pdf\", None, cmap=\"gray\")\n",
    "            save_image(sqdiff, f\"imgs/approach1a_sigma{self.sigma}_sqdiff.pdf\", None, cmap=\"gray\")\n",
    "\n",
    "        return absmean, absvar, sqmean, sqvar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualize difference image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/kleinsteuber/vscode/py/Session.py:278: UserWarning: There are multiple lapse images for date 2021-04-27 13:00:00! Choosing the first one.\n",
      "  warn(f\"There are multiple lapse images for date {previous_date}! Choosing the first one.\")\n",
      "/home/kleinsteuber/vscode/py/Session.py:280: UserWarning: There are multiple lapse images for date 2021-04-27 14:00:00! Choosing the first one.\n",
      "  warn(f\"There are multiple lapse images for date {next_date}! Choosing the first one.\")\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 958580 characters]",
      "text/plain": [
       "<Figure size 1728x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 319004 characters]",
      "text/plain": [
       "<Figure size 1728x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "img = session.get_random_motion_image(day_only=True)\n",
    "# img = session.get_motion_image_from_filename(\"Beaver_01_00025.jpg\")\n",
    "classifier = FrameDiffClassifier()\n",
    "out = classifier.evaluate(img, display=True, save=False)\n",
    "classifier2 = GaussianFrameDiffClassifier(sigma=4)\n",
    "out = classifier2.evaluate(img, display=True, save=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluate on all Motion images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 3105/3105 [07:51<00:00,  6.58it/s]\n"
     ]
    }
   ],
   "source": [
    "classifier = GaussianFrameDiffClassifier(sigma=6)\n",
    "with warnings.catch_warnings():\n",
    "    warnings.simplefilter(\"ignore\")\n",
    "    normal_scores_g, anomalous_scores_g = generate_test_scores(classifier)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualize data points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 185968 characters]",
      "text/plain": [
       "<Figure size 1800x1800 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "scale = \"log\"\n",
    "plt.figure(figsize=(25, 25))\n",
    "plt.subplot(2, 2, 1)\n",
    "plot(0, 1, normal_scores, anomalous_scores, scale=scale)\n",
    "plt.subplot(2, 2, 2)\n",
    "plot(2, 3, normal_scores, anomalous_scores, scale=scale)\n",
    "plt.subplot(2, 2, 3)\n",
    "plot(0, 1, normal_scores_g, anomalous_scores_g, scale=scale)\n",
    "plt.subplot(2, 2, 4)\n",
    "plot(2, 3, normal_scores_g, anomalous_scores_g, scale=scale)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3105, 4)\n",
      "(3105,)\n",
      "absmean sigma=6 auc=0.7531850232234679\n",
      "0.9 percentile : TPR = 0.9016, FPR = 0.8740 <-> TNR = 0.1260 @ thresh 0.032425076185018734\n",
      "0.95 percentile : TPR = 0.9508, FPR = 0.9288 <-> TNR = 0.0712 @ thresh 0.02073934352418058\n",
      "0.98 percentile : TPR = 0.9809, FPR = 0.9587 <-> TNR = 0.0413 @ thresh 0.013175973601756659\n",
      "0.99 percentile : TPR = 0.9904, FPR = 0.9633 <-> TNR = 0.0367 @ thresh 0.011898081155165488\n",
      "absvar sigma=6 auc=0.7790002625161481\n",
      "0.9 percentile : TPR = 0.9003, FPR = 0.7577 <-> TNR = 0.2423 @ thresh 0.005026038003266494\n",
      "0.95 percentile : TPR = 0.9508, FPR = 0.8213 <-> TNR = 0.1787 @ thresh 0.0032058668136211088\n",
      "0.98 percentile : TPR = 0.9809, FPR = 0.8972 <-> TNR = 0.1028 @ thresh 0.0014498453031559072\n",
      "0.99 percentile : TPR = 0.9904, FPR = 0.9351 <-> TNR = 0.0649 @ thresh 0.0007798755273484217\n",
      "sqmean sigma=6 auc=0.7759122436149855\n",
      "0.9 percentile : TPR = 0.9003, FPR = 0.7813 <-> TNR = 0.2187 @ thresh 0.007083786384728686\n",
      "0.95 percentile : TPR = 0.9508, FPR = 0.8576 <-> TNR = 0.1424 @ thresh 0.003654762133574996\n",
      "0.98 percentile : TPR = 0.9809, FPR = 0.9161 <-> TNR = 0.0839 @ thresh 0.0016773318450396247\n",
      "0.99 percentile : TPR = 0.9904, FPR = 0.9423 <-> TNR = 0.0577 @ thresh 0.0009521497020519684\n",
      "sqvar sigma=6 auc=0.8011581222265975\n",
      "0.9 percentile : TPR = 0.9016, FPR = 0.6473 <-> TNR = 0.3527 @ thresh 0.002380969995933468\n",
      "0.95 percentile : TPR = 0.9508, FPR = 0.7526 <-> TNR = 0.2474 @ thresh 0.0008641906028275065\n",
      "0.98 percentile : TPR = 0.9822, FPR = 0.8828 <-> TNR = 0.1172 @ thresh 0.00015404167851602993\n",
      "0.99 percentile : TPR = 0.9904, FPR = 0.9035 <-> TNR = 0.0965 @ thresh 7.99515427284091e-05\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 20204 characters]",
      "text/plain": [
       "<Figure size 360x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 20436 characters]",
      "text/plain": [
       "<Figure size 360x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 20240 characters]",
      "text/plain": [
       "<Figure size 360x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 20328 characters]",
      "text/plain": [
       "<Figure size 360x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Display ROC Curve\n",
    "sigma = 6\n",
    "y_anom = np.array(anomalous_scores_g)\n",
    "assert y_anom.shape[1] == 4\n",
    "\n",
    "y_norm = np.array(normal_scores_g)\n",
    "assert y_norm.shape[1] == 4\n",
    "\n",
    "X = np.concatenate([y_norm, y_anom])\n",
    "print(X.shape)\n",
    "y = np.concatenate([-np.ones((y_norm.shape[0])), np.ones((y_anom.shape[0]))])\n",
    "print(y.shape)\n",
    "\n",
    "vals = [\"absmean\", \"absvar\", \"sqmean\", \"sqvar\"]\n",
    "for i in range(4):\n",
    "    fpr, tpr, thresholds, auc_score = plot_roc_curve(y, X[:,i], f\"Lapse frame differencing ({vals[i]}, σ={sigma})\", savefile=f\"plots/approach1a/roc_curves/{session.name}_{vals[i]}_sigma{sigma}\", show=False, figsize=(5,5))\n",
    "    print(f\"{vals[i]} sigma={sigma} auc={auc_score}\")\n",
    "    get_percentiles(fpr, tpr, thresholds)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.10.4 ('pytorch-gpu')",
   "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.10.4"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "17cd5c528a3345b75540c61f907eece919c031d57a2ca1e5653325af249173c9"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
