Jetson nano部署yolov5车牌检测

一、前言

        Jetson nano不同于其他Linux系统,不能直接pip install torch。也不建议使用conda环境,因为有的库是系统自带的,使用sudo apt-get安装,不会直接安装到虚拟环境。

前后端实现:基于Yolov5使用Jetson nano车牌检测前后端实现

二、安装环境

        查看当前系统版本,python3.8, jetpack4.6

jetson@nano:~$ jtop

        到nvidia 官网下载对应的torch版本传送门  
 

        下载完成后,就可以通过scp命令将下载的文件传到板子上了,因为是共享网络,用arp -a查看板子的ip,就可以传输文件啦。

        切换到板子,安装torch先把numpy更新到1.19版本以上,然后就可以pip install  torch-1.13.0a0+d0d6b1f2.nv22.10-cp38-cp38-linux_aarch64.whl,静静等待安装即可。系统自带opencv,可以不用安装,但是没有pillow库,需要手动安装。

sudo apt install libfreetype6-dev
sudo apt install libtbb-dev libjpeg-dev libtiff-dev libwebp-dev libpng-dev
sudo pip3 install pillow==8.4

        目前opencv版本对于yolov5是足够的,有需求可以自行升级,升级挺麻烦的,又费时间。

        然后把电脑能运行的yolov5项目传到板子上,缺哪个库就装哪个。

三、数据集训练

        使用CCPD数据集进行训练,数据集主要在合肥市某停车场采集得来,采集时间早上7:30到晚上10:00,手工标注车牌位置。拍摄的车牌照片涉及多种复杂环境,包括模糊、倾斜、阴雨天、雪天等等。CCPD数据集一共包含将近30万张图片。数据集链接

        配置car.yaml


train: ./dataset/train/images
val: ./dataset/val/images
# number of classes
nc: 2

# class names
names: [ 'single_plate','double_plate']

        配置yolov5.yaml, nc改为2

python train.py --img 640 --batch 4 --epoch 50 --data data/car.yaml --cfg models/yolov5n.yaml 

        训练完成后,在./runs/detect/exp里面有训练结果,也有训练后的权重。

四、模型推理

def get_plate_rec_landmark(img, xyxy, conf, landmarks, class_num,device,plate_rec_model,is_color=False):  #获取车牌坐标以及四个角点坐标并获取车牌号
    h,w,c = img.shape
    result_dict={}
    tl = 1 or round(0.002 * (h + w) / 2) + 1  # line/font thickness

    x1 = int(xyxy[0])
    y1 = int(xyxy[1])
    x2 = int(xyxy[2])
    y2 = int(xyxy[3])
    height=y2-y1
    landmarks_np=np.zeros((4,2))
    rect=[x1,y1,x2,y2]
    for i in range(4):
        point_x = int(landmarks[2 * i])
        point_y = int(landmarks[2 * i + 1])
        landmarks_np[i]=np.array([point_x,point_y])

    class_label= int(class_num)  #车牌的的类型0代表单牌,1代表双层车牌
    roi_img = four_point_transform(img,landmarks_np)   #透视变换得到车牌小图
    if class_label:        #判断是否是双层车牌,是双牌的话进行分割后然后拼接
        roi_img=get_split_merge(roi_img)
    if not is_color:
        plate_number,rec_prob = get_plate_result(roi_img,device,plate_rec_model,is_color=is_color)                 #对车牌小图进行识别
    else:
        plate_number,rec_prob,plate_color,color_conf=get_plate_result(roi_img,device,plate_rec_model,is_color=is_color) 
    # cv2.imwrite("roi.jpg",roi_img)
    result_dict['rect']=rect                      #车牌roi区域
    result_dict['detect_conf']=conf              #检测区域得分
    result_dict['landmarks']=landmarks_np.tolist() #车牌角点坐标
    result_dict['plate_no']=plate_number   #车牌号
    result_dict['rec_conf']=rec_prob   #每个字符的概率
    result_dict['roi_height']=roi_img.shape[0]  #车牌高度
    result_dict['plate_color']=""
    if is_color:
        result_dict['plate_color']=plate_color   #车牌颜色
        result_dict['color_conf']=color_conf    #颜色得分
    result_dict['plate_type']=class_label   #单双层 0单层 1双层
    
    return result_dict
