从零开始学习 YOLOv8:目标检测与车牌识别实例-繁依Fanyi

1. 引言

什么是目标检测?

目标检测就像是在寻找隐藏的宝藏。想象一下,你在一个巨大的图画里,里面藏着无数的物体,而你的任务是迅速找到其中的几样,比如说,一只流浪的小猫和一辆红色的小轿车。目标检测就是让计算机“眼明手快”,准确找出这些目标,甚至告诉你“喵,那个小猫正躲在花丛里!”

YOLO(You Only Look Once)概述

在目标检测的世界里,YOLO(You Only Look Once)就像是一位“侦探界的快枪手”。它不像某些方法那样耐心地逐步扫描整个图像,而是一次性快速看完,立即给出答案。可以说,YOLO 是个效率极高的工作狂,不管是监控、自动驾驶还是人脸识别,YOLO 都能帮你迅速解决问题。

YOLOv8 的发展背景

YOLOv8 是 YOLO 系列的最新版本,它在速度、精度和易用性上都有了显著提升。就像电影系列的续集一样,YOLOv8 带来了更多惊喜和更酷的特效。它不仅能处理常规的目标检测任务,还能扩展到实例分割和关键点检测,仿佛是变身为超级英雄,能够应对各种挑战。

请添加图片描述


2. YOLOv8 基础知识

YOLOv8 的架构

YOLOv8 的结构可谓是“全能选手”,主要分为三个部分:主干网络、颈部网络和头部网络。

  • 主干网络:就像是一位“特征猎人”,负责从图像中提取出各种特征。它通常使用深度卷积神经网络(CNN),能够识别出不同的物体特征。

  • 颈部网络:此部分负责将不同尺度的特征进行融合,简直就是“信息调解者”,把各方的意见汇总成最准确的结论。

  • 头部网络:最后,头部网络会输出每个物体的边界框和类别概率,完成目标的检测。它就像是一位“决策者”,告诉你每个目标在哪里,以及它是谁。

这种模块化的设计让 YOLOv8 能够灵活应对各种任务,无论是要找出一个小猫,还是识别一辆车牌。

YOLOv8 的优势

  • 速度快:YOLOv8 的速度如同子弹般迅速,几乎可以实时处理视频流,特别适合自动驾驶这样的高强度应用。

  • 精度高:在复杂的环境下,YOLOv8 的准确率也非常出色,能够准确地找到你要的目标,就像侦探们精准无误地抓住了犯罪嫌疑人。

  • 易用性:YOLOv8 提供了简单易用的 API,让你轻松上手,仿佛是在和一位友好的导师合作,指导你如何成为目标检测的高手。


请添加图片描述

最近对人工智能、计算机视觉等一类的东西很感兴趣,突发奇想想做一个停车场管理系统,从其中就需要车牌识别,于是尝试学习并尝试做一下这个yolo车牌检测识别的项目。

在构建停车场管理系统的过程中,车牌识别是核心功能之一。为了实现这一目标,选择了YOLO(You Only Look Once)作为车牌检测与识别的工具。以下将详细解读项目中的各个模块,包括 main.pyvisualize.pyadd_missing_data.pyutil.py,并逐步讲解它们的处理过程和背后的知识点。

3. 探索车牌识别、构建停车场管理系统的实践

在构建停车场管理系统的过程中,车牌识别是核心功能之一。为了实现这一目标,选择了YOLO(You Only Look Once)作为车牌检测与识别的工具。以下将详细解读项目中的各个模块,包括 main.pyvisualize.pyadd_missing_data.pyutil.py,并逐步讲解它们的处理过程和背后的知识点。

1. main.py:项目的核心入口

main.py 作为整个项目的主入口,负责整体流程的控制。该模块的核心功能包括加载YOLO模型、读取输入视频、进行图像处理以及输出检测结果。

加载模型

在项目开始时,首先导入必要的库和模块,如 OpenCV、YOLO 和自定义的工具模块。接着,使用 YOLO 模型加载函数载入预训练的模型文件。这一步骤至关重要,因为它为后续的车辆和车牌检测提供了必要的网络结构和参数。

