{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lateral line detection in the video -- definitivo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "from pathlib import Path\n",
    "import numpy as np\n",
    "import math\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Load video"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "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",
   "metadata": {},
   "source": [
    "Import horizontal lines"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the path to the CSV file\n",
    "input_data_path = (\n",
    "    project_root\n",
    "    / \"notebook\"\n",
    "    / \"lane_detection\"\n",
    "    / \"intermediate_data\"\n",
    "    / \"lane_lines\"\n",
    "    / f\"horizontal_lines_{video_number}.csv\"\n",
    ")\n",
    "\n",
    "# Load the CSV file into a DataFrame\n",
    "horizontal_lines = pd.read_csv(input_data_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Funzione per estendere una linea\n",
    "def extend_line(x1, y1, x2, y2, length=1000):\n",
    "    # Calcola la lunghezza originale della linea\n",
    "    dx, dy = x2 - x1, y2 - y1\n",
    "    norm = np.sqrt(dx**2 + dy**2)  # Distanza euclidea tra i due punti\n",
    "\n",
    "    # Evita divisioni per zero\n",
    "    if norm == 0:\n",
    "        return x1, y1, x2, y2\n",
    "\n",
    "    # Calcola i punti estesi\n",
    "    x1_ext = int(x1 - length * (dx / norm))\n",
    "    y1_ext = int(y1 - length * (dy / norm))\n",
    "    x2_ext = int(x2 + length * (dx / norm))\n",
    "    y2_ext = int(y2 + length * (dy / norm))\n",
    "\n",
    "    return x1_ext, y1_ext, x2_ext, y2_ext"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Drow one line on the frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"Disegna la linea sul frame\"\"\"\n",
    "\n",
    "\n",
    "def write_line_on_frame(frame, line):\n",
    "    # Create a copy of the original frame to draw the first line\n",
    "    modified_frame = np.copy(frame)\n",
    "\n",
    "    if line is not None:\n",
    "        x1, y1, x2, y2 = line\n",
    "\n",
    "        # Allunga la linea di 1000 pixel da entrambe le estremità\n",
    "        x1_ext, y1_ext, x2_ext, y2_ext = extend_line(x1, y1, x2, y2, length=1000)\n",
    "\n",
    "        # Disegna la linea estesa\n",
    "        cv2.line(modified_frame, (x1_ext, y1_ext), (x2_ext, y2_ext), (0, 255, 0), 2)\n",
    "\n",
    "        # x1, y1, x2, y2 = map(int, line)\n",
    "        # cv2.line(modified_frame, (x1, y1), (x2, y2), (0, 255, 0), 2)\n",
    "\n",
    "    # return the modified frame\n",
    "    return modified_frame"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Drow all the lines on the frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def write_lines_on_frame(frame, lines):\n",
    "    for i in range(len(lines)):\n",
    "        frame = write_line_on_frame(frame, lines[i])\n",
    "    frame = write_line_on_frame(frame, [960, 0, 960, 1300])\n",
    "    return frame"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Transform the line from 'polar coordinates' (hough transform coordinates) to cartesian"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def polar_to_cartesian(line):\n",
    "    rho, theta = line\n",
    "    a = np.cos(theta)\n",
    "    b = np.sin(theta)\n",
    "    x0 = a * rho\n",
    "    y0 = b * rho\n",
    "    x1 = x0 + 1000 * (-b)\n",
    "    y1 = y0 + 1000 * (a)\n",
    "    x2 = x0 - 1000 * (-b)\n",
    "    y2 = y0 - 1000 * (a)\n",
    "    return np.array([[x1, y1, x2, y2]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Select the central point of the line on the frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def select_central_point(line, frame):\n",
    "    rho, theta = line\n",
    "    a = np.cos(theta)\n",
    "    b = np.sin(theta)\n",
    "\n",
    "    # Get the x-size of the image\n",
    "    x_size = frame.shape[1]\n",
    "\n",
    "    # Calculate the x-coordinate that is half of the x-size\n",
    "    x_half = x_size // 2\n",
    "    print(\"b:\", b)\n",
    "    # Calculate the corresponding y-coordinate using the line equation\n",
    "    y_half = int((rho - x_half * a) / b)\n",
    "\n",
    "    return x_half, y_half"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Get the edges from the colored image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_edges(frame):\n",
    "    # Define the range for light brown color in HSV\n",
    "    lower_brown = np.array([00, 30, 100])\n",
    "    upper_brown = np.array([20, 200, 255])\n",
    "\n",
    "    # Define the range for rose color in HSV\n",
    "    lower_rose = np.array([150, 30, 200])\n",
    "    upper_rose = np.array([180, 200, 255])\n",
    "\n",
    "    # Convert the image to HSV color space\n",
    "    hsv_image = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)\n",
    "\n",
    "    # Create masks for brown and rose colors\n",
    "    mask_brown = cv2.inRange(hsv_image, lower_brown, upper_brown)\n",
    "    mask_rose = cv2.inRange(hsv_image, lower_rose, upper_rose)\n",
    "\n",
    "    # Combine the masks\n",
    "    combined_mask = cv2.bitwise_or(mask_brown, mask_rose)\n",
    "\n",
    "    # apply brown and rose mask\n",
    "    extracted_image = cv2.bitwise_and(frame, frame, mask=combined_mask)\n",
    "\n",
    "    # blur the image\n",
    "    blurred_image = cv2.GaussianBlur(extracted_image, (15, 15), 0)\n",
    "\n",
    "    # Convert the bottom image to grayscale\n",
    "    gray_image = cv2.cvtColor(blurred_image, cv2.COLOR_BGR2GRAY)\n",
    "\n",
    "    # Compute Otsu's threshold\n",
    "    otsu_thresh, _ = cv2.threshold(\n",
    "        gray_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU\n",
    "    )\n",
    "\n",
    "    # Set lower and upper thresholds relative to Otsu's threshold\n",
    "    lower = 0.5 * otsu_thresh\n",
    "    upper = 1.5 * otsu_thresh\n",
    "\n",
    "    # get edges\n",
    "    edges = cv2.Canny(gray_image, lower, upper)\n",
    "\n",
    "    return edges"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Get the lines from the edges"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_lines(edges):\n",
    "    # Apply Probabilistic Hough Line Transform (allow to set minLineLength and maxLineGap)\n",
    "    min_line_length = 50\n",
    "    max_line_gap = 5\n",
    "    lines_p = cv2.HoughLinesP(\n",
    "        edges,\n",
    "        1,\n",
    "        np.pi / 180,\n",
    "        100,\n",
    "        minLineLength=min_line_length,\n",
    "        maxLineGap=max_line_gap,\n",
    "    )\n",
    "\n",
    "    return lines_p"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Compute the slope of the line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Function to calculate the angle of a line\n",
    "def calculate_angle(x1, y1, x2, y2):\n",
    "    return math.degrees(math.atan2(y2 - y1, x2 - x1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Transform the line from 2 points to homogeneous coordinates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cartesian_to_homogeneous(line):\n",
    "    hom_line = np.cross([line[0], line[1], 1], [line[2], line[3], 1])\n",
    "    hom_line = hom_line / hom_line[2]\n",
    "\n",
    "    return hom_line"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Compute the intersection between the lines and the horizontal line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_intersection(lines, horizontal_line):\n",
    "    intersection_points_x = []\n",
    "    # compute the intersection of each line with the horizontal line\n",
    "    for line in lines:\n",
    "        hom_line = cartesian_to_homogeneous(line[0])\n",
    "        hom_hor_line = cartesian_to_homogeneous(horizontal_line[0])\n",
    "\n",
    "        int_point = np.cross(hom_line, hom_hor_line)\n",
    "        int_point = int_point / int_point[2]\n",
    "\n",
    "        intersection_points_x.append(int_point[0])\n",
    "\n",
    "    return intersection_points_x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Select the closest left and right line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def select_closest_lines(lines, horizontal_line, center):\n",
    "    # compute the intersection of the lines with the horizontal lines\n",
    "    intersections_points_x = compute_intersection(lines, horizontal_line)\n",
    "    left_lines = []\n",
    "    right_lines = []\n",
    "    left_distances = []\n",
    "    right_distances = []\n",
    "    for i in range(len(lines)):\n",
    "        # if the intersection in at the left of the center\n",
    "        if intersections_points_x[i] < center:\n",
    "            left_lines.append(lines[i])\n",
    "            left_distances.append(abs(center - intersections_points_x[i]))\n",
    "\n",
    "        else:  # if the intersection is at the right of the center\n",
    "            right_lines.append(lines[i])\n",
    "            right_distances.append(abs(center - intersections_points_x[i]))\n",
    "\n",
    "    # compute the indeces of the minimum distance point\n",
    "    min_left_index = (\n",
    "        left_distances.index(min(left_distances)) if left_distances else None\n",
    "    )\n",
    "    min_right_index = (\n",
    "        right_distances.index(min(right_distances)) if right_distances else None\n",
    "    )\n",
    "\n",
    "    # if exists, return the lines closest to the point\n",
    "    if min_left_index is None:\n",
    "        if min_right_index is None:\n",
    "            return None, None\n",
    "        return None, right_lines[min_right_index]\n",
    "\n",
    "    if min_right_index is None:\n",
    "        return left_lines[min_left_index], None\n",
    "\n",
    "    return left_lines[min_left_index], right_lines[min_right_index]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Select the non horizontal lines that have both points over the horizontal line - divide left and rigth"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def filter_lines(lines_p, horizontal_line, image_center, tolerance_angle=20):\n",
    "    # Calculate the homogeneous coordinates of the horizontal line\n",
    "    x1, y1, x2, y2 = horizontal_line[0]\n",
    "    horizontal_line_homogeneous = np.cross([x1, y1, 1], [x2, y2, 1])\n",
    "    horizontal_line_homogeneous = (\n",
    "        horizontal_line_homogeneous / horizontal_line_homogeneous[0]\n",
    "    )\n",
    "\n",
    "    # Filter out lines that are 'quite horizontal' with a tolerance of 20 degrees\n",
    "    filtered_lines = []\n",
    "    if lines_p is not None:\n",
    "        for line in lines_p:\n",
    "            x1, y1, x2, y2 = line[0]\n",
    "            angle = calculate_angle(x1, y1, x2, y2)\n",
    "            if abs(angle) > tolerance_angle:\n",
    "                y_max = max(y1, y2)\n",
    "                x_max = x1 if y_max == y1 else x2\n",
    "                # Filter the lines that have both endpoints over the horizontal line\n",
    "                if (\n",
    "                    x_max\n",
    "                    + y_max * horizontal_line_homogeneous[1]\n",
    "                    + horizontal_line_homogeneous[2]\n",
    "                    > 0\n",
    "                ):  # se a*x + b*y + c > 0 allora il punto è sopra la linea\n",
    "                    filtered_lines.append(line)\n",
    "\n",
    "    if len(filtered_lines) == 0:\n",
    "        return None, None\n",
    "\n",
    "    # divide the lines in left and right and select the closests\n",
    "    left_line, right_line = select_closest_lines(\n",
    "        filtered_lines, horizontal_line, image_center\n",
    "    )\n",
    "\n",
    "    return left_line, right_line"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Compute the lateral lines for a single frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_lines(frame, horizontal_line):\n",
    "    # define the null line\n",
    "    null_line = np.array([[0, 0, 0, 0]])\n",
    "    # create an empty list\n",
    "    all_lines = []\n",
    "    # convert the lines in 2 points\n",
    "    horizontal_line_carteisan = polar_to_cartesian(horizontal_line)\n",
    "    # add the horizontal line\n",
    "    all_lines.append(horizontal_line_carteisan[0])\n",
    "    # define the central point on the horizontal line\n",
    "    central_point = select_central_point(horizontal_line, frame)\n",
    "    # compute the edges\n",
    "    edges = get_edges(frame)\n",
    "    # get the lateral lines\n",
    "    lines_p = get_lines(edges)\n",
    "\n",
    "    # select the closest left an right line\n",
    "    left_line, right_line = filter_lines(\n",
    "        lines_p, horizontal_line_carteisan, central_point[0]\n",
    "    )\n",
    "\n",
    "    # add the lines to the list\n",
    "    if left_line is None:\n",
    "        all_lines.append(null_line[0])\n",
    "    else:\n",
    "        all_lines.append(left_line[0])\n",
    "\n",
    "    if right_line is None:\n",
    "        all_lines.append(null_line[0])\n",
    "    else:\n",
    "        all_lines.append(right_line[0])\n",
    "\n",
    "    return all_lines"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Main"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "227\n",
      "b: 0.9999352459591057\n",
      "b: 0.9999099545922074\n",
      "b: 0.9998804512545729\n",
      "b: 0.9998568255432034\n",
      "b: 0.9998527664601821\n",
      "b: 0.9998557691252282\n",
      "b: 0.9998683611476573\n",
      "b: 0.9998814976014934\n",
      "b: 0.9998895606632995\n",
      "b: 0.9998901556943395\n",
      "b: 0.9998845641079749\n",
      "b: 0.9998857123452798\n",
      "b: 0.9998806225972304\n",
      "b: 0.9998867611329645\n",
      "b: 0.9998879503607253\n",
      "b: 0.9998952363060616\n",
      "b: 0.9998991135387997\n",
      "b: 0.9999086076991831\n",
      "b: 0.9999200332461285\n",
      "b: 0.9999260946342385\n",
      "b: 0.9999273358715206\n",
      "b: 0.999921528944179\n",
      "b: 0.9999299333408088\n",
      "b: 0.9999251199349254\n",
      "b: 0.9999201574878317\n",
      "b: 0.9999150491064517\n",
      "b: 0.9999147820782102\n",
      "b: 0.9998983765995302\n",
      "b: 0.9998862050383474\n",
      "b: 0.9998794609305839\n",
      "b: 0.9998872536241195\n",
      "b: 0.9998950506171649\n",
      "b: 0.999870874890744\n",
      "b: 0.999813672975844\n",
      "b: 0.9997454637462588\n",
      "b: 0.9996768703977311\n",
      "b: 0.9995996053199921\n",
      "b: 0.9995793589761323\n",
      "b: 0.9996055846700124\n",
      "b: 0.9996419424845241\n",
      "b: 0.9996399516907685\n",
      "b: 0.9996242923879346\n",
      "b: 0.9996079467077668\n",
      "b: 0.9996037570882312\n",
      "b: 0.9995876527024623\n",
      "b: 0.9995831399110006\n",
      "b: 0.9996011225574956\n",
      "b: 0.9996207642419855\n",
      "b: 0.9996277534883864\n",
      "b: 0.9996277928764999\n",
      "b: 0.9995993475450655\n",
      "b: 0.9995615318853331\n",
      "b: 0.9995198918049472\n",
      "b: 0.9994788635416031\n",
      "b: 0.999443094468464\n",
      "b: 0.9994394577584143\n",
      "b: 0.9994339733919415\n",
      "b: 0.9994620863988346\n",
      "b: 0.9995211737036884\n",
      "b: 0.9995791326005927\n",
      "b: 0.9996354358447255\n",
      "b: 0.9996895537251627\n",
      "b: 0.9997166013184763\n",
      "b: 0.9997192915753913\n",
      "b: 0.9997212992231203\n",
      "b: 0.9996724005506846\n",
      "b: 0.9996186396544936\n",
      "b: 0.9996616821455988\n",
      "b: 0.9997019917386248\n",
      "b: 0.9996560497144404\n",
      "b: 0.9996619742831359\n",
      "b: 0.999748749250127\n",
      "b: 0.9997532162537726\n",
      "b: 0.999757615316332\n",
      "b: 0.9998294989581157\n",
      "b: 0.9998593853759654\n",
      "b: 0.9998535170243139\n",
      "b: 0.9998646097065224\n",
      "b: 0.9998674472116144\n",
      "b: 0.9998715785661836\n",
      "b: 0.9999014478180217\n",
      "b: 0.9998956405185663\n",
      "b: 0.9998690203715975\n",
      "b: 0.9998506225362515\n",
      "b: 0.9998206515487136\n",
      "b: 0.9997793286600268\n",
      "b: 0.9997909111328099\n",
      "b: 0.999800187805\n",
      "b: 0.9998108529750774\n",
      "b: 0.9998257871031965\n",
      "b: 0.99985956187491\n",
      "b: 0.9998661117381741\n",
      "b: 0.9998760794258541\n",
      "b: 0.9998802401987993\n",
      "b: 0.9998876287708831\n",
      "b: 0.9998726059346832\n",
      "b: 0.9998779638768238\n",
      "b: 0.9998831145253774\n",
      "b: 0.999889908687669\n",
      "b: 0.9998983180427963\n",
      "b: 0.99990658332165\n",
      "b: 0.9999083805278187\n",
      "b: 0.999902246989958\n",
      "b: 0.9999007192076472\n",
      "b: 0.9998950277045546\n",
      "b: 0.9999026401653248\n",
      "b: 0.9999025787849267\n",
      "b: 0.9999103797759475\n",
      "b: 0.9999014640420433\n",
      "b: 0.9998944469628173\n",
      "b: 0.9998759814604811\n",
      "b: 0.9998520196215154\n",
      "b: 0.9998259347681495\n",
      "b: 0.9998432913847581\n",
      "b: 0.9998597135993074\n",
      "b: 0.999874154576434\n",
      "b: 0.9998876929206812\n",
      "b: 0.999891975271201\n",
      "b: 0.999868257934949\n",
      "b: 0.9998475113032204\n",
      "b: 0.999831493818174\n",
      "b: 0.9998332300104823\n",
      "b: 0.999845479127809\n",
      "b: 0.9998644832660794\n",
      "b: 0.9998775212001805\n",
      "b: 0.9998919169402337\n",
      "b: 0.9998891472984569\n",
      "b: 0.9998830644190126\n",
      "b: 0.9998747382066531\n",
      "b: 0.9998661074487519\n",
      "b: 0.999859861161036\n",
      "b: 0.9998561744490447\n",
      "b: 0.9998561215574864\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "b: 0.9998560951007662\n",
      "Adjusted video saved to C:\\Users\\miche\\OneDrive\\Documenti\\GitHub\\bowling-analysis\\data\\recording_3\\Lines_video_non_processed.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 = (\n",
    "    project_root\n",
    "    / \"data\"\n",
    "    / f\"recording_{video_number}\"\n",
    "    / \"Lines_video_non_processed.mp4\"\n",
    ")\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",
    "# Loop through each frame in the video\n",
    "frame_index = 0\n",
    "lines_array = []\n",
    "print(len(horizontal_lines))\n",
    "while frame_index < len(horizontal_lines):\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",
    "\n",
    "    # Compute the three lines in the frame\n",
    "    all_lines = compute_lines(video_frame, horizontal_lines.iloc[frame_index])\n",
    "\n",
    "    if all_lines is None:\n",
    "        print(\"No lines found in frame\", frame_index)\n",
    "        modified_frame = video_frame\n",
    "\n",
    "    else:\n",
    "        # draw the lines on the frame\n",
    "        modified_frame = write_lines_on_frame(video_frame, all_lines)\n",
    "        # add lines to the output array\n",
    "        lines_array.append(all_lines)\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}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Save lines in csv file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Lines array saved to C:\\Users\\miche\\OneDrive\\Documenti\\GitHub\\bowling-analysis\\notebook\\lane_detection\\intermediate_data\\lane_lines\\three_lines_3.csv\n"
     ]
    }
   ],
   "source": [
    "# Define the output path for the lines CSV file\n",
    "output_lines_path = (\n",
    "    project_root\n",
    "    / \"notebook\"\n",
    "    / \"lane_detection\"\n",
    "    / \"intermediate_data\"\n",
    "    / \"lane_lines\"\n",
    "    / f\"three_lines_{video_number}.csv\"\n",
    ")\n",
    "\n",
    "# Convert lines_array to a DataFrame\n",
    "lines_df = pd.DataFrame(lines_array)\n",
    "\n",
    "# Save the DataFrame to a CSV file\n",
    "lines_df.to_csv(output_lines_path, index=False)\n",
    "\n",
    "print(f\"Lines array saved to {output_lines_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": 2
}
