AIlib2/AI.py

970 lines
43 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import cv2,os,time,json
from models.experimental import attempt_load
from segutils.segmodel import SegModel,get_largest_contours
from segutils.trtUtils import segtrtEval,yolov5Trtforward,OcrTrtForward
from segutils.trafficUtils import tracfficAccidentMixFunction
from utils.torch_utils import select_device
from utilsK.queRiver import get_labelnames, img_pad, getDetections, getDetectionsFromPreds, scale_back
from utilsK.jkmUtils import pre_process, post_process, get_return_data
from trackUtils.sort import moving_average_wang
from utils.datasets import letterbox
from utils.general import non_max_suppression, scale_coords,xyxy2xywh,overlap_box_suppression
from utils.plots import draw_painting_joint,get_label_arrays
import numpy as np
import torch
import math
from PIL import Image
import torch.nn.functional as F
from copy import deepcopy
from scipy import interpolate
import glob
from loguru import logger
def get_images_videos(impth, imageFixs=['.jpg','.JPG','.PNG','.png'],videoFixs=['.MP4','.mp4','.avi']):
imgpaths=[];###获取文件里所有的图像
videopaths=[]###获取文件里所有的视频
if os.path.isdir(impth):
for postfix in imageFixs:
imgpaths.extend(glob.glob('%s/*%s'%(impth,postfix )) )
for postfix in videoFixs:
videopaths.extend(glob.glob('%s/*%s'%(impth,postfix )) )
else:
postfix = os.path.splitext(impth)[-1]
if postfix in imageFixs: imgpaths=[ impth ]
if postfix in videoFixs: videopaths = [impth ]
print('%s: test Images:%d , test videos:%d '%(impth, len(imgpaths), len(videopaths)))
return imgpaths,videopaths
def xywh2xy(box,iW=None,iH=None):
xc,yc,w,h = box[0:4]
x0 =max(0, xc-w/2.0)
x1 =min(1, xc+w/2.0)
y0=max(0, yc-h/2.0)
y1=min(1,yc+h/2.0)
if iW: x0,x1 = x0*iW,x1*iW
if iH: y0,y1 = y0*iH,y1*iH
return [x0,y0,x1,y1]
def get_ms(t2,t1):
return (t2-t1)*1000.0
def get_postProcess_para(parfile):
with open(parfile) as fp:
par = json.load(fp)
assert 'post_process' in par.keys(), ' parfile has not key word:post_process'
parPost=par['post_process']
return parPost["conf_thres"],parPost["iou_thres"],parPost["classes"],parPost["rainbows"]
def get_postProcess_para_dic(parfile):
with open(parfile) as fp:
par = json.load(fp)
parPost=par['post_process']
return parPost
def score_filter_byClass(pdetections,score_para_2nd):
ret=[]
for det in pdetections:
score,cls = det[4],det[5]
if int(cls) in score_para_2nd.keys():
score_th = score_para_2nd[int(cls)]
elif str(int(cls)) in score_para_2nd.keys():
score_th = score_para_2nd[str(int(cls))]
else:
score_th = 0.25
if score > score_th:
ret.append(det)
return ret
# 按类过滤
def filter_byClass(pdetections, fiterList):
ret = []
for det in pdetections:
score, cls = det[4], det[5]
if int(cls) in fiterList:
continue
elif str(int(cls)) in fiterList:
continue
else:
ret.append(det)
return ret
# 对ocr识别车牌格式化处理
def plat_format(ocr):
carDct = ['','','','','','','','','','','','','','','','',\
'','','','','','','','','','','','','','','','使','']
label = ocr[0]
# print(label)
label = list(filter(lambda x: (ord(x) > 19968 and ord(x) < 63865) or (ord(x) > 96 and ord(x) < 123)
or (ord(x) > 47 and ord(x) < 58) or (ord(x) in [33, 73, 65281]), label))
def spt(x):
if x in ['I', 'i', '!', '']:
return '1'
else:
return x
label = list(map(spt, label))
if len(label) < 7 or len(label) >8:
return None
if not label[0] in carDct:
return None
label.insert(2, '')
label = ' '.join(label)
# label = label.split('I','1').split('!','1').split('i','1').split('','1')
# label = label.split('I','1').split('!','1').split('i','1').split('','1
return label.upper()
def post_process_det(pred,padInfos,img,im0s,conf_thres,iou_thres,label_arraylist,rainbows,font,score_byClass,fiterList,ovlap_thres=None):
time0 = time.time()
pred = non_max_suppression(pred, conf_thres, iou_thres, classes=None, agnostic=False)
if ovlap_thres:
pred = overlap_box_suppression(pred, ovlap_thres)
time1 = time.time()
det = pred[0] ###一次检测一张图片
det_xywh = [];
im0 = im0s.copy()
#im0 = im0s[0]
if len(det) > 0:
# Rescale boxes from img_size to im0 size
if not padInfos:
det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
else:
# print('####line131:',det[:, :])
det[:, :4] = scale_back(det[:, :4], padInfos).round()
for *xyxy, conf, cls in reversed(det):
cls_c = cls.cpu().numpy()
conf_c = conf.cpu().numpy()
tt = [int(x.cpu()) for x in xyxy]
if fiterList:
if int(cls) in fiterList: ###如果不是所需要的目标,则不显示
continue
if score_byClass:
if int(cls) in score_byClass.keys():
if conf < score_byClass[int(cls)]:
continue
line = [*tt, float(conf_c), float(cls_c)] # label format
det_xywh.append(line)
time2 = time.time()
strout='nms:%s ,detDraw:%s '%(get_ms(time0,time1), get_ms(time1,time2) )
return [im0s[0],im0s[0], det_xywh, 10],strout
def post_process_seg(im0s,segmodel,boxes,ksize):
time0 = time.time()
im0 = im0s[0].copy()
segmodel.set_image(im0s[0])
# # 创建一个空白掩码用于保存所有火焰
# combined_mask = np.zeros((im0.shape[0], im0.shape[1]), dtype=np.uint8)
# # 创建边缘可视化图像
# edge_image = np.zeros_like(im0s[0])
# 处理每个火焰检测框
det_xywhP = []
for box in boxes:
x_min, y_min, x_max, y_max = box[:4]
# 转换为SAM需要的格式
input_box = np.array([x_min, y_min, x_max, y_max])
# 使用框提示进行分割
masks, _, _ = segmodel.predict(
box=input_box,
multimask_output=False # 只返回最佳掩码
)
# 获取分割掩码
flame_mask = masks[0].astype(np.uint8)
# 使用形态学操作填充小孔洞
filled_mask = cv2.morphologyEx(flame_mask, cv2.MORPH_CLOSE, ksize)
# 查找所有轮廓(包括内部小点)
contours, _ = cv2.findContours(filled_mask.astype(np.uint8),
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 0:
continue
largest_contour = max(contours, key=cv2.contourArea)
# 通过轮廓填充。
#cv2.drawContours(im0, [largest_contour], -1, (0, 0, 255), 2)
box.append(largest_contour)
det_xywhP.append(box)
time1 = time.time()
strout = 'segDraw:%s ' % get_ms(time0, time1)
return [im0s[0], im0s[0], det_xywhP, 10], strout
def AI_process(im0s, model, segmodel, names, label_arraylist, rainbows,
objectPar={'half': True, 'device': 'cuda:0', 'conf_thres': 0.25, 'iou_thres': 0.45,
'segRegionCnt': 1, 'trtFlag_det': False,'trtFlag_seg': False,'score_byClass':None,'fiterList':[]},
font={'line_thickness': None, 'fontSize': None, 'boxLine_thickness': None,
'waterLineColor': (0, 255, 255), 'waterLineWidth': 3},
segPar={'modelSize': (640, 360), 'mean': (0.485, 0.456, 0.406), 'std': (0.229, 0.224, 0.225),
'numpy': False, 'RGB_convert_first': True}, mode='others', postPar=None):
# 输入参数
# im0s---原始图像列表
# model---检测模型segmodel---分割模型如若没有用到则为None
#
#输出:两个元素(列表,字符)构成的元组,[im0s[0],im0,det_xywh,iframe],strout
# [im0s[0],im0,det_xywh,iframe]中,
# im0s[0]--原始图像im0--AI处理后的图像,iframe--帧号/暂时不需用到。
# det_xywh--检测结果,是一个列表。
# 其中每一个元素表示一个目标构成如:[ xc,yc,w,h, float(conf_c),float(cls_c) ] ,2023.08.03修改输出格式
# #cls_c--类别如0,1,2,3; xc,yc,w,h--中心点坐标及宽conf_c--得分, 取值范围在0-1之间
# #strout---统计AI处理个环节的时间
# Letterbox
half, device, conf_thres, iou_thres, fiterList,score_byClass = objectPar['half'], objectPar['device'], objectPar['conf_thres'], \
objectPar['iou_thres'], objectPar['fiterList'], objectPar['score_byClass']
trtFlag_det, trtFlag_seg, segRegionCnt = objectPar['trtFlag_det'], objectPar['trtFlag_seg'], objectPar[
'segRegionCnt']
time0 = time.time()
if trtFlag_det:
img, padInfos = img_pad(im0s[0], size=(640,640,3)) ;img = [img]
else:
#print('####line72:',im0s[0][10:12,10:12,2])
img = [letterbox(x, 640, auto=True, stride=32)[0] for x in im0s];padInfos=None
#print('####line74:',img[0][10:12,10:12,2])
# Stack
img = np.stack(img, 0)
# Convert
img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to bsx3x416x416
img = np.ascontiguousarray(img)
img = torch.from_numpy(img).to(device)
img = img.half() if half else img.float() # uint8 to fp16/32
img /= 255.0
time01 = time.time()
if segmodel:
seg_pred,segstr = segmodel.eval(im0s[0])
segFlag=True
else:
seg_pred = None;segFlag=False;segstr='Not implemented'
time1=time.time()
if trtFlag_det:
pred = yolov5Trtforward(model,img)
else:
#print('####line96:',img[0,0,10:12,10:12])
pred = model(img,augment=False)[0]
time2=time.time()
p_result, timeOut = getDetectionsFromPreds(pred, img, im0s[0], conf_thres=conf_thres, iou_thres=iou_thres,
ovlap_thres=None, padInfos=padInfos)
# if mode=='highWay3.0':
# if segmodel:
if segPar and segPar['mixFunction']['function']:
mixFunction = segPar['mixFunction']['function'];H,W = im0s[0].shape[0:2]
parMix = segPar['mixFunction']['pars'];#print('###line117:',parMix,p_result[2])
parMix['imgSize'] = (W,H)
#print(' -----------line110: ',p_result[2] ,'\n', seg_pred)
p_result[2] , timeMixPost= mixFunction(p_result[2], seg_pred, pars=parMix )
#print(' -----------line112: ',p_result[2] )
p_result.append(seg_pred)
else:
timeMixPost = ':0 ms'
# print('#### line121: segstr:%s timeMixPost:%s timeOut:%s'%( segstr.strip(), timeMixPost,timeOut ))
time_info = 'letterbox:%.1f, seg:%.1f , infer:%.1f,%s, seginfo:%s ,timeMixPost:%s ' % (
(time01 - time0) * 1000, (time1 - time01) * 1000, (time2 - time1) * 1000, timeOut, segstr.strip(), timeMixPost)
if fiterList:
p_result[2] = filter_byClass(p_result[2], fiterList)
if score_byClass:
p_result[2] = score_filter_byClass(p_result[2], score_byClass)
print('-' * 10, p_result[2])
return p_result, time_info
def default_mix(predlist, par):
return predlist[0], ''
def AI_process_N(im0s, modelList, postProcess,score_byClass=None,fiterList=[]):
# 输入参数
## im0s---原始图像列表
## modelList--所有的模型
# postProcess--字典{},包括后处理函数,及其参数
#输出参数
##ret[0]--检测结果;
##ret[1]--时间信息
# modelList包括模型每个模型是一个类里面的eval函数可以输出该模型的推理结果
modelRets = [model.eval(im0s[0]) for model in modelList]
timeInfos = [x[1] for x in modelRets]
timeInfos = ''.join(timeInfos)
timeInfos = timeInfos
# postProcess['function']--后处理函数,输入的就是所有模型输出结果
mixFunction = postProcess['function']
predsList = [modelRet[0] for modelRet in modelRets]
H, W = im0s[0].shape[0:2]
postProcess['pars']['imgSize'] = (W, H)
# ret就是混合处理后的结果
ret = mixFunction(predsList, postProcess['pars'])
det = ret[0]
if fiterList:
det = filter_byClass(det, fiterList)
if score_byClass:
det = score_filter_byClass(det, score_byClass)
return det, timeInfos + ret[1]
def getMaxScoreWords(detRets0):
maxScore=-1;maxId=0
for i,detRet in enumerate(detRets0):
if detRet[4]>maxScore:
maxId=i
maxScore = detRet[4]
return maxId
def AI_process_C(im0s, modelList, postProcess,score_byClass,fiterList):
# 函数定制的原因:
## 之前模型处理流是
## 图片---> 模型1-->result1图片---> 模型2->result2[result1,result2]--->后处理函数
## 本函数的处理流程是
## 图片---> 模型1-->result1[图片,result1]---> 模型2->result2[result1,result2]--->后处理函数
## 模型2的输入是有模型1的输出决定的。如模型2是ocr模型需要将模型1检测出来的船名抠图出来输入到模型2.
## 之前的模型流都是模型2是分割模型输入就是原始图片与模型1的输出无关。
#输入参数
## im0s---原始图像列表
## modelList--所有的模型
# postProcess--字典{},包括后处理函数,及其参数
#输出参数
##ret[0]--检测结果;
##ret[1]--时间信息
#modelList包括模型每个模型是一个类里面的eval函数可以输出该模型的推理结果
t0=time.time()
detRets0 = modelList[0].eval(im0s[0])
#detRets0=[[12, 46, 1127, 1544, 0.2340087890625, 2.0], [1884, 1248, 2992, 1485, 0.64208984375, 1.0]]
detRets0 = detRets0[0]
parsIn=postProcess['pars']
_detRets0_obj = list(filter(lambda x: x[5] in parsIn['objs'], detRets0 ))
_detRets0_others = list(filter(lambda x: x[5] not in parsIn['objs'], detRets0 ))
_detRets0 = []
if postProcess['name']=='channel2':
if len(_detRets0_obj)>0:
maxId=getMaxScoreWords(_detRets0_obj)
_detRets0 = _detRets0_obj[maxId:maxId+1]
else: _detRets0 = detRets0
t1=time.time()
imagePatches = [ im0s[0][int(x[1]):int(x[3] ) ,int(x[0]):int(x[2])] for x in _detRets0 ]
detRets1 = [modelList[1].eval(patch) for patch in imagePatches]
print('###line240:',detRets1)
if postProcess['name']=='crackMeasurement':
detRets1 = [x[0]*255 for x in detRets1]
t2=time.time()
mixFunction =postProcess['function']
crackInfos = [mixFunction(patchMask,par=parsIn) for patchMask in detRets1]
rets = [detRets0[i]+ crackInfos[i] for i in range(len(imagePatches)) ]
t3=time.time()
outInfos='total:%.1f (det:%.1f %d次segs:%.1f mixProcess:%.1f) '%( (t3-t0)*1000, (t1-t0)*1000, len(detRets1),(t2-t1)*1000, (t3-t2)*1000 )
elif postProcess['name']=='channel2':
H,W = im0s[0].shape[0:2];parsIn['imgSize'] = (W,H)
mixFunction =postProcess['function']
_detRets0_others = mixFunction([_detRets0_others], parsIn)
ocrInfo='no ocr'
if len(_detRets0_obj)>0:
res_real = detRets1[0][0]
res_real="".join( list(filter(lambda x:(ord(x) >19968 and ord(x)<63865 ) or (ord(x) >47 and ord(x)<58 ),res_real)))
# detRets1[0][0]="".join( list(filter(lambda x:(ord(x) >19968 and ord(x)<63865 ) or (ord(x) >47 and ord(x)<58 ),detRets1[0][0])))
_detRets0_obj[maxId].append(res_real)
_detRets0_obj = [_detRets0_obj[maxId]] ##只输出有OCR的那个船名结果
ocrInfo = detRets1[0][1]
print(' _detRets0_obj:{} _detRets0_others:{} '.format(_detRets0_obj, _detRets0_others))
rets = _detRets0_obj + _detRets0_others
if fiterList:
rets = filter_byClass(rets, fiterList)
if score_byClass:
rets = score_filter_byClass(rets, score_byClass)
t3 = time.time()
outInfos = 'total:%.1f ,where det:%.1f, ocr:%s' % ((t3 - t0) * 1000, (t1 - t0) * 1000, ocrInfo)
#print('###line233:',detRets1,detRets0 )
return rets,outInfos
def AI_process_forest(im0s, model, segmodel, names, label_arraylist, rainbows, half=True, device=' cuda:0',
conf_thres=0.25, iou_thres=0.45,
font={'line_thickness': None, 'fontSize': None, 'boxLine_thickness': None,
'waterLineColor': (0, 255, 255), 'waterLineWidth': 3}, trtFlag_det=False,
SecNms=None,ksize=None,score_byClass=None,fiterList=[]):
# 输入参数
# im0s---原始图像列表
# model---检测模型segmodel---分割模型如若没有用到则为None
#输出:两个元素(列表,字符)构成的元组,[im0s[0],im0,det_xywh,iframe],strout
# [im0s[0],im0,det_xywh,iframe]中,
# im0s[0]--原始图像im0--AI处理后的图像,iframe--帧号/暂时不需用到。
# det_xywh--检测结果,是一个列表。
# 其中每一个元素表示一个目标构成如:[ xc,yc,w,h, float(conf_c),float(cls_c)],#2023.08.03,修改输出格式
# #cls_c--类别如0,1,2,3; xc,yc,w,h--中心点坐标及宽conf_c--得分, 取值范围在0-1之间
# #strout---统计AI处理个环节的时间
# Letterbox
time0 = time.time()
if trtFlag_det:
img, padInfos = img_pad(im0s[0], size=(640,640,3)) ;img = [img]
else:
img = [letterbox(x, 640, auto=True, stride=32)[0] for x in im0s];padInfos=None
#img = [letterbox(x, 640, auto=True, stride=32)[0] for x in im0s]
# Stack
img = np.stack(img, 0)
# Convert
img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to bsx3x416x416
img = np.ascontiguousarray(img)
img = torch.from_numpy(img).to(device)
img = img.half() if half else img.float() # uint8 to fp16/32
img /= 255.0 # 0 - 255 to 0.0 - 1.0
time1 = time.time()
pred = yolov5Trtforward(model, img) if trtFlag_det else model(img, augment=False)[0]
p_result, timeOut = post_process_det(pred,padInfos,img,im0s,conf_thres,iou_thres,label_arraylist,rainbows,font,score_byClass,fiterList)
if segmodel and len(p_result[2])>0:
segmodel.set_image(im0s[0])
p_result, timeOut = post_process_seg(im0s,segmodel,p_result[2],ksize)
time2 = time.time()
time_info = 'letterbox:%.1f, infer:%.1f, ' % ((time1 - time0) * 1000, (time2 - time1) * 1000)
return p_result, time_info + timeOut
def AI_det_track(im0s_in, modelPar, processPar, sort_tracker, segPar=None):
im0s, iframe = im0s_in[0], im0s_in[1]
model = modelPar['det_Model']
segmodel = modelPar['seg_Model']
half,device,conf_thres, iou_thres,trtFlag_det = processPar['half'], processPar['device'], processPar['conf_thres'], processPar['iou_thres'],processPar['trtFlag_det']
if 'score_byClass' in processPar.keys(): score_byClass = processPar['score_byClass']
else: score_byClass = None
iou2nd = processPar['iou2nd']
time0=time.time()
if trtFlag_det:
img, padInfos = img_pad(im0s[0], size=(640,640,3)) ;img = [img]
else:
img = [letterbox(x, 640, auto=True, stride=32)[0] for x in im0s];padInfos=None
img = np.stack(img, 0)
# Convert
img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to bsx3x416x416
img = np.ascontiguousarray(img)
img = torch.from_numpy(img).to(device)
img = img.half() if half else img.float() # uint8 to fp16/32
img /= 255.0 # 0 - 255 to 0.0 - 1.0
seg_pred = None;segFlag=False
time1=time.time()
pred = yolov5Trtforward(model,img) if trtFlag_det else model(img,augment=False)[0]
time2=time.time()
#p_result,timeOut = getDetections(datas,conf_thres, iou_thres,names,label_arraylist,rainbows,10,ObjectPar=ObjectPar,font=font,padInfos=padInfos)
p_result, timeOut = getDetectionsFromPreds(pred,img,im0s[0],conf_thres=conf_thres,iou_thres=iou_thres,ovlap_thres=iou2nd,padInfos=padInfos)
if score_byClass:
p_result[2] = score_filter_byClass(p_result[2],score_byClass)
if segmodel:
seg_pred,segstr = segmodel.eval(im0s[0] )
segFlag=True
else:
seg_pred = None;segFlag=False;segstr='No segmodel'
if segPar and segPar['mixFunction']['function']:
mixFunction = segPar['mixFunction']['function']
H,W = im0s[0].shape[0:2]
parMix = segPar['mixFunction']['pars'];#print('###line117:',parMix,p_result[2])
parMix['imgSize'] = (W,H)
p_result[2],timeInfos_post = mixFunction(p_result[2], seg_pred, pars=parMix )
timeInfos_seg_post = 'segInfer:%s ,postMixProcess:%s'%( segstr, timeInfos_post )
else:
timeInfos_seg_post = ' '
'''
if segmodel:
timeS1=time.time()
#seg_pred,segstr = segtrtEval(segmodel,im0s[0],par=segPar) if segPar['trtFlag_seg'] else segmodel.eval(im0s[0] )
seg_pred,segstr = segmodel.eval(im0s[0] )
timeS2=time.time()
mixFunction = segPar['mixFunction']['function']
p_result[2],timeInfos_post = mixFunction(p_result[2], seg_pred, pars=segPar['mixFunction']['pars'] )
timeInfos_seg_post = 'segInfer:%.1f ,postProcess:%s'%( (timeS2-timeS1)*1000, timeInfos_post )
else:
timeInfos_seg_post = ' '
#print('######line341:',seg_pred.shape,np.max(seg_pred),np.min(seg_pred) , len(p_result[2]) )
'''
time_info = 'letterbox:%.1f, detinfer:%.1f, '%( (time1-time0)*1000,(time2-time1)*1000 )
if sort_tracker:
#在这里增加设置调用追踪器的频率
#..................USE TRACK FUNCTION....................
#pass an empty array to sort
dets_to_sort = np.empty((0,7), dtype=np.float32)
# NOTE: We send in detected object class too
#for detclass,x1,y1,x2,y2,conf in p_result[2]:
for x1,y1,x2,y2,conf, detclass in p_result[2]:
#print('#######line342:',x1,y1,x2,y2,img.shape,[x1, y1, x2, y2, conf, detclass,iframe])
dets_to_sort = np.vstack((dets_to_sort,
np.array([x1, y1, x2, y2, conf, detclass,iframe],dtype=np.float32) ))
# Run SORT
tracked_dets = deepcopy(sort_tracker.update(dets_to_sort) )
tracks =sort_tracker.getTrackers()
p_result.append(tracked_dets) ###index=4
p_result.append(tracks) ###index=5
return p_result,time_info+timeOut+timeInfos_seg_post
def AI_det_track_batch(imgarray_list, iframe_list ,modelPar,processPar,sort_tracker,trackPar,segPar=None):
'''
输入:
imgarray_list--图像列表
iframe_list -- 帧号列表
modelPar--模型参数,字典,modelPar={'det_Model':,'seg_Model':}
processPar--字典,存放检测相关参数,'half', 'device', 'conf_thres', 'iou_thres','trtFlag_det'
sort_tracker--对象,初始化的跟踪对象。为了保持一致,即使是单帧也要有。
trackPar--跟踪参数关键字包括det_cntwindowsize
segPar--None,分割模型相关参数。如果用不到则为None
输入retResults,timeInfos
retResultslist
retResults[0]--imgarray_list
retResults[1]--所有结果用numpy格式所有的检测结果包括8类每列分别是x1, y1, x2, y2, conf, detclass,iframe,trackId
retResults[2]--所有结果用list表示,其中每一个元素为一个list表示每一帧的检测结果每一个结果是由多个list构成每个list表示一个框格式为[ x0 ,y0 ,x1 ,y1 ,conf, cls ,ifrmae,trackId ],如 retResults[2][j][k]表示第j帧的第k个框。2023.08.03,修改输出格式
'''
det_cnt,windowsize = trackPar['det_cnt'] ,trackPar['windowsize']
trackers_dic={}
index_list = list(range( 0, len(iframe_list) ,det_cnt ));
if len(index_list)>1 and index_list[-1]!= iframe_list[-1]:
index_list.append( len(iframe_list) - 1 )
if len(imgarray_list)==1: #如果是单帧图片,则不用跟踪
retResults = []
p_result,timeOut = AI_det_track( [ [imgarray_list[0]] ,iframe_list[0] ],modelPar,processPar,None,segPar )
##下面4行内容只是为了保持格式一致
detArray = np.array(p_result[2])
#print('##line371:',detArray)
if len(p_result[2])==0:res=[]
else:
cnt = detArray.shape[0];trackIds=np.zeros((cnt,1));iframes = np.zeros((cnt,1)) + iframe_list[0]
#detArray = np.hstack( (detArray[:,1:5], detArray[:,5:6] ,detArray[:,0:1],iframes, trackIds ) )
detArray = np.hstack( (detArray[:,0:4], detArray[:,4:6] ,iframes, trackIds ) ) ##2023.08.03 修改输入格式
res = [[ b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7] ] for b in detArray ]
retResults=[imgarray_list,detArray,res ]
#print('##line380:',retResults[2])
return retResults,timeOut
else:
t0 = time.time()
timeInfos_track=''
for iframe_index, index_frame in enumerate(index_list):
p_result,timeOut = AI_det_track( [ [imgarray_list[index_frame]] ,iframe_list[index_frame] ],modelPar,processPar,sort_tracker,segPar )
timeInfos_track='%s:%s'%(timeInfos_track,timeOut)
for tracker in p_result[5]:
trackers_dic[tracker.id]=deepcopy(tracker)
t1 = time.time()
track_det_result = np.empty((0,8))
for trackId in trackers_dic.keys():
tracker = trackers_dic[trackId]
bbox_history = np.array(tracker.bbox_history)
if len(bbox_history)<2: continue
###把(x0,y0,x1,y1)转换成(xc,yc,w,h)
xcs_ycs = (bbox_history[:,0:2] + bbox_history[:,2:4] )/2
whs = bbox_history[:,2:4] - bbox_history[:,0:2]
bbox_history[:,0:2] = xcs_ycs;bbox_history[:,2:4] = whs;
arrays_box = bbox_history[:,0:7].transpose();frames=bbox_history[:,6]
#frame_min--表示该批次图片的起始帧,如该批次是[1,100],则frame_min=1[101,200]--frame_min=101
#frames[0]--表示该目标出现的起始帧,如[1,11,21,31,41],则frames[0]=1frames[0]可能会在frame_min之前出现即一个横跨了多个批次。
##如果要最好化插值范围,则取内区间[frame_min,则frame_max ]和[frames[0],frames[-1] ]的交集
#inter_frame_min = int(max(frame_min, frames[0])); inter_frame_max = int(min( frame_max, frames[-1] )) ##
##如果要求得到完整的目标轨迹,则插值区间要以目标出现的起始点为准
inter_frame_min=int(frames[0]);inter_frame_max=int(frames[-1])
new_frames= np.linspace(inter_frame_min,inter_frame_max,inter_frame_max-inter_frame_min+1 )
f_linear = interpolate.interp1d(frames,arrays_box); interpolation_x0s = (f_linear(new_frames)).transpose()
move_cnt_use =(len(interpolation_x0s)+1)//2*2-1 if len(interpolation_x0s)<windowsize else windowsize
for im in range(4):
interpolation_x0s[:,im] = moving_average_wang(interpolation_x0s[:,im],move_cnt_use )
cnt = inter_frame_max-inter_frame_min+1; trackIds = np.zeros((cnt,1)) + trackId
interpolation_x0s = np.hstack( (interpolation_x0s, trackIds ) )
track_det_result = np.vstack(( track_det_result, interpolation_x0s) )
#print('#####line116:',trackId,frame_min,frame_max,'----------',interpolation_x0s.shape,track_det_result.shape ,'-----')
##将[xc,yc,w,h]转为[x0,y0,x1,y1]
x0s = track_det_result[:,0] - track_det_result[:,2]/2 ; x1s = track_det_result[:,0] + track_det_result[:,2]/2
y0s = track_det_result[:,1] - track_det_result[:,3]/2 ; y1s = track_det_result[:,1] + track_det_result[:,3]/2
track_det_result[:,0] = x0s; track_det_result[:,1] = y0s;
track_det_result[:,2] = x1s; track_det_result[:,3] = y1s;
detResults=[]
for iiframe in iframe_list:
boxes_oneFrame = track_det_result[ track_det_result[:,6]==iiframe ]
res = [[ b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7] ] for b in boxes_oneFrame ]
#[ x0 ,y0 ,x1 ,y1 ,conf,cls,ifrmae,trackId ]
#[ifrmae, x0 ,y0 ,x1 ,y1 ,conf,cls,trackId ]
detResults.append( res )
retResults=[imgarray_list,track_det_result,detResults ]
t2 = time.time()
timeInfos = 'detTrack:%.1f TrackPost:%.1f, %s'%(get_ms(t1,t0),get_ms(t2,t1), timeInfos_track )
return retResults,timeInfos
def AI_det_track_N( im0s_in,modelList,postProcess,sort_tracker):
im0s,iframe=im0s_in[0],im0s_in[1]
dets = AI_process_N(im0s,modelList,postProcess)
p_result=[[],[],dets[0],[] ]
if sort_tracker:
#在这里增加设置调用追踪器的频率
#..................USE TRACK FUNCTION....................
#pass an empty array to sort
dets_to_sort = np.empty((0,7), dtype=np.float32)
# NOTE: We send in detected object class too
#for detclass,x1,y1,x2,y2,conf in p_result[2]:
for x1,y1,x2,y2,conf, detclass in p_result[2]:
#print('#######line342:',x1,y1,x2,y2,img.shape,[x1, y1, x2, y2, conf, detclass,iframe])
dets_to_sort = np.vstack((dets_to_sort,
np.array([x1, y1, x2, y2, conf, detclass,iframe],dtype=np.float32) ))
# Run SORT
tracked_dets = deepcopy(sort_tracker.update(dets_to_sort) )
tracks =sort_tracker.getTrackers()
p_result.append(tracked_dets) ###index=4
p_result.append(tracks) ###index=5
return p_result,dets[1]
def get_tracker_cls(boxes,scId=4,clsId=5):
#正常来说一各跟踪链上是一个类别,但是有时目标框检测错误,导致有的跟踪链上有多个类别
#为此,根据跟踪链上每一个类别对应的所有框的置信度之和,作为这个跟踪链上目标的类别
#输入boxes--跟踪是保留的box_history,[[xc,yc,width,height,score,class,iframe],[...],[...]]
## scId=4,score所在的序号; clsId=5;类别所在的序号
#输出类别
##这个跟踪链上目标的类别
ids = list(set(boxes[:,clsId].tolist()))
scores = [np.sum( boxes[:,scId] [ boxes[:,clsId]==x ] ) for x in ids]
maxScoreId = scores.index(np.max(scores))
return int(ids[maxScoreId])
def AI_det_track_batch_N(imgarray_list, iframe_list ,modelList,postProcess,sort_tracker,trackPar):
'''
输入:
imgarray_list--图像列表
iframe_list -- 帧号列表
modelPar--模型参数,字典,modelPar={'det_Model':,'seg_Model':}
processPar--字典,存放检测相关参数,'half', 'device', 'conf_thres', 'iou_thres','trtFlag_det'
sort_tracker--对象,初始化的跟踪对象。为了保持一致,即使是单帧也要有。
trackPar--跟踪参数关键字包括det_cntwindowsize
segPar--None,分割模型相关参数。如果用不到则为None
输入retResults,timeInfos
retResultslist
retResults[0]--imgarray_list
retResults[1]--所有结果用numpy格式所有的检测结果包括8类每列分别是x1, y1, x2, y2, conf, detclass,iframe,trackId
retResults[2]--所有结果用list表示,其中每一个元素为一个list表示每一帧的检测结果每一个结果是由多个list构成每个list表示一个框格式为[ x0 ,y0 ,x1 ,y1 ,conf, cls ,ifrmae,trackId ],如 retResults[2][j][k]表示第j帧的第k个框。2023.08.03,修改输出格式
'''
det_cnt,windowsize = trackPar['det_cnt'] ,trackPar['windowsize']
trackers_dic={}
index_list = list(range( 0, len(iframe_list) ,det_cnt ));
if len(index_list)>1 and index_list[-1]!= iframe_list[-1]:
index_list.append( len(iframe_list) - 1 )
if len(imgarray_list)==1: #如果是单帧图片,则不用跟踪
retResults = []
p_result,timeOut = AI_det_track_N( [ [imgarray_list[0]] ,iframe_list[0] ],modelList,postProcess,None )
##下面4行内容只是为了保持格式一致
detArray = np.array(p_result[2])
if len(p_result[2])==0:res=[]
else:
cnt = detArray.shape[0];trackIds=np.zeros((cnt,1));iframes = np.zeros((cnt,1)) + iframe_list[0]
#detArray = np.hstack( (detArray[:,1:5], detArray[:,5:6] ,detArray[:,0:1],iframes, trackIds ) )
detArray = np.hstack( (detArray[:,0:4], detArray[:,4:6] ,iframes, trackIds ) ) ##2023.08.03 修改输入格式
res = [[ b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7] ] for b in detArray ]
retResults=[imgarray_list,detArray,res ]
#print('##line380:',retResults[2])
return retResults,timeOut
else:
t0 = time.time()
timeInfos_track=''
for iframe_index, index_frame in enumerate(index_list):
p_result,timeOut = AI_det_track_N( [ [imgarray_list[index_frame]] ,iframe_list[index_frame] ],modelList,postProcess,sort_tracker )
timeInfos_track='%s:%s'%(timeInfos_track,timeOut)
for tracker in p_result[5]:
trackers_dic[tracker.id]=deepcopy(tracker)
t1 = time.time()
track_det_result = np.empty((0,8))
for trackId in trackers_dic.keys():
tracker = trackers_dic[trackId]
bbox_history = np.array(tracker.bbox_history).copy()
if len(bbox_history)<2: continue
###把(x0,y0,x1,y1)转换成(xc,yc,w,h)
xcs_ycs = (bbox_history[:,0:2] + bbox_history[:,2:4] )/2
whs = bbox_history[:,2:4] - bbox_history[:,0:2]
bbox_history[:,0:2] = xcs_ycs;bbox_history[:,2:4] = whs;
#2023.11.17添加的。目的是修正跟踪链上所有的框的类别一样
chainClsId = get_tracker_cls(bbox_history,scId=4,clsId=5)
bbox_history[:,5] = chainClsId
arrays_box = bbox_history[:,0:7].transpose();frames=bbox_history[:,6]
#frame_min--表示该批次图片的起始帧,如该批次是[1,100],则frame_min=1[101,200]--frame_min=101
#frames[0]--表示该目标出现的起始帧,如[1,11,21,31,41],则frames[0]=1frames[0]可能会在frame_min之前出现即一个横跨了多个批次。
##如果要最好化插值范围,则取内区间[frame_min,则frame_max ]和[frames[0],frames[-1] ]的交集
#inter_frame_min = int(max(frame_min, frames[0])); inter_frame_max = int(min( frame_max, frames[-1] )) ##
##如果要求得到完整的目标轨迹,则插值区间要以目标出现的起始点为准
inter_frame_min=int(frames[0]);inter_frame_max=int(frames[-1])
new_frames= np.linspace(inter_frame_min,inter_frame_max,inter_frame_max-inter_frame_min+1 )
f_linear = interpolate.interp1d(frames,arrays_box); interpolation_x0s = (f_linear(new_frames)).transpose()
move_cnt_use =(len(interpolation_x0s)+1)//2*2-1 if len(interpolation_x0s)<windowsize else windowsize
for im in range(4):
interpolation_x0s[:,im] = moving_average_wang(interpolation_x0s[:,im],move_cnt_use )
cnt = inter_frame_max-inter_frame_min+1; trackIds = np.zeros((cnt,1)) + trackId
interpolation_x0s = np.hstack( (interpolation_x0s, trackIds ) )
track_det_result = np.vstack(( track_det_result, interpolation_x0s) )
#print('#####line116:',trackId,'----------',interpolation_x0s.shape,track_det_result.shape,bbox_history ,'-----')
##将[xc,yc,w,h]转为[x0,y0,x1,y1]
x0s = track_det_result[:,0] - track_det_result[:,2]/2 ; x1s = track_det_result[:,0] + track_det_result[:,2]/2
y0s = track_det_result[:,1] - track_det_result[:,3]/2 ; y1s = track_det_result[:,1] + track_det_result[:,3]/2
track_det_result[:,0] = x0s; track_det_result[:,1] = y0s;
track_det_result[:,2] = x1s; track_det_result[:,3] = y1s;
detResults=[]
for iiframe in iframe_list:
boxes_oneFrame = track_det_result[ track_det_result[:,6]==iiframe ]
res = [[ b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7] ] for b in boxes_oneFrame ]
#[ x0 ,y0 ,x1 ,y1 ,conf,cls,ifrmae,trackId ]
#[ifrmae, x0 ,y0 ,x1 ,y1 ,conf,cls,trackId ]
detResults.append( res )
retResults=[imgarray_list,track_det_result,detResults ]
t2 = time.time()
timeInfos = 'detTrack:%.1f TrackPost:%.1f, %s'%(get_ms(t1,t0),get_ms(t2,t1), timeInfos_track )
return retResults,timeInfos
def ocr_process(pars):
img_patch,engine,context,converter,AlignCollate_normal,device=pars[0:6]
time1 = time.time()
img_tensor = AlignCollate_normal([ Image.fromarray(img_patch,'L') ])
img_input = img_tensor.to('cuda:0')
time2 = time.time()
preds,trtstr=OcrTrtForward(engine,[img_input],context)
time3 = time.time()
batch_size = preds.size(0)
preds_size = torch.IntTensor([preds.size(1)] * batch_size)
######## filter ignore_char, rebalance
preds_prob = F.softmax(preds, dim=2)
preds_prob = preds_prob.cpu().detach().numpy()
pred_norm = preds_prob.sum(axis=2)
preds_prob = preds_prob/np.expand_dims(pred_norm, axis=-1)
preds_prob = torch.from_numpy(preds_prob).float().to(device)
_, preds_index = preds_prob.max(2)
preds_index = preds_index.view(-1)
time4 = time.time()
preds_str = converter.decode_greedy(preds_index.data.cpu().detach().numpy(), preds_size.data)
time5 = time.time()
info_str= ('pre-process:%.2f TRTforward:%.2f (%s) postProcess:%2.f decoder:%.2f, Total:%.2f , pred:%s'%(get_ms(time2,time1 ),get_ms(time3,time2 ),trtstr, get_ms(time4,time3 ), get_ms(time5,time4 ), get_ms(time5,time1 ), preds_str ) )
return preds_str,info_str
def AI_process_Ocr(im0s, modelList, device, detpar):
timeMixPost = ':0 ms'
new_device = torch.device(device)
time0 = time.time()
img, padInfos = pre_process(im0s[0], new_device)
ocrModel = modelList[1]
time1 = time.time()
if not detpar['trtFlag_det']:
preds, timeOut = modelList[0].eval(img)
boxes = post_process(preds, padInfos, device, conf_thres=detpar['conf_thres'], iou_thres=detpar['iou_thres'],
nc=detpar['nc']) # 后处理
else:
boxes, timeOut = modelList[0].eval(im0s[0])
time2 = time.time()
imagePatches = [im0s[0][int(x[1]):int(x[3]), int(x[0]):int(x[2])] for x in boxes]
detRets1 = [ocrModel.eval(patch) for patch in imagePatches]
time3 = time.time()
dets = []
for i, (box, ocr) in enumerate(zip(boxes, detRets1)):
label = plat_format(ocr)
if label:
xyxy = box[0:4]
dets.append([label, xyxy])
time_info = 'pre_process:%.1f, det:%.1f , ocr:%.1f ,timeMixPost:%s ' % (
(time1 - time0) * 1000, (time2 - time1) * 1000, (time3 - time2) * 1000, timeMixPost)
return [im0s[0], im0s[0], dets, 0], time_info
def AI_process_Crowd(im0s,model,device,postPar):
timeMixPost = ':0 ms'
time0 = time.time()
h, w = im0s[0].shape[:2]
Wrate = w // 128 * 128 / w
Hrate = h // 128 * 128 / h
detM = np.array([])
if len(model) == 1:
detP = model[0].eval(im0s[0])
p_postPar = postPar[0]
else:
detP = model[1].eval(im0s[0])
p_postPar = postPar[1]
detM = np.array(model[0].eval(im0s[0])[0])
# d_postPar = postPar[0]
time1 = time.time()
outputs_scores = torch.nn.functional.softmax(detP['pred_logits'], -1)[:, :, 1][0]
outputs_points = detP['pred_points'][0]
detP = outputs_points[outputs_scores > p_postPar['conf']].detach().cpu().numpy()
detP[:, 0] = detP[:, 0] / Wrate
detP[:, 1] = detP[:, 1] / Hrate
dets = []
if not detM.size==0:
P = detP.shape[0] # 第二类边界框数量
if P == 0:
time_info = 'No Valid object find'
return [im0s[0], im0s[0], dets, 0], time_info
x1 = detP[:, 0] - p_postPar['expend']
y1 = detP[:, 1] - p_postPar['expend']
x2 = detP[:, 0] + p_postPar['expend']
y2 = detP[:, 1] + p_postPar['expend']
detP = np.column_stack((x1, y1, x2, y2))
detM = detM[:,:4]
a_x1, a_y1, a_x2, a_y2 = detM[:, 0], detM[:, 1], detM[:, 2], detM[:, 3]
b_x1, b_y1, b_x2, b_y2 = detP[:, 0], detP[:, 1], detP[:, 2], detP[:, 3]
# 扩展维度以便广播 [N,1]
a_x1 = a_x1[:, np.newaxis]
a_y1 = a_y1[:, np.newaxis]
a_x2 = a_x2[:, np.newaxis]
a_y2 = a_y2[:, np.newaxis]
# 计算相交区域坐标 [N,M]
inter_x1 = np.maximum(a_x1, b_x1)
inter_y1 = np.maximum(a_y1, b_y1)
inter_x2 = np.minimum(a_x2, b_x2)
inter_y2 = np.minimum(a_y2, b_y2)
# 计算相交区域面积 [N,M]
inter_area = np.maximum(0, inter_x2 - inter_x1) * np.maximum(0, inter_y2 - inter_y1)
# 计算每个A框与多少个B框相交相交面积>0
counts = np.sum(inter_area > 0, axis=1).astype(int)
# 构建结果数组前4列是A框坐标第5列是相交计数
detM = np.hstack((detM, counts.reshape(-1, 1)))
detM = detM[detM[:, -1] != 0]
# 找出所有与A框相交的B框索引
p_preds_index = np.any(inter_area > 0, axis=0)
p_indices = np.where(p_preds_index)[0]
# 提取与第一类相交的第二类边界框
if len(p_indices) > 0:
detP = detP[p_indices]
detP = detP[:, :2]
detP[:, 0] = detP[:, 0] + p_postPar['expend']
detP[:, 1] = detP[:, 1] + p_postPar['expend']
dets= [[detM.tolist(), detP.tolist(),p_postPar['psize']]]
else:
dets = [[detP.tolist(),p_postPar['psize']]]
# for b in detM:
# b_label = '该建筑物下行人及数量:%d'%(int(b[4]))
time2 = time.time()
time_info = 'det:%.1f , post:%.1f ,timeMixPost:%s ' % (
(time1 - time0) * 1000, (time2 - time1) * 1000, timeMixPost)
return [im0s[0], im0s[0], dets, 0], time_info
def main():
##预先设置的参数
device_='1' ##选定模型,可选 cpu,'0','1'
##以下参数目前不可改
Detweights = "weights/yolov5/class5/best_5classes.pt"
seg_nclass = 2
Segweights = "weights/BiSeNet/checkpoint.pth"
conf_thres,iou_thres,classes= 0.25,0.45,5
labelnames = "weights/yolov5/class5/labelnames.json"
rainbows = [ [0,0,255],[0,255,0],[255,0,0],[255,0,255],[255,255,0],[255,129,0],[255,0,127],[127,255,0],[0,255,127],[0,127,255],[127,0,255],[255,127,255],[255,255,127],[127,255,255],[0,255,255],[255,127,255],[127,255,255], [0,127,0],[0,0,127],[0,255,255]]
allowedList=[0,1,2,3]
##加载模型,准备好显示字符
device = select_device(device_)
names=get_labelnames(labelnames)
label_arraylist = get_label_arrays(names,rainbows,outfontsize=40,fontpath="conf/platech.ttf")
half = device.type != 'cpu' # half precision only supported on CUDA
model = attempt_load(Detweights, map_location=device) # load FP32 model
if half: model.half()
segmodel = SegModel(nclass=seg_nclass,weights=Segweights,device=device)
##图像测试
#url='images/examples/20220624_响水河_12300_1621.jpg'
impth = 'images/examples/'
outpth = 'images/results/'
folders = os.listdir(impth)
for i in range(len(folders)):
imgpath = os.path.join(impth, folders[i])
im0s=[cv2.imread(imgpath)]
time00 = time.time()
p_result,timeOut = AI_process(im0s,model,segmodel,names,label_arraylist,rainbows,half,device,conf_thres, iou_thres,allowedList,fontSize=1.0)
time11 = time.time()
image_array = p_result[1]
cv2.imwrite( os.path.join( outpth,folders[i] ) ,image_array )
#print('----process:%s'%(folders[i]), (time.time() - time11) * 1000)
if __name__=="__main__":
main()