盘算机视觉底子——基于yolov5-face算法的车牌检测

打印 上一主题 下一主题

主题 664|帖子 664|积分 1992

车牌检测算法检测实现

1.环境部署



  • torch==1.8.1
  • torchvision==0.9.1
  1. pip install -r requirements.txt
复制代码
2.数据处置惩罚

2.1 CCPD数据集先容

2.1.1 ccpd2019及2020

CCPD数据集重要采集于安徽某停车场一段时间内的数据,
全部图片尺寸固定为720×1160(w×h),
大约包含25w+的各种场景图片,如下图所示:

类别描述图片数CCPD-Base通用车牌图片200kCCPD-FN车牌离摄像头拍摄位置相对较近或较远20kCCPD-DB车牌区域亮度较亮、较暗或者不匀称20kCCPD-Rotate车牌程度倾斜 20 到 50 度,竖直倾斜-10到 10 度10kCCPD-Tilt车牌程度倾斜 15 到 45 度,竖直倾斜 15 到 45 度10kCCPD-Weather车牌在雨雪雾天气拍摄得到10kCCPD-Challenge在车牌检测识别使命中较有挑衅性的图片10kCCPD-Blur由于摄像机镜头抖动导致的模楜车牌图片5kCCPD-NP没有安装车牌的新车图片5k 2.1.2 文件名字解析


  1. 1、01:车牌占整个界面比例;(一般没用,可忽略)
  2. 2、86_91: 车牌的水平角度和垂直角度
  3. 3、298\&341_449\&414: 车牌标注框左上角和右下角的坐标
  4. 4、458\&394_308\&410_304\&357_454\&341:车牌四个顶点的坐标,顺序为右下、左下、左上、右上
  5. 5、0_0_14_28_24_26_29: 这个代表着和省份 (第一位)、地市 (第二位)、车牌号 (剩余部分) 的映射关系
  6. 6、124: 亮度,值越大亮度越高(仅供参考)
  7. 7、24:模糊度,值越小越模糊(仅供参考)
复制代码
2.2数据集处置惩罚

2.2.1 CCPD数据处置惩罚

1.解压ccpd,cprd数据集2019,ccpd文件太大,解压慢,使用步伐举行解压
  1. import tarfile
  2. # 指定tar文件路径
  3. tar_path = r".\CCPD2019\CCPD2019.tar"
  4. # 打开tar文件
  5. with tarfile.open(tar_path, "r") as tar:
  6.     # 解压所有文件到指定目录
  7.     tar.extractall(r".\ccpd")
  8. # 解压完成
  9. print("解压完成")
