`import sqlite3
import datetime
from Status import Status

class Database:
    """
    A class to handle interactions with the SQLite database for object tracking.

    Attributes:
        conn (sqlite3.Connection): The database connection.
        cursor (sqlite3.Cursor): The database cursor.
    """
    def __init__(self, db_path='object_tracking.db'):
        """
        Initializes the Database class with a connection to the specified SQLite database.

        Args:
            db_path (str): The path to the SQLite database file.
        """
        self.conn = sqlite3.connect(db_path)
        self.cursor = self.conn.cursor()
        self.create_table()

    def create_table(self):
        """
        Creates the 'tracked_objects' table if it does not already exist.
        """
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS tracked_objects (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                class_name TEXT,
                x1 INTEGER,
                y1 INTEGER,
                width INTEGER,
                height INTEGER,
                last_seen DATETIME,
                status TEXT,
                detection_count INTEGER DEFAULT 0
            )
        ''')
        self.conn.commit()

    def fetch_objects(self, class_name=None):
        """
        Fetches objects from the database, optionally filtered by class name.

        Args:
            class_name (str, optional): The class name to filter objects.

        Returns:
            list: A list of tuples representing the objects.
        """
        if class_name:
            self.cursor.execute('SELECT * FROM tracked_objects WHERE class_name=?', (class_name,))
        else:
            self.cursor.execute('SELECT * FROM tracked_objects')
        return self.cursor.fetchall()

    def fetch_all_objects(self):
        """
        Fetches all objects from the database.

        Returns:
            list: A list of tuples representing all objects.
        """
        self.cursor.execute('SELECT * FROM tracked_objects')
        return self.cursor.fetchall()

    def fetch_object_by_id(self, obj_id):
        """
        Fetches a single object by its ID.

        Args:
            obj_id (int): The ID of the object.

        Returns:
            tuple: The object data as a tuple.
        """
        self.cursor.execute('SELECT * FROM tracked_objects WHERE id=?', (obj_id,))
        return self.cursor.fetchone()

    def update_object(self, obj_id, x1, y1, width, height):
        """
        Updates the position and size of an existing object in the database, and increments detection_count.

        Args:
            obj_id (int): The ID of the object to update.
            x1 (int): The new x-coordinate of the object's top-left corner.
            y1 (int): The new y-coordinate of the object's top-left corner.
            width (int): The new width of the object.
            height (int): The new height of the object.

        Returns:
            int: The ID of the updated object.
        """
        last_seen = datetime.datetime.now().isoformat()
        status = Status.IN_FRAME.value  # Set status to 'In Frame'
        self.cursor.execute('''
            UPDATE tracked_objects 
            SET x1=?, y1=?, width=?, height=?, last_seen=?, status=?, detection_count=detection_count+1 
            WHERE id=?
        ''', (x1, y1, width, height, last_seen, status, obj_id))
        self.conn.commit()
        return obj_id

    def insert_object(self, class_name, x1, y1, width, height):
        """
        Inserts a new object into the database, and returns the new object's ID.

        Args:
            class_name (str): The class name of the object.
            x1 (int): The x-coordinate of the object's top-left corner.
            y1 (int): The y-coordinate of the object's top-left corner.
            width (int): The width of the object.
            height (int): The height of the object.

        Returns:
            int: The ID of the newly inserted object.
        """
        last_seen = datetime.datetime.now().isoformat()
        status = Status.IN_FRAME.value  # Set status to 'In Frame'
        detection_count = 1
        self.cursor.execute('''
            INSERT INTO tracked_objects (class_name, x1, y1, width, height, last_seen, status, detection_count) 
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ''', (class_name, x1, y1, width, height, last_seen, status, detection_count))
        self.conn.commit()
        return self.cursor.lastrowid

    def update_status(self, obj_id, status):
        """
        Updates the status of an object in the database.

        Args:
            obj_id (int): The ID of the object to update.
            status (Status): The new status of the object.
        """
        self.cursor.execute('''
            UPDATE tracked_objects 
            SET status=? 
            WHERE id=?
        ''', (status.value, obj_id))
        self.conn.commit()

    def delete_object(self, obj_id):
        """
        Deletes an object from the database.

        Args:
            obj_id (int): The ID of the object to delete.
        """
        self.cursor.execute('''
            DELETE FROM tracked_objects WHERE id=?
        ''', (obj_id,))
        self.conn.commit()`, `from ultralytics import YOLO

class ObjectDetection:
    """
    A class for object detection using a YOLO model.

    Attributes:
        model (YOLO): The YOLO model used for detection.
        classNames (list): List of class names that the model can detect.
        allowed_classes (set): Set of class indices that are allowed for tracking.
    """
    def __init__(self, model_path="yolo-Weights/yolov8n.pt"):
        """
        Initializes the ObjectDetection class with the specified YOLO model.

        Args:
            model_path (str): The path to the YOLO model weights.
        """
        self.model = YOLO(model_path)
        self.classNames = ["person", "bicycle", "car", "motorbike", "aeroplane", "bus", "train", "truck", "boat",
                           "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat",
                           "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella",
                           "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
                           "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup",
                           "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli",
                           "carrot", "hot dog", "pizza", "donut", "cake", "chair", "sofa", "pottedplant", "bed",
                           "diningtable", "toilet", "tvmonitor", "laptop", "mouse", "remote", "keyboard", "cell phone",
                           "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors",
                           "teddy bear", "hair drier", "toothbrush"]
        # Only allow certain classes for tracking
        self.allowed_classes = {0, 24, 25, 26, 31, 36, 37, 39, 40, 41, 53, 63, 65, 67}

    def detect_objects(self, img):
        """
        Detects objects in the given image.

        Args:
            img (numpy.ndarray): The image in which to detect objects.

        Returns:
            list: A list of detections, each containing class name, bounding box coordinates, width, height, and confidence.
        """
        results = self.model(img, stream=True)
        detections = []
        for r in results:
            for box in r.boxes:
                # Get the confidence score
                confidence = box.conf[0].item()
                if confidence < 0.55:
                    continue  # Skip detections below confidence threshold

                # Get the class index
                cls = int(box.cls[0])
                if cls not in self.allowed_classes:
                    continue  # Skip classes that are not allowed

                # Get bounding box coordinates
                x1, y1, x2, y2 = map(int, box.xyxy[0])
                width, height = x2 - x1, y2 - y1
                class_name = self.classNames[cls]
                detections.append((class_name, x1, y1, width, height, confidence))
        return detections`, `import cv2
from deep_sort_realtime.deepsort_tracker import DeepSort
from datetime import datetime, timedelta
from Status import Status

class ObjectTracker:
    """
    A class for tracking objects using Deep Sort and updating their status in the database.

    Attributes:
        db (Database): The database instance for storing object data.
        detection_model (ObjectDetection): The object detection model.
        tracker (DeepSort): The Deep Sort tracker instance.
    """
    def __init__(self, db, detection_model):
        """
        Initializes the ObjectTracker class with the given database and detection model.

        Args:
            db (Database): The database instance.
            detection_model (ObjectDetection): The object detection model.
        """
        self.db = db
        self.detection_model = detection_model
        # Initialize the Deep Sort tracker with specified parameters
        self.tracker = DeepSort(max_age=10, n_init=3, nms_max_overlap=1.0, max_cosine_distance=0.4, nn_budget=None)

    def is_near(self, existing_obj, new_obj, threshold=30):
        """
        Determines if a new object is near an existing object based on a threshold.

        Args:
            existing_obj (tuple): The existing object's coordinates and size (x, y, w, h).
            new_obj (tuple): The new object's coordinates and size (x, y, w, h).
            threshold (int, optional): The distance threshold to consider.

        Returns:
            bool: True if the objects are near each other, False otherwise.
        """
        ex, ey, ew, eh = existing_obj
        nx, ny, nw, nh = new_obj
        # Check if bounding boxes are close enough
        return not (nx > ex + ew + threshold or
                    nx + nw < ex - threshold or
                    ny > ey + eh + threshold or
                    ny + nh < ey - threshold)

    def is_within_border(self, x1, y1, width, height, frame_width, frame_height, threshold=10):
        """
        Checks if the bounding box is within the frame borders based on threshold percentage overlap.

        Args:
            x1 (float): The x-coordinate of the top-left corner of the bounding box.
            y1 (float): The y-coordinate of the top-left corner of the bounding box.
            width (float): The width of the bounding box.
            height (float): The height of the bounding box.
            frame_width (float): The width of the frame.
            frame_height (float): The height of the frame.
            threshold (float, optional): Minimum percentage of the object's area that should be within
                                        the frame to consider it 'in'. Defaults to 10.

        Returns:
            bool: True if the object's overlap with the frame is greater than or equal to the threshold
                percentage, False otherwise.
        """
        # Calculate the coordinates of the intersection rectangle
        x_left = max(x1, 0)
        y_top = max(y1, 0)
        x_right = min(x1 + width, frame_width)
        y_bottom = min(y1 + height, frame_height)

        # Compute width and height of the intersection
        intersect_width = x_right - x_left
        intersect_height = y_bottom - y_top

        # If there is no overlap
        if intersect_width <= 0 or intersect_height <= 0:
            intersection_area = 0
        else:
            intersection_area = intersect_width * intersect_height

        # Calculate the area of the bounding box
        bbox_area = width * height

        # Avoid division by zero
        if bbox_area == 0:
            return False

        # Calculate the overlap percentage
        overlap_percentage = (intersection_area / bbox_area) * 100

        return overlap_percentage >= threshold

    def check_for_false_positives(self):
        """
        Checks the database for objects that haven't been seen for more than 10 seconds.
        If an object hasn't been seen for more than 10 seconds and detection_count <10, deletes it.
        Else, updates its status to 'Left Frame'
        """
        all_objects = self.db.fetch_all_objects()
        now = datetime.now()
        minimum_detection_timeout = datetime.now() - timedelta(seconds=1)

        for obj in all_objects:
            obj_id = obj[0]
            class_name = obj[1]
            x1 = obj[2]
            y1 = obj[3]
            width = obj[4]
            height = obj[5]
            last_seen_str = obj[6]
            status = obj[7]
            detection_count = obj[8]

            last_seen = datetime.fromisoformat(last_seen_str)

            # If the object hasn't been seen for more than 10 seconds
            if last_seen < minimum_detection_timeout:
                if detection_count < 5:
                    # Delete the object from the database
                    self.db.delete_object(obj_id)

    def track_objects(self, img):
        """
        Performs object detection and tracking on the given image.

        Args:
            img (numpy.ndarray): The image on which to perform tracking.

        Returns:
            numpy.ndarray: The image with tracking annotations.
        """
        frame_height, frame_width = img.shape[:2]
        detections = self.detection_model.detect_objects(img)
        formatted_detections = []

        for class_name, x1, y1, width, height, confidence in detections:
            new_obj = (x1, y1, width, height)
            # Prepare detections for the tracker
            formatted_detections.append(([x1, y1, width, height], confidence, class_name))
            # Draw bounding boxes and labels on the image
            cv2.rectangle(img, (x1, y1), (x1 + width, y1 + height), (255, 0, 255), 3)
            cv2.putText(img, f'{class_name} {confidence:.2f}', (x1, y1 - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.9, (255, 0, 0), 2)

            existing_objs = self.db.fetch_objects(class_name)
            preexisting_obj = False
            obj_id = None

            # Check if the detected object matches any existing object in the database
            for existing_obj in existing_objs:
                db_x1, db_y1, db_width, db_height, last_seen, status = existing_obj[2], existing_obj[3], existing_obj[4], existing_obj[5], datetime.fromisoformat(existing_obj[6]), Status(existing_obj[7])
                if self.is_near((db_x1, db_y1, db_width, db_height), new_obj):
                    preexisting_obj = True
                    obj_id = existing_obj[0]  # Get the ID
                    # Update the existing object's position and reset its status to 'In Frame'
                    self.db.update_object(obj_id, x1, y1, width, height)
                    break  # Update only one matching object

            if not preexisting_obj:
                # Insert a new object into the database
                obj_id = self.db.insert_object(class_name, x1, y1, width, height)
            else:
                if (last_seen < datetime.now() - timedelta(milliseconds=500)) and not self.is_within_border(x1, y1, width, height, frame_width, frame_height):
                    # Update the object's status to 'Left Frame'
                    self.db.update_status(obj_id, Status.LEFT_FRAME)

            # Check if the object is near the frame border
            if self.is_within_border(x1, y1, width, height, frame_width, frame_height) and preexisting_obj:
                # Update object's status to 'In Frame'
                self.db.update_status(obj_id, Status.IN_FRAME)

        # Update the tracker with new detections
        tracks = self.tracker.update_tracks(formatted_detections, frame=img)
        # Check for objects that may have left the frame
        self.check_for_false_positives()
        return img`,`from enum import Enum

class Status(str, Enum):
    """
    An enumeration to represent the status of tracked objects.
    """
    IN_FRAME = "In Frame"
    LEFT_FRAME = "Left Frame"`. For that code, modify it so that instead of checking if its within the bounds of the frame, check if its not been detected in 500ms and if it was heading out of the frame and if so mark if left frame.