from ultralytics import YOLO

import cv2

import util

from sort.sort import *

from util import get_car, read_license_plate, write_csv



# 初始化检测结果字典和 SORT 追踪器

results = {}

mot_tracker = Sort()



# 加载 YOLO 模型

coco_model = YOLO('yolov8n.pt')

license_plate_detector = YOLO('./models/license_plate_detector.pt')
读取视频

接下来,使用 OpenCV 读取输入视频并逐帧进行处理。每帧的处理包括检测车辆和车牌的过程。

# 加载视频

cap = cv2.VideoCapture('./sample.mp4')



# 初始化帧计数器

frame_nmr = -1

ret = True

while ret:

    frame_nmr += 1

    ret, frame = cap.read()

    if ret:

        results[frame_nmr] = {}

        ...
检测车辆

对于每帧图像,首先使用 YOLO 模型检测车辆。检测结果包含每个车辆的边界框信息及其置信度分数。通过过滤车辆类别,只保留主要关心的车辆(如轿车、SUV等)。

# 检测车辆

detections = coco_model(frame)[0]

detections_ = []

for detection in detections.boxes.data.tolist():

    x1, y1, x2, y2, score, class_id = detection

    if int(class_id) in vehicles:

        detections_.append([x1, y1, x2, y2, score])
追踪车辆

使用 SORT 算法对检测到的车辆进行追踪。每个车辆在视频中分配一个唯一的 ID,以便后续识别和关联车牌信息。

# 追踪车辆

track_ids = mot_tracker.update(np.asarray(detections_))
检测车牌

对于每帧图像,使用车牌检测模型来识别车牌。检测到的每个车牌都被分配到相应的车辆 ID,以确保每个车牌和其对应的车辆保持一致。

# 检测车牌

license_plates = license_plate_detector(frame)[0]

for license_plate in license_plates.boxes.data.tolist():

    x1, y1, x2, y2, score, class_id = license_plate



    # 将车牌分配给车辆

    xcar1, ycar1, xcar2, ycar2, car_id = get_car(license_plate, track_ids)
裁剪和处理车牌

成功分配车牌后,裁剪出车牌区域,并对其进行灰度转换和二值化处理,以便于后续的字符识别。

if car_id != -1:

    # 裁剪车牌图像

    license_plate_crop = frame[int(y1):int(y2), int(x1): int(x2), :]



    # 处理车牌图像

    license_plate_crop_gray = cv2.cvtColor(license_plate_crop, cv2.COLOR_BGR2GRAY)

    _, license_plate_crop_thresh = cv2.threshold(license_plate_crop_gray, 64, 255, cv2.THRESH_BINARY_INV)



    # 读取车牌号码

    license_plate_text, license_plate_text_score = read_license_plate(license_plate_crop_thresh)



    if license_plate_text is not None:

        results[frame_nmr][car_id] = {'car': {'bbox': [xcar1, ycar1, xcar2, ycar2]},

                                      'license_plate': {'bbox': [x1, y1, x2, y2],

                                                        'text': license_plate_text,

                                                        'bbox_score': score,

                                                        'text_score': license_plate_text_score}}
写入结果

最后,将处理后的检测结果写入 CSV 文件,以便后续的数据分析和处理。

# 写入结果

write_csv(results, './test.csv')

main.py 模块主要实现了视频中的车辆和车牌检测功能,并将结果存储为结构化数据。

好的,下面是更加详细和自然的描述,包含对 visualize.py 功能的讲解及其重要性。

2. visualize.py:结果可视化模块

visualize.py 模块的主要功能是将车牌识别的结果以可视化的形式展示在视频中。这不仅可以帮助开发者直观地理解识别系统的表现,还能用于展示最终的产品效果,增强用户体验。

导入所需库

首先需要导入一些必要的库:

  • cv2:用于图像和视频处理。
  • numpy:用于数值计算和数组操作。
  • pandas:用于数据处理和分析。
import ast

import cv2

import numpy as np

import pandas as pd
绘制边框的函数

