{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "28f3ac13",
   "metadata": {},
   "source": [
    "# Detection of the upper line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "86a044ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import cv2\n",
    "from pathlib import Path\n",
    "from matplotlib import pyplot as plt\n",
    "import pandas as pd\n",
    "import math"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1afbe479",
   "metadata": {},
   "source": [
    "Import video"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "78473bfc",
   "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": "05151689",
   "metadata": {},
   "source": [
    "Import lines"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f272e8df",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the iinput path for the lines CSV file\n",
    "input_lines_path = (\n",
    "    project_root\n",
    "    / \"notebook\"\n",
    "    / \"lane_detection\"\n",
    "    / \"intermediate_data\"\n",
    "    / \"lane_lines\"\n",
    "    / f\"definitive_lines_{video_number}.csv\"\n",
    ")\n",
    "df = pd.read_csv(input_lines_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a8ba329",
   "metadata": {},
   "source": [
    "Import the template"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c1d6aec6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Function to display an image\n",
    "def showImage(image, title=\"Image\"):\n",
    "    plt.figure(figsize=(10, 6))\n",
    "    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))\n",
    "    plt.title(title)\n",
    "    plt.axis(\"off\")\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7aea01b5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "template = cv2.imread(\n",
    "    \"intermediate_data/Template_pin_3.png\", 0\n",
    ")  # 0 for the grayscale image\n",
    "\n",
    "template_heigth, template_width = template.shape\n",
    "\n",
    "showImage(template, \"Template\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6dff7ef",
   "metadata": {},
   "source": [
    "## Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38230b77",
   "metadata": {},
   "source": [
    "Draw line - lines on a single frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "cb68bceb",
   "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": "code",
   "execution_count": 8,
   "id": "690e7640",
   "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",
    "    # return the modified frame\n",
    "    return modified_frame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "59e0ced9",
   "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",
    "    return frame"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ab9da61",
   "metadata": {},
   "source": [
    "Extend the lines until the edges of the image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b485bd4c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- Helper functions ---\n",
    "def get_extended_line(line, img_width, img_height):\n",
    "    \"\"\"Extend a line to the image boundaries.\"\"\"\n",
    "    x1, y1, x2, y2 = line\n",
    "    if x1 == x2:\n",
    "        return (x1, 0), (x2, img_height)\n",
    "\n",
    "    m = (y2 - y1) / (x2 - x1)\n",
    "    b = y1 - m * x1\n",
    "    points = []\n",
    "\n",
    "    y_left = int(m * 0 + b)\n",
    "    y_right = int(m * img_width + b)\n",
    "    if 0 <= y_left <= img_height:\n",
    "        points.append((0, y_left))\n",
    "    if 0 <= y_right <= img_height:\n",
    "        points.append((img_width, y_right))\n",
    "\n",
    "    if m != 0:\n",
    "        x_top = int((0 - b) / m)\n",
    "        x_bottom = int((img_height - b) / m)\n",
    "        if 0 <= x_top <= img_width:\n",
    "            points.append((x_top, 0))\n",
    "        if 0 <= x_bottom <= img_width:\n",
    "            points.append((x_bottom, img_height))\n",
    "    if len(points) < 2:\n",
    "        return [x1, y1, x2, y2]\n",
    "    extended_line = [points[0][0], points[0][1], points[1][0], points[1][1]]\n",
    "\n",
    "    return extended_line"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59f9a079",
   "metadata": {},
   "source": [
    "compute the determinant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "16e881ba",
   "metadata": {},
   "outputs": [],
   "source": [
    "def det(a, b):\n",
    "    return a[0] * b[1] - a[1] * b[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5cc664e2",
   "metadata": {},
   "source": [
    "Get the intersection point between 2 lines"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "7736127f",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_intersection(line_1, line_2):\n",
    "    \"\"\"Find the intersection point of two lines.\"\"\"\n",
    "    xdiff = (line_1[0] - line_1[2], line_2[0] - line_2[2])\n",
    "    ydiff = (line_1[1] - line_1[3], line_2[1] - line_2[3])\n",
    "\n",
    "    div = det(xdiff, ydiff)\n",
    "    if div == 0:\n",
    "        return None\n",
    "\n",
    "    d = (\n",
    "        det((line_1[0], line_1[1]), (line_1[2], line_1[3])),\n",
    "        det((line_2[0], line_2[1]), (line_2[2], line_2[3])),\n",
    "    )\n",
    "    x = int(det(d, xdiff) / div)\n",
    "    y = int(det(d, ydiff) / div)\n",
    "    return x, y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e6b6ef7",
   "metadata": {},
   "source": [
    "Cut the part of the image that is inside the triangle created by the lines"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "51085d95",
   "metadata": {},
   "outputs": [],
   "source": [
    "def cut_frame(frame, bottom_line, left_line, rigth_line):\n",
    "    \"\"\"Cut the image based on the lines defined in the DataFrame.\"\"\"\n",
    "    width = frame.shape[1]\n",
    "    height = frame.shape[0]\n",
    "    # --- Get extended lines ---\n",
    "    bottom_line = get_extended_line(bottom_line, width, height)\n",
    "    left_line = get_extended_line(left_line, width, height)\n",
    "    rigth_line = get_extended_line(rigth_line, width, height)\n",
    "\n",
    "    # --- Get triangle intersection points ---\n",
    "    int1 = get_intersection(bottom_line, left_line)\n",
    "    int2 = get_intersection(bottom_line, rigth_line)\n",
    "    int3 = get_intersection(left_line, rigth_line)\n",
    "\n",
    "    if None in [int1, int2, int3]:\n",
    "        raise ValueError(\"Could not find all three triangle points\")\n",
    "\n",
    "    triangle = np.array([int1, int2, int3])\n",
    "\n",
    "    # --- Create mask and apply it ---\n",
    "    mask = np.zeros((height, width), dtype=np.uint8)\n",
    "    cv2.drawContours(mask, [triangle], 0, 255, -1)\n",
    "\n",
    "    masked_frame = cv2.bitwise_and(frame, frame, mask=mask)\n",
    "\n",
    "    # showImage(masked_frame, \"After removing background\")\n",
    "\n",
    "    return masked_frame, triangle"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "148af7bf",
   "metadata": {},
   "source": [
    "Extract only brown and rose colors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "dc009f6b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def extract_br_frame(frame):\n",
    "    # Convert frame to HSV color space\n",
    "    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)\n",
    "\n",
    "    # Brown range\n",
    "    lower_brown = np.array([00, 00, 50])\n",
    "    upper_brown = np.array([20, 255, 255])\n",
    "\n",
    "    \"\"\"\n",
    "    Hue -> Covers reddish to yellowish-brown tones\n",
    "    Saturation -> Filters out grays\n",
    "    Value -> Keeps medium to bright pixels, avoids too-dark shadows\n",
    "    \"\"\"\n",
    "\n",
    "    # Rose (pinkish-red)\n",
    "    lower_rose = np.array([150, 30, 200])\n",
    "    upper_rose = np.array([180, 200, 255])\n",
    "\n",
    "    \"\"\"\n",
    "    Hue -> Covers magenta, pink, and rose hues\n",
    "    Saturation -> Avoids overly dull or overly neon colors\n",
    "    Value -> Captures only the bright parts\n",
    "    \"\"\"\n",
    "\n",
    "    # Create masks\n",
    "    mask_brown = cv2.inRange(hsv, lower_brown, upper_brown)\n",
    "    mask_rose = cv2.inRange(hsv, lower_rose, upper_rose)\n",
    "\n",
    "    # Combine both masks\n",
    "    combined_mask = cv2.bitwise_or(mask_brown, mask_rose)\n",
    "\n",
    "    # Apply the combined mask to the original frame\n",
    "    brown_and_rose_frame = cv2.bitwise_and(frame, frame, mask=combined_mask)\n",
    "\n",
    "    return brown_and_rose_frame"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2fb60d8",
   "metadata": {},
   "source": [
    "Get the first horizontal line where the % of black is > 98%"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "f0bddcd2",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_upper_horizontal_line_first_estimate(frame, triangle):\n",
    "    # Threshold for black (treat anything darker than this as black)\n",
    "    black_thresh = 30\n",
    "\n",
    "    # Convert masked image to grayscale for easier intensity check\n",
    "    gray_masked = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
    "\n",
    "    # Start from row y = 100\n",
    "    start_y = triangle[0][1]\n",
    "    height = gray_masked.shape[0]\n",
    "    width = gray_masked.shape[1]\n",
    "    stop_row = None\n",
    "\n",
    "    for y in range(start_y, -1, -1):  # go from int1 down to 0\n",
    "        row = gray_masked[y, :]\n",
    "        non_black_pixels = np.count_nonzero(row > black_thresh)\n",
    "        percentage_non_black = (non_black_pixels / len(row)) * 100\n",
    "\n",
    "        if percentage_non_black < 2:\n",
    "            stop_row = y\n",
    "            print(\n",
    "                f\"Stopped at row {y} with {percentage_non_black:.2f}% non-black pixels\"\n",
    "            )\n",
    "            break\n",
    "\n",
    "    if stop_row is None:\n",
    "        print(\"No row found with <2% non-black pixels after y=100.\")\n",
    "        return None\n",
    "\n",
    "    # # Optional: visualize the stopping row on the image\n",
    "    # annotated = frame.copy()\n",
    "    # cv2.line(annotated, (0, stop_row), (annotated.shape[1], stop_row), (0, 255, 0), 2)\n",
    "\n",
    "    # plt.figure(figsize=(10, 5))\n",
    "    # plt.title(\"Detected Stop Row\")\n",
    "    # plt.imshow(cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB))\n",
    "    # plt.axis('off')\n",
    "    # plt.show()\n",
    "\n",
    "    # --- Define the horizontal line  ---\n",
    "    horizontal_upper_line = [0, y, width, y]\n",
    "\n",
    "    return horizontal_upper_line"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "831d2133",
   "metadata": {},
   "source": [
    "Compute euclidean distance between 2 points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "a46072e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- Calculate the distance between the two intersection points ---\n",
    "def euclidean_distance(p1, p2):\n",
    "    return np.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "705ee061",
   "metadata": {},
   "source": [
    "Apply template matching to detect a better line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "c6d8e167",
   "metadata": {},
   "outputs": [],
   "source": [
    "def template_matching(\n",
    "    br_frame, template, upper_horizontal_estimated, left_line, right_line\n",
    "):\n",
    "    # computed estimated intersection between upper and lateral lines\n",
    "    intersection_left = get_intersection(left_line, upper_horizontal_estimated)\n",
    "    intersection_right = get_intersection(right_line, upper_horizontal_estimated)\n",
    "    # compute the length of the upper line in the frame\n",
    "    distance = euclidean_distance(intersection_left, intersection_right)\n",
    "\n",
    "    # Compute the correct dimension of the template\n",
    "    lane_width = 1066\n",
    "    pin_height_real = 381 + 40  # 20 is the margin taken from the template\n",
    "    pin_height_template = template.shape[0]\n",
    "    pin_width_template = template.shape[1]\n",
    "\n",
    "    pin_height = (pin_height_real * distance) / lane_width\n",
    "    f = pin_height / pin_height_template\n",
    "\n",
    "    template = cv2.resize(template, (0, 0), fx=f, fy=f)\n",
    "\n",
    "    # print(\"Original template size:\", pin_width_template, pin_height_template)\n",
    "    # print(\"Scaling factors -> fx:\", f, \"fy:\", f)\n",
    "\n",
    "    new_width = int(pin_width_template * f)\n",
    "    new_height = int(pin_height_template * f)\n",
    "\n",
    "    # print(\"New template size:\", new_width, new_height)\n",
    "\n",
    "    # --- Template matching ---\n",
    "    gray_frame = cv2.cvtColor(br_frame, cv2.COLOR_BGR2GRAY)\n",
    "\n",
    "    # Method for doing Template Matching\n",
    "    method = cv2.TM_CCOEFF\n",
    "\n",
    "    img = gray_frame.copy()\n",
    "    result = cv2.matchTemplate(\n",
    "        img, template, method\n",
    "    )  # This performs Convolution, the output will be (Width - w + 1, Height - h + 1)\n",
    "    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(\n",
    "        result\n",
    "    )  # This returns min, max values, min, max locations\n",
    "    location = max_loc\n",
    "\n",
    "    bottom_right = (location[0] + new_width, location[1] + new_height)\n",
    "    # print(f\"Coordinates of the bottom right location:\", bottom_right)\n",
    "\n",
    "    # # Optional: visualize the template matching result\n",
    "    # img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)\n",
    "    # cv2.rectangle(img, location, bottom_right, color=(0,255,0), thickness=2)\n",
    "    # cv2.circle(img, bottom_right, 8, (0, 0, 255), -1)\n",
    "    # showImage(img, \"Pin detection\")\n",
    "\n",
    "    return bottom_right"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd05441b",
   "metadata": {},
   "source": [
    "Calculate the angle of the line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "e4ca650f",
   "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",
   "id": "a5abdbfb",
   "metadata": {},
   "source": [
    "Correct the inclination of the upper line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "efcc829c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def correct_inclination(bottom_right, bottom_line, frame):\n",
    "    slope_bottom_line = np.deg2rad(\n",
    "        calculate_angle(bottom_line[0], bottom_line[1], bottom_line[2], bottom_line[3])\n",
    "    )\n",
    "    # Lenght between the detected point and the point I want to create\n",
    "    length = 100\n",
    "\n",
    "    # Calculate two points along the line\n",
    "    ux1 = int(bottom_right[0] - length)\n",
    "    uy1 = int(\n",
    "        bottom_right[1] - slope_bottom_line / 2 * length\n",
    "    )  # TODO: change the /2 because it is wrong\n",
    "    ux2 = int(bottom_right[0] + length)\n",
    "    uy2 = int(\n",
    "        bottom_right[1] + slope_bottom_line / 2 * length\n",
    "    )  # TODO: change the /2 because it is wrong\n",
    "\n",
    "    # Calculate the extended line points\n",
    "    width = frame.shape[1]\n",
    "    height = frame.shape[0]\n",
    "    upper_line = get_extended_line([ux1, uy1, ux2, uy2], width, height)\n",
    "\n",
    "    return upper_line"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0bf028a2",
   "metadata": {},
   "source": [
    "Main"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "c875837f",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_upper_line(frame, bottom_line, left_line, right_line, template):\n",
    "    cutted_frame, triangle = cut_frame(frame, bottom_line, left_line, right_line)\n",
    "    br_frame = extract_br_frame(cutted_frame)\n",
    "    upper_horizontal_estimated = get_upper_horizontal_line_first_estimate(\n",
    "        br_frame, triangle\n",
    "    )\n",
    "    bottom_rigth_point_pin = template_matching(\n",
    "        cutted_frame, template, upper_horizontal_estimated, left_line, right_line\n",
    "    )\n",
    "\n",
    "    upper_line = correct_inclination(\n",
    "        bottom_rigth_point_pin, bottom_line, frame\n",
    "    )  # TO CHANGE\n",
    "    return upper_line"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c6ed568",
   "metadata": {},
   "source": [
    "Generate video"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "e6b3919b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "227\n",
      "Stopped at row 443 with 0.78% non-black pixels\n",
      "Stopped at row 443 with 0.78% non-black pixels\n",
      "Stopped at row 443 with 0.78% non-black pixels\n",
      "Stopped at row 443 with 1.67% non-black pixels\n",
      "Stopped at row 441 with 1.15% non-black pixels\n",
      "Stopped at row 439 with 1.15% non-black pixels\n",
      "Stopped at row 437 with 1.15% non-black pixels\n",
      "Stopped at row 435 with 1.15% non-black pixels\n",
      "Stopped at row 437 with 1.82% non-black pixels\n",
      "Stopped at row 435 with 1.56% non-black pixels\n",
      "Stopped at row 433 with 1.51% non-black pixels\n",
      "Stopped at row 431 with 1.56% non-black pixels\n",
      "Stopped at row 431 with 1.72% non-black pixels\n",
      "Stopped at row 429 with 0.99% non-black pixels\n",
      "Stopped at row 427 with 0.68% non-black pixels\n",
      "Stopped at row 425 with 0.94% non-black pixels\n",
      "Stopped at row 425 with 1.61% non-black pixels\n",
      "Stopped at row 423 with 1.46% non-black pixels\n",
      "Stopped at row 421 with 1.72% non-black pixels\n",
      "Stopped at row 419 with 1.56% non-black pixels\n",
      "Stopped at row 417 with 1.20% non-black pixels\n",
      "Stopped at row 415 with 0.89% non-black pixels\n",
      "Stopped at row 413 with 1.15% non-black pixels\n",
      "Stopped at row 411 with 1.35% non-black pixels\n",
      "Stopped at row 409 with 0.83% non-black pixels\n",
      "Stopped at row 407 with 0.83% non-black pixels\n",
      "Stopped at row 405 with 1.09% non-black pixels\n",
      "Stopped at row 403 with 1.30% non-black pixels\n",
      "Stopped at row 403 with 1.88% non-black pixels\n",
      "Stopped at row 399 with 1.35% non-black pixels\n",
      "Stopped at row 398 with 1.98% non-black pixels\n",
      "Stopped at row 395 with 1.35% non-black pixels\n",
      "Stopped at row 395 with 1.88% non-black pixels\n",
      "Stopped at row 394 with 1.88% non-black pixels\n",
      "Stopped at row 391 with 1.46% non-black pixels\n",
      "Stopped at row 387 with 1.35% non-black pixels\n",
      "Stopped at row 387 with 1.72% non-black pixels\n",
      "Stopped at row 385 with 1.82% non-black pixels\n",
      "Stopped at row 383 with 1.77% non-black pixels\n",
      "Stopped at row 380 with 1.93% non-black pixels\n",
      "Stopped at row 379 with 1.20% non-black pixels\n",
      "Stopped at row 379 with 1.72% non-black pixels\n",
      "Stopped at row 375 with 1.30% non-black pixels\n",
      "Stopped at row 373 with 1.41% non-black pixels\n",
      "Stopped at row 373 with 1.35% non-black pixels\n",
      "Stopped at row 372 with 1.98% non-black pixels\n",
      "Stopped at row 370 with 1.82% non-black pixels\n",
      "Stopped at row 367 with 1.67% non-black pixels\n",
      "Stopped at row 367 with 1.77% non-black pixels\n",
      "Stopped at row 366 with 1.88% non-black pixels\n",
      "Stopped at row 363 with 0.83% non-black pixels\n",
      "Stopped at row 362 with 1.98% non-black pixels\n",
      "Stopped at row 362 with 1.98% non-black pixels\n",
      "Stopped at row 360 with 1.72% non-black pixels\n",
      "Stopped at row 359 with 1.77% non-black pixels\n",
      "Stopped at row 357 with 1.41% non-black pixels\n",
      "Stopped at row 358 with 1.77% non-black pixels\n",
      "Stopped at row 358 with 1.93% non-black pixels\n",
      "Stopped at row 359 with 1.93% non-black pixels\n",
      "Stopped at row 357 with 1.82% non-black pixels\n",
      "Stopped at row 357 with 1.67% non-black pixels\n",
      "Stopped at row 357 with 1.67% non-black pixels\n",
      "Stopped at row 357 with 1.82% non-black pixels\n",
      "Stopped at row 357 with 1.72% non-black pixels\n",
      "Stopped at row 358 with 1.98% non-black pixels\n",
      "Stopped at row 359 with 1.61% non-black pixels\n",
      "Stopped at row 361 with 1.77% non-black pixels\n",
      "Stopped at row 361 with 1.77% non-black pixels\n",
      "Stopped at row 363 with 1.67% non-black pixels\n",
      "Stopped at row 363 with 1.72% non-black pixels\n",
      "Stopped at row 367 with 1.51% non-black pixels\n",
      "Stopped at row 368 with 1.98% non-black pixels\n",
      "Stopped at row 369 with 1.72% non-black pixels\n",
      "Stopped at row 373 with 1.98% non-black pixels\n",
      "Stopped at row 376 with 1.56% non-black pixels\n",
      "Stopped at row 378 with 1.67% non-black pixels\n",
      "Stopped at row 381 with 1.93% non-black pixels\n",
      "Stopped at row 384 with 1.98% non-black pixels\n",
      "Stopped at row 388 with 1.61% non-black pixels\n",
      "Stopped at row 391 with 1.88% non-black pixels\n",
      "Stopped at row 391 with 1.93% non-black pixels\n",
      "Stopped at row 389 with 1.25% non-black pixels\n",
      "Stopped at row 395 with 1.72% non-black pixels\n",
      "Stopped at row 399 with 1.67% non-black pixels\n",
      "Stopped at row 405 with 1.51% non-black pixels\n",
      "Stopped at row 409 with 1.82% non-black pixels\n",
      "Stopped at row 413 with 1.25% non-black pixels\n",
      "Stopped at row 415 with 1.41% non-black pixels\n",
      "Stopped at row 419 with 1.51% non-black pixels\n",
      "Stopped at row 421 with 1.04% non-black pixels\n",
      "Stopped at row 423 with 1.25% non-black pixels\n",
      "Stopped at row 425 with 1.35% non-black pixels\n",
      "Stopped at row 429 with 1.82% non-black pixels\n",
      "Stopped at row 431 with 1.72% non-black pixels\n",
      "Stopped at row 434 with 1.61% non-black pixels\n",
      "Stopped at row 435 with 1.98% non-black pixels\n",
      "Stopped at row 437 with 1.88% non-black pixels\n",
      "Stopped at row 437 with 1.72% non-black pixels\n",
      "Stopped at row 439 with 1.61% non-black pixels\n",
      "Stopped at row 441 with 1.72% non-black pixels\n",
      "Stopped at row 443 with 1.72% non-black pixels\n",
      "Stopped at row 443 with 1.93% non-black pixels\n",
      "Stopped at row 441 with 1.82% non-black pixels\n",
      "Stopped at row 439 with 1.93% non-black pixels\n",
      "Stopped at row 445 with 1.88% non-black pixels\n",
      "Stopped at row 445 with 1.56% non-black pixels\n",
      "Stopped at row 447 with 1.41% non-black pixels\n",
      "Stopped at row 447 with 1.88% non-black pixels\n",
      "Stopped at row 449 with 1.72% non-black pixels\n",
      "Stopped at row 447 with 1.72% non-black pixels\n",
      "Stopped at row 449 with 1.77% non-black pixels\n",
      "Stopped at row 443 with 1.82% non-black pixels\n",
      "Stopped at row 451 with 1.77% non-black pixels\n",
      "Stopped at row 451 with 1.35% non-black pixels\n",
      "Stopped at row 453 with 1.61% non-black pixels\n",
      "Stopped at row 447 with 1.67% non-black pixels\n",
      "Stopped at row 449 with 1.04% non-black pixels\n",
      "Stopped at row 449 with 1.09% non-black pixels\n",
      "Stopped at row 449 with 0.94% non-black pixels\n",
      "Stopped at row 449 with 1.72% non-black pixels\n",
      "Stopped at row 451 with 1.67% non-black pixels\n",
      "Stopped at row 451 with 1.61% non-black pixels\n",
      "Stopped at row 451 with 1.51% non-black pixels\n",
      "Stopped at row 451 with 1.93% non-black pixels\n",
      "Stopped at row 453 with 1.51% non-black pixels\n",
      "Stopped at row 453 with 1.67% non-black pixels\n",
      "Stopped at row 451 with 1.93% non-black pixels\n",
      "Stopped at row 451 with 1.82% non-black pixels\n",
      "Stopped at row 452 with 1.88% non-black pixels\n",
      "Stopped at row 451 with 1.35% non-black pixels\n",
      "Stopped at row 453 with 1.88% non-black pixels\n",
      "Stopped at row 452 with 1.88% non-black pixels\n",
      "Stopped at row 453 with 1.41% non-black pixels\n",
      "Stopped at row 453 with 0.99% non-black pixels\n",
      "Stopped at row 454 with 1.82% non-black pixels\n",
      "Stopped at row 454 with 1.72% non-black pixels\n",
      "Stopped at row 455 with 1.93% non-black pixels\n",
      "Stopped at row 454 with 1.46% non-black pixels\n",
      "Stopped at row 454 with 1.56% non-black pixels\n",
      "Stopped at row 455 with 1.98% non-black pixels\n",
      "Stopped at row 455 with 1.35% non-black pixels\n",
      "Stopped at row 455 with 1.15% non-black pixels\n",
      "Stopped at row 463 with 1.88% non-black pixels\n",
      "Stopped at row 457 with 0.99% non-black pixels\n",
      "Stopped at row 459 with 1.30% non-black pixels\n",
      "Stopped at row 459 with 1.51% non-black pixels\n",
      "Stopped at row 465 with 1.67% non-black pixels\n",
      "Stopped at row 467 with 1.77% non-black pixels\n",
      "Stopped at row 473 with 1.98% non-black pixels\n",
      "Stopped at row 473 with 1.98% non-black pixels\n",
      "Stopped at row 475 with 1.88% non-black pixels\n",
      "Stopped at row 475 with 1.72% non-black pixels\n",
      "Stopped at row 473 with 1.51% non-black pixels\n",
      "Stopped at row 473 with 1.77% non-black pixels\n",
      "Stopped at row 483 with 1.72% non-black pixels\n",
      "Stopped at row 485 with 1.77% non-black pixels\n",
      "Stopped at row 493 with 1.98% non-black pixels\n",
      "Stopped at row 479 with 1.67% non-black pixels\n",
      "Stopped at row 471 with 1.56% non-black pixels\n",
      "Stopped at row 471 with 1.20% non-black pixels\n",
      "Stopped at row 477 with 1.93% non-black pixels\n",
      "Stopped at row 490 with 1.88% non-black pixels\n",
      "Stopped at row 493 with 1.41% non-black pixels\n",
      "Stopped at row 491 with 1.67% non-black pixels\n",
      "Stopped at row 477 with 1.04% non-black pixels\n",
      "Stopped at row 479 with 1.77% non-black pixels\n",
      "Stopped at row 493 with 1.88% non-black pixels\n",
      "Stopped at row 503 with 1.35% non-black pixels\n",
      "Stopped at row 505 with 1.46% non-black pixels\n",
      "Stopped at row 507 with 1.82% non-black pixels\n",
      "Stopped at row 488 with 1.93% non-black pixels\n",
      "Stopped at row 479 with 1.93% non-black pixels\n",
      "Stopped at row 489 with 1.98% non-black pixels\n",
      "Stopped at row 509 with 1.67% non-black pixels\n",
      "Stopped at row 511 with 1.93% non-black pixels\n",
      "Stopped at row 513 with 1.82% non-black pixels\n",
      "Stopped at row 513 with 1.61% non-black pixels\n",
      "Stopped at row 513 with 1.30% non-black pixels\n",
      "Stopped at row 513 with 1.98% non-black pixels\n",
      "Stopped at row 513 with 1.77% non-black pixels\n",
      "Stopped at row 512 with 1.67% non-black pixels\n",
      "Stopped at row 511 with 1.67% non-black pixels\n",
      "Stopped at row 511 with 1.77% non-black pixels\n",
      "Stopped at row 510 with 1.82% non-black pixels\n",
      "Stopped at row 509 with 1.56% non-black pixels\n",
      "Stopped at row 509 with 0.94% non-black pixels\n",
      "Stopped at row 511 with 1.15% non-black pixels\n",
      "Stopped at row 511 with 1.46% non-black pixels\n",
      "Stopped at row 509 with 1.04% non-black pixels\n",
      "Stopped at row 510 with 1.56% non-black pixels\n",
      "Stopped at row 510 with 1.77% non-black pixels\n",
      "Stopped at row 509 with 1.67% non-black pixels\n",
      "Stopped at row 510 with 1.20% non-black pixels\n",
      "Stopped at row 511 with 1.88% non-black pixels\n",
      "Stopped at row 526 with 1.93% non-black pixels\n",
      "Stopped at row 513 with 1.04% non-black pixels\n",
      "Stopped at row 527 with 1.77% non-black pixels\n",
      "Stopped at row 527 with 1.56% non-black pixels\n",
      "Stopped at row 510 with 0.83% non-black pixels\n",
      "Stopped at row 511 with 1.41% non-black pixels\n",
      "Stopped at row 513 with 1.67% non-black pixels\n",
      "Stopped at row 513 with 1.56% non-black pixels\n",
      "Stopped at row 513 with 1.88% non-black pixels\n",
      "Stopped at row 512 with 1.82% non-black pixels\n",
      "Stopped at row 511 with 0.16% non-black pixels\n",
      "Stopped at row 513 with 1.30% non-black pixels\n",
      "Stopped at row 509 with 1.72% non-black pixels\n",
      "Stopped at row 511 with 1.98% non-black pixels\n",
      "Stopped at row 515 with 1.35% non-black pixels\n",
      "Stopped at row 515 with 1.04% non-black pixels\n",
      "Stopped at row 515 with 1.88% non-black pixels\n",
      "Stopped at row 514 with 1.56% non-black pixels\n",
      "Stopped at row 515 with 1.41% non-black pixels\n",
      "Stopped at row 515 with 1.67% non-black pixels\n",
      "Stopped at row 515 with 0.94% non-black pixels\n",
      "Stopped at row 515 with 1.67% non-black pixels\n",
      "Stopped at row 515 with 1.15% non-black pixels\n",
      "Stopped at row 516 with 1.82% non-black pixels\n",
      "Stopped at row 518 with 1.56% non-black pixels\n",
      "Stopped at row 525 with 0.21% non-black pixels\n",
      "Stopped at row 525 with 0.73% non-black pixels\n",
      "Stopped at row 525 with 0.31% non-black pixels\n",
      "Stopped at row 525 with 0.83% non-black pixels\n",
      "Stopped at row 527 with 1.46% non-black pixels\n",
      "Stopped at row 527 with 0.83% non-black pixels\n",
      "Stopped at row 529 with 1.88% non-black pixels\n",
      "Stopped at row 535 with 1.56% non-black pixels\n",
      "Adjusted video saved to C:\\Users\\miche\\OneDrive\\Documenti\\GitHub\\bowling-analysis\\data\\recording_3\\All_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",
    "    / \"All_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",
    "intersection_points = []\n",
    "print(len(df))\n",
    "while frame_index < len(df):\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",
    "    frame_data = df.iloc[frame_index]\n",
    "    # --- Extract line endpoints ---\n",
    "    bottom_line = [\n",
    "        frame_data[\"hx1\"],\n",
    "        frame_data[\"hy1\"],\n",
    "        frame_data[\"hx2\"],\n",
    "        frame_data[\"hy2\"],\n",
    "    ]\n",
    "    left_line = [\n",
    "        frame_data[\"lx1\"],\n",
    "        frame_data[\"ly1\"],\n",
    "        frame_data[\"lx2\"],\n",
    "        frame_data[\"ly2\"],\n",
    "    ]\n",
    "    rigth_line = [\n",
    "        frame_data[\"rx1\"],\n",
    "        frame_data[\"ry1\"],\n",
    "        frame_data[\"rx2\"],\n",
    "        frame_data[\"ry2\"],\n",
    "    ]\n",
    "\n",
    "    # Compute the three lines in the frame\n",
    "    upper_line = get_upper_line(\n",
    "        video_frame, bottom_line, left_line, rigth_line, template\n",
    "    )\n",
    "    all_lines = [bottom_line, left_line, rigth_line, upper_line]\n",
    "    intersection_points.append(\n",
    "        [\n",
    "            get_intersection(bottom_line, left_line),\n",
    "            get_intersection(bottom_line, rigth_line),\n",
    "            get_intersection(upper_line, left_line),\n",
    "            get_intersection(upper_line, rigth_line),\n",
    "        ]\n",
    "    )\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",
   "id": "e2d6ad1d",
   "metadata": {},
   "source": [
    "Save the 4 points in a CSV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "c7205a48",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Intersection points saved to C:\\Users\\miche\\OneDrive\\Documenti\\GitHub\\bowling-analysis\\data\\auxiliary_data\\lane_points\\lane_points_raw_3.csv\n"
     ]
    }
   ],
   "source": [
    "# Create a DataFrame from the intersection_points and frame indices\n",
    "columns = [\n",
    "    \"Frame\",\n",
    "    \"bottom_left_x\",\n",
    "    \"bottom_left_y\",\n",
    "    \"bottom_right_x\",\n",
    "    \"bottom_right_y\",\n",
    "    \"up_left_x\",\n",
    "    \"up_left_y\",\n",
    "    \"up_right_x\",\n",
    "    \"up_right_y\",\n",
    "]\n",
    "data = []\n",
    "\n",
    "for frame_idx, points in enumerate(intersection_points):\n",
    "    if points is not None and len(points) == 4:\n",
    "        bottom_left, bottom_right, up_left, up_right = points\n",
    "        data.append(\n",
    "            [\n",
    "                frame_idx,\n",
    "                bottom_left[0],\n",
    "                bottom_left[1],\n",
    "                bottom_right[0],\n",
    "                bottom_right[1],\n",
    "                up_left[0],\n",
    "                up_left[1],\n",
    "                up_right[0],\n",
    "                up_right[1],\n",
    "            ]\n",
    "        )\n",
    "\n",
    "# Create the DataFrame\n",
    "intersection_df = pd.DataFrame(data, columns=columns)\n",
    "\n",
    "# Display the DataFrame\n",
    "# print(intersection_df)\n",
    "\n",
    "output_path = (\n",
    "    project_root\n",
    "    / \"data\"\n",
    "    / \"auxiliary_data\"\n",
    "    / \"lane_points\"\n",
    "    / f\"lane_points_raw_{video_number}.csv\"\n",
    ")\n",
    "intersection_df.to_csv(output_path, index=False)\n",
    "print(f\"Intersection points 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
}