def detect_Recognition_plate(model, orgimg, device,plate_rec_model,img_size,is_color=False):#获取车牌信息
    # Load model
    # img_size = opt_img_size
    conf_thres = 0.3      #得分阈值
    iou_thres = 0.5       #nms的iou值   
    dict_list=[]
    # orgimg = cv2.imread(image_path)  # BGR
    img0 = copy.deepcopy(orgimg)
    assert orgimg is not None, 'Image Not Found ' 
    h0, w0 = orgimg.shape[:2]  # orig hw
    r = img_size / max(h0, w0)  # resize image to img_size
    if r != 1:  # always resize down, only resize up if training with augmentation
        interp = cv2.INTER_AREA if r < 1  else cv2.INTER_LINEAR
        img0 = cv2.resize(img0, (int(w0 * r), int(h0 * r)), interpolation=interp)

    imgsz = check_img_size(img_size, s=model.stride.max())  # check img_size  

    img = letterbox(img0, new_shape=imgsz)[0]           #检测前处理,图片长宽变为32倍数,比如变为640X640
    # img =process_data(img0)
    # Convert
    img = img[:, :, ::-1].transpose(2, 0, 1).copy()  # BGR to RGB, to 3x416x416  图片的BGR排列转为RGB,然后将图片的H,W,C排列变为C,H,W排列

    # Run inference
    t0 = time.time()

    img = torch.from_numpy(img).to(device)
    img = img.float()  # uint8 to fp16/32
    img /= 255.0  # 0 - 255 to 0.0 - 1.0
    if img.ndimension() == 3:
        img = img.unsqueeze(0)

    # Inference
    # t1 = time_synchronized()/
    pred = model(img)[0]
    # t2=time_synchronized()
    # print(f"infer time is {(t2-t1)*1000} ms")

    # Apply NMS
    pred = non_max_suppression_face(pred, conf_thres, iou_thres)

    # print('img.shape: ', img.shape)
    # print('orgimg.shape: ', orgimg.shape)

    # Process detections
    for i, det in enumerate(pred):  # detections per image
        if len(det):
            # Rescale boxes from img_size to im0 size
            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], orgimg.shape).round()

            # Print results
            for c in det[:, -1].unique():
                n = (det[:, -1] == c).sum()  # detections per class

            det[:, 5:13] = scale_coords_landmarks(img.shape[2:], det[:, 5:13], orgimg.shape).round()

            for j in range(det.size()[0]):
                xyxy = det[j, :4].view(-1).tolist()
                conf = det[j, 4].cpu().numpy()
                landmarks = det[j, 5:13].view(-1).tolist()
                class_num = det[j, 13].cpu().numpy()
                result_dict = get_plate_rec_landmark(orgimg, xyxy, conf, landmarks, class_num,device,plate_rec_model,is_color=is_color)
                dict_list.append(result_dict)
    return dict_list

        运行效果

五、模拟停车场识别

        将红外感应传感器out引脚接在Pin7口,另外两个脚接在5V和GND,当前面有物体时,输出低电平。这就模拟汽车接近时,才会拍照检测。