draw_border 函数负责在图像上绘制车辆和车牌的边框。通过这种可视化,可以清晰地看到识别的区域,帮助分析模型的准确性。

def draw_border(img, top_left, bottom_right, color=(0, 255, 0), thickness=10, line_length_x=200, line_length_y=200):

    x1, y1 = top_left

    x2, y2 = bottom_right



    # 绘制左上角边框

    cv2.line(img, (x1, y1), (x1, y1 + line_length_y), color, thickness)  # 左侧

    cv2.line(img, (x1, y1), (x1 + line_length_x, y1), color, thickness)  # 上侧



    # 绘制左下角边框

    cv2.line(img, (x1, y2), (x1, y2 - line_length_y), color, thickness)  # 左侧

    cv2.line(img, (x1, y2), (x1 + line_length_x, y2), color, thickness)  # 下侧



    # 绘制右上角边框

    cv2.line(img, (x2, y1), (x2 - line_length_x, y1), color, thickness)  # 上侧

    cv2.line(img, (x2, y1), (x2, y1 + line_length_y), color, thickness)  # 右侧



    # 绘制右下角边框

    cv2.line(img, (x2, y2), (x2, y2 - line_length_y), color, thickness)  # 右侧

    cv2.line(img, (x2, y2), (x2 - line_length_x, y2), color, thickness)  # 下侧



    return img
读取识别结果数据

通过 Pandas 读取 CSV 文件中的识别结果,这些结果是模型处理视频后生成的,包括每个车牌的置信度和位置信息。

results = pd.read_csv('./test_interpolated.csv')  # 读取包含识别结果的 CSV 文件
加载视频

使用 OpenCV 加载视频文件。同时设置了输出视频的编码格式和帧率,以确保生成的视频与原视频质量一致。

# 加载视频

video_path = 'sample.mp4'

cap = cv2.VideoCapture(video_path)  # 创建视频捕获对象



# 指定视频编码和帧率

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

fps = cap.get(cv2.CAP_PROP_FPS)  # 获取原视频的帧率

width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # 获取视频宽度

height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # 获取视频高度

out = cv2.VideoWriter('./out.mp4', fourcc, fps, (width, height))  # 创建输出视频文件
初始化车牌信息字典

为每个车辆提取最大置信度的车牌信息,并存储对应的车牌图像。这样做的目的是在后续绘制过程中,能够快速访问每辆车的识别结果。

license_plate = {}

for car_id in np.unique(results['car_id']):  # 遍历所有唯一的车ID

    max_ = np.amax(results[results['car_id'] == car_id]['license_number_score'])  # 找到最大置信度

    license_plate[car_id] = {

        'license_crop': None,  # 初始化车牌裁剪图像

        'license_plate_number': results[(results['car_id'] == car_id) &

                                         (results['license_number_score'] == max_)]['license_number'].iloc[0]  # 存储车牌号

    }

    

    # 设置视频帧的位置

    cap.set(cv2.CAP_PROP_POS_FRAMES, results[(results['car_id'] == car_id) &

                                             (results['license_number_score'] == max_)]['frame_nmr'].iloc[0])

    ret, frame = cap.read()  # 读取该帧



    # 获取车牌的边界框坐标

    x1, y1, x2, y2 = ast.literal_eval(results[(results['car_id'] == car_id) &

                                              (results['license_number_score'] == max_)]['license_plate_bbox'].iloc[0].replace('[ ', '[').replace('   ', ' ').replace('  ', ' ').replace(' ', ','))



    # 裁剪车牌图像并调整大小

    license_crop = frame[int(y1):int(y2), int(x1):int(x2), :]

    license_crop = cv2.resize(license_crop, (int((x2 - x1) * 400 / (y2 - y1)), 400))  # 调整裁剪图像的大小



    license_plate[car_id]['license_crop'] = license_crop  # 保存裁剪的车牌图像
逐帧读取视频并绘制识别结果

在这一部分,逐帧读取视频,并根据识别结果在每帧上绘制车辆和车牌的边界框。通过这种方式,用户可以直观地看到模型的识别效果,并评估其准确性和可靠性。

