基于YOLOv8的目标检测系统

源码已上传github,需要请自取

https://github.com/0101110AC/My-project/tree/main/yolo%20v8%20object%20detection%20system

一、简介

本文将详细介绍一个基于YOLOv8的目标检测系统。该系统使用Python编写,结合了OpenCV、PyTorch、Tkinter等多个库,实现了实时目标检测、结果保存、历史记录查询、自定义识别类别(提供框架)以及数据统计分析等功能。

二、功能

1. 实时目标检测:使用摄像头进行实时视频流的目标检测。

2. 结果保存:保存检测结果的截图和元数据。

3. 历史记录查询:查看之前保存的检测记录。

4. 自定义识别类别:允许用户上传样本数据并训练自定义模型。(需自行添加训练代码,这里只提供框架以供后续拓展使用)

5. 数据统计分析:统计不同物体类别的出现频率并展示柱状图。

三、 环境依赖

- Python 3.x(3.11)

- OpenCV (`cv2`)

- PyTorch (`torch`)

- Tkinter (`tkinter`)

- Ultralytics YOLO (`ultralytics`)

- Pandas (`pandas`)

- Matplotlib (`matplotlib`)

四、代码结构

简略

  • 模块导入:导入所需的所有模块。
  • 配置和日志:设置配置参数和日志记录。
  • ObjectDetector类:实现目标检测的核心功能。
  • ObjectDetectorApp类:实现GUI和应用逻辑。
  • 主程序:运行应用的主事件循环。

4.1 初始化配置

  • 导入模块:代码导入了多个Python模块,包括OpenCV(cv2)、PyTorch(torch)、JSON处理、文件操作、GUI创建(tkinter)、多线程(threading)、YOLO模型(ultralytics)、日志记录(logging)、数据处理(pandas)和绘图(matplotlib)。
  • 设置中文字体:通过plt.rcParams设置Matplotlib使用中文字体,解决中文显示问题。
  • 日志记录:使用logging模块记录日志信息,方便调试和跟踪。
  • 配置参数:在CONFIG字典中定义了一些配置参数,如保存目录、模型路径、置信度阈值和摄像头索引。
CONFIG = {

    "save_dir": "detection_results",

    "model": "yolov8n.pt",  # 预训练模型

    "confidence_threshold": 0.5,

    "camera_index": 0  # 通常前置摄像头为0

}

4.2 ObjectDetector类

  • 初始化:创建保存目录,加载YOLO模型,获取类别名称,并初始化摄像头。
  • 初始化摄像头:使用OpenCV打开摄像头,并设置帧宽高。
  • 处理帧:对每一帧执行目标检测,返回包含检测结果的DataFrame。只保留置信度高于阈值的检测结果,并添加类别名称。
  • 保存结果:保存检测帧和检测结果为文件,包括图像文件和JSON格式的元数据。
  • 运行循环:主运行循环,持续从摄像头读取帧,执行目标检测,绘制检测框,并显示画面。支持键盘控制保存结果和退出程序。
4.2.1 初始化方法 __init__
  • 创建保存目录:检查并创建保存检测结果的目录。
  • 加载YOLO模型:使用ultralytics库加载YOLOv8模型。
  • 获取类别名称:从模型中获取所有类别名称。
  • 初始化摄像头:调用init_camera方法初始化摄像头。
class ObjectDetector:

    def __init__(self):

        self.save_path = Path(CONFIG["save_dir"])

        self.save_path.mkdir(exist_ok=True)

        

        try:

            self.model = YOLO(CONFIG["model"]).to('cpu')

            logging.info("模型加载成功")

        except Exception as e:

            logging.error(f"模型加载失败: {e}")

            raise

        

        self.class_names = self.model.names

        self.initialize_camera()
4.2.2 初始化摄像头方法 init_camera
  • 打开摄像头:使用OpenCV打开指定索引的摄像头。
  • 设置帧宽高:设置摄像头的帧宽高。
