Skip to content

Register now for

# Reference for `ultralytics/solutions/parking_management.py`

Note

This file is available at https://github.com/ultralytics/ultralytics/blob/main/ultralytics/solutions/parking_management.py. If you spot a problem please help fix it by contributing a Pull Request 🛠️. Thank you 🙏!

## `` ultralytics.solutions.parking_management.ParkingPtsSelection

    ParkingPtsSelection()

A class for selecting and managing parking zone points on images using a Tkinter-based UI.

This class provides functionality to upload an image, select points to define parking zones, and save the selected points to a JSON file. It uses Tkinter for the graphical user interface.

Attributes:

Name | Type | Description
--- | --- | ---
`tk` | `module` | The Tkinter module for GUI operations.
`filedialog` | `module` | Tkinter's filedialog module for file selection operations.
`messagebox` | `module` | Tkinter's messagebox module for displaying message boxes.
`master` | `Tk` | The main Tkinter window.
`canvas` | `Canvas` | The canvas widget for displaying the image and drawing bounding boxes.
`image` | `Image` | The uploaded image.
`canvas_image` | `PhotoImage` | The image displayed on the canvas.
`rg_data` | `list[list[tuple[int, int]]]` | List of bounding boxes, each defined by 4 points.
`current_box` | `list[tuple[int, int]]` | Temporary storage for the points of the current bounding box.
`imgw` | `int` | Original width of the uploaded image.
`imgh` | `int` | Original height of the uploaded image.
`canvas_max_width` | `int` | Maximum width of the canvas.
`canvas_max_height` | `int` | Maximum height of the canvas.

Methods:

Name | Description
--- | ---
`initialize_properties` | Initialize properties for image, canvas, bounding boxes, and dimensions.
`upload_image` | Upload and display an image on the canvas, resizing it to fit within specified dimensions.
`on_canvas_click` | Handle mouse clicks to add points for bounding boxes on the canvas.
`draw_box` | Draw a bounding box on the canvas using the provided coordinates.
`remove_last_bounding_box` | Remove the last bounding box from the list and redraw the canvas.
`redraw_canvas` | Redraw the canvas with the image and all bounding boxes.
`save_to_json` | Save the selected parking zone points to a JSON file with scaled coordinates.

Examples:

    >>> parking_selector = ParkingPtsSelection()
    >>> # Use the GUI to upload an image, select parking zones, and save the data

Source code in `ultralytics/solutions/parking_management.py`

     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    def __init__(self) -> None:
        """Initialize the ParkingPtsSelection class, setting up UI and properties for parking zone point selection."""
        try:  # Check if tkinter is installed
            import tkinter as tk
            from tkinter import filedialog, messagebox
        except ImportError:  # Display error with recommendations
            import platform

            install_cmd = {
                "Linux": "sudo apt install python3-tk (Debian/Ubuntu) | sudo dnf install python3-tkinter (Fedora) | "
                "sudo pacman -S tk (Arch)",
                "Windows": "reinstall Python and enable the checkbox `tcl/tk and IDLE` on **Optional Features** during installation",
                "Darwin": "reinstall Python from https://www.python.org/downloads/macos/ or `brew install python-tk`",
            }.get(platform.system(), "Unknown OS. Check your Python installation.")

            LOGGER.warning(f" Tkinter is not configured or supported. Potential fix: {install_cmd}")
            return

        if not check_imshow(warn=True):
            return

        self.tk, self.filedialog, self.messagebox = tk, filedialog, messagebox
        self.master = self.tk.Tk()  # Reference to the main application window
        self.master.title("Ultralytics Parking Zones Points Selector")
        self.master.resizable(False, False)

        self.canvas = self.tk.Canvas(self.master, bg="white")  # Canvas widget for displaying images
        self.canvas.pack(side=self.tk.BOTTOM)

        self.image = None  # Variable to store the loaded image
        self.canvas_image = None  # Reference to the image displayed on the canvas
        self.canvas_max_width = None  # Maximum allowed width for the canvas
        self.canvas_max_height = None  # Maximum allowed height for the canvas
        self.rg_data = None  # Data for region annotation management
        self.current_box = None  # Stores the currently selected bounding box
        self.imgh = None  # Height of the current image
        self.imgw = None  # Width of the current image

        # Button frame with buttons
        button_frame = self.tk.Frame(self.master)
        button_frame.pack(side=self.tk.TOP)

        for text, cmd in [
            ("Upload Image", self.upload_image),
            ("Remove Last BBox", self.remove_last_bounding_box),
            ("Save", self.save_to_json),
        ]:
            self.tk.Button(button_frame, text=text, command=cmd).pack(side=self.tk.LEFT)

        self.initialize_properties()
        self.master.mainloop()

### `` draw_box

    draw_box(box: list[tuple[int, int]]) -> None

Draw a bounding box on the canvas using the provided coordinates.

Source code in `ultralytics/solutions/parking_management.py`

    146
    147
    148
    149
    def draw_box(self, box: list[tuple[int, int]]) -> None:
        """Draw a bounding box on the canvas using the provided coordinates."""
        for i in range(4):
            self.canvas.create_line(box[i], box[(i + 1) % 4], fill="blue", width=2)