frame_nmr = -1  # 帧计数器

cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # 重置视频到开头



# 读取帧

ret = True

while ret:

    ret, frame = cap.read()  # 读取一帧

    frame_nmr += 1  # 增加帧计数

    if ret:

        df_ = results[results['frame_nmr'] == frame_nmr]  # 获取当前帧的结果

        for row_indx in range(len(df_)):

            # 绘制车辆边界框

            car_x1, car_y1, car_x2, car_y2 = ast.literal_eval(df_.iloc[row_indx]['car_bbox'].replace('[ ', '[').replace('   ', ' ').replace('  ', ' ').replace(' ', ','))

            draw_border(frame, (int(car_x1), int(car_y1)), (int(car_x2), int(car_y2)), (0, 255, 0), 25,

                        line_length_x=200, line_length_y=200)



            # 绘制车牌边界框

            x1, y1, x2, y2 = ast.literal_eval(df_.iloc[row_indx]['license_plate_bbox'].replace('[ ', '[').replace('   ', ' ').replace('  ', ' ').replace(' ', ','))

            cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 12)  # 绘制车牌的矩形框



            # 获取并显示车牌裁剪图像

            license_crop = license_plate[df_.iloc[row_indx]['car_id']]['license_crop']  # 获取车牌裁剪图像

            H, W, _ = license_crop.shape  # 获取车牌裁剪图像的高度和宽度



            try:

                # 在车辆上方插入车牌图像

                frame[int(car_y1) - H - 100:int(car_y1) - 100,

                      int((car_x2 + car_x1 - W) / 2):int((car_x2 + car_x1 + W) / 2), :] = license_crop



                # 在车牌上方添加白色背景

                frame[int(car_y1) - H - 400:int(car_y1) - H - 100,

                      int((car_x2 + car_x1 - W) / 2):int((car_x2 + car_x1 + W) / 2), :] = (255, 255, 255)



                # 获取文本的尺寸

                (text_width, text_height), _ = cv2.getTextSize(

                    license_plate[df_.iloc[row_indx]['car_id']]['license_plate_number'],

                    cv2.FONT_HERSHEY_SIMPLEX,

                    4.3,

                    17)



                # 在帧中绘制车牌号码

                cv2.putText(frame,

                            license_plate[df_.iloc[row_indx]['car_id']]['license_plate_number'],





                            (int((car_x2 + car_x1 - text_width) / 2), int(car_y1 - H - 250 + (text_height / 2))),

                            cv2.FONT_HERSHEY_SIMPLEX,

                            4.3,

                            (0, 0, 0),

                            17)



            except:

                pass  # 忽略可能出现的错误



        out.write(frame)  # 将处理后的帧写入输出视频

        frame = cv2.resize(frame, (1280, 720))  # 调整输出帧的尺寸



out.release()  # 释放视频写入对象

cap.release()  # 释放视频捕获对象

好的,我会将 util.py 的内容进行详细描述,并在代码中加入中文注释,便于理解。以下是修改后的内容:

3. add_missing_data.py:处理缺失数据

在构建车牌识别系统时,确保数据的完整性和质量至关重要。add_missing_data.py 模块专注于处理数据中的缺失部分,以保证数据集的连贯性和准确性。为此,采用插值填补的方法,以填补在数据收集中可能遗漏的车牌检测结果。

在实际应用中,数据常常不完整,尤其是在视频监控场景中,某些帧可能缺失了车牌的检测结果。为了保证后续分析和处理的准确性,要对这些缺失数据进行补充。插值填补的方法通过已有数据推测缺失值,维持数据的连续性。

具体实现中,首先从输入的CSV文件中读取车牌检测的数据,提取帧编号、车辆ID及其对应的边界框。利用 numpy 数组,来快速处理和过滤这些数据。针对每个车辆ID,筛选出该车辆在不同帧中的检测结果,检查连续帧之间是否存在缺失。当发现某一帧与上一帧之间存在间隔时,利用插值方法填补缺失的边界框。

