Search code examples
pythonpycharmpyinstallerexeyolov8

YOLOv8 Default.yaml error for making exe with pyinstaller --onefile


Hello hoodies I have trained a model for yolov8.

I want to use this in python exe.

Here is my code below:

try:
    import time
    import cv2
    import mss
    import numpy as np
    from ultralytics import YOLO
    import math
    import os
    import sys

    def screen_capture():
        with mss.mss() as sct:
            monitor = sct.monitors[2]
            sct_img = sct.grab(monitor)
            frame = np.array(sct_img)
            frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR)
            return frame

    def detect_realtime(model):
        while True:
            frame = screen_capture()
            results = model(frame,device="cpu")

            highest_conf = 0
            best_box = None

            for r in results:
                boxes = r.boxes
                for box in boxes:
                    conf = box.conf[0]
                    if conf > highest_conf:
                        highest_conf = conf
                        best_box = box
            if best_box:
                x1, y1, x2, y2 = best_box.xyxy[0]
                x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
                cls_id = int(best_box.cls[0])
                conf = math.ceil(highest_conf * 100) / 100

                cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
                cv2.putText(frame, f'{model.names[cls_id]} {conf:.2f}', (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
                print([(x1+x2)//2, (y1+y2)//2])

            resized_frame = cv2.resize(frame, (1366, 768))
            cv2.imshow('YOLO Realtime Detection', resized_frame)
            cv2.moveWindow('YOLO Realtime Detection', 2000, 100)

            if cv2.waitKey(500) == ord('q'):
                break

        cv2.destroyAllWindows()

    if __name__ == '__main__':

            base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
            print(base_path)
            anvil_model= os.path.join(base_path,'best.pt')
            model = YOLO(anvil_model) 
            detect_realtime(model)
except Exception as e:
    time.sleep(5555)

After, i make an exe with this command:

pyinstaller --onefile --add-data "best.pt;." main.py

Console wrote this error: [Errno 2] No such file or directory: 'C:\Users\User\AppData\Local\Temp\_MEI119602\ultralytics\cfg\default.yaml'

I have searched the YOLOv8 issues, I fount two issues below but there is not solution.

https://github.com/ultralytics/ultralytics/issues/7143

https://github.com/ultralytics/ultralytics/issues/1158

--onedir is not solution for me. I need one exe this can workable other pc's.

What sould I need do?


Solution

  • When packaging Python applications into a standalone executable (e.g., using PyInstaller), it's important to correctly determine the base path where the application's resources are located. This is crucial for accessing files bundled with the executable. There are different approaches to find this path, and understanding their differences can help in selecting the right method for your application.

    First Approach Using _MEIPASS and file:

    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    

    In this approach, getattr(sys, '_MEIPASS', ...) tries to get the attribute _MEIPASS from the sys module. _MEIPASS is a special attribute set by PyInstaller at runtime when the application is frozen (i.e., compiled as an executable). It points to a temporary folder where PyInstaller unpacks your bundled resources.

    If _MEIPASS is not present (which is the case when running the script in an IDE or normally via Python interpreter), os.path.dirname(os.path.abspath(file)) is used. This gives the directory where the Python script is located.

    if getattr(sys, 'frozen', False):
        application_path = sys._MEIPASS
    else:
        application_path = os.path.dirname(os.path.abspath(__file__))
    

    This approach uses an explicit check for the 'frozen' state of the application. getattr(sys, 'frozen', False) checks if the attribute frozen exists in the sys module and returns its value, or False if it doesn't exist. When a Python application is compiled into an executable, PyInstaller sets sys.frozen to True.

    Based on this check, if the application is frozen, it uses sys._MEIPASS as the application path, otherwise, it falls back to the script's directory.