def initialize_camera(self):

    try:

        self.cap = cv2.VideoCapture(CONFIG["camera_index"])

        if not self.cap.isOpened():

            raise Exception("无法打开摄像头")

        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)

        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

        logging.info("摄像头初始化成功")

    except Exception as e:

        logging.error(f"摄像头初始化失败: {e}")

        raise
4.2.3 处理帧方法 process_frame
  • 目标检测:对输入帧执行目标检测,返回包含检测结果的DataFrame。
  • 过滤结果:只保留置信度高于阈值的检测结果,并添加类别名称。
def process_frame(self, frame):

    try:

        results = self.model(frame)

        if not results or not results[0].boxes:

            logging.error("检测结果为空")

            return pd.DataFrame()

        

        boxes = results[0].boxes

        data = boxes.data.cpu().numpy()

        df = pd.DataFrame(data, columns=['xmin', 'ymin', 'xmax', 'ymax', 'confidence', 'class'])

        if 'confidence' not in df.columns:

            logging.error(f"DataFrame列名错误: {df.columns}")

            return pd.DataFrame()

        

        df['name'] = df['class'].map(self.class_names)

        

        return df[df['confidence'] > CONFIG["confidence_threshold"]]

    except Exception as e:

        logging.error(f"处理帧时出错: {e}")

        return pd.DataFrame()
4.2.4 保存结果方法 save_result
  • 保存检测帧:将检测帧保存为图像文件。
  • 保存检测结果:将检测结果保存为JSON格式的元数据文件。
def save_results(self, frame, detections):

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S%f")

    

    img_path = self.save_path / f"{timestamp}.png"

    cv2.imwrite(str(img_path), frame)

    

    meta = {

        "timestamp": timestamp,

        "detections": detections.to_dict(orient='records')

    }

    with open(self.save_path / f"{timestamp}.json", 'w') as f:

        json.dump(meta, f)
4.2.5 运行循环方法 run_loop
  • 读取帧:从摄像头读取帧。
  • 执行目标检测:调用process_frame方法处理帧。
  • 绘制检测框:在帧上绘制检测框和类别标签。
  • 显示画面:使用OpenCV显示处理后的帧。
  • 键盘控制:通过键盘事件控制保存结果和退出程序。
def run(self, running_flag):

    while running_flag.is_set():

        ret, frame = self.cap.read()

        if not ret:

            logging.error("无法获取帧")

            break



        detections = self.process_frame(frame)

        valid_detections = detections[detections['confidence'] > CONFIG["confidence_threshold"]]



        for _, row in valid_detections.iterrows():

            x1, y1, x2, y2 = map(int, row[['xmin', 'ymin', 'xmax', 'ymax']])

            label = f"{row['name']} {row['confidence']:.2f}"

            

            cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)

            cv2.putText(frame, label, (x1, y1-10),

                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)



        cv2.imshow('Real-time Detection', frame)



        key = cv2.waitKey(1)

        if key == ord('s'):  # 按s保存

            self.save_results(frame, detections)

            logging.info("结果已保存")

        elif key == ord('q'):  # 按q退出

            break



    self.cap.release()

    cv2.destroyAllWindows()

4.3 ObjectDetectorApp类

  • 初始化:创建ObjectDetector实例和线程事件标志,用于控制检测线程。
  • 创建主界面:使用tkinter创建GUI主界面,包括开始识别、停止识别、保存结果、历史记录查询、自定义识别类别和数据统计分析等按钮。
  • 开始识别:启动检测线程,初始化摄像头,并设置按钮状态。
  • 停止识别:停止检测线程,释放摄像头资源,并设置按钮状态。
  • 保存结果:保存当前帧和检测结果,弹出保存成功提示。
  • 历史记录查询:创建新窗口显示历史记录,加载并显示所有检测结果。
  • 自定义识别类别:创建新窗口,允许用户输入类别名称和上传样本数据,并提供训练模型的按钮。
  • 数据统计分析:创建新窗口显示统计分析结果,加载历史数据,统计不同物体类别的出现频率,并绘制柱状图。