导入所需库
import csv

import numpy as np

from scipy.interpolate import interp1d
**提取必要列**

首先提取输入数据中的帧编号、车辆ID和边界框。

def interpolate_bounding_boxes(data):

    frame_numbers = np.array([int(row['frame_nmr']) for row in data])

    car_ids = np.array([int(float(row['car_id'])) for row in data])

    car_bboxes = np.array([list(map(float, row['car_bbox'][1:-1].split())) for row in data])

    license_plate_bboxes = np.array([list(map(float, row['license_plate_bbox'][1:-1].split())) for row in data])
**处理每个车辆ID**

接着,对每个唯一的车辆ID进行处理,筛选该车辆在不同帧中的检测结果,并检测是否存在缺失。

    interpolated_data = []

    unique_car_ids = np.unique(car_ids)



    for car_id in unique_car_ids:

        frame_numbers_ = [p['frame_nmr'] for p in data if int(float(p['car_id'])) == int(float(car_id))]

        car_mask = car_ids == car_id

        car_frame_numbers = frame_numbers[car_mask]

        car_bboxes_interpolated = []

        license_plate_bboxes_interpolated = []
**插值填补**

当检测到某一帧与上一帧之间存在间隔时,使用插值方法填补缺失的边界框。

        for i in range(len(car_bboxes[car_mask])):

            frame_number = car_frame_numbers[i]

            car_bbox = car_bboxes[car_mask][i]

            license_plate_bbox = license_plate_bboxes[car_mask][i]



            if i > 0:

                prev_frame_number = car_frame_numbers[i - 1]

                prev_car_bbox = car_bboxes_interpolated[-1]

                prev_license_plate_bbox = license_plate_bboxes_interpolated[-1]



                if frame_number - prev_frame_number > 1:

                    frames_gap = frame_number - prev_frame_number

                    x = np.array([prev_frame_number, frame_number])

                    x_new = np.linspace(prev_frame_number, frame_number, num=frames_gap, endpoint=False)



                    interp_func = interp1d(x, np.vstack((prev_car_bbox, car_bbox)), axis=0, kind='linear')

                    interpolated_car_bboxes = interp_func(x_new)

                    interp_func = interp1d(x, np.vstack((prev_license_plate_bbox, license_plate_bbox)), axis=0, kind='linear')

                    interpolated_license_plate_bboxes = interp_func(x_new)



                    car_bboxes_interpolated.extend(interpolated_car_bboxes[1:])

                    license_plate_bboxes_interpolated.extend(interpolated_license_plate_bboxes[1:])
**构建输出数据**

最后,将插值后的数据构建成新的记录,并准备写入CSV文件。

            car_bboxes_interpolated.append(car_bbox)

            license_plate_bboxes_interpolated.append(license_plate_bbox)



        for i in range(len(car_bboxes_interpolated)):

            frame_number = first_frame_number + i

            row = {

                'frame_nmr': str(frame_number),

                'car_id': str(car_id),

                'car_bbox': ' '.join(map(str, car_bboxes_interpolated[i])),

                'license_plate_bbox': ' '.join(map(str, license_plate_bboxes_interpolated[i])),

                'license_plate_bbox_score': '0',

                'license_number': '0',

                'license_number_score': '0'

            }



            if str(frame_number) in frame_numbers_:

                original_row = [p for p in data if int(p['frame_nmr']) == frame_number and int(float(p['car_id'])) == int(float(car_id))][0]

                row['license_plate_bbox_score'] = original_row.get('license_plate_bbox_score', '0')

                row['license_number'] = original_row.get('license_number', '0')

                row['license_number_score'] = original_row.get('license_number_score', '0')



            interpolated_data.append(row)



    return interpolated_data
**从CSV文件加载数据并写入更新后的数据**:
with open('test.csv', 'r') as file:

    reader = csv.DictReader(file)

    data = list(reader)



interpolated_data = interpolate_bounding_boxes(data)



header = ['frame_nmr', 'car_id', 'car_bbox', 'license_plate_bbox', 'license_plate_bbox_score', 'license_number', 'license_number_score']

