Saltar al contenido

Referencia para ultralytics/solutions/parking_management.py

Nota

Este archivo está disponible en https://github.com/ultralytics/ ultralytics/blob/main/ ultralytics/solutions/parking_management .py. Si detectas algún problema, por favor, ayuda a solucionarlo contribuyendo con una Pull Request 🛠️. ¡Gracias 🙏!



ultralytics.solutions.parking_management.ParkingPtsSelection

Código fuente en ultralytics/solutions/parking_management.py
class ParkingPtsSelection:
    def __init__(self, master):
        """Initializes the UI for selecting parking zone points in a tkinter window."""
        self.master = master
        master.title("Ultralytics Parking Zones Points Selector")

        # Resizable false
        master.resizable(False, False)

        # Setup canvas for image display
        self.canvas = tk.Canvas(master, bg="white")

        # Setup buttons
        button_frame = tk.Frame(master)
        button_frame.pack(side=tk.TOP)

        tk.Button(button_frame, text="Upload Image", command=self.upload_image).grid(row=0, column=0)
        tk.Button(button_frame, text="Remove Last BBox", command=self.remove_last_bounding_box).grid(row=0, column=1)
        tk.Button(button_frame, text="Save", command=self.save_to_json).grid(row=0, column=2)

        # Initialize properties
        self.image_path = None
        self.image = None
        self.canvas_image = None
        self.canvas = None
        self.bounding_boxes = []
        self.current_box = []
        self.img_width = 0
        self.img_height = 0

        # Constants
        self.canvas_max_width = 1280
        self.canvas_max_height = 720

    def upload_image(self):
        """Upload an image and resize it to fit canvas."""
        self.image_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
        if not self.image_path:
            return

        self.image = Image.open(self.image_path)
        self.img_width, self.img_height = self.image.size

        # Calculate the aspect ratio and resize image
        aspect_ratio = self.img_width / self.img_height
        if aspect_ratio > 1:
            # Landscape orientation
            canvas_width = min(self.canvas_max_width, self.img_width)
            canvas_height = int(canvas_width / aspect_ratio)
        else:
            # Portrait orientation
            canvas_height = min(self.canvas_max_height, self.img_height)
            canvas_width = int(canvas_height * aspect_ratio)

        # Check if canvas is already initialized
        if self.canvas:
            self.canvas.destroy()  # Destroy previous canvas

        self.canvas = tk.Canvas(self.master, bg="white", width=canvas_width, height=canvas_height)
        resized_image = self.image.resize((canvas_width, canvas_height), Image.LANCZOS)
        self.canvas_image = ImageTk.PhotoImage(resized_image)
        self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas_image)

        self.canvas.pack(side=tk.BOTTOM)
        self.canvas.bind("<Button-1>", self.on_canvas_click)

        # Reset bounding boxes and current box
        self.bounding_boxes = []
        self.current_box = []

    def on_canvas_click(self, event):
        """Handle mouse clicks on canvas to create points for bounding boxes."""
        self.current_box.append((event.x, event.y))
        x0, y0 = event.x - 3, event.y - 3
        x1, y1 = event.x + 3, event.y + 3
        self.canvas.create_oval(x0, y0, x1, y1, fill="red")

        if len(self.current_box) == 4:
            self.bounding_boxes.append(self.current_box)
            self.draw_bounding_box(self.current_box)
            self.current_box = []

    def draw_bounding_box(self, box):
        """
        Draw bounding box on canvas.

        Args:
            box (list): Bounding box data
        """

        for i in range(4):
            x1, y1 = box[i]
            x2, y2 = box[(i + 1) % 4]
            self.canvas.create_line(x1, y1, x2, y2, fill="blue", width=2)

    def remove_last_bounding_box(self):
        """Remove the last drawn bounding box from canvas."""
        if self.bounding_boxes:
            self.bounding_boxes.pop()  # Remove the last bounding box
            self.canvas.delete("all")  # Clear the canvas
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas_image)  # Redraw the image

            # Redraw all bounding boxes
            for box in self.bounding_boxes:
                self.draw_bounding_box(box)

            messagebox.showinfo("Success", "Last bounding box removed.")
        else:
            messagebox.showwarning("Warning", "No bounding boxes to remove.")

    def save_to_json(self):
        """Saves rescaled bounding boxes to 'bounding_boxes.json' based on image-to-canvas size ratio."""
        canvas_width, canvas_height = self.canvas.winfo_width(), self.canvas.winfo_height()
        width_scaling_factor = self.img_width / canvas_width
        height_scaling_factor = self.img_height / canvas_height
        bounding_boxes_data = []
        for box in self.bounding_boxes:
            rescaled_box = []
            for x, y in box:
                rescaled_x = int(x * width_scaling_factor)
                rescaled_y = int(y * height_scaling_factor)
                rescaled_box.append((rescaled_x, rescaled_y))
            bounding_boxes_data.append({"points": rescaled_box})
        with open("bounding_boxes.json", "w") as json_file:
            json.dump(bounding_boxes_data, json_file, indent=4)

        messagebox.showinfo("Success", "Bounding boxes saved to bounding_boxes.json")