4.3.1 初始化方法 __init__
  • 创建ObjectDetector实例:实例化ObjectDetector,用于执行目标检测。
  • 创建线程事件标志:创建一个线程事件标志,用于控制检测线程的启动和停止。
class ObjectDetectorApp:

    def __init__(self, root):

        self.root = root

        self.detector = ObjectDetector()

        self.running_flag = threading.Event()



        self.create_main_interface()

4.3.2 创建主界面 create_main_interface
  • 创建主界面:使用tkinter创建GUI主界面,包括各种按钮和标签。
def create_main_interface(self):

    self.root.title("YOLOv5 Object Detection")

    self.root.geometry("800x600")



    custom_font = tk_font.Font(family="SimHei", size=12)



    self.start_button = tk.Button(self.root, text="开始识别", command=self.start_detection, font=custom_font)

    self.start_button.pack(pady=10)



    self.stop_button = tk.Button(self.root, text="停止识别", command=self.stop_detection, state=tk.DISABLED, font=custom_font)

    self.stop_button.pack(pady=10)



    self.save_button = tk.Button(self.root, text="保存结果", command=self.save_results, font=custom_font)

    self.save_button.pack(pady=10)



    self.history_button = tk.Button(self.root, text="历史记录查询", command=self.show_history, font=custom_font)

    self.history_button.pack(pady=10)



    self.customize_button = tk.Button(self.root, text="自定义识别类别", command=self.customize_categories, font=custom_font)

    self.customize_button.pack(pady=10)



    self.stats_button = tk.Button(self.root, text="数据统计分析", command=self.show_stats, font=custom_font)

    self.stats_button.pack(pady=10)

4.3.3 开始识别方法 start_recognition
  • 启动检测线程:启动一个新的线程运行run_loop方法。
  • 初始化摄像头:调用init_camera方法初始化摄像头。
  • 设置按钮状态:禁用开始识别按钮,启用停止识别按钮。

def start_detection(self):

    if not self.running_flag.is_set():

        self.running_flag.set()

        self.start_button.config(state=tk.DISABLED)

        self.stop_button.config(state=tk.NORMAL)

        self.detector.initialize_camera()

        self.detection_thread = threading.Thread(target=self.detector.run, args=(self.running_flag,))

        self.detection_thread.start()

4.3.4 停止识别方法 stop_recognition
  • 停止检测线程:设置线程事件标志为False,停止检测线程。
  • 释放摄像头资源:调用release_camera方法释放摄像头资源。
  • 设置按钮状态:启用开始识别按钮,禁用停止识别按钮。
def stop_detection(self):

    if self.running_flag.is_set():

        self.running_flag.clear()

        self.start_button.config(state=tk.NORMAL)

        self.stop_button.config(state=tk.DISABLED)

        if hasattr(self, 'detection_thread'):

            self.detection_thread.join()

        self.detector.cap.release()

        cv2.destroyAllWindows()

        logging.info("检测已停止并释放资源")

4.3.5 保存结果方法 save_result
  • 保存当前帧和检测结果:调用save_result方法保存当前帧和检测结果。
  • 弹出提示:使用tkinter弹出保存成功的提示。
def save_results(self):

    if self.detector.cap.isOpened():

        ret, frame = self.detector.cap.read()

        if ret:

            detections = self.detector.process_frame(frame)

            self.detector.save_results(frame, detections)

            messagebox.showinfo("保存成功", "结果已保存")

    else:

        messagebox.showwarning("警告", "摄像头未打开")

4.3.6 历史记录查询方法 query_history
  • 创建新窗口:创建一个新的tkinter窗口显示历史记录。
  • 加载历史记录:从保存的JSON文件中加载所有历史记录。
  • 显示历史记录:在新窗口中显示历史记录。