with open('test_interpolated.csv', 'w', newline='') as file:

    writer = csv.DictWriter(file, fieldnames=header)

    writer.writeheader()

    writer.writerows(interpolated_data)

这种处理方式确保即使在没有检测到车牌的帧中,也能提供合理的边界框数据,从而提升数据集的完整性和准确性。填补完成后,将补充的数据输出到一个新的CSV文件中,确保数据集的完整性。这样做的意义在于,系统能够在处理过程中自动适应和修复数据的缺失,减少人为干预,提升了自动化处理的效率。

4. util.py:实用工具函数模块

util.py 模块包含了一些辅助函数,这些函数为整个车牌识别系统的其他模块提供支持,包括模型的加载、车牌的读取和格式化等功能。

OCR读取器初始化

首先,使用 easyocr 库初始化了一个OCR读取器,它支持英文字符的识别。以下是代码:

import string

import easyocr



# 初始化OCR读取器,指定语言为英语,未启用GPU

reader = easyocr.Reader(['en'], gpu=False)
字符映射字典

这里定义了两个字典,用于在车牌识别过程中进行字符与数字之间的转换。

# 字符到数字的映射

dict_char_to_int = {

    'O': '0',

    'I': '1',

    'J': '3',

    'A': '4',

    'G': '6',

    'S': '5'

}



# 数字到字符的映射

dict_int_to_char = {

    '0': 'O',

    '1': 'I',

    '3': 'J',

    '4': 'A',

    '6': 'G',

    '5': 'S'

}
写入CSV文件的函数

write_csv 函数用于将识别结果写入CSV文件。它接受两个参数:结果字典和输出文件路径。

def write_csv(results, output_path):

    """

    将结果写入CSV文件。



    参数:

        results (dict): 包含结果的字典。

        output_path (str): 输出CSV文件的路径。

    """

    with open(output_path, 'w') as f:

        # 写入CSV文件的表头

        f.write('{},{},{},{},{},{},{}n'.format(

            'frame_nmr', 'car_id', 'car_bbox',

            'license_plate_bbox', 'license_plate_bbox_score', 'license_number',

            'license_number_score'

        ))



        # 遍历结果字典并写入每一行

        for frame_nmr in results.keys():

            for car_id in results[frame_nmr].keys():

                print(results[frame_nmr][car_id])  # 打印当前车辆的信息

                if 'car' in results[frame_nmr][car_id].keys() and 

                   'license_plate' in results[frame_nmr][car_id].keys() and 

                   'text' in results[frame_nmr][car_id]['license_plate'].keys():

                    # 写入车牌识别结果到CSV文件

                    f.write('{},{},{},{},{},{},{}n'.format(

                        frame_nmr,

                        car_id,

                        '[{} {} {} {}]'.format(

                            results[frame_nmr][car_id]['car']['bbox'][0],

                            results[frame_nmr][car_id]['car']['bbox'][1],

                            results[frame_nmr][car_id]['car']['bbox'][2],

                            results[frame_nmr][car_id]['car']['bbox'][3]

                        ),

                        '[{} {} {} {}]'.format(

                            results[frame_nmr][car_id]['license_plate']['bbox'][0],

                            results[frame_nmr][car_id]['license_plate']['bbox'][1],

                            results[frame_nmr][car_id]['license_plate']['bbox'][2],

                            results[frame_nmr][car_id]['license_plate']['bbox'][3]

                        ),

                        results[frame_nmr][car_id]['license_plate']['bbox_score'],

                        results[frame_nmr][car_id]['license_plate']['text'],

                        results[frame_nmr][car_id]['license_plate']['text_score']

                    ))

        f.close()  # 关闭文件
检查车牌格式的函数

license_complies_format 函数用于检查车牌文本是否符合规定的格式。该格式要求车牌文本长度为7个字符,并且每个字符的位置都有特定的要求。