### `` initialize_properties

    initialize_properties() -> None

Initialize properties for image, canvas, bounding boxes, and dimensions.

Source code in `ultralytics/solutions/parking_management.py`

    104
    105
    106
    107
    108
    109
    def initialize_properties(self) -> None:
        """Initialize properties for image, canvas, bounding boxes, and dimensions."""
        self.image = self.canvas_image = None
        self.rg_data, self.current_box = [], []
        self.imgw = self.imgh = 0
        self.canvas_max_width, self.canvas_max_height = 1280, 720

### `` on_canvas_click

    on_canvas_click(event) -> None

Handle mouse clicks to add points for bounding boxes on the canvas.

Source code in `ultralytics/solutions/parking_management.py`

    137
    138
    139
    140
    141
    142
    143
    144
    def on_canvas_click(self, event) -> None:
        """Handle mouse clicks to add points for bounding boxes on the canvas."""
        self.current_box.append((event.x, event.y))
        self.canvas.create_oval(event.x - 3, event.y - 3, event.x + 3, event.y + 3, fill="red")
        if len(self.current_box) == 4:
            self.rg_data.append(self.current_box.copy())
            self.draw_box(self.current_box)
            self.current_box.clear()

### `` redraw_canvas

    redraw_canvas() -> None

Redraw the canvas with the image and all bounding boxes.

Source code in `ultralytics/solutions/parking_management.py`

    159
    160
    161
    162
    163
    164
    def redraw_canvas(self) -> None:
        """Redraw the canvas with the image and all bounding boxes."""
        self.canvas.delete("all")
        self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image)
        for box in self.rg_data:
            self.draw_box(box)

### `` remove_last_bounding_box

    remove_last_bounding_box() -> None

Remove the last bounding box from the list and redraw the canvas.

Source code in `ultralytics/solutions/parking_management.py`

    151
    152
    153
    154
    155
    156
    157
    def remove_last_bounding_box(self) -> None:
        """Remove the last bounding box from the list and redraw the canvas."""
        if not self.rg_data:
            self.messagebox.showwarning("Warning", "No bounding boxes to remove.")
            return
        self.rg_data.pop()
        self.redraw_canvas()

### `` save_to_json

    save_to_json() -> None

Save the selected parking zone points to a JSON file with scaled coordinates.

Source code in `ultralytics/solutions/parking_management.py`

    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    def save_to_json(self) -> None:
        """Save the selected parking zone points to a JSON file with scaled coordinates."""
        scale_w, scale_h = self.imgw / self.canvas.winfo_width(), self.imgh / self.canvas.winfo_height()
        data = [{"points": [(int(x * scale_w), int(y * scale_h)) for x, y in box]} for box in self.rg_data]

        from io import StringIO  # Function level import, as it's only required to store coordinates

        write_buffer = StringIO()
        json.dump(data, write_buffer, indent=4)
        with open("bounding_boxes.json", "w", encoding="utf-8") as f:
            f.write(write_buffer.getvalue())
        self.messagebox.showinfo("Success", "Bounding boxes saved to bounding_boxes.json")

### `` upload_image

    upload_image() -> None

Upload and display an image on the canvas, resizing it to fit within specified dimensions.

Source code in `ultralytics/solutions/parking_management.py`

    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    def upload_image(self) -> None:
        """Upload and display an image on the canvas, resizing it to fit within specified dimensions."""
        from PIL import Image, ImageTk  # Scoped import because ImageTk requires tkinter package

        file = self.filedialog.askopenfilename(filetypes=[("Image Files", "*.png *.jpg *.jpeg")])
        if not file:
            LOGGER.info("No image selected.")
            return

        self.image = Image.open(file)
        self.imgw, self.imgh = self.image.size
        aspect_ratio = self.imgw / self.imgh
        canvas_width = (
            min(self.canvas_max_width, self.imgw) if aspect_ratio > 1 else int(self.canvas_max_height * aspect_ratio)
        )
        canvas_height = (
            min(self.canvas_max_height, self.imgh) if aspect_ratio <= 1 else int(canvas_width / aspect_ratio)
        )

        self.canvas.config(width=canvas_width, height=canvas_height)
        self.canvas_image = ImageTk.PhotoImage(self.image.resize((canvas_width, canvas_height)))
        self.canvas.create_image(0, 0, anchor=self.tk.NW, image=self.canvas_image)
        self.canvas.bind("<Button-1>", self.on_canvas_click)

        self.rg_data.clear(), self.current_box.clear()

## `` ultralytics.solutions.parking_management.ParkingManagement

    ParkingManagement(**kwargs: Any)

Bases: `BaseSolution`

Manages parking occupancy and availability using YOLO model for real-time monitoring and visualization.

This class extends BaseSolution to provide functionality for parking lot management, including detection of occupied spaces, visualization of parking regions, and display of occupancy statistics.

Attributes:

