{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "92bf7b4a",
   "metadata": {},
   "source": [
    "# Test the quality of the data of Camera Motion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "04f920cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "from pathlib import Path\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1aa60348",
   "metadata": {},
   "source": [
    "Import video"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "0dd22680",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opened: True, FPS: 59.94005994005994, Total Frames: 227.0\n"
     ]
    }
   ],
   "source": [
    "video_number = \"3\"\n",
    "# Define the relative path to the video file\n",
    "notebook_dir = Path().resolve()\n",
    "project_root = notebook_dir.parent.parent\n",
    "video_path = (\n",
    "    project_root\n",
    "    / \"data\"\n",
    "    / f\"recording_{video_number}\"\n",
    "    / f\"Recording_{video_number}.mp4\"\n",
    ")\n",
    "video_path = str(video_path)\n",
    "\n",
    "# Load the video\n",
    "cap = cv2.VideoCapture(video_path)\n",
    "\n",
    "# Check\n",
    "print(\n",
    "    f\"Opened: {cap.isOpened()}, FPS: {cap.get(cv2.CAP_PROP_FPS)}, Total Frames: {cap.get(cv2.CAP_PROP_FRAME_COUNT)}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd25c64b",
   "metadata": {},
   "source": [
    "Import data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "a6a323e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the iinput path for the lines CSV file\n",
    "motion = (\n",
    "    project_root\n",
    "    / \"notebook\"\n",
    "    / \"lane_detection\"\n",
    "    / \"intermediate_data\"\n",
    "    / \"background_motion\"\n",
    "    / f\"motion_{video_number}.csv\"\n",
    ")\n",
    "df = pd.read_csv(motion)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "298d9038",
   "metadata": {},
   "source": [
    "Process the motion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "0f2dbab7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "               dx            dy\n",
      "0    2.039125e-12  1.108998e-12\n",
      "1    1.359889e-12  4.476052e-13\n",
      "2    0.000000e+00  0.000000e+00\n",
      "3   -1.266178e+01  0.000000e+00\n",
      "4    1.465242e+01  0.000000e+00\n",
      "..            ...           ...\n",
      "221  3.414250e+00  1.546667e+00\n",
      "222  1.636811e+00  5.689573e-01\n",
      "223  3.211425e+00  5.978990e-01\n",
      "224  3.204671e+00  4.091686e-01\n",
      "225  5.896944e+00  1.380317e+00\n",
      "\n",
      "[226 rows x 2 columns]\n"
     ]
    }
   ],
   "source": [
    "# Define a function to remove outliers and replace them with 0\n",
    "def remove_outliers(series, threshold=3):\n",
    "    # Calculate the first quartile (Q1) and third quartile (Q3)\n",
    "    Q1 = series.quantile(0.25)\n",
    "    Q3 = series.quantile(0.75)\n",
    "\n",
    "    # Compute the interquartile range (IQR)\n",
    "    IQR = Q3 - Q1\n",
    "\n",
    "    # Define the lower and upper bounds for outliers\n",
    "    lower_bound = Q1 - threshold * IQR\n",
    "    upper_bound = Q3 + threshold * IQR\n",
    "\n",
    "    # Replace values outside the bounds with 0, otherwise keep the value\n",
    "    return series.apply(lambda x: 0 if x < lower_bound or x > upper_bound else x)\n",
    "\n",
    "\n",
    "# Apply the function to 'dx' and 'dy'\n",
    "df[\"dx\"] = remove_outliers(df[\"dx\"])\n",
    "df[\"dy\"] = remove_outliers(df[\"dy\"])\n",
    "\n",
    "print(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1572bbbe",
   "metadata": {},
   "source": [
    "Select a point in the first frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "3ec50930",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Central Point: (1400, 540)\n"
     ]
    }
   ],
   "source": [
    "# Get the width and height of the video frame\n",
    "frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n",
    "frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n",
    "\n",
    "# Calculate the central point\n",
    "# point = (frame_width // 2, frame_height // 2)\n",
    "\n",
    "point = (1400, 540)\n",
    "\n",
    "print(f\"Central Point: {point}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a45643f8",
   "metadata": {},
   "source": [
    "Add to the point the detected motion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "1fd82a18",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the starting point\n",
    "current_point = list(point)\n",
    "\n",
    "# Create a list to store the updated points for each frame\n",
    "updated_points = []\n",
    "\n",
    "# Iterate through the dataframe to add the motion to the point\n",
    "for _, row in df.iterrows():\n",
    "    motion_x, motion_y = row[\"dx\"], row[\"dy\"]\n",
    "    current_point[0] += motion_x\n",
    "    current_point[1] += motion_y\n",
    "    updated_points.append(tuple(current_point))\n",
    "\n",
    "# # Print the updated points\n",
    "# print(updated_points)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2c66081",
   "metadata": {},
   "source": [
    "Draw the point on the video on each frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "05431229",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adjusted video saved to C:\\Users\\miche\\OneDrive\\Documenti\\GitHub\\bowling-analysis\\data\\recording_3\\Motion_test.mp4\n"
     ]
    }
   ],
   "source": [
    "# Reset the video to the beginning\n",
    "cap.set(cv2.CAP_PROP_POS_FRAMES, 0)\n",
    "\n",
    "# Define the codec and create a VideoWriter object to save the modified frames\n",
    "output_path = project_root / \"data\" / f\"recording_{video_number}\" / \"Motion_test.mp4\"\n",
    "fourcc = cv2.VideoWriter_fourcc(*\"mp4v\")  # Use 'mp4v' codec for MP4 format\n",
    "fps = int(cap.get(cv2.CAP_PROP_FPS))\n",
    "frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n",
    "frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n",
    "out = cv2.VideoWriter(str(output_path), fourcc, fps, (frame_width, frame_height))\n",
    "\n",
    "\n",
    "# Loop through each frame in the video\n",
    "frame_index = 0\n",
    "while frame_index < len(updated_points):\n",
    "    ret, video_frame = cap.read()\n",
    "    if not ret:\n",
    "        print(\"End of video or failed to read the frame at iteration\", frame_index)\n",
    "        break\n",
    "    # print(f\"Processing frame {frame_index}\")\n",
    "\n",
    "    modified_frame = video_frame.copy()\n",
    "\n",
    "    # Draw the updated point on the frame\n",
    "    updated_point = updated_points[frame_index]\n",
    "    cv2.circle(\n",
    "        modified_frame,\n",
    "        (int(updated_point[0]), int(updated_point[1])),\n",
    "        radius=5,\n",
    "        color=(0, 0, 255),\n",
    "        thickness=-1,\n",
    "    )\n",
    "\n",
    "    # Write the modified frame to the output video\n",
    "    out.write(modified_frame)\n",
    "\n",
    "    # Increment the frame index\n",
    "    frame_index += 1\n",
    "\n",
    "# Release the video capture and writer objects\n",
    "# cap.release()\n",
    "out.release()\n",
    "\n",
    "print(f\"Adjusted video saved to {output_path}\")"
   ]
  }
 ],
 "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.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