检测部分代码

    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        print("Error: Could not open video.")
        exit()

    previous_result = []

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        flag = 0
        if frame.shape[-1] == 4:  # 如果图片是4个通道的,将其转为3个通道
            frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR)

        cv2.imshow('Frame', frame)  # 显示当前帧
        key = cv2.waitKey(1) & 0xFF
        if GPIO.input(but_pin) == GPIO.LOW:  # 当红外检测到有车

            time.sleep(0.3)               # 消抖
            if GPIO.input(but_pin) == GPIO.LOW:
                if flag != 1:
                    if frame.shape[-1] == 4:  # 如果图片是4个通道的,将其转为3个通道
                        frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR)
                    dict_list = detect_Recognition_plate(detect_model, frame, device, plate_rec_model, opt.img_size,
                                                         opt.is_color)  # 检测及识别车牌
                    ori_img, result = draw_result(frame, dict_list)  # 将结果画在图上
                    save_img_path = "result/None.jpg"
                    for i in result:
                        if len(i) > 8:
                            current_time = datetime.now().strftime("%Y%m%d%H%M%S")
                            save_img_path = os.path.join(save_path, i + " " + current_time + '.jpg')

                # sanitized_restr = re.sub(r'[\\/:*?"<>|]', '_', restr)  # 替换非法字符
                # save_img_path = os.path.join(save_path, f"{sanitized_restr}_{current_time}.jpg")

                    print("save as", save_img_path)


                    pil_img = Image.fromarray(cv2.cvtColor(ori_img, cv2.COLOR_BGR2RGB))
                    pil_img.save(save_img_path)
                    send_image(save_img_path, url)

                    flag = 1
                while GPIO.input(but_pin) == GPIO.LOW:
                    continue

            # cv2.imshow('Captured Frame', ori_img)  # 显示处理后的帧
        flag = 0  # 清除标志位

        if key == ord('q'):  # 按下'q'键退出
            break

    cap.release()
    cv2.destroyAllWindows()
    GPIO.cleanup()  # cleanup all GPIOs

        逻辑:检测到有物体,也就是低电平,延迟0.3秒,防止误触,再读取是否是低电平,是的话,检测当前帧,保存,发送到后端;死循环等待低电平结束。也就是单片机检测按键的逻辑。

        发送到后端的代码:

def send_image(image_path, url):
    # 读取图像文件并编码为Base64
    with open(image_path, "rb") as image_file:
        encoded_string = base64.b64encode(image_file.read()).decode('utf-8')

    # 构建请求数据
    data = {
        "index": image_path.split("/")[-1],  # 使用文件名作为index
        "img": encoded_string
    }

    # 发送POST请求
    headers = {'Content-Type': 'application/json'}
    response = requests.post(url, headers=headers, data=json.dumps(data))

    # 打印响应
    if response.status_code == 200:
        print("Image uploaded successfully!")
        print("Response:", response.json())
    else:
        print("Failed to upload image.")
        print("Status Code:", response.status_code)
        print("Response:", response.text)

运行结果:

参考开源:Chinese_license_plate_detection_recognition

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLOv5是一种目标检测深度学习算法,它在推理速度和精度上都有较好的性能。要在Jetson Nano上部署YOLOv5目标检测,可以按照以下步骤进行操作: 1. 首先,需要将训练好的YOLOv5s权重文件转换为wts文件格式。然后,使用build工具将wts文件转换为TensorRT的engine文件。这样就可以对输入的Tensors进行加速处理并得到推理的输出结果。\[2\] 2. 在Jetson Nano上部署YOLOv5目标检测,还需要修改文件夹DeepStream-Yolo/external/yolov5/nvdsinfer_custom_impl_Yolo下的文件yololayer.h和yololayer.cu,以使其可以在YOLOv5 V4.0上正常工作。\[3\] 通过以上步骤,你就可以在Jetson Nano上成功部署YOLOv5目标检测算法了。希望对你有所帮助! #### 引用[.reference_title] - *1* *2* [Jetson Nano 部署(1):YOLOv5 目标检测实战介绍](https://blog.csdn.net/weixin_38346042/article/details/126399006)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Jetson Nano部署实现(一)——Yolov5目标检测-Jetson Nano部署](https://blog.csdn.net/qq_40305597/article/details/117320573)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值