__init__(master)

Inicializa la interfaz para seleccionar puntos de zonas de aparcamiento en una ventana tkinter.

Código fuente en ultralytics/solutions/parking_management.py
def __init__(self, master):
    """Initializes the UI for selecting parking zone points in a tkinter window."""
    self.master = master
    master.title("Ultralytics Parking Zones Points Selector")

    # Resizable false
    master.resizable(False, False)

    # Setup canvas for image display
    self.canvas = tk.Canvas(master, bg="white")

    # Setup buttons
    button_frame = tk.Frame(master)
    button_frame.pack(side=tk.TOP)

    tk.Button(button_frame, text="Upload Image", command=self.upload_image).grid(row=0, column=0)
    tk.Button(button_frame, text="Remove Last BBox", command=self.remove_last_bounding_box).grid(row=0, column=1)
    tk.Button(button_frame, text="Save", command=self.save_to_json).grid(row=0, column=2)

    # Initialize properties
    self.image_path = None
    self.image = None
    self.canvas_image = None
    self.canvas = None
    self.bounding_boxes = []
    self.current_box = []
    self.img_width = 0
    self.img_height = 0

    # Constants
    self.canvas_max_width = 1280
    self.canvas_max_height = 720

draw_bounding_box(box)

Dibuja un cuadro delimitador en el lienzo.

Parámetros:

Nombre Tipo Descripción Por defecto
box list

Datos del cuadro delimitador

necesario
Código fuente en ultralytics/solutions/parking_management.py
def draw_bounding_box(self, box):
    """
    Draw bounding box on canvas.

    Args:
        box (list): Bounding box data
    """

    for i in range(4):
        x1, y1 = box[i]
        x2, y2 = box[(i + 1) % 4]
        self.canvas.create_line(x1, y1, x2, y2, fill="blue", width=2)

on_canvas_click(event)

Maneja los clics del ratón en el lienzo para crear puntos para las cajas delimitadoras.

Código fuente en ultralytics/solutions/parking_management.py
def on_canvas_click(self, event):
    """Handle mouse clicks on canvas to create points for bounding boxes."""
    self.current_box.append((event.x, event.y))
    x0, y0 = event.x - 3, event.y - 3
    x1, y1 = event.x + 3, event.y + 3
    self.canvas.create_oval(x0, y0, x1, y1, fill="red")

    if len(self.current_box) == 4:
        self.bounding_boxes.append(self.current_box)
        self.draw_bounding_box(self.current_box)
        self.current_box = []

remove_last_bounding_box()

Elimina del lienzo el último cuadro delimitador dibujado.

Código fuente en ultralytics/solutions/parking_management.py
def remove_last_bounding_box(self):
    """Remove the last drawn bounding box from canvas."""
    if self.bounding_boxes:
        self.bounding_boxes.pop()  # Remove the last bounding box
        self.canvas.delete("all")  # Clear the canvas
        self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas_image)  # Redraw the image

        # Redraw all bounding boxes
        for box in self.bounding_boxes:
            self.draw_bounding_box(box)

        messagebox.showinfo("Success", "Last bounding box removed.")
    else:
        messagebox.showwarning("Warning", "No bounding boxes to remove.")

save_to_json()

Guarda los cuadros delimitadores reescalados en 'bounding_boxes.json' en función de la relación entre el tamaño de la imagen y el lienzo.

Código fuente en ultralytics/solutions/parking_management.py
def save_to_json(self):
    """Saves rescaled bounding boxes to 'bounding_boxes.json' based on image-to-canvas size ratio."""
    canvas_width, canvas_height = self.canvas.winfo_width(), self.canvas.winfo_height()
    width_scaling_factor = self.img_width / canvas_width
    height_scaling_factor = self.img_height / canvas_height
    bounding_boxes_data = []
    for box in self.bounding_boxes:
        rescaled_box = []
        for x, y in box:
            rescaled_x = int(x * width_scaling_factor)
            rescaled_y = int(y * height_scaling_factor)
            rescaled_box.append((rescaled_x, rescaled_y))
        bounding_boxes_data.append({"points": rescaled_box})
    with open("bounding_boxes.json", "w") as json_file:
        json.dump(bounding_boxes_data, json_file, indent=4)

    messagebox.showinfo("Success", "Bounding boxes saved to bounding_boxes.json")