def license_complies_format(text):

    """

    检查车牌文本是否符合规定格式。



    参数:

        text (str): 车牌文本。



    返回:

        bool: 如果符合格式返回True,否则返回False。

    """

    if len(text) != 7:

        return False



    # 检查每个字符是否符合要求

    if (text[0] in string.ascii_uppercase or text[0] in dict_int_to_char.keys()) and 

       (text[1] in string.ascii_uppercase or text[1] in dict_int_to_char.keys()) and 

       (text[2] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] or text[2] in dict_char_to_int.keys()) and 

       (text[3] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] or text[3] in dict_char_to_int.keys()) and 

       (text[4] in string.ascii_uppercase or text[4] in dict_int_to_char.keys()) and 

       (text[5] in string.ascii_uppercase or text[5] in dict_int_to_char.keys()) and 

       (text[6] in string.ascii_uppercase or text[6] in dict_int_to_char.keys()):

        return True

    else:

        return False
格式化车牌的函数

format_license 函数用于将车牌文本格式化,使用预定义的映射字典转换字符。

def format_license(text):

    """

    通过使用映射字典格式化车牌文本。



    参数:

        text (str): 车牌文本。



    返回:

        str: 格式化后的车牌文本。

    """

    license_plate_ = ''

    mapping = {

        0: dict_int_to_char,

        1: dict_int_to_char,

        4: dict_int_to_char,

        5: dict_int_to_char,

        6: dict_int_to_char,

        2: dict_char_to_int,

        3: dict_char_to_int

    }

    for j in [0, 1, 2, 3, 4, 5, 6]:

        if text[j] in mapping[j].keys():

            license_plate_ += mapping[j][text[j]]  # 根据映射字典转换字符

        else:

            license_plate_ += text[j]  # 如果字符不在字典中,直接添加



    return license_plate_
读取车牌文本的函数

read_license_plate 函数从给定的裁剪图像中读取车牌文本,并返回格式化后的文本及其置信度分数。

def read_license_plate(license_plate_crop):

    """

    从给定的裁剪图像中读取车牌文本。



    参数:

        license_plate_crop (PIL.Image.Image): 裁剪后的车牌图像。



    返回:

        tuple: 包含格式化车牌文本和置信度分数的元组。

    """

    detections = reader.readtext(license_plate_crop)  # 使用OCR读取文本



    for detection in detections:

        bbox, text, score = detection  # 解包检测结果



        text = text.upper().replace(' ', '')  # 将文本转换为大写并去除空格



        if license_complies_format(text):  # 检查格式是否符合

            return format_license(text), score  # 返回格式化后的文本和分数



    return None, None  # 如果没有符合的文本,返回None
获取车辆坐标的函数

get_car 函数根据车牌坐标和车辆的追踪ID,返回车辆的坐标和ID。

def get_car(license_plate, vehicle_track_ids):

    """

    根据车牌坐标和车辆追踪ID获取车辆坐标和ID。



    参数:

        license_plate (tuple): 包含车牌坐标 (x1, y1, x2, y2, score, class_id) 的元组。

        vehicle_track_ids (list): 车辆追踪ID及其对应坐标的列表。



    返回:

        tuple: 包含车辆坐标 (x1, y1, x2, y2) 和ID的元组。

    """

    x1, y1, x2, y2, score, class_id = license_plate



    foundIt = False

    for j in range(len(vehicle_track_ids)):

        xcar1, ycar1, xcar2, ycar2, car_id = vehicle_track_ids[j]



        # 检查车牌坐标是否在车辆坐标内

        if x1 > xcar1 and y1 > ycar1 and x2 < xcar2 and y2 < ycar2:

            car_indx = j

            foundIt = True

            break



    if foundIt:

        return vehicle_track_ids[car_indx]  # 返回找到的车辆坐标和ID



    return -1, -1, -1, -1, -1  # 如果没有找到,返回负值

这部分实现了车牌的读取、格式化及输出,确保车牌识别的准确性和结果的有效管理。

至此,代码结束,理解并实现车辆车牌识别代码对我这样的小白还是有些困难,还需多实践,多学习 yolov8 的相关项目及知识,加油加油!

© 版权声明
THE END
喜欢就支持一下吧
点赞179 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容