复制代码
ccpd数据集处置惩罚方法
  1. import os
  2. import shutil
  3. import cv2
  4. import numpy as np
  5. from tqdm import tqdm
  6. def allFilePath(rootPath, allFIleList):
  7.     '''
  8.     获取指定目录下所有以.jpg结尾的文件的路径,并将这些路径存储在一个列表中。
  9.     '''
  10.     fileList = os.listdir(rootPath)
  11.     for temp in fileList:
  12.         if os.path.isfile(os.path.join(rootPath, temp)):
  13.             if temp.endswith(".jpg"):
  14.                 allFIleList.append(os.path.join(rootPath, temp))
  15.         else:
  16.             allFilePath(os.path.join(rootPath, temp), allFIleList)
  17. def order_points(pts):
  18.     '''
  19.     对给定的坐标点进行排序,使得列表中的第一个点是左上角,第二个点是右上角,第三个点是右下角,第四个点是左下角。返回排序后的坐标点列表。
  20.     '''
  21.     # initialzie a list of coordinates that will be ordered
  22.     # such that the first entry in the list is the top-left,
  23.     # the second entry is the top-right, the third is the
  24.     # bottom-right, and the fourth is the bottom-left
  25.     pts = pts[:4, :]
  26.     rect = np.zeros((5, 2), dtype="float32")
  27.     # the top-left point will have the smallest sum, whereas
  28.     # the bottom-right point will have the largest sum
  29.     s = pts.sum(axis=1)
  30.     rect[0] = pts[np.argmin(s)]
  31.     rect[2] = pts[np.argmax(s)]
  32.     # now, compute the difference between the points, the
  33.     # top-right point will have the smallest difference,
  34.     # whereas the bottom-left will have the largest difference
  35.     diff = np.diff(pts, axis=1)
  36.     rect[1] = pts[np.argmin(diff)]
  37.     rect[3] = pts[np.argmax(diff)]
  38.     # return the ordered coordinates
  39.     return rect
  40. def get_rect_and_landmarks(img_path):
  41.     '''该函数用于从图像文件路径中解析出矩形框和关键点的坐标,并返回解析后的结果。'''
  42.     file_name = img_path.split("/")[-1].split("-")
  43.     landmarks_np = np.zeros((5, 2))
  44.     rect = file_name[2].split("_")
  45.     landmarks = file_name[3].split("_")
  46.     rect_str = "&".join(rect)
  47.     landmarks_str = "&".join(landmarks)
  48.     rect = rect_str.split("&")
  49.     landmarks = landmarks_str.split("&")
  50.     rect = [int(x) for x in rect]
  51.     landmarks = [int(x) for x in landmarks]
  52.     for i in range(4):
  53.         landmarks_np[i][0] = landmarks[2 * i]
  54.         landmarks_np[i][1] = landmarks[2 * i + 1]
  55.     #    middle_landmark_w =int((landmarks[4]+landmarks[6])/2)
  56.     #    middle_landmark_h =int((landmarks[5]+landmarks[7])/2)
  57.     #    landmarks.append(middle_landmark_w)
  58.     #    landmarks.append(middle_landmark_h)
  59.     landmarks_np_new = order_points(landmarks_np)
  60.     #    landmarks_np_new[4]=np.array([middle_landmark_w,middle_landmark_h])
  61.     return rect, landmarks, landmarks_np_new
  62. def x1x2y1y2_yolo(rect, landmarks, img):
  63.     h, w, c = img.shape
  64.     rect[0] = max(0, rect[0])
  65.     rect[1] = max(0, rect[1])
  66.     rect[2] = min(w - 1, rect[2] - rect[0])
  67.     rect[3] = min(h - 1, rect[3] - rect[1])
  68.     annotation = np.zeros((1, 14))
  69.     annotation[0, 0] = (rect[0] + rect[2] / 2) / w  # cx
  70.     annotation[0, 1] = (rect[1] + rect[3] / 2) / h  # cy
  71.     annotation[0, 2] = rect[2] / w  # w
  72.     annotation[0, 3] = rect[3] / h  # h
  73.     annotation[0, 4] = landmarks[0] / w  # l0_x
  74.     annotation[0, 5] = landmarks[1] / h  # l0_y
  75.     annotation[0, 6] = landmarks[2] / w  # l1_x
  76.     annotation[0, 7] = landmarks[3] / h  # l1_y
  77.     annotation[0, 8] = landmarks[4] / w  # l2_x
  78.     annotation[0, 9] = landmarks[5] / h  # l2_y
  79.     annotation[0, 10] = landmarks[6] / w  # l3_x
  80.     annotation[0, 11] = landmarks[7] / h  # l3_y
  81.     # annotation[0, 12] = landmarks[8] / w  # l4_x
  82.     # annotation[0, 13] = landmarks[9] / h  # l4_y
  83.     return annotation
  84. def xywh2yolo(rect, landmarks_sort, img):
  85.     h, w, c = img.shape
  86.     rect[0] = max(0, rect[0])
  87.     rect[1] = max(0, rect[1])
  88.     rect[2] = min(w - 1, rect[2] - rect[0])
  89.     rect[3] = min(h - 1, rect[3] - rect[1])
  90.     annotation = np.zeros((1, 12))
  91.     annotation[0, 0] = (rect[0] + rect[2] / 2) / w  # cx
  92.     annotation[0, 1] = (rect[1] + rect[3] / 2) / h  # cy
  93.     annotation[0, 2] = rect[2] / w  # w
  94.     annotation[0, 3] = rect[3] / h  # h
  95.     annotation[0, 4] = landmarks_sort[0][0] / w  # l0_x
  96.     annotation[0, 5] = landmarks_sort[0][1] / h  # l0_y
  97.     annotation[0, 6] = landmarks_sort[1][0] / w  # l1_x
  98.     annotation[0, 7] = landmarks_sort[1][1] / h  # l1_y
  99.     annotation[0, 8] = landmarks_sort[2][0] / w  # l2_x
  100.     annotation[0, 9] = landmarks_sort[2][1] / h  # l2_y
  101.     annotation[0, 10] = landmarks_sort[3][0] / w  # l3_x
  102.     annotation[0, 11] = landmarks_sort[3][1] / h  # l3_y
  103.     # annotation[0, 12] = landmarks_sort[4][0] / w  # l4_x
  104.     # annotation[0, 13] = landmarks_sort[4][1] / h  # l4_y
  105.     return annotation
  106. def yolo2x1y1x2y2(annotation, img):
  107.     h, w, c = img.shape
  108.     rect = annotation[:, 0:4].squeeze().tolist()
  109.     landmarks = annotation[:, 4:].squeeze().tolist()
  110.     rect_w = w * rect[2]
  111.     rect_h = h * rect[3]
  112.     rect_x = int(rect[0] * w - rect_w / 2)
  113.     rect_y = int(rect[1] * h - rect_h / 2)
  114.     new_rect = [rect_x, rect_y, rect_x + rect_w, rect_y + rect_h]
  115.     for i in range(5):
  116.         landmarks[2 * i] = landmarks[2 * i] * w
  117.         landmarks[2 * i + 1] = landmarks[2 * i + 1] * h
  118.     return new_rect, landmarks
  119. def update_txt(file_root = r"I:/CCPD2019/ccpd",save_img_path=r"H:\data\images",save_txt_path="H:\data\labels"):
  120.     print(file_root, "start!!!!!")
  121.     file_list = []
  122.     count = 0
  123.     allFilePath(file_root, file_list)
  124.     # print(file_list)
  125.     # exit()
  126.     for img_path in file_list:
  127.         count += 1
  128.         # img_path = r"ccpd_yolo_test/02-90_85-173&466_452&541-452&553_176&556_178&463_454&460-0_0_6_26_15_26_32-68-53.jpg"
  129.         text_path = img_path.replace(".jpg", ".txt")
  130.         # 读取图片
  131.         img = cv2.imread(img_path)
  132.         rect, landmarks, landmarks_sort = get_rect_and_landmarks(img_path)
  133.         # annotation=x1x2y1y2_yolo(rect,landmarks,img)
  134.         annotation = xywh2yolo(rect, landmarks_sort, img)
  135.         str_label = "0 "
  136.         for i in range(len(annotation[0])):
  137.             str_label = str_label + " " + str(annotation[0][i])
  138.         str_label = str_label.replace('[', '').replace(']', '')
  139.         str_label = str_label.replace(',', '') + '\n'
  140.         # if os.path.exists(text_path):
  141.         #     continue
  142.         # else:
  143.         shutil.move(img_path,os.path.join(os.path.join(save_img_path,os.path.basename(img_path))))
  144.         text_path_save = os.path.join(save_txt_path,os.path.basename(text_path))
  145.         # print(text_path_save)
  146.         # exit()
  147.         with open(text_path_save, "w") as f:
  148.             f.write(str_label)
  149.         print(text_path,"finished!")
  150.         # print(count, img_path)
  151.     print(os.getpid(),"end!!!")
  152. def delete_non_jpg_images(image_folder):
  153.     for filename in os.listdir(image_folder):
  154.         if not filename.endswith(".jpg"):
  155.             file_path = os.path.join(image_folder, filename)
  156.             os.remove(file_path)
  157.             print("删除完毕")
  158. def move_files_to_folders(images_folder, folders_folder, labels_folder):
  159.     for filename in os.listdir(images_folder):
  160.         if filename.endswith(".jpg"):
  161.             image_path = os.path.join(images_folder, filename)
  162.             label_path = os.path.join(images_folder, os.path.splitext(filename)[0] + ".txt")
  163.             folder_path = os.path.join(folders_folder, filename)
  164.             labels_folder_path = os.path.join(labels_folder, os.path.splitext(filename)[0] + ".txt")
  165.             if not os.path.exists(folder_path) and not os.path.exists(labels_folder_path) and os.path.exists(label_path):
  166.                 # 不存在同名
  167.                 shutil.move(image_path, folder_path)
  168.                 shutil.move(label_path, labels_folder_path)
  169. if __name__ == '__main__':
  170.     # 1. 处理ccpd文件夹
  171.     import multiprocessing
  172.     pool = multiprocessing.Pool(processes=14)  # 这里使用4个进程
  173.     files = []
  174.     for dir in os.listdir(r"I:/CCPD2019/ccpd"):
  175.         files.append(os.path.join(r"I:/CCPD2019/ccpd",dir))
  176.     # 使用进程池执行任务
  177.     results = pool.map(update_txt,files)
  178.     # 关闭进程池,防止新任务被提交
  179.     pool.close()
  180.     # 等待所有任务完成
  181.     pool.join()
  182.     # 2. 清理异常文件夹
  183.     # 调用删除非jpg图像的函数
  184.     image_folder = r"H:\data\images"
  185.     # 删除文件
  186.     delete_non_jpg_images(image_folder)
  187.     # 3.加入一些新增文件夹文件
  188.     # 指定文件夹路径
  189.     # images_folder = r"single_yellow_val"
  190.     # folders_folder = r"H:\data\images"
  191.     # labels_folder = r"H:\data\labels"
  192.     # # 调用移动文件的函数
  193.     # move_files_to_folders(images_folder, folders_folder, labels_folder)