def show_history(self):

    history_window = tk.Toplevel(self.root)

    history_window.title("历史记录查询")

    history_window.geometry("800x600")



    history_files = list(self.detector.save_path.glob("*.json"))

    history_data = []

    for file in history_files:

        with open(file, 'r') as f:

            data = json.load(f)

            history_data.append(data)



    tree = ttk.Treeview(history_window, columns=("Timestamp", "Detections"), show='headings')

    tree.heading("Timestamp", text="时间戳")

    tree.heading("Detections", text="检测结果")

    tree.pack(fill=tk.BOTH, expand=True)



    for data in history_data:

        timestamp = data["timestamp"]

        detections = ", ".join([f"{d['name']} ({d['confidence']:.2f})" for d in data["detections"]])

        tree.insert("", "end", values=(timestamp, detections))
4.3.7 自定义识别类别方法 custom_categories
  • 创建新窗口:创建一个新的tkinter窗口允许用户输入类别名称和上传样本数据。
  • 训练模型:提供训练模型的按钮,调用相应的训练方法。

(需自行添加训练代码,这里只提供框架)

def customize_categories(self):

    customize_window = tk.Toplevel(self.root)

    customize_window.title("自定义识别类别")

    customize_window.geometry("400x300")

    tk.Label(customize_window, text="类别名称:").pack(pady=5)

    self.category_entry = tk.Entry(customize_window)

    self.category_entry.pack(pady=5)

    tk.Label(customize_window, text="上传样本数据:").pack(pady=5)

    self.sample_button = tk.Button(customize_window, text="选择文件", command=self.select_sample)

    self.sample_button.pack(pady=5)

    self.train_button = tk.Button(customize_window, text="训练模型", command=self.train_model)

    self.train_button.pack(pady=10)

(1 ) 选择样本数据

def select_sample(self):

    self.sample_path = filedialog.askopenfilename()

    if self.sample_path:

        messagebox.showinfo("文件选择", f"已选择文件: {self.sample_path}")

(2 )训练模型

def train_model(self):

    if hasattr(self, 'sample_path'):

        messagebox.showinfo("训练模型", "开始训练模型...")

        # 这里可以添加训练模型的代码

    else:

        messagebox.showwarning("警告", "请先选择样本数据文件")

4.3.8 数据统计分析方法 statistic_analysis
  • 创建新窗口:创建一个新的tkinter窗口显示统计分析结果。
  • 加载历史数据:从保存的JSON文件中加载所有历史数据。
  • 统计频率:统计不同类别物体的出现频率。
  • 绘制柱状图:使用Matplotlib绘制柱状图显示统计结果。
def show_stats(self):

    stats_window = tk.Toplevel(self.root)

    stats_window.title("数据统计分析")

    stats_window.geometry("800x600")



    history_files = list(self.detector.save_path.glob("*.json"))

    history_data = []

    for file in history_files:

        with open(file, 'r') as f:

            data = json.load(f)

            history_data.extend(data["detections"])



    if not history_data:

        messagebox.showinfo("数据统计分析", "没有历史数据")

        return



    df = pd.DataFrame(history_data)

    if 'name' not in df.columns:

        logging.error(f"DataFrame列名错误: {df.columns}")

        messagebox.showinfo("数据统计分析", "数据列名错误")

        return



    category_counts = df['name'].value_counts()



    fig, ax = plt.subplots()

    category_counts.plot(kind='bar', ax=ax)

    ax.set_title('物体类别出现频率')

    ax.set_xlabel('类别')

    ax.set_ylabel('频率')



    canvas = FigureCanvasTkAgg(fig, master=stats_window)

    canvas.draw()

    canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

4.4 主程序

  • 创建tkinter主窗口:实例化tkinter主窗口。
  • 实例化ObjectDetectorApp:创建ObjectDetectorApp实例。
  • 运行主事件循环:启动tkinter主事件循环,捕获并处理异常。

五、 总结

本文详细介绍了基于YOLOv8的目标检测系统,包括其功能、环境依赖、代码结构和运行方法。本系统不仅实现了实时目标检测,还提供了丰富的附加功能,如结果保存、历史记录查询、自定义识别类别(仅提供框架)和数据统计分析,适用于多种应用场景。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值