onnx_infer.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import onnxruntime
  2. import numpy as np
  3. import cv2
  4. import copy
  5. import os
  6. import argparse
  7. from PIL import Image, ImageDraw, ImageFont
  8. import time
  9. plate_color_list=['黑色','蓝色','绿色','白色','黄色']
  10. plateName=r"#京沪津渝冀晋蒙辽吉黑苏浙皖闽赣鲁豫鄂湘粤桂琼川贵云藏陕甘青宁新学警港澳挂使领民航危0123456789ABCDEFGHJKLMNPQRSTUVWXYZ险品"
  11. mean_value,std_value=((0.588,0.193))#识别模型均值标准差
  12. def decodePlate(preds): #识别后处理
  13. pre=0
  14. newPreds=[]
  15. for i in range(len(preds)):
  16. if preds[i]!=0 and preds[i]!=pre:
  17. newPreds.append(preds[i])
  18. pre=preds[i]
  19. plate=""
  20. for i in newPreds:
  21. plate+=plateName[int(i)]
  22. return plate
  23. # return newPreds
  24. def rec_pre_precessing(img,size=(48,168)): #识别前处理
  25. img =cv2.resize(img,(168,48))
  26. img = img.astype(np.float32)
  27. img = (img/255-mean_value)/std_value #归一化 减均值 除标准差
  28. img = img.transpose(2,0,1) #h,w,c 转为 c,h,w
  29. img = img.reshape(1,*img.shape) #channel,height,width转为batch,channel,height,channel
  30. return img
  31. def get_plate_result(img,session_rec): #识别后处理
  32. img =rec_pre_precessing(img)
  33. y_onnx_plate,y_onnx_color = session_rec.run([session_rec.get_outputs()[0].name,session_rec.get_outputs()[1].name], {session_rec.get_inputs()[0].name: img})
  34. index =np.argmax(y_onnx_plate,axis=-1)
  35. index_color = np.argmax(y_onnx_color)
  36. plate_color = plate_color_list[index_color]
  37. # print(y_onnx[0])
  38. plate_no = decodePlate(index[0])
  39. return plate_no,plate_color
  40. def allFilePath(rootPath,allFIleList): #遍历文件
  41. fileList = os.listdir(rootPath)
  42. for temp in fileList:
  43. if os.path.isfile(os.path.join(rootPath,temp)):
  44. allFIleList.append(os.path.join(rootPath,temp))
  45. else:
  46. allFilePath(os.path.join(rootPath,temp),allFIleList)
  47. def get_split_merge(img): #双层车牌进行分割后识别
  48. h,w,c = img.shape
  49. img_upper = img[0:int(5/12*h),:]
  50. img_lower = img[int(1/3*h):,:]
  51. img_upper = cv2.resize(img_upper,(img_lower.shape[1],img_lower.shape[0]))
  52. new_img = np.hstack((img_upper,img_lower))
  53. return new_img
  54. def order_points(pts): # 关键点排列 按照(左上,右上,右下,左下)的顺序排列
  55. rect = np.zeros((4, 2), dtype = "float32")
  56. s = pts.sum(axis = 1)
  57. rect[0] = pts[np.argmin(s)]
  58. rect[2] = pts[np.argmax(s)]
  59. diff = np.diff(pts, axis = 1)
  60. rect[1] = pts[np.argmin(diff)]
  61. rect[3] = pts[np.argmax(diff)]
  62. return rect
  63. def four_point_transform(image, pts): #透视变换得到矫正后的图像,方便识别
  64. rect = order_points(pts)
  65. (tl, tr, br, bl) = rect
  66. widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
  67. widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
  68. maxWidth = max(int(widthA), int(widthB))
  69. heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
  70. heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
  71. maxHeight = max(int(heightA), int(heightB))
  72. dst = np.array([
  73. [0, 0],
  74. [maxWidth - 1, 0],
  75. [maxWidth - 1, maxHeight - 1],
  76. [0, maxHeight - 1]], dtype = "float32")
  77. M = cv2.getPerspectiveTransform(rect, dst)
  78. warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
  79. # return the warped image
  80. return warped
  81. def my_letter_box(img,size=(640,640)): #
  82. h,w,c = img.shape
  83. r = min(size[0]/h,size[1]/w)
  84. new_h,new_w = int(h*r),int(w*r)
  85. top = int((size[0]-new_h)/2)
  86. left = int((size[1]-new_w)/2)
  87. bottom = size[0]-new_h-top
  88. right = size[1]-new_w-left
  89. img_resize = cv2.resize(img,(new_w,new_h))
  90. img = cv2.copyMakeBorder(img_resize,top,bottom,left,right,borderType=cv2.BORDER_CONSTANT,value=(114,114,114))
  91. return img,r,left,top
  92. def xywh2xyxy(boxes): #xywh坐标变为 左上 ,右下坐标 x1,y1 x2,y2
  93. xywh =copy.deepcopy(boxes)
  94. xywh[:,0]=boxes[:,0]-boxes[:,2]/2
  95. xywh[:,1]=boxes[:,1]-boxes[:,3]/2
  96. xywh[:,2]=boxes[:,0]+boxes[:,2]/2
  97. xywh[:,3]=boxes[:,1]+boxes[:,3]/2
  98. return xywh
  99. def my_nms(boxes,iou_thresh): #nms
  100. index = np.argsort(boxes[:,4])[::-1]
  101. keep = []
  102. while index.size >0:
  103. i = index[0]
  104. keep.append(i)
  105. x1=np.maximum(boxes[i,0],boxes[index[1:],0])
  106. y1=np.maximum(boxes[i,1],boxes[index[1:],1])
  107. x2=np.minimum(boxes[i,2],boxes[index[1:],2])
  108. y2=np.minimum(boxes[i,3],boxes[index[1:],3])
  109. w = np.maximum(0,x2-x1)
  110. h = np.maximum(0,y2-y1)
  111. inter_area = w*h
  112. union_area = (boxes[i,2]-boxes[i,0])*(boxes[i,3]-boxes[i,1])+(boxes[index[1:],2]-boxes[index[1:],0])*(boxes[index[1:],3]-boxes[index[1:],1])
  113. iou = inter_area/(union_area-inter_area)
  114. idx = np.where(iou<=iou_thresh)[0]
  115. index = index[idx+1]
  116. return keep
  117. def restore_box(boxes,r,left,top): #返回原图上面的坐标
  118. boxes[:,[0,2,5,7,9,11]]-=left
  119. boxes[:,[1,3,6,8,10,12]]-=top
  120. boxes[:,[0,2,5,7,9,11]]/=r
  121. boxes[:,[1,3,6,8,10,12]]/=r
  122. return boxes
  123. def detect_pre_precessing(img,img_size): #检测前处理
  124. img,r,left,top=my_letter_box(img,img_size)
  125. # cv2.imwrite("1.jpg",img)
  126. img =img[:,:,::-1].transpose(2,0,1).copy().astype(np.float32)
  127. img=img/255
  128. img=img.reshape(1,*img.shape)
  129. return img,r,left,top
  130. def post_precessing(dets,r,left,top,conf_thresh=0.3,iou_thresh=0.5):#检测后处理
  131. choice = dets[:,:,4]>conf_thresh
  132. dets=dets[choice]
  133. dets[:,13:15]*=dets[:,4:5]
  134. box = dets[:,:4]
  135. boxes = xywh2xyxy(box)
  136. score= np.max(dets[:,13:15],axis=-1,keepdims=True)
  137. index = np.argmax(dets[:,13:15],axis=-1).reshape(-1,1)
  138. output = np.concatenate((boxes,score,dets[:,5:13],index),axis=1)
  139. reserve_=my_nms(output,iou_thresh)
  140. output=output[reserve_]
  141. output = restore_box(output,r,left,top)
  142. return output
  143. def rec_plate(outputs,img0,session_rec): #识别车牌
  144. dict_list=[]
  145. for output in outputs:
  146. result_dict={}
  147. rect=output[:4].tolist()
  148. land_marks = output[5:13].reshape(4,2)
  149. roi_img = four_point_transform(img0,land_marks)
  150. label = int(output[-1])
  151. score = output[4]
  152. if label==1: #代表是双层车牌
  153. roi_img = get_split_merge(roi_img)
  154. plate_no,plate_color = get_plate_result(roi_img,session_rec)
  155. result_dict['rect']=rect
  156. result_dict['landmarks']=land_marks.tolist()
  157. result_dict['plate_no']=plate_no
  158. result_dict['roi_height']=roi_img.shape[0]
  159. result_dict['plate_color']=plate_color
  160. dict_list.append(result_dict)
  161. return dict_list
  162. def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20): #将识别结果画在图上
  163. if (isinstance(img, np.ndarray)): #判断是否OpenCV图片类型
  164. img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
  165. draw = ImageDraw.Draw(img)
  166. fontText = ImageFont.truetype(
  167. "fonts/platech.ttf", textSize, encoding="utf-8")
  168. draw.text((left, top), text, textColor, font=fontText)
  169. return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
  170. def draw_result(orgimg,dict_list):
  171. result_str =""
  172. for result in dict_list:
  173. rect_area = result['rect']
  174. x,y,w,h = rect_area[0],rect_area[1],rect_area[2]-rect_area[0],rect_area[3]-rect_area[1]
  175. padding_w = 0.05*w
  176. padding_h = 0.11*h
  177. rect_area[0]=max(0,int(x-padding_w))
  178. rect_area[1]=min(orgimg.shape[1],int(y-padding_h))
  179. rect_area[2]=max(0,int(rect_area[2]+padding_w))
  180. rect_area[3]=min(orgimg.shape[0],int(rect_area[3]+padding_h))
  181. height_area = result['roi_height']
  182. landmarks=result['landmarks']
  183. result = result['plate_no']
  184. result_str+=result+" "
  185. for i in range(4): #关键点
  186. cv2.circle(orgimg, (int(landmarks[i][0]), int(landmarks[i][1])), 5, clors[i], -1)
  187. cv2.rectangle(orgimg,(rect_area[0],rect_area[1]),(rect_area[2],rect_area[3]),(255,255,0),2) #画框
  188. if len(result)>=1:
  189. orgimg=cv2ImgAddText(orgimg,result,rect_area[0]-height_area,rect_area[1]-height_area-10,(0,255,0),height_area)
  190. print(result_str)
  191. return orgimg
  192. if __name__ == "__main__":
  193. begin = time.time()
  194. parser = argparse.ArgumentParser()
  195. parser.add_argument('--detect_model',type=str, default=r'weights/plate_detect.onnx', help='model.pt path(s)') #检测模型
  196. parser.add_argument('--rec_model', type=str, default='weights/plate_rec_color.onnx', help='model.pt path(s)')#识别模型
  197. parser.add_argument('--image_path', type=str, default='imgs', help='source')
  198. parser.add_argument('--img_size', type=int, default=640, help='inference size (pixels)')
  199. parser.add_argument('--output', type=str, default='result1', help='source')
  200. opt = parser.parse_args()
  201. file_list = []
  202. allFilePath(opt.image_path,file_list)
  203. providers = ['CPUExecutionProvider']
  204. clors = [(255,0,0),(0,255,0),(0,0,255),(255,255,0),(0,255,255)]
  205. img_size = (opt.img_size,opt.img_size)
  206. session_detect = onnxruntime.InferenceSession(opt.detect_model, providers=providers )
  207. session_rec = onnxruntime.InferenceSession(opt.rec_model, providers=providers )
  208. if not os.path.exists(opt.output):
  209. os.mkdir(opt.output)
  210. save_path = opt.output
  211. count = 0
  212. for pic_ in file_list:
  213. count+=1
  214. print(count,pic_,end=" ")
  215. img=cv2.imread(pic_)
  216. img0 = copy.deepcopy(img)
  217. img,r,left,top = detect_pre_precessing(img,img_size) #检测前处理
  218. # print(img.shape)
  219. y_onnx = session_detect.run([session_detect.get_outputs()[0].name], {session_detect.get_inputs()[0].name: img})[0]
  220. outputs = post_precessing(y_onnx,r,left,top) #检测后处理
  221. result_list=rec_plate(outputs,img0,session_rec)
  222. ori_img = draw_result(img0,result_list)
  223. img_name = os.path.basename(pic_)
  224. save_img_path = os.path.join(save_path,img_name)
  225. cv2.imwrite(save_img_path,ori_img)
  226. print(f"总共耗时{time.time()-begin} s")