复制代码
处置惩罚后文件,共计329499个文件

处置惩罚后为类别+左上角+右下角+4个角点

2.2.2 CRPD数据集处置惩罚

Unified Chinese License Plate Detection and Recognition with High Efficiency(Arxiv 2022)
这段话描述了标签文件夹中的txt文件的注释格式。每个txt文件的文件名与相应图像的名称相同。
在txt文件中,每一行表现图像中的一个车牌(LP)的注释。
一个LP的注释格式如下:
  1. x1,y1,x2,y2,x3,y3,x4,y4,type,content
复制代码
前八个数字表现边界四边形的坐标。
"type"注释表现LP的类型,0表现蓝色车牌,1表现黄色单线车牌,2表现黄色双线车牌,3表现白色车牌。
"content"注释表现LP的内容。
2.3 检测算法

YOLOv5-Face是YOLOv5的一个改进版本,特别针对人脸检测使命。它添加了一个5-Point Landmark Regression Head(关键点回归),并对Landmark Regression Head使用了Wing loss举行束缚。此外,YOLOv5-Face还设计了差别模子尺寸的检测器,从大模子到超小模子,以实如今嵌入式或移动装备上的实时检测。在WiderFace数据集上的实验结果表明,YOLOv5-Face在几乎全部的Easy、Medium和Hard子集上都能到达开始进的性能,超过了特定设计的人脸检测器。与很多其他的人脸检测器差别,YOLOv5-Face把人脸检测作为一个一般的目标检测使命来看待。
这里将yolov5-face 修改为四个关键点,做目标检测使命
2.3.1 数据设置car_plate.yaml

  1. # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC/
  2. # Train command: python train.py --data voc.yaml
  3. # Default dataset location is next to /yolov5:
  4. #   /parent_folder
  5. #     /VOC
  6. #     /yolov5
  7. # download command/URL (optional)
  8. download: bash data/scripts/get_voc.sh
  9. # train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
  10. train: E:/data/train/images
  11. val: E:/data/val_detect/val
  12. # number of classes
  13. nc: 2
  14. # class names
  15. names: [ 'single_plate','double_plate']