upload_image()

Sube una imagen y redimensiónala para ajustarla al lienzo.

Código fuente en ultralytics/solutions/parking_management.py
def upload_image(self):
    """Upload an image and resize it to fit canvas."""
    self.image_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
    if not self.image_path:
        return

    self.image = Image.open(self.image_path)
    self.img_width, self.img_height = self.image.size

    # Calculate the aspect ratio and resize image
    aspect_ratio = self.img_width / self.img_height
    if aspect_ratio > 1:
        # Landscape orientation
        canvas_width = min(self.canvas_max_width, self.img_width)
        canvas_height = int(canvas_width / aspect_ratio)
    else:
        # Portrait orientation
        canvas_height = min(self.canvas_max_height, self.img_height)
        canvas_width = int(canvas_height * aspect_ratio)

    # Check if canvas is already initialized
    if self.canvas:
        self.canvas.destroy()  # Destroy previous canvas

    self.canvas = tk.Canvas(self.master, bg="white", width=canvas_width, height=canvas_height)
    resized_image = self.image.resize((canvas_width, canvas_height), Image.LANCZOS)
    self.canvas_image = ImageTk.PhotoImage(resized_image)
    self.canvas.create_image(0, 0, anchor=tk.NW, image=self.canvas_image)

    self.canvas.pack(side=tk.BOTTOM)
    self.canvas.bind("<Button-1>", self.on_canvas_click)

    # Reset bounding boxes and current box
    self.bounding_boxes = []
    self.current_box = []



ultralytics.solutions.parking_management.ParkingManagement

Código fuente en ultralytics/solutions/parking_management.py
class ParkingManagement:
    def __init__(
        self,
        model_path,
        txt_color=(0, 0, 0),
        bg_color=(255, 255, 255),
        occupied_region_color=(0, 255, 0),
        available_region_color=(0, 0, 255),
        margin=10,
    ):
        # Model path and initialization
        self.model_path = model_path
        self.model = self.load_model()

        # Labels dictionary
        self.labels_dict = {"Occupancy": 0, "Available": 0}

        # Visualization details
        self.margin = margin
        self.bg_color = bg_color
        self.txt_color = txt_color
        self.occupied_region_color = occupied_region_color
        self.available_region_color = available_region_color

        self.window_name = "Ultralytics YOLOv8 Parking Management System"
        # Check if environment support imshow
        self.env_check = check_imshow(warn=True)

    def load_model(self):
        """Load the Ultralytics YOLOv8 model for inference and analytics."""
        from ultralytics import YOLO

        self.model = YOLO(self.model_path)
        return self.model

    @staticmethod
    def parking_regions_extraction(json_file):
        """
        Extract parking regions from json file.

        Args:
            json_file (str): file that have all parking slot points
        """

        with open(json_file, "r") as json_file:
            return json.load(json_file)

    def process_data(self, json_data, im0, boxes, clss):
        """
        Process the model data for parking lot management.

        Args:
            json_data (str): json data for parking lot management
            im0 (ndarray): inference image
            boxes (list): bounding boxes data
            clss (list): bounding boxes classes list
        Returns:
            filled_slots (int): total slots that are filled in parking lot
            empty_slots (int): total slots that are available in parking lot
        """
        annotator = Annotator(im0)
        total_slots, filled_slots = len(json_data), 0
        empty_slots = total_slots

        for region in json_data:
            points = region["points"]
            points_array = np.array(points, dtype=np.int32).reshape((-1, 1, 2))
            region_occupied = False

            for box, cls in zip(boxes, clss):
                x_center = int((box[0] + box[2]) / 2)
                y_center = int((box[1] + box[3]) / 2)
                text = f"{self.model.names[int(cls)]}"

                annotator.display_objects_labels(
                    im0, text, self.txt_color, self.bg_color, x_center, y_center, self.margin
                )
                dist = cv2.pointPolygonTest(points_array, (x_center, y_center), False)
                if dist >= 0:
                    region_occupied = True
                    break

            color = self.occupied_region_color if region_occupied else self.available_region_color
            cv2.polylines(im0, [points_array], isClosed=True, color=color, thickness=2)
            if region_occupied:
                filled_slots += 1
                empty_slots -= 1

        self.labels_dict["Occupancy"] = filled_slots
        self.labels_dict["Available"] = empty_slots

        annotator.display_analytics(im0, self.labels_dict, self.txt_color, self.bg_color, self.margin)

    def display_frames(self, im0):
        """
        Display frame.

        Args:
            im0 (ndarray): inference image
        """
        if self.env_check:
            cv2.namedWindow(self.window_name)
            cv2.imshow(self.window_name, im0)
            # Break Window
            if cv2.waitKey(1) & 0xFF == ord("q"):
                return

