赞
踩
最近刚好想研究一下嵌入式方面的知识就看到了香橙派新出的板子 Orange pi AIpro,果断搞来研究一下
昇腾AI技术路线:高性能,低功耗 4核64位处理器 + AI处理器,速度更快,功耗更低,可为各类AI应用场景带来卓越的性能表现。
多通道输出,支持多屏异显:支持双HDMI视频输出,支持双4K高清输出,支持一个MIPI DSI屏输出,支持两个MIPI接口摄像头输入。
丰富接口,易于扩展:汇聚了MIPI DSI、MIPI CSI、USB 3.0、Type-C 3.0、HDMI 2.0、千兆以太网、支持SATA/NVMe SSD 2280的M.2插槽等各类流行的接口,可应用于外部设备控制和扩展。
应用场景广泛 覆盖 AIoT各行各业:可广泛适用于AI教学实训、AI算法验证、智能小车、机械臂、边缘计算、无人机、人工智能、云计算、AR/VR、智能安防、智能家居、智能交通等领域。
可运行openEuler系统:高效、稳定、安全。可运行openEuler系统,支持多种硬件架构和虚拟化技术,可广泛应用于企业级云计算、边缘计算场景等。
正面
背面
物品清单
正面图
背面图
在提交申请后,也是很快就收到了快递包裹,开箱后,有一个快充头和数据线,板子同标准的盒子装着,同时用两块薄海绵包裹着,可以预防静电对板子造成损害
实物颜值非常高,且已经自带了一块32G的TF卡,里面也已经烧录了openeuler镜像系统
开发板默认支持 ubuntu系统和 openeuler系统,由于 TF卡中已经预先烧录好了 openeuler系统,所以下面我就直接使用该系统进行搭建和部署了,熟悉和习惯 ubuntu系统的用户也可以格式化,重新烧录一个 ubuntu系统。
官方也提供了烧录工具
连接电源后,开发板会自动启动
由于手边没有 HDMI 线,我就直接用远程连接的方式连接吧
拿到开发板的 ip
使用 MobaXterm 远程连接
该项目是一个基于深度学习与yolov5 的车牌检测 、车牌识别、中文车牌识别与检测、支持12种中文车牌、支持双层车牌的目标识别系统。
项目开源地址:Chinese_license_plate_detection_recognition
mkdir yolov5
git clone https://github.com/we0091234/Chinese_license_plate_detection_recognition.git
cd Chinese_license_plate_detection_recognition
pip install -r ./requirements.txt -i https://mirrors.aliyun.com/pypi/simple
需要下载的依赖比较多,这里可能需要多等待一下
出现绿色的 Successfully 就代表依赖下载成功了
可以看到文件还是很多的
# -*- coding: UTF-8 -*- import argparse import time from pathlib import Path import os import cv2 import torch import torch.backends.cudnn as cudnn from numpy import random import copy import numpy as np from models.experimental import attempt_load from utils.datasets import letterbox from utils.general import check_img_size, non_max_suppression_face, apply_classifier, scale_coords, xyxy2xywh, \ strip_optimizer, set_logging, increment_path from utils.plots import plot_one_box from utils.torch_utils import select_device, load_classifier, time_synchronized from utils.cv_puttext import cv2ImgAddText from plate_recognition.plate_rec import get_plate_result,allFilePath,init_model,cv_imread # from plate_recognition.plate_cls import cv_imread from plate_recognition.double_plate_split_merge import get_split_merge clors = [(255,0,0),(0,255,0),(0,0,255),(255,255,0),(0,255,255)] danger=['危','险'] def order_points(pts): #四个点按照左上 右上 右下 左下排列 rect = np.zeros((4, 2), dtype = "float32") s = pts.sum(axis = 1) rect[0] = pts[np.argmin(s)] rect[2] = pts[np.argmax(s)] diff = np.diff(pts, axis = 1) rect[1] = pts[np.argmin(diff)] rect[3] = pts[np.argmax(diff)] return rect def four_point_transform(image, pts): #透视变换得到车牌小图 # rect = order_points(pts) rect = pts.astype('float32') (tl, tr, br, bl) = rect widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2)) widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2)) maxWidth = max(int(widthA), int(widthB)) heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2)) heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2)) maxHeight = max(int(heightA), int(heightB)) dst = np.array([ [0, 0], [maxWidth - 1, 0], [maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtype = "float32") M = cv2.getPerspectiveTransform(rect, dst) warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight)) return warped def load_model(weights, device): #加载检测模型 model = attempt_load(weights, map_location=device) # load FP32 model return model def scale_coords_landmarks(img1_shape, coords, img0_shape, ratio_pad=None): #返回到原图坐标 # Rescale coords (xyxy) from img1_shape to img0_shape if ratio_pad is None: # calculate from img0_shape gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding else: gain = ratio_pad[0][0] pad = ratio_pad[1] coords[:, [0, 2, 4, 6]] -= pad[0] # x padding coords[:, [1, 3, 5, 7]] -= pad[1] # y padding coords[:, :8] /= gain #clip_coords(coords, img0_shape) coords[:, 0].clamp_(0, img0_shape[1]) # x1 coords[:, 1].clamp_(0, img0_shape[0]) # y1 coords[:, 2].clamp_(0, img0_shape[1]) # x2 coords[:, 3].clamp_(0, img0_shape[0]) # y2 coords[:, 4].clamp_(0, img0_shape[1]) # x3 coords[:, 5].clamp_(0, img0_shape[0]) # y3 coords[:, 6].clamp_(0, img0_shape[1]) # x4 coords[:, 7].clamp_(0, img0_shape[0]) # y4 # coords[:, 8].clamp_(0, img0_shape[1]) # x5 # coords[:, 9].clamp_(0, img0_shape[0]) # y5 return coords 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 # cv2.imwrite('result.jpg', orgimg) def draw_result(orgimg,dict_list,is_color=False): # 车牌结果画出来 result_str ="" for result in dict_list: rect_area = result['rect'] x,y,w,h = rect_area[0],rect_area[1],rect_area[2]-rect_area[0],rect_area[3]-rect_area[1] padding_w = 0.05*w padding_h = 0.11*h rect_area[0]=max(0,int(x-padding_w)) rect_area[1]=max(0,int(y-padding_h)) rect_area[2]=min(orgimg.shape[1],int(rect_area[2]+padding_w)) rect_area[3]=min(orgimg.shape[0],int(rect_area[3]+padding_h)) height_area = result['roi_height'] landmarks=result['landmarks'] result_p = result['plate_no'] if result['plate_type']==0:#单层 result_p+=" "+result['plate_color'] else: #双层 result_p+=" "+result['plate_color']+"双层" result_str+=result_p+" " for i in range(4): #关键点 cv2.circle(orgimg, (int(landmarks[i][0]), int(landmarks[i][1])), 5, clors[i], -1) cv2.rectangle(orgimg,(rect_area[0],rect_area[1]),(rect_area[2],rect_area[3]),(0,0,255),2) #画框 labelSize = cv2.getTextSize(result_p,cv2.FONT_HERSHEY_SIMPLEX,0.5,1) #获得字体的大小 if rect_area[0]+labelSize[0][0]>orgimg.shape[1]: #防止显示的文字越界 rect_area[0]=int(orgimg.shape[1]-labelSize[0][0]) orgimg=cv2.rectangle(orgimg,(rect_area[0],int(rect_area[1]-round(1.6*labelSize[0][1]))),(int(rect_area[0]+round(1.2*labelSize[0][0])),rect_area[1]+labelSize[1]),(255,255,255),cv2.FILLED)#画文字框,背景白色 if len(result)>=1: orgimg=cv2ImgAddText(orgimg,result_p,rect_area[0],int(rect_area[1]-round(1.6*labelSize[0][1])),(0,0,0),21) # orgimg=cv2ImgAddText(orgimg,result_p,rect_area[0]-height_area,rect_area[1]-height_area-10,(0,255,0),height_area) print(result_str) return orgimg def get_second(capture): if capture.isOpened(): rate = capture.get(5) # 帧速率 FrameNumber = capture.get(7) # 视频文件的帧数 duration = FrameNumber/rate # 帧速率/视频总帧数 是时间,除以60之后单位是分钟 return int(rate),int(FrameNumber),int(duration) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--detect_model', nargs='+', type=str, default='weights/plate_detect.pt', help='model.pt path(s)') #检测模型 parser.add_argument('--rec_model', type=str, default='weights/plate_rec_color.pth', help='model.pt path(s)')#车牌识别+颜色识别模型 parser.add_argument('--is_color',type=bool,default=True,help='plate color') #是否识别颜色 parser.add_argument('--image_path', type=str, default='imgs', help='source') #图片路径 parser.add_argument('--img_size', type=int, default=640, help='inference size (pixels)') #网络输入图片大小 parser.add_argument('--output', type=str, default='result', help='source') #图片结果保存的位置 parser.add_argument('--video', type=str, default='', help='source') #视频的路径 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") #使用gpu还是cpu进行识别 # device =torch.device("cpu") opt = parser.parse_args() print(opt) save_path = opt.output count=0 if not os.path.exists(save_path): os.mkdir(save_path) detect_model = load_model(opt.detect_model, device) #初始化检测模型 plate_rec_model=init_model(device,opt.rec_model,is_color=opt.is_color) #初始化识别模型 #算参数量 total = sum(p.numel() for p in detect_model.parameters()) total_1 = sum(p.numel() for p in plate_rec_model.parameters()) print("detect params: %.2fM,rec params: %.2fM" % (total/1e6,total_1/1e6)) # plate_color_model =init_color_model(opt.color_model,device) time_all = 0 time_begin=time.time() if not opt.video: #处理图片 if not os.path.isfile(opt.image_path): #目录 file_list=[] allFilePath(opt.image_path,file_list) #将这个目录下的所有图片文件路径读取到file_list里面 for img_path in file_list: #遍历图片文件 print(count,img_path,end=" ") time_b = time.time() #开始时间 img =cv_imread(img_path) #opencv 读取图片 if img is None: continue if img.shape[-1]==4: #图片如果是4个通道的,将其转为3个通道 img=cv2.cvtColor(img,cv2.COLOR_BGRA2BGR) # detect_one(model,img_path,device) dict_list=detect_Recognition_plate(detect_model, img, device,plate_rec_model,opt.img_size,is_color=opt.is_color)#检测以及识别车牌 ori_img=draw_result(img,dict_list) #将结果画在图上 img_name = os.path.basename(img_path) save_img_path = os.path.join(save_path,img_name) #图片保存的路径 time_e=time.time() time_gap = time_e-time_b #计算单个图片识别耗时 if count: time_all+=time_gap cv2.imwrite(save_img_path,ori_img) #opencv将识别的图片保存 count+=1 print(f"sumTime time is {time.time()-time_begin} s, average pic time is {time_all/(len(file_list)-1)}") else: #单个图片 print(count,opt.image_path,end=" ") img =cv_imread(opt.image_path) if img.shape[-1]==4: img=cv2.cvtColor(img,cv2.COLOR_BGRA2BGR) # detect_one(model,img_path,device) dict_list=detect_Recognition_plate(detect_model, img, device,plate_rec_model,opt.img_size,is_color=opt.is_color) ori_img=draw_result(img,dict_list) img_name = os.path.basename(opt.image_path) save_img_path = os.path.join(save_path,img_name) cv2.imwrite(save_img_path,ori_img) else: #处理视频 video_name = opt.video capture=cv2.VideoCapture(video_name) fourcc = cv2.VideoWriter_fourcc(*'MP4V') fps = capture.get(cv2.CAP_PROP_FPS) # 帧数 width, height = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 宽高 out = cv2.VideoWriter('result.mp4', fourcc, fps, (width, height)) # 写入视频 frame_count = 0 fps_all=0 rate,FrameNumber,duration=get_second(capture) if capture.isOpened(): while True: t1 = cv2.getTickCount() frame_count+=1 print(f"第{frame_count} 帧",end=" ") ret,img=capture.read() if not ret: break # if frame_count%rate==0: img0 = copy.deepcopy(img) dict_list=detect_Recognition_plate(detect_model, img, device,plate_rec_model,opt.img_size,is_color=opt.is_color) ori_img=draw_result(img,dict_list) t2 =cv2.getTickCount() infer_time =(t2-t1)/cv2.getTickFrequency() fps=1.0/infer_time fps_all+=fps str_fps = f'fps:{fps:.4f}' cv2.putText(ori_img,str_fps,(20,20),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2) # cv2.imshow("haha",ori_img) # cv2.waitKey(1) out.write(ori_img) # current_time = int(frame_count/FrameNumber*duration) # sec = current_time%60 # minute = current_time//60 # for result_ in result_list: # plate_no = result_['plate_no'] # if not is_car_number(pattern_str,plate_no): # continue # print(f'车牌号:{plate_no},时间:{minute}分{sec}秒') # time_str =f'{minute}分{sec}秒' # writer.writerow({"车牌":plate_no,"时间":time_str}) # out.write(ori_img) else: print("失败") capture.release() out.release() cv2.destroyAllWindows() print(f"all frame is {frame_count},average fps is {fps_all/frame_count} fps")
result_dict
用于存储结果。NumPy
数组 landmarks_np
用于存储车牌的四个角点坐标。landmarks
(车牌角点坐标列表),将每个角点坐标(x, y)存入 landmarks_np
。class_num
获取车牌类型(0代表单牌,1代表双层车牌)。four_point_transform
函数(需要预先定义或导入)对车牌区域进行透视变换,得到车牌的正面视图 roi_img
。class_label
为1),则调用 get_split_merge
函数(需要预先定义或导入)对车牌小图进行分割和合并处理。is_color
参数决定是否需要识别车牌颜色。get_plate_result
函数(需要预先定义或导入)对车牌小图roi_img进行识别,获取车牌号 plate_number
、识别概率 rec_prob
,以及(如果 is_color
为 True
)车牌颜色 plate_color
和颜色置信度 color_conf
。plate_number
、识别概率 rec_prob
、车牌高度 roi_img.shape[0]
、车牌颜色(如果 is_color
为True)以及车牌类型 class_label
等信息存入result_dict。result_dict
。需要下载一定量的数据集,项目的作者有提供,需要的可以联系项目作者,格式为 yolov5 格式
label x y w h pt1x pt1y pt2x pt2y pt3x pt3y pt4x pt4y
自己的数据集可以通过lablme 软件,create polygons标注车牌四个点即可,然后通过json2yolo.py 将数据集转为yolo格式,也可进行训练
data/widerface.yaml
train
和 val
路径,换成你的数据路径train: /your/train/path #修改成你的训练集路径
val: /your/val/path #修改成你的验证集路径
# number of classes
nc: 2 #这里用的是2分类,0 单层车牌 1 双层车牌
# class names
names: [ 'single','double']
python3 train.py --data data/widerface.yaml --cfg models/yolov5n-0.5.yaml --weights weights/plate_detect.pt --epoch 120
下载数据集
数据集可以自己收集,或者找项目作者提供
数据集打上标签,生成train.txt和val.txt
图片命名如上图:车牌号_序号.jpg 然后执行如下命令,得到 train.txt
和 val.txt
python plateLabel.py --image_path your/train/img/path/ --label_file datasets/train.txt
python plateLabel.py --image_path your/val/img/path/ --label_file datasets/val.txt
数据格式如下:
train.txt
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_ALL/冀BAJ731_3.jpg 5 53 52 60 49 45 43
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_ALL/冀BD387U_2454.jpg 5 53 55 45 50 49 70
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_ALL/冀BG150C_3.jpg 5 53 58 43 47 42 54
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖A656V3_8090.jpg 13 52 48 47 48 71 45
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖C91546_7979.jpg 13 54 51 43 47 46 48
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖G88950_1540.jpg 13 58 50 50 51 47 42
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖GX9Y56_2113.jpg 13 58 73 51 74 47 48
train.txt
val.txt
路径写入 lib/config/360CC_config.yaml
中DATASET:
DATASET: 360CC
ROOT: ""
CHAR_FILE: 'lib/dataset/txt/plate2.txt'
JSON_FILE: {'train': 'datasets/train.txt', 'val': 'datasets/val.txt'}
python train.py --cfg lib/config/360CC_config.yaml
项目基础图片集
项目中已经预先存放了一些车牌图片,我们可以使用这些图片来测试一下
执行图片检测命令
python detect_plate.py --detect_model weights/plate_detect.pt --rec_model weights/plate_rec_color.pth --image_path imgs --output result
输入完命令后,大约在3秒后,程序持续输出识别结果,可以看到程序的启动速度还是挺快了,总共的识别时间在8.5秒左右,平均一张图片的识别速度在0.5秒左右,这速度已经是相当的快了
yolov2车牌识别视频
视频截图:
视频时间长度在 54 秒左右,视频类型为 mp4,视频内容主要是以行驶中的车尾视角拍摄马路上的车辆。
上传视频到项目文件中
我连接软件用的 MobaXterm,不知道为什么,上传文件总是会卡住,没办法,只能用 Xftp 再连接一次然后上传视频了
执行视频检测命令
python detect_plate.py --detect_model weights/plate_detect.pt --rec_model weights/plate_rec_color.pth --video 2.mp4
输入执行命令后,系统大约在 5 秒后启动了,然后将视频分帧处理
处理过程中ing
视频的后半部分就已经没有车了,处理显示的也都是空帧,就没有任何意义了,这里就不进行展示了。
可以看到,54 秒的视频,共划分了 1501 帧,香橙派 Orange pi AIpro 这块板子,处理速度在 2.7 fps 左右,相对比其他开发板子来说,速度已经可以了。
出了点问题。如果源镜像曾被压缩过,请检查它是否已损坏。
The writer process ended unexpectedly
直接点击跳过即可
sudo setcap cap_net_raw+p /bin/ping
成功解决
使用下来体验感还挺好的,板子在通电启动后,5秒内散热风扇的噪音还是比较大的,5秒后,声音就变的很小了,后续即使在跑项目的时候,声音也没有较大的变化,散热做的也非常的好,整体体验下来板子的温度一直维持在一个正常的温度,没有出现温度过高的情况。
除了个人体验外,OrangePi AIpro 凭借其卓越的即插即用特性,极大地加速了开发进程。通过简单的配置步骤,省去了繁琐的硬件调试环节。在软件生态方面,香橙派社区构建了一个资源丰富、文档详尽的生态系统,对初学者来说可以轻松访问并选用适合的文字识别模型和框架,通过直观易懂的指南,快速部署至开发板上。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。