复制代码
2.3.2 模子设置

  1. # parameters
  2. nc: 2  # number of classes
  3. depth_multiple: 1.0  # model depth multiple
  4. width_multiple: 0.5  # layer channel multiple
  5. # anchors
  6. anchors:
  7.   - [4,5,  8,10,  13,16]  # P3/8
  8.   - [23,29,  43,55,  73,105]  # P4/16
  9.   - [146,217,  231,300,  335,433]  # P5/32
  10. # YOLOv5 backbone
  11. backbone:
  12.   # [from, number, module, args]
  13.   [[-1, 1, StemBlock, [32, 3, 2]],    # 0-P2/4
  14.    [-1, 1, ShuffleV2Block, [128, 2]], # 1-P3/8
  15.    [-1, 3, ShuffleV2Block, [128, 1]], # 2
  16.    [-1, 1, ShuffleV2Block, [256, 2]], # 3-P4/16
  17.    [-1, 7, ShuffleV2Block, [256, 1]], # 4
  18.    [-1, 1, ShuffleV2Block, [512, 2]], # 5-P5/32
  19.    [-1, 3, ShuffleV2Block, [512, 1]], # 6
  20.   ]
  21. # YOLOv5 head
  22. head:
  23.   [[-1, 1, Conv, [128, 1, 1]],
  24.    [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  25.    [[-1, 4], 1, Concat, [1]],  # cat backbone P4
  26.    [-1, 1, C3, [128, False]],  # 10
  27.    [-1, 1, Conv, [128, 1, 1]],
  28.    [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  29.    [[-1, 2], 1, Concat, [1]],  # cat backbone P3
  30.    [-1, 1, C3, [128, False]],  # 14 (P3/8-small)
  31.    [-1, 1, Conv, [128, 3, 2]],
  32.    [[-1, 11], 1, Concat, [1]],  # cat head P4
  33.    [-1, 1, C3, [128, False]],  # 17 (P4/16-medium)
  34.    [-1, 1, Conv, [128, 3, 2]],
  35.    [[-1, 7], 1, Concat, [1]],  # cat head P5
  36.    [-1, 1, C3, [128, False]],  # 20 (P5/32-large)
  37.    [[14, 17, 20], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  38.   ]
  39.          
复制代码
2.3.3 train.py

  1.     parser = argparse.ArgumentParser()
  2.     # 权重
  3.     parser.add_argument('--weights', type=str, default='best.pt', help='initial weights path')
  4.     # 默认配置文件
  5.     parser.add_argument('--cfg', type=str, default='models/car_plate.yaml', help='model.yaml path')
  6.     parser.add_argument('--data', type=str, default='data/car_plate.yaml', help='data.yaml path')
  7.     parser.add_argument('--hyp', type=str, default='data/hyp.scratch.yaml', help='hyperparameters path')
  8.     parser.add_argument('--epochs', type=int, default=10)
  9.     parser.add_argument('--batch-size', type=int, default=64, help='total batch size for all GPUs')
  10.     parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes')
  11.     parser.add_argument('--rect', action='store_true', help='rectangular training')
  12.     parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training')
  13.     parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
  14.     parser.add_argument('--notest', action='store_true', help='only test final epoch')
  15.     parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check')
  16.     parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters')
  17.     parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
  18.     parser.add_argument('--cache-images', action='store_true', help='cache images for faster training')
  19.     parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
  20.     parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
  21.     parser.add_argument('--multi-scale', action='store_true', default=True, help='vary img-size +/- 50%%')
  22.     parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
  23.     parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer')
  24.     parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
  25.     parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')
  26.     parser.add_argument('--log-imgs', type=int, default=2, help='number of images for W&B logging, max 100')
  27.     parser.add_argument('--log-artifacts', action='store_true', help='log artifacts, i.e. final trained model')
  28.     parser.add_argument('--workers', type=int, default=4, help='maximum number of dataloader workers')
  29.     parser.add_argument('--project', default='runs/train', help='save to project/name')
  30.     parser.add_argument('--name', default='exp', help='save to project/name')
  31.     parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
复制代码
2.3.4 训练结果




2.4 部署

2.4.1 pth推理(detect.py)

  1. #!/usr/bin/env python
  2. import warnings
  3. warnings.filterwarnings("ignore")
  4. import os
  5. import cv2
  6. import numpy as np
  7. import time
  8. import torch
  9. import copy
  10. from models.experimental import attempt_load
  11. from utils.datasets import letterbox
  12. from utils.general import check_img_size, non_max_suppression_face, scale_coords
  13. from utils.torch_utils import time_synchronized
  14. clors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255)]
  15. def load_model(weights, device):
  16.     model = attempt_load(weights, map_location=device)  # load FP32 model
  17.     return model
  18. def scale_coords_landmarks(img1_shape, coords, img0_shape, ratio_pad=None):
  19.     # Rescale coords (xyxy) from img1_shape to img0_shape
  20.     if ratio_pad is None:  # calculate from img0_shape
  21.         gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])  # gain  = old / new
  22.         pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2  # wh padding
  23.     else:
  24.         gain = ratio_pad[0][0]
  25.         pad = ratio_pad[1]
  26.     coords[:, [0, 2, 4, 6]] -= pad[0]  # x padding
  27.     coords[:, [1, 3, 5, 7]] -= pad[1]  # y padding
  28.     coords[:, :10] /= gain
  29.     # clip_coords(coords, img0_shape)
  30.     coords[:, 0].clamp_(0, img0_shape[1])  # x1
  31.     coords[:, 1].clamp_(0, img0_shape[0])  # y1
  32.     coords[:, 2].clamp_(0, img0_shape[1])  # x2
  33.     coords[:, 3].clamp_(0, img0_shape[0])  # y2
  34.     coords[:, 4].clamp_(0, img0_shape[1])  # x3
  35.     coords[:, 5].clamp_(0, img0_shape[0])  # y3
  36.     coords[:, 6].clamp_(0, img0_shape[1])  # x4
  37.     coords[:, 7].clamp_(0, img0_shape[0])  # y4
  38.     # coords[:, 8].clamp_(0, img0_shape[1])  # x5
  39.     # coords[:, 9].clamp_(0, img0_shape[0])  # y5
  40.     return coords
  41. def get_plate_rec_landmark(img, xyxy, conf, landmarks, class_num, device):
  42.     h, w, c = img.shape
  43.     result_dict = {}
  44.     tl = 1 or round(0.002 * (h + w) / 2) + 1  # line/font thickness
  45.     x1 = int(xyxy[0])
  46.     y1 = int(xyxy[1])
  47.     x2 = int(xyxy[2])
  48.     y2 = int(xyxy[3])
  49.     landmarks_np = np.zeros((4, 2))
  50.     rect = [x1, y1, x2, y2]
  51.     for i in range(4):
  52.         point_x = int(landmarks[2 * i])
  53.         point_y = int(landmarks[2 * i + 1])
  54.         landmarks_np[i] = np.array([point_x, point_y])
  55.     class_label = int(class_num)  # 车牌的的类型0代表单牌,1代表双层车牌
  56.     result_dict['box'] = rect
  57.     result_dict['landmarks'] = landmarks_np.tolist()
  58.     result_dict['class'] = class_label
  59.     return result_dict
  60. class Detect:
  61.     def __init__(self, conf_thres=0.6, iou_thres=0.5, img_size=640):
  62.         self.conf_thres = conf_thres
  63.         self.iou_thres = iou_thres
  64.         self.img_size = img_size
  65.         self.device = "cuda" if torch.cuda.is_available() else "cpu"
  66.         self.detect_model = load_model("weights/best.pt", self.device)
  67.     def detect(self, orgimg):
  68.         dict_list = []
  69.         if orgimg is None:
  70.             return []
  71.         if orgimg.shape[-1] == 4:
  72.             orgimg = cv2.cvtColor(orgimg, cv2.COLOR_BGRA2BGR)
  73.         h0, w0 = orgimg.shape[:2]  # orig hw
  74.         img0 = copy.deepcopy(orgimg)
  75.         r = self.img_size / max(h0, w0)  # resize image to img_size
  76.         if r != 1:  # always resize down, only resize up if training with augmentation
  77.             interp = cv2.INTER_AREA if r < 1 else cv2.INTER_LINEAR
  78.             img0 = cv2.resize(img0, (int(w0 * r), int(h0 * r)), interpolation=interp)
  79.         imgsz = check_img_size(self.img_size, s=self.detect_model.stride.max())  # check img_size
  80.         img = letterbox(img0, new_shape=imgsz,auto=False)[0]
  81.         # Convert
  82.         img = img[:, :, ::-1].transpose(2, 0, 1).copy()  # BGR to RGB, to 3x416x416
  83.         # Run inference
  84.         t0 = time.time()
  85.         img = torch.from_numpy(img).to(self.device)
  86.         img = img.float()  # uint8 to fp16/32
  87.         img /= 255.0  # 0 - 255 to 0.0 - 1.0
  88.         if img.ndimension() == 3:
  89.             img = img.unsqueeze(0)
  90.         # Inference
  91.         t1 = time_synchronized()
  92.         pred = self.detect_model(img)[0]
  93.         print(pred.shape)
  94.         t2 = time_synchronized()
  95.         print(f"infer time is {(t2-t1)*1000} ms")
  96.         # Apply NMS
  97.         pred = non_max_suppression_face(pred, self.conf_thres, self.iou_thres)
  98.         # print(pred.shape)
  99.         # Process detections
  100.         for i, det in enumerate(pred):  # detections per image
  101.             if len(det):
  102.                 # Rescale boxes from img_size to im0 size
  103.                 det[:, :4] = scale_coords(img.shape[2:], det[:, :4], orgimg.shape).round()
  104.                 # Print results
  105.                 for c in det[:, -1].unique():
  106.                     n = (det[:, -1] == c).sum()  # detections per class
  107.                 det[:, 5:13] = scale_coords_landmarks(img.shape[2:], det[:, 5:13], orgimg.shape).round()
  108.                 for j in range(det.size()[0]):
  109.                     xyxy = det[j, :4].view(-1).tolist()
  110.                     conf = det[j, 4].cpu().numpy()
  111.                     landmarks = det[j, 5:13].view(-1).tolist()
  112.                     class_num = det[j, 13].cpu().numpy()
  113.                     result_dict = get_plate_rec_landmark(orgimg, xyxy, conf, landmarks, class_num, self.device)
  114.                     dict_list.append(result_dict)
  115.         return dict_list
  116.     def draw_result(self, orgimg, dict_list):
  117.         '''
  118.         返回绘制之后的原图
  119.         '''
  120.         for result in dict_list:
  121.             rect_area = result['box']
  122.             x, y, w, h = rect_area[0], rect_area[1], rect_area[2] - rect_area[0], rect_area[3] - rect_area[1]
  123.             padding_w = 0.05 * w
  124.             padding_h = 0.11 * h
  125.             rect_area[0] = max(0, int(x - padding_w))
  126.             rect_area[1] = max(0, int(y - padding_h))
  127.             rect_area[2] = min(orgimg.shape[1], int(rect_area[2] + padding_w))
  128.             rect_area[3] = min(orgimg.shape[0], int(rect_area[3] + padding_h))
  129.             landmarks = result['landmarks']
  130.             label = result['class']
  131.             # result_str+=result+" "
  132.             for i in range(4):  # 关键点
  133.                 cv2.circle(orgimg, (int(landmarks[i][0]), int(landmarks[i][1])), 5, clors[i], -1)
  134.             cv2.rectangle(orgimg, (rect_area[0], rect_area[1]), (rect_area[2], rect_area[3]), clors[label], 2)  # 画框
  135.             cv2.putText(img, str(label), (rect_area[0], rect_area[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, clors[label], 2)
  136.         return orgimg
  137. if __name__ == '__main__':
  138.     det = Detect()
  139.     img_dir = "images"
  140.     save_dir = "result"
  141.     if not os.path.exists(save_dir):
  142.         os.makedirs(save_dir)
  143.     for file in os.listdir(img_dir):
  144.         img_path = os.path.join(img_dir,file)
  145.         img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
  146.         dict_list = det.detect(img)
  147.         # print(dict_list)
  148.         result_img = det.draw_result(img, dict_list)
  149.         save_dir_path = os.path.join(save_dir,file)
  150.         cv2.imwrite(save_dir_path,result_img)
复制代码
2.4.2 onnx推理

  1. import argparse
  2. import time, os
  3. import torch
  4. from detect import scale_coords_landmarks, get_plate_rec_landmark
  5. from torch2trt.trt_model import TrtModel
  6. from utils.general import non_max_suppression_face, scale_coords, check_img_size
  7. import cv2
  8. import copy
  9. from utils.torch_utils import time_synchronized
  10. import numpy as np
  11. clors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255)]
  12. def letterbox(img, size=(640, 640)):
  13.     h, w, c = img.shape
  14.     # 缩放因子
  15.     ratio = min(size[0] / h, size[1] / w)
  16.     new_h, new_w = int(h * ratio), int(w * ratio)
  17.     top = int((size[0] - new_h) / 2)
  18.     left = int((size[1] - new_w) / 2)
  19.     bottom = size[0] - new_h - top
  20.     right = size[1] - new_w - left
  21.     img_resize = cv2.resize(img, (new_w, new_h))
  22.     img = cv2.copyMakeBorder(img_resize, top, bottom, left, right, borderType=cv2.BORDER_CONSTANT,
  23.                              value=(114, 114, 114))
  24.     return img, ratio, left, top
  25. def nms(boxes, iou_thresh):
  26.     # numpy nms
  27.     index = np.argsort(boxes[:, 4])[::-1]
  28.     keep = []
  29.     while index.size > 0:
  30.         i = index[0]
  31.         keep.append(i)
  32.         x1 = np.maximum(boxes[i, 0], boxes[index[1:], 0])
  33.         y1 = np.maximum(boxes[i, 1], boxes[index[1:], 1])
  34.         x2 = np.minimum(boxes[i, 2], boxes[index[1:], 2])
  35.         y2 = np.minimum(boxes[i, 3], boxes[index[1:], 3])
  36.         w = np.maximum(0, x2 - x1)
  37.         h = np.maximum(0, y2 - y1)
  38.         inter_area = w * h
  39.         union_area = (boxes[i, 2] - boxes[i, 0]) * (boxes[i, 3] - boxes[i, 1]) + (
  40.                 boxes[index[1:], 2] - boxes[index[1:], 0]) * (boxes[index[1:], 3] - boxes[index[1:], 1])
  41.         iou = inter_area / (union_area - inter_area)
  42.         idx = np.where(iou <= iou_thresh)[0]
  43.         index = index[idx + 1]
  44.     return keep
  45. def restore_box(boxes, r, left, top):  # 返回原图上面的坐标
  46.     boxes[:, [0, 2, 5, 7, 9, 11]] -= left
  47.     boxes[:, [1, 3, 6, 8, 10, 12]] -= top
  48.     boxes[:, [0, 2, 5, 7, 9, 11]] /= r
  49.     boxes[:, [1, 3, 6, 8, 10, 12]] /= r
  50.     return boxes
  51. def post_precessing(dets, ratio, left, top, conf_thresh=0.3, iou_thresh=0.5):  # 检测后处理
  52.     # 选取大于置信度的
  53.     choice = dets[:, :, 4] > conf_thresh
  54.     dets = dets[choice]
  55.     dets[:, 13:15] *= dets[:, 4:5]
  56.     box = dets[:, :4]
  57.     boxes = xywh2xyxy(box)
  58.     score = np.max(dets[:, 13:15], axis=-1, keepdims=True)
  59.     index = np.argmax(dets[:, 13:15], axis=-1).reshape(-1, 1)
  60.     output = np.concatenate((boxes, score, dets[:, 5:13], index), axis=1)
  61.     reserve_ = nms(output, iou_thresh)
  62.     output = output[reserve_]
  63.     output = restore_box(output, ratio, left, top)
  64.     return output
  65. def xywh2xyxy(boxes):  # xywh坐标变为 左上 ,右下坐标 x1,y1  x2,y2
  66.     xywh = copy.deepcopy(boxes)
  67.     xywh[:, 0] = boxes[:, 0] - boxes[:, 2] / 2
  68.     xywh[:, 1] = boxes[:, 1] - boxes[:, 3] / 2
  69.     xywh[:, 2] = boxes[:, 0] + boxes[:, 2] / 2
  70.     xywh[:, 3] = boxes[:, 1] + boxes[:, 3] / 2
  71.     return xywh
  72. class Detect:
  73.     def __init__(self, conf_thres=0.6, iou_thres=0.5, img_size=640, trt_path="weights/best.trt"):
  74.         self.conf_thres = conf_thres
  75.         self.iou_thres = iou_thres
  76.         self.img_size = img_size
  77.         self.device = "cuda" if torch.cuda.is_available() else "cpu"
  78.         self.detect_model = TrtModel(trt_path)
  79.     def detect_processing(self, img, img_size=(640, 640)):
  80.         img, ratio, left, top = letterbox(img, size=img_size)
  81.         img = img[:, :, ::-1].transpose(2, 0, 1).copy().astype(np.float32)
  82.         img = img / 255
  83.         img = img.reshape(1, *img.shape)
  84.         return img, ratio, left, top
  85.     def detect(self, orgimg):
  86.         dict_list = []
  87.         if orgimg is None:
  88.             return []
  89.         if orgimg.shape[-1] == 4:
  90.             orgimg = cv2.cvtColor(orgimg, cv2.COLOR_BGRA2BGR)
  91.         h0, w0 = orgimg.shape[:2]  # orig hw
  92.         img0 = copy.deepcopy(orgimg)
  93.         # imgsz = check_img_size(self.img_size, s=32)  # check img_size
  94.         img, ratio, left, top = self.detect_processing(img0)
  95.         if img.ndim == 3:
  96.             img = img[None, ...]
  97.         # Inference
  98.         t1 = time_synchronized()
  99.         pred = self.detect_model(img).reshape([1, 25200, 15])
  100.         output = post_precessing(pred, ratio, left, top, conf_thresh=self.conf_thres, iou_thresh=self.iou_thres)
  101.         for output in output:
  102.             result_dict = {}
  103.             rect = output[:4].astype(int).tolist()
  104.             land_marks = output[5:13].astype(int).reshape(4, 2)
  105.             conf =  output[4].astype(int).tolist()
  106.             result_dict['box'] = rect
  107.             result_dict['class'] = conf
  108.             result_dict['landmarks'] = land_marks.tolist()
  109.             dict_list.append(result_dict)
  110.         return dict_list
  111.     def draw_result(self, orgimg, dict_list):
  112.         '''
  113.         返回绘制之后的原图
  114.         '''
  115.         for result in dict_list:
  116.             rect_area = result['box']
  117.             x, y, w, h = rect_area[0], rect_area[1], rect_area[2] - rect_area[0], rect_area[3] - rect_area[1]
  118.             padding_w = 0.05 * w
  119.             padding_h = 0.11 * h
  120.             rect_area[0] = max(0, int(x - padding_w))
  121.             rect_area[1] = max(0, int(y - padding_h))
  122.             rect_area[2] = min(orgimg.shape[1], int(rect_area[2] + padding_w))
  123.             rect_area[3] = min(orgimg.shape[0], int(rect_area[3] + padding_h))
  124.             landmarks = result['landmarks']
  125.             label = result['class']
  126.             # result_str+=result+" "
  127.             for i in range(4):  # 关键点
  128.                 cv2.circle(orgimg, (int(landmarks[i][0]), int(landmarks[i][1])), 5, clors[i], -1)
  129.             cv2.rectangle(orgimg, (rect_area[0], rect_area[1]), (rect_area[2], rect_area[3]), clors[label], 2)  # 画框
  130.             cv2.putText(img, str(label), (rect_area[0], rect_area[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, clors[label], 2)
  131.         return orgimg
  132.     def __del__(self):
  133.         self.detect_model.destroy()
  134. if __name__ == '__main__':
  135.     # ============可视化================
  136.     # img_vis(img, orgimg, pred)
  137.     det = Detect()
  138.     img_dir = "images"
  139.     save_dir = "result"
  140.     if not os.path.exists(save_dir):
  141.         os.makedirs(save_dir)
  142.     for file in os.listdir(img_dir):
  143.         img_path = os.path.join(img_dir, file)
  144.         img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
  145.         dict_list = det.detect(img)
  146.         print(dict_list)
  147.         result_img = det.draw_result(img, dict_list)
  148.         save_dir_path = os.path.join(save_dir, file)
  149.         cv2.imwrite(save_dir_path, result_img)
复制代码
2.4.3 trt推理

  1. import argparse
  2. import time,os
  3. import torch
  4. from detect import scale_coords_landmarks, get_plate_rec_landmark
  5. from torch2trt.trt_model import TrtModel
  6. from utils.datasets import letterbox
  7. from utils.general import non_max_suppression_face, scale_coords, check_img_size
  8. import cv2
  9. import copy
  10. from utils.torch_utils import time_synchronized
  11. import numpy as np
  12. clors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255)]
  13. def img_process(img_path,long_side=640,stride_max=32):
  14.     '''
  15.     图像预处理
  16.     '''
  17.     orgimg=cv2.imread(img_path)
  18.     img0 = copy.deepcopy(orgimg)
  19.     h0, w0 = orgimg.shape[:2]  # orig hw
  20.     r = long_side/ max(h0, w0)  # resize image to img_size
  21.     if r != 1:  # always resize down, only resize up if training with augmentation
  22.         interp = cv2.INTER_AREA if r < 1 else cv2.INTER_LINEAR
  23.         img0 = cv2.resize(img0, (int(w0 * r), int(h0 * r)), interpolation=interp)
  24.     imgsz = check_img_size(long_side, s=stride_max)  # check img_size
  25.     img = letterbox(img0, new_shape=imgsz,auto=False)[0] # auto True最小矩形   False固定尺度
  26.     # Convert
  27.     img = img[:, :, ::-1].transpose(2, 0, 1).copy()  # BGR to RGB, to 3x416x416
  28.     img = torch.from_numpy(img)
  29.     img = img.float()  # uint8 to fp16/32
  30.     img /= 255.0  # 0 - 255 to 0.0 - 1.0
  31.     if img.ndimension() == 3:
  32.         img = img.unsqueeze(0)
  33.     return img,orgimg
  34. class Detect:
  35.     def __init__(self, conf_thres=0.6, iou_thres=0.5, img_size=640,trt_path="weights/best.trt"):
  36.         self.conf_thres = conf_thres
  37.         self.iou_thres = iou_thres
  38.         self.img_size = img_size
  39.         self.device = "cuda" if torch.cuda.is_available() else "cpu"
  40.         self.detect_model = TrtModel(trt_path)
  41.     def detect(self, orgimg):
  42.         dict_list = []
  43.         if orgimg is None:
  44.             return []
  45.         if orgimg.shape[-1] == 4:
  46.             orgimg = cv2.cvtColor(orgimg, cv2.COLOR_BGRA2BGR)
  47.         h0, w0 = orgimg.shape[:2]  # orig hw
  48.         img0 = copy.deepcopy(orgimg)
  49.         r = self.img_size / max(h0, w0)  # resize image to img_size
  50.         if r != 1:  # always resize down, only resize up if training with augmentation
  51.             interp = cv2.INTER_AREA if r < 1 else cv2.INTER_LINEAR
  52.             img0 = cv2.resize(img0, (int(w0 * r), int(h0 * r)), interpolation=interp)
  53.         imgsz = check_img_size(self.img_size, s=32)  # check img_size
  54.         img = letterbox(img0, new_shape=imgsz,auto=False)[0]
  55.         # Convert
  56.         img = img[:, :, ::-1].transpose(2, 0, 1).copy()  # BGR to RGB, to 3x416x416
  57.         # Run inference
  58.         t0 = time.time()
  59.         # img = torch.from_numpy(img).to(self.device)
  60.         img = img.astype(float)  # uint8 to fp16/32
  61.         img /= 255.0  # 0 - 255 to 0.0 - 1.0
  62.         if img.ndim == 3:
  63.             img = img[None,...]
  64.         # Inference
  65.         t1 = time_synchronized()
  66.         pred = self.detect_model(img).reshape([1, 25200, 15])
  67.         t2 = time_synchronized()
  68.         print(f"infer time is {(t2-t1)*1000} ms")
  69.         # Apply NMS
  70.         # pred = torch.tensor(pred)
  71.         pred = non_max_suppression_face(torch.tensor(pred), self.conf_thres, self.iou_thres)
  72.         # print(type(pred))
  73.         # Process detections
  74.         for i, det in enumerate(pred):  # detections per image
  75.             if len(det):
  76.                 # Rescale boxes from img_size to im0 size
  77.                 # print(type(det))
  78.                 det[:, :4] = scale_coords(img.shape[2:], det[:, :4], orgimg.shape).round()
  79.                 # Print results
  80.                 for c in det[:, -1].unique():
  81.                     n = (det[:, -1] == c).sum()  # detections per class
  82.                 det[:, 5:13] = scale_coords_landmarks(img.shape[2:], det[:, 5:13], orgimg.shape).round()
  83.                 for j in range(det.size()[0]):
  84.                     xyxy = det[j, :4].view(-1).tolist()
  85.                     conf = det[j, 4].cpu().numpy()
  86.                     landmarks = det[j, 5:13].view(-1).tolist()
  87.                     class_num = det[j, 13].cpu().numpy()
  88.                     result_dict = get_plate_rec_landmark(orgimg, xyxy, conf, landmarks, class_num, self.device)
  89.                     dict_list.append(result_dict)
  90.         return dict_list
  91.     def draw_result(self, orgimg, dict_list):
  92.         '''
  93.         返回绘制之后的原图
  94.         '''
  95.         for result in dict_list:
  96.             rect_area = result['box']
  97.             x, y, w, h = rect_area[0], rect_area[1], rect_area[2] - rect_area[0], rect_area[3] - rect_area[1]
  98.             padding_w = 0.05 * w
  99.             padding_h = 0.11 * h
  100.             rect_area[0] = max(0, int(x - padding_w))
  101.             rect_area[1] = max(0, int(y - padding_h))
  102.             rect_area[2] = min(orgimg.shape[1], int(rect_area[2] + padding_w))
  103.             rect_area[3] = min(orgimg.shape[0], int(rect_area[3] + padding_h))
  104.             landmarks = result['landmarks']
  105.             label = result['class']
  106.             # result_str+=result+" "
  107.             for i in range(4):  # 关键点
  108.                 cv2.circle(orgimg, (int(landmarks[i][0]), int(landmarks[i][1])), 5, clors[i], -1)
  109.             cv2.rectangle(orgimg, (rect_area[0], rect_area[1]), (rect_area[2], rect_area[3]), clors[label], 2)  # 画框
  110.             cv2.putText(img, str(label), (rect_area[0], rect_area[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, clors[label], 2)
  111.         return orgimg
  112.     def __del__(self):
  113.         self.detect_model.destroy()
  114. if __name__ == '__main__':
  115.     # ============可视化================
  116.     # img_vis(img, orgimg, pred)
  117.     det = Detect()
  118.     img_dir = "images"
  119.     save_dir = "result"
  120.     if not os.path.exists(save_dir):
  121.         os.makedirs(save_dir)
  122.     for file in os.listdir(img_dir):
  123.         img_path = os.path.join(img_dir, file)
  124.         img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
  125.         dict_list = det.detect(img)
  126.         print(dict_list)
  127.         result_img = det.draw_result(img, dict_list)
  128.         save_dir_path = os.path.join(save_dir, file)
  129.         cv2.imwrite(save_dir_path, result_img)
复制代码
2.4.4 numpy版本trt推理

  1. import argparse
  2. import time, os
  3. import torch
  4. from detect import scale_coords_landmarks, get_plate_rec_landmark
  5. from torch2trt.trt_model import TrtModel
  6. from utils.general import non_max_suppression_face, scale_coords, check_img_size
  7. import cv2
  8. import copy
  9. from utils.torch_utils import time_synchronized
  10. import numpy as np
  11. clors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255)]
  12. def letterbox(img, size=(640, 640)):
  13.     h, w, c = img.shape
  14.     # 缩放因子
  15.     ratio = min(size[0] / h, size[1] / w)
  16.     new_h, new_w = int(h * ratio), int(w * ratio)
  17.     top = int((size[0] - new_h) / 2)
  18.     left = int((size[1] - new_w) / 2)
  19.     bottom = size[0] - new_h - top
  20.     right = size[1] - new_w - left
  21.     img_resize = cv2.resize(img, (new_w, new_h))
  22.     img = cv2.copyMakeBorder(img_resize, top, bottom, left, right, borderType=cv2.BORDER_CONSTANT,
  23.                              value=(114, 114, 114))
  24.     return img, ratio, left, top
  25. def nms(boxes, iou_thresh):
  26.     # numpy nms
  27.     index = np.argsort(boxes[:, 4])[::-1]
  28.     keep = []
  29.     while index.size > 0:
  30.         i = index[0]
  31.         keep.append(i)
  32.         x1 = np.maximum(boxes[i, 0], boxes[index[1:], 0])
  33.         y1 = np.maximum(boxes[i, 1], boxes[index[1:], 1])
  34.         x2 = np.minimum(boxes[i, 2], boxes[index[1:], 2])
  35.         y2 = np.minimum(boxes[i, 3], boxes[index[1:], 3])
  36.         w = np.maximum(0, x2 - x1)
  37.         h = np.maximum(0, y2 - y1)
  38.         inter_area = w * h
  39.         union_area = (boxes[i, 2] - boxes[i, 0]) * (boxes[i, 3] - boxes[i, 1]) + (
  40.                 boxes[index[1:], 2] - boxes[index[1:], 0]) * (boxes[index[1:], 3] - boxes[index[1:], 1])
  41.         iou = inter_area / (union_area - inter_area)
  42.         idx = np.where(iou <= iou_thresh)[0]
  43.         index = index[idx + 1]
  44.     return keep
  45. def restore_box(boxes, r, left, top):  # 返回原图上面的坐标
  46.     boxes[:, [0, 2, 5, 7, 9, 11]] -= left
  47.     boxes[:, [1, 3, 6, 8, 10, 12]] -= top
  48.     boxes[:, [0, 2, 5, 7, 9, 11]] /= r
  49.     boxes[:, [1, 3, 6, 8, 10, 12]] /= r
  50.     return boxes
  51. def post_precessing(dets, ratio, left, top, conf_thresh=0.3, iou_thresh=0.5):  # 检测后处理
  52.     # 选取大于置信度的
  53.     choice = dets[:, :, 4] > conf_thresh
  54.     dets = dets[choice]
  55.     dets[:, 13:15] *= dets[:, 4:5]
  56.     box = dets[:, :4]
  57.     boxes = xywh2xyxy(box)
  58.     score = np.max(dets[:, 13:15], axis=-1, keepdims=True)
  59.     index = np.argmax(dets[:, 13:15], axis=-1).reshape(-1, 1)
  60.     output = np.concatenate((boxes, score, dets[:, 5:13], index), axis=1)
  61.     reserve_ = nms(output, iou_thresh)
  62.     output = output[reserve_]
  63.     output = restore_box(output, ratio, left, top)
  64.     return output
  65. def xywh2xyxy(boxes):  # xywh坐标变为 左上 ,右下坐标 x1,y1  x2,y2
  66.     xywh = copy.deepcopy(boxes)
  67.     xywh[:, 0] = boxes[:, 0] - boxes[:, 2] / 2
  68.     xywh[:, 1] = boxes[:, 1] - boxes[:, 3] / 2
  69.     xywh[:, 2] = boxes[:, 0] + boxes[:, 2] / 2
  70.     xywh[:, 3] = boxes[:, 1] + boxes[:, 3] / 2
  71.     return xywh
  72. class Detect:
  73.     def __init__(self, conf_thres=0.6, iou_thres=0.5, img_size=640, trt_path="weights/best.trt"):
  74.         self.conf_thres = conf_thres
  75.         self.iou_thres = iou_thres
  76.         self.img_size = img_size
  77.         self.device = "cuda" if torch.cuda.is_available() else "cpu"
  78.         self.detect_model = TrtModel(trt_path)
  79.     def detect_processing(self, img, img_size=(640, 640)):
  80.         img, ratio, left, top = letterbox(img, size=img_size)
  81.         img = img[:, :, ::-1].transpose(2, 0, 1).copy().astype(np.float32)
  82.         img = img / 255
  83.         img = img.reshape(1, *img.shape)
  84.         return img, ratio, left, top
  85.     def detect(self, orgimg):
  86.         dict_list = []
  87.         if orgimg is None:
  88.             return []
  89.         if orgimg.shape[-1] == 4:
  90.             orgimg = cv2.cvtColor(orgimg, cv2.COLOR_BGRA2BGR)
  91.         h0, w0 = orgimg.shape[:2]  # orig hw
  92.         img0 = copy.deepcopy(orgimg)
  93.         # imgsz = check_img_size(self.img_size, s=32)  # check img_size
  94.         img, ratio, left, top = self.detect_processing(img0)
  95.         if img.ndim == 3:
  96.             img = img[None, ...]
  97.         # Inference
  98.         t1 = time_synchronized()
  99.         pred = self.detect_model(img).reshape([1, 25200, 15])
  100.         output = post_precessing(pred, ratio, left, top, conf_thresh=self.conf_thres, iou_thresh=self.iou_thres)
  101.         for output in output:
  102.             result_dict = {}
  103.             rect = output[:4].astype(int).tolist()
  104.             land_marks = output[5:13].astype(int).reshape(4, 2)
  105.             conf =  output[4].astype(int).tolist()
  106.             result_dict['box'] = rect
  107.             result_dict['class'] = conf
  108.             result_dict['landmarks'] = land_marks.tolist()
  109.             dict_list.append(result_dict)
  110.         return dict_list
  111.     def draw_result(self, orgimg, dict_list):
  112.         '''
  113.         返回绘制之后的原图
  114.         '''
  115.         for result in dict_list:
  116.             rect_area = result['box']
  117.             x, y, w, h = rect_area[0], rect_area[1], rect_area[2] - rect_area[0], rect_area[3] - rect_area[1]
  118.             padding_w = 0.05 * w
  119.             padding_h = 0.11 * h
  120.             rect_area[0] = max(0, int(x - padding_w))
  121.             rect_area[1] = max(0, int(y - padding_h))
  122.             rect_area[2] = min(orgimg.shape[1], int(rect_area[2] + padding_w))
  123.             rect_area[3] = min(orgimg.shape[0], int(rect_area[3] + padding_h))
  124.             landmarks = result['landmarks']
  125.             label = result['class']
  126.             # result_str+=result+" "
  127.             for i in range(4):  # 关键点
  128.                 cv2.circle(orgimg, (int(landmarks[i][0]), int(landmarks[i][1])), 5, clors[i], -1)
  129.             cv2.rectangle(orgimg, (rect_area[0], rect_area[1]), (rect_area[2], rect_area[3]), clors[label], 2)  # 画框
  130.             cv2.putText(img, str(label), (rect_area[0], rect_area[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, clors[label], 2)
  131.         return orgimg
  132.     def __del__(self):
  133.         self.detect_model.destroy()
  134. if __name__ == '__main__':
  135.     # ============可视化================
  136.     # img_vis(img, orgimg, pred)
  137.     det = Detect()
  138.     img_dir = "images"
  139.     save_dir = "result"
  140.     if not os.path.exists(save_dir):
  141.         os.makedirs(save_dir)
  142.     for file in os.listdir(img_dir):
  143.         img_path = os.path.join(img_dir, file)
  144.         img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
  145.         dict_list = det.detect(img)
  146.         print(dict_list)
  147.         result_img = det.draw_result(img, dict_list)
  148.         save_dir_path = os.path.join(save_dir, file)
  149.         cv2.imwrite(save_dir_path, result_img)
复制代码
2.4.5 推理结果展示







参考开源

Chinese_license_plate_detection_recognition

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

怀念夏天

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表