Name | Type | Description
--- | --- | ---
`json_file` | `str` | Path to the JSON file containing parking region details.
`json` | `list[dict]` | Loaded JSON data containing parking region information.
`pr_info` | `dict[str, int]` | Dictionary storing parking information (Occupancy and Available spaces).
`arc` | `tuple[int, int, int]` | RGB color tuple for available region visualization.
`occ` | `tuple[int, int, int]` | RGB color tuple for occupied region visualization.
`dc` | `tuple[int, int, int]` | RGB color tuple for centroid visualization of detected objects.

Methods:

Name | Description
--- | ---
`process` | Process the input image for parking lot management and visualization.

Examples:

    >>> from ultralytics.solutions import ParkingManagement
    >>> parking_manager = ParkingManagement(model="yolo11n.pt", json_file="parking_regions.json")
    >>> print(f"Occupied spaces: {parking_manager.pr_info['Occupancy']}")
    >>> print(f"Available spaces: {parking_manager.pr_info['Available']}")

Source code in `ultralytics/solutions/parking_management.py`

    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    def __init__(self, **kwargs: Any) -> None:
        """Initialize the parking management system with a YOLO model and visualization settings."""
        super().__init__(**kwargs)

        self.json_file = self.CFG["json_file"]  # Load parking regions JSON data
        if self.json_file is None:
            LOGGER.warning("json_file argument missing. Parking region details required.")
            raise ValueError("❌ Json file path can not be empty")

        with open(self.json_file) as f:
            self.json = json.load(f)

        self.pr_info = {"Occupancy": 0, "Available": 0}  # Dictionary for parking information

        self.arc = (0, 0, 255)  # Available region color
        self.occ = (0, 255, 0)  # Occupied region color
        self.dc = (255, 0, 189)  # Centroid color for each box

### `` process

    process(im0: ndarray) -> SolutionResults

Process the input image for parking lot management and visualization.

This function analyzes the input image, extracts tracks, and determines the occupancy status of parking regions defined in the JSON file. It annotates the image with occupied and available parking spots, and updates the parking information.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`im0` | `ndarray` | The input inference image. | required

Returns:

Type | Description
--- | ---
`SolutionResults` | Contains processed image `plot_im`, 'filled_slots' (number of occupied parking slots), 'available_slots' (number of available parking slots), and 'total_tracks' (total number of tracked objects).

Examples:

    >>> parking_manager = ParkingManagement(json_file="parking_regions.json")
    >>> image = cv2.imread("parking_lot.jpg")
    >>> results = parking_manager.process(image)

Source code in `ultralytics/solutions/parking_management.py`

    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    def process(self, im0: np.ndarray) -> SolutionResults:
        """
        Process the input image for parking lot management and visualization.

        This function analyzes the input image, extracts tracks, and determines the occupancy status of parking
        regions defined in the JSON file. It annotates the image with occupied and available parking spots,
        and updates the parking information.

        Args:
            im0 (np.ndarray): The input inference image.

        Returns:
            (SolutionResults): Contains processed image `plot_im`, 'filled_slots' (number of occupied parking slots),
                'available_slots' (number of available parking slots), and 'total_tracks' (total number of tracked objects).

        Examples:
            >>> parking_manager = ParkingManagement(json_file="parking_regions.json")
            >>> image = cv2.imread("parking_lot.jpg")
            >>> results = parking_manager.process(image)
        """
        self.extract_tracks(im0)  # Extract tracks from im0
        es, fs = len(self.json), 0  # Empty slots, filled slots
        annotator = SolutionAnnotator(im0, self.line_width)  # Initialize annotator

        for region in self.json:
            # Convert points to a NumPy array with the correct dtype and reshape properly
            pts_array = np.array(region["points"], dtype=np.int32).reshape((-1, 1, 2))
            rg_occupied = False  # Occupied region initialization
            for box, cls in zip(self.boxes, self.clss):
                xc, yc = int((box[0] + box[2]) / 2), int((box[1] + box[3]) / 2)
                dist = cv2.pointPolygonTest(pts_array, (xc, yc), False)
                if dist >= 0:
                    # cv2.circle(im0, (xc, yc), radius=self.line_width * 4, color=self.dc, thickness=-1)
                    annotator.display_objects_labels(
                        im0, self.model.names[int(cls)], (104, 31, 17), (255, 255, 255), xc, yc, 10
                    )
                    rg_occupied = True
                    break
            fs, es = (fs + 1, es - 1) if rg_occupied else (fs, es)
            # Plot regions
            cv2.polylines(im0, [pts_array], isClosed=True, color=self.occ if rg_occupied else self.arc, thickness=2)

        self.pr_info["Occupancy"], self.pr_info["Available"] = fs, es

        annotator.display_analytics(im0, self.pr_info, (104, 31, 17), (255, 255, 255), 10)

        plot_im = annotator.result()
        self.display_output(plot_im)  # Display output with base class function

        # Return SolutionResults
        return SolutionResults(
            plot_im=plot_im,
            filled_slots=self.pr_info["Occupancy"],
            available_slots=self.pr_info["Available"],
            total_tracks=len(self.track_ids),
        )

📅 Created 1 year ago ✏️ Updated 1 year ago