display_frames(im0)

Marco de la pantalla.

Parámetros:

Nombre Tipo Descripción Por defecto
im0 ndarray

imagen de inferencia

necesario
Código fuente en ultralytics/solutions/parking_management.py
def display_frames(self, im0):
    """
    Display frame.

    Args:
        im0 (ndarray): inference image
    """
    if self.env_check:
        cv2.namedWindow(self.window_name)
        cv2.imshow(self.window_name, im0)
        # Break Window
        if cv2.waitKey(1) & 0xFF == ord("q"):
            return

load_model()

Carga el modelo Ultralytics YOLOv8 para inferencias y análisis.

Código fuente en ultralytics/solutions/parking_management.py
def load_model(self):
    """Load the Ultralytics YOLOv8 model for inference and analytics."""
    from ultralytics import YOLO

    self.model = YOLO(self.model_path)
    return self.model

parking_regions_extraction(json_file) staticmethod

Extrae las zonas de aparcamiento del archivo json.

Parámetros:

Nombre Tipo Descripción Por defecto
json_file str

archivo que tiene todos los puntos de ranura de aparcamiento

necesario
Código fuente en ultralytics/solutions/parking_management.py
@staticmethod
def parking_regions_extraction(json_file):
    """
    Extract parking regions from json file.

    Args:
        json_file (str): file that have all parking slot points
    """

    with open(json_file, "r") as json_file:
        return json.load(json_file)

process_data(json_data, im0, boxes, clss)

Procesa los datos del modelo para la gestión del aparcamiento.

Parámetros:

Nombre Tipo Descripción Por defecto
json_data str

datos json para la gestión de aparcamientos

necesario
im0 ndarray

imagen de inferencia

necesario
boxes list

datos de las cajas delimitadoras

necesario
clss list

lista de clases de cajas delimitadoras

necesario

Devuelve: plazas_llenas (int): total de plazas que están llenas en el aparcamiento plazas_vacías (int): total de plazas disponibles en el aparcamiento

Código fuente en ultralytics/solutions/parking_management.py
def process_data(self, json_data, im0, boxes, clss):
    """
    Process the model data for parking lot management.

    Args:
        json_data (str): json data for parking lot management
        im0 (ndarray): inference image
        boxes (list): bounding boxes data
        clss (list): bounding boxes classes list
    Returns:
        filled_slots (int): total slots that are filled in parking lot
        empty_slots (int): total slots that are available in parking lot
    """
    annotator = Annotator(im0)
    total_slots, filled_slots = len(json_data), 0
    empty_slots = total_slots

    for region in json_data:
        points = region["points"]
        points_array = np.array(points, dtype=np.int32).reshape((-1, 1, 2))
        region_occupied = False

        for box, cls in zip(boxes, clss):
            x_center = int((box[0] + box[2]) / 2)
            y_center = int((box[1] + box[3]) / 2)
            text = f"{self.model.names[int(cls)]}"

            annotator.display_objects_labels(
                im0, text, self.txt_color, self.bg_color, x_center, y_center, self.margin
            )
            dist = cv2.pointPolygonTest(points_array, (x_center, y_center), False)
            if dist >= 0:
                region_occupied = True
                break

        color = self.occupied_region_color if region_occupied else self.available_region_color
        cv2.polylines(im0, [points_array], isClosed=True, color=color, thickness=2)
        if region_occupied:
            filled_slots += 1
            empty_slots -= 1

    self.labels_dict["Occupancy"] = filled_slots
    self.labels_dict["Available"] = empty_slots

    annotator.display_analytics(im0, self.labels_dict, self.txt_color, self.bg_color, self.margin)





Creado 2024-04-29, Actualizado 2024-05-08
Autores: Burhan-Q (1), lakshanthad (1), RizwanMunawar (1)