@@ -165,32 +165,63 @@ def default_mix(predlist,par): | |||
def AI_process_N(im0s,modelList,postProcess): | |||
#输入参数 | |||
# 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 | |||
## 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']) | |||
return ret[0],timeInfos+ret[1] | |||
def AI_process_C(im0s,modelList,postProcess): | |||
#输入参数 | |||
## im0s---原始图像列表 | |||
## modelList--所有的模型 | |||
# postProcess--字典{},包括后处理函数,及其参数 | |||
#输出参数 | |||
##ret[0]--检测结果; | |||
##ret[1]--时间信息 | |||
#modelList包括模型,每个模型是一个类,里面的eval函数可以输出该模型的推理结果 | |||
t0=time.time() | |||
detRets0 = modelList[0].eval(im0s[0]) | |||
detRets0 = detRets0[0] | |||
#detRets0=[[12, 46, 1127, 1544, 0.2340087890625, 2.0], [1884, 1248, 2992, 1485, 0.64208984375, 1.0]] | |||
detRets0 = list(filter(lambda x: x[5]<=2, 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] | |||
detRets1 = [x[0]*255 for x in detRets1] | |||
t2=time.time() | |||
mixFunction =postProcess['function'] | |||
crackInfos = [mixFunction(patchMask) 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 ) | |||
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,allowedList=[0,1,2,3], font={ 'line_thickness':None, 'fontSize':None,'boxLine_thickness':None,'waterLineColor':(0,255,255),'waterLineWidth':3} ,trtFlag_det=False,SecNms=None): | |||
@@ -457,6 +488,18 @@ def AI_det_track_N( im0s_in,modelList,postProcess,sort_tracker): | |||
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): | |||
''' | |||
输入: | |||
@@ -506,17 +549,21 @@ def AI_det_track_batch_N(imgarray_list, iframe_list ,modelList,postProcess,sort_ | |||
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) | |||
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]=1,frames[0]可能会在frame_min之前出现,即一个横跨了多个批次。 | |||
@@ -535,7 +582,7 @@ def AI_det_track_batch_N(imgarray_list, iframe_list ,modelList,postProcess,sort_ | |||
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 ,'-----') | |||
#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 |
@@ -1,4 +1,4 @@ | |||
gpu=2080Ti | |||
url=/mnt/thsw2/DSP2/weights/crowdCounting/weights | |||
#python toTrt.py --weights ${url}/crowdCounting.pth | |||
python toTrt.py --weights ${url}/crowdCounting.pth | |||
mv ${url}/crowdCounting_dynamic.engine ${url}/crowdCounting_${gpu}_dynamic.engine |
@@ -92,4 +92,10 @@ | |||
2023.11.06 | |||
1.增加cityMangement3,和cityMangement2一样的检测目标。但用了三个模型。 | |||
2.所有的demo3.0.py采用模型列表的方式输入参数 | |||
3.从cityMangement3 没有更新A100的trt文件和权重,因为云端A100服务器不存在了 | |||
3.从cityMangement3 没有更新A100的trt文件和权重,因为云端A100服务器不存在了 | |||
2023.11.17 | |||
1.修改stdc网络,增加了pth模式下,动态输入模型。Trt等其他方式不支持动态。 | |||
2.增加crackMeasure模型,返回值ret,timeInfos,其中ret为:[[ x0,y0,x1,y1,score,class,裂缝长度,平均宽度,最大宽度,最小宽度],[...],[...]。 | |||
3.Debug 跟踪模型中一条跟踪链上,历史框上有不同的类别, 修正为同一类别 | |||
@@ -0,0 +1,32 @@ | |||
import numpy as np | |||
from skimage.morphology import medial_axis | |||
def Crack_measure(_mask_cv_gray,dsx=(123-30)*1000/35*0.004387636): | |||
'''裂缝实际尺寸测量''' | |||
'''输入:单个裂缝分割图像 | |||
过程:。 | |||
返回:最终绘制的结果图、最终落水人员(坐标、类别、置信度), | |||
''' | |||
# 图像转化 | |||
###READ | |||
img = np.array(_mask_cv_gray.astype(np.int32)) | |||
image0 = binary = img | |||
###SKELETONIZATION | |||
img_skeletonized, distance = medial_axis(image0, return_distance=True) | |||
#print(img_skeletonized) | |||
img_skeletonized = np.array(img_skeletonized.astype(np.int32)) | |||
###COMPUTING WIDTH | |||
dist_on_skel = distance * img_skeletonized | |||
width = dist_on_skel[dist_on_skel != 0] * 2 | |||
for i in range(len(width)): | |||
if width[i] <= 2.0: | |||
width[i] = width[i] | |||
else: | |||
width[i] = width[i] - 2 | |||
###OUTPUT | |||
real_length = np.count_nonzero(img_skeletonized) *dsx # Each pixel remaining after | |||
real_mean_width = np.mean(width)*dsx | |||
real_max_width = np.max(width)*dsx | |||
real_min_width = np.min(width)*dsx | |||
return real_length,real_mean_width,real_max_width,real_min_width |
@@ -69,9 +69,9 @@ class BiSeNetOutput(nn.Module): | |||
return wd_params, nowd_params | |||
class AttentionRefinementModule(nn.Module): | |||
class AttentionRefinementModule_static(nn.Module): | |||
def __init__(self, in_chan, out_chan,avg_pool2d_kernel_size, *args, **kwargs): | |||
super(AttentionRefinementModule, self).__init__() | |||
super(AttentionRefinementModule_static, self).__init__() | |||
self.conv = ConvBNReLU(in_chan, out_chan, ks=3, stride=1, padding=1) | |||
self.conv_atten = nn.Conv2d(out_chan, out_chan, kernel_size= 1, bias=False) | |||
# self.bn_atten = nn.BatchNorm2d(out_chan) | |||
@@ -85,6 +85,7 @@ class AttentionRefinementModule(nn.Module): | |||
def forward(self, x): | |||
feat = self.conv(x) | |||
#atten = F.avg_pool2d(feat, feat.size()[2:]) | |||
atten = F.avg_pool2d(feat, self.avg_pool2d_kernel_size) | |||
#print('------------------newline89:','out:',atten.size(),'in:',feat.size(), self.avg_pool2d_kernel_size) | |||
atten = self.conv_atten(atten) | |||
@@ -98,16 +99,48 @@ class AttentionRefinementModule(nn.Module): | |||
if isinstance(ly, nn.Conv2d): | |||
nn.init.kaiming_normal_(ly.weight, a=1) | |||
if not ly.bias is None: nn.init.constant_(ly.bias, 0) | |||
class AttentionRefinementModule(nn.Module): | |||
def __init__(self, in_chan, out_chan, *args, **kwargs): | |||
super(AttentionRefinementModule, self).__init__() | |||
self.conv = ConvBNReLU(in_chan, out_chan, ks=3, stride=1, padding=1) | |||
self.conv_atten = nn.Conv2d(out_chan, out_chan, kernel_size= 1, bias=False) | |||
# self.bn_atten = nn.BatchNorm2d(out_chan) | |||
# self.bn_atten = BatchNorm2d(out_chan, activation='none') | |||
self.bn_atten = nn.BatchNorm2d(out_chan)########################2 | |||
self.sigmoid_atten = nn.Sigmoid() | |||
self.init_weight() | |||
class ContextPath(nn.Module): | |||
def forward(self, x): | |||
feat = self.conv(x) | |||
atten = F.avg_pool2d(feat, feat.size()[2:]) | |||
#atten = F.avg_pool2d(feat, self.avg_pool2d_kernel_size) | |||
#print('------------------newline89:','out:',atten.size(),'in:',feat.size(), self.avg_pool2d_kernel_size) | |||
atten = self.conv_atten(atten) | |||
atten = self.bn_atten(atten) | |||
atten = self.sigmoid_atten(atten) | |||
out = torch.mul(feat, atten) | |||
return out | |||
def init_weight(self): | |||
for ly in self.children(): | |||
if isinstance(ly, nn.Conv2d): | |||
nn.init.kaiming_normal_(ly.weight, a=1) | |||
if not ly.bias is None: nn.init.constant_(ly.bias, 0) | |||
class ContextPath_static(nn.Module): | |||
def __init__(self, backbone='CatNetSmall', pretrain_model='', use_conv_last=False,modelSize=(360,640), *args, **kwargs): | |||
super(ContextPath, self).__init__() | |||
super(ContextPath_static, self).__init__() | |||
self.backbone_name = backbone | |||
self.modelSize = modelSize | |||
self.avg_pool_kernel_size_32=[ int(modelSize[0]/32+0.999), int( modelSize[1]/32+0.999 ) ] | |||
self.avg_pool_kernel_size_16=[ int(modelSize[0]/16+0.999), int( modelSize[1]/16+0.999 ) ] | |||
if backbone == 'STDCNet1446': | |||
self.backbone = STDCNet1446(pretrain_model=pretrain_model, use_conv_last=use_conv_last) | |||
self.arm16 = AttentionRefinementModule(512, 128) | |||
@@ -121,11 +154,15 @@ class ContextPath(nn.Module): | |||
elif backbone == 'STDCNet813': | |||
self.backbone = STDCNet813(pretrain_model=pretrain_model, use_conv_last=use_conv_last) | |||
self.arm16 = AttentionRefinementModule(512, 128,self.avg_pool_kernel_size_16) | |||
self.arm16 = AttentionRefinementModule_static(512, 128,self.avg_pool_kernel_size_16) | |||
inplanes = 1024 | |||
if use_conv_last: | |||
inplanes = 1024 | |||
self.arm32 = AttentionRefinementModule(inplanes, 128,self.avg_pool_kernel_size_32) | |||
self.arm32 = AttentionRefinementModule_static(inplanes, 128,self.avg_pool_kernel_size_32) | |||
self.conv_head32 = ConvBNReLU(128, 128, ks=3, stride=1, padding=1) | |||
self.conv_head16 = ConvBNReLU(128, 128, ks=3, stride=1, padding=1) | |||
self.conv_avg = ConvBNReLU(inplanes, 128, ks=1, stride=1, padding=0) | |||
@@ -182,10 +219,92 @@ class ContextPath(nn.Module): | |||
nowd_params += list(module.parameters()) | |||
return wd_params, nowd_params | |||
class ContextPath(nn.Module): | |||
def __init__(self, backbone='CatNetSmall', pretrain_model='', use_conv_last=False, *args, **kwargs): | |||
super(ContextPath, self).__init__() | |||
self.backbone_name = backbone | |||
if backbone == 'STDCNet1446': | |||
self.backbone = STDCNet1446(pretrain_model=pretrain_model, use_conv_last=use_conv_last) | |||
self.arm16 = AttentionRefinementModule(512, 128) | |||
inplanes = 1024 | |||
if use_conv_last: | |||
inplanes = 1024 | |||
self.arm32 = AttentionRefinementModule(inplanes, 128) | |||
self.conv_head32 = ConvBNReLU(128, 128, ks=3, stride=1, padding=1) | |||
self.conv_head16 = ConvBNReLU(128, 128, ks=3, stride=1, padding=1) | |||
self.conv_avg = ConvBNReLU(inplanes, 128, ks=1, stride=1, padding=0) | |||
elif backbone == 'STDCNet813': | |||
self.backbone = STDCNet813(pretrain_model=pretrain_model, use_conv_last=use_conv_last) | |||
self.arm16 = AttentionRefinementModule(512, 128) | |||
inplanes = 1024 | |||
if use_conv_last: | |||
inplanes = 1024 | |||
self.arm32 = AttentionRefinementModule(inplanes, 128) | |||
self.conv_head32 = ConvBNReLU(128, 128, ks=3, stride=1, padding=1) | |||
self.conv_head16 = ConvBNReLU(128, 128, ks=3, stride=1, padding=1) | |||
self.conv_avg = ConvBNReLU(inplanes, 128, ks=1, stride=1, padding=0) | |||
else: | |||
print("backbone is not in backbone lists") | |||
exit(0) | |||
class FeatureFusionModule(nn.Module): | |||
self.init_weight() | |||
def forward(self, x): | |||
H0, W0 = x.size()[2:] | |||
feat2, feat4, feat8, feat16, feat32 = self.backbone(x) | |||
H8, W8 = feat8.size()[2:] | |||
H16, W16 = feat16.size()[2:] | |||
H32, W32 = feat32.size()[2:] | |||
avg = F.avg_pool2d(feat32, feat32.size()[2:]) | |||
#print('line147:self.avg_pool_kernel_size_32:',self.avg_pool_kernel_size_32) | |||
#avg = F.avg_pool2d(feat32, self.avg_pool_kernel_size_32) | |||
#print('------------------newline140:','out:','out;',avg.size(),' in:',feat32.size()) | |||
avg = self.conv_avg(avg) | |||
avg_up = F.interpolate(avg, (H32, W32), mode='nearest') | |||
#print('------------line143,arm32:',feat32.size()) | |||
feat32_arm = self.arm32(feat32) | |||
feat32_sum = feat32_arm + avg_up | |||
feat32_up = F.interpolate(feat32_sum, (H16, W16), mode='nearest') | |||
feat32_up = self.conv_head32(feat32_up) | |||
#print('------------line148,arm16:',feat16.size()) | |||
feat16_arm = self.arm16(feat16) | |||
feat16_sum = feat16_arm + feat32_up | |||
feat16_up = F.interpolate(feat16_sum, (H8, W8), mode='nearest') | |||
feat16_up = self.conv_head16(feat16_up) | |||
return feat2, feat4, feat8, feat16, feat16_up, feat32_up # x8, x16 | |||
# return feat8, feat16_up # x8, x16 | |||
def init_weight(self): | |||
for ly in self.children(): | |||
if isinstance(ly, nn.Conv2d): | |||
nn.init.kaiming_normal_(ly.weight, a=1) | |||
if not ly.bias is None: nn.init.constant_(ly.bias, 0) | |||
def get_params(self): | |||
wd_params, nowd_params = [], [] | |||
for name, module in self.named_modules(): | |||
if isinstance(module, (nn.Linear, nn.Conv2d)): | |||
wd_params.append(module.weight) | |||
if not module.bias is None: | |||
nowd_params.append(module.bias) | |||
elif isinstance(module, nn.BatchNorm2d):#################3 | |||
nowd_params += list(module.parameters()) | |||
return wd_params, nowd_params | |||
class FeatureFusionModule_static(nn.Module): | |||
def __init__(self, in_chan, out_chan,modelSize ,*args, **kwargs): | |||
super(FeatureFusionModule, self).__init__() | |||
super(FeatureFusionModule_static, self).__init__() | |||
self.convblk = ConvBNReLU(in_chan, out_chan, ks=1, stride=1, padding=0) | |||
self.avg_pool_kernel_size=[ int(modelSize[0]/8+0.9999), int( modelSize[1]/8+0.9999 ) ] | |||
self.conv1 = nn.Conv2d(out_chan, | |||
@@ -237,19 +356,81 @@ class FeatureFusionModule(nn.Module): | |||
elif isinstance(module, nn.BatchNorm2d):##################4 | |||
nowd_params += list(module.parameters()) | |||
return wd_params, nowd_params | |||
class FeatureFusionModule(nn.Module): | |||
def __init__(self, in_chan, out_chan ,*args, **kwargs): | |||
super(FeatureFusionModule, self).__init__() | |||
self.convblk = ConvBNReLU(in_chan, out_chan, ks=1, stride=1, padding=0) | |||
self.conv1 = nn.Conv2d(out_chan, | |||
out_chan//4, | |||
kernel_size = 1, | |||
stride = 1, | |||
padding = 0, | |||
bias = False) | |||
self.conv2 = nn.Conv2d(out_chan//4, | |||
out_chan, | |||
kernel_size = 1, | |||
stride = 1, | |||
padding = 0, | |||
bias = False) | |||
self.relu = nn.ReLU(inplace=True) | |||
self.sigmoid = nn.Sigmoid() | |||
self.init_weight() | |||
def forward(self, fsp, fcp): | |||
fcat = torch.cat([fsp, fcp], dim=1) | |||
feat = self.convblk(fcat) | |||
atten = F.avg_pool2d(feat, feat.size()[2:]) | |||
#atten = F.avg_pool2d(feat, kernel_size=self.avg_pool_kernel_size) | |||
#print('------------------newline199:',' out:',atten.size(),'in:',feat.size()) | |||
atten = self.conv1(atten) | |||
atten = self.relu(atten) | |||
atten = self.conv2(atten) | |||
atten = self.sigmoid(atten) | |||
feat_atten = torch.mul(feat, atten) | |||
feat_out = feat_atten + feat | |||
return feat_out | |||
def init_weight(self): | |||
for ly in self.children(): | |||
if isinstance(ly, nn.Conv2d): | |||
nn.init.kaiming_normal_(ly.weight, a=1) | |||
if not ly.bias is None: nn.init.constant_(ly.bias, 0) | |||
def get_params(self): | |||
wd_params, nowd_params = [], [] | |||
for name, module in self.named_modules(): | |||
if isinstance(module, (nn.Linear, nn.Conv2d)): | |||
wd_params.append(module.weight) | |||
if not module.bias is None: | |||
nowd_params.append(module.bias) | |||
elif isinstance(module, nn.BatchNorm2d):##################4 | |||
nowd_params += list(module.parameters()) | |||
return wd_params, nowd_params | |||
class BiSeNet_STDC(nn.Module): | |||
def __init__(self, backbone, n_classes, pretrain_model='', use_boundary_2=False, use_boundary_4=False, | |||
use_boundary_8=False, use_boundary_16=False, use_conv_last=False,modelSize=(360,640)): | |||
use_boundary_8=False, use_boundary_16=False, use_conv_last=False,**kwargs): | |||
super(BiSeNet_STDC, self).__init__() | |||
if 'modelSize' in kwargs: | |||
modelSize = kwargs['modelSize'] | |||
else: | |||
modelSize=None | |||
self.use_boundary_2 = use_boundary_2 | |||
self.use_boundary_4 = use_boundary_4 | |||
self.use_boundary_8 = use_boundary_8 | |||
self.use_boundary_16 = use_boundary_16 | |||
# self.heat_map = heat_map | |||
self.cp = ContextPath(backbone, pretrain_model, use_conv_last=use_conv_last,modelSize=modelSize) | |||
if modelSize: | |||
self.cp = ContextPath_static(backbone, pretrain_model, use_conv_last=use_conv_last,modelSize=modelSize) | |||
else: | |||
self.cp = ContextPath(backbone, pretrain_model, use_conv_last=use_conv_last) | |||
if backbone == 'STDCNet1446': | |||
conv_out_inplanes = 128 | |||
@@ -270,8 +451,10 @@ class BiSeNet_STDC(nn.Module): | |||
else: | |||
print("backbone is not in backbone lists") | |||
exit(0) | |||
self.ffm = FeatureFusionModule(inplane, 256,modelSize) | |||
if modelSize: | |||
self.ffm = FeatureFusionModule_static(inplane, 256,modelSize) | |||
else: | |||
self.ffm = FeatureFusionModule(inplane, 256) | |||
self.conv_out = BiSeNetOutput(256, 256, n_classes) | |||
self.conv_out16 = BiSeNetOutput(conv_out_inplanes, 64, n_classes) | |||
self.conv_out32 = BiSeNetOutput(conv_out_inplanes, 64, n_classes) | |||
@@ -343,12 +526,16 @@ class BiSeNet_STDC(nn.Module): | |||
if __name__ == "__main__": | |||
net = BiSeNet('STDCNet813', 19) | |||
net.cuda() | |||
net.eval() | |||
in_ten = torch.randn(1, 3, 768, 1536).cuda() | |||
out, out16, out32 = net(in_ten) | |||
print(out.shape) | |||
model = BiSeNet_STDC(backbone='STDCNet813', n_classes=2, | |||
use_boundary_2=False, use_boundary_4=False, | |||
use_boundary_8=True, use_boundary_16=False, | |||
use_conv_last=False, | |||
# modelSize=[360,640] | |||
) | |||
#modelSize=[360,640] | |||
print() | |||
# torch.save(net.state_dict(), 'STDCNet813.pth')### | |||
@@ -1,5 +1,5 @@ | |||
gpu=2080Ti | |||
name=cityMangement3 | |||
name=crackMeasurement | |||
nclass=2 | |||
mWidth=640 | |||
mHeight=360 |
@@ -0,0 +1,9 @@ | |||
#动态尺寸的stdc转trt没有成功,因为里有用到了全局池化,池化的过程中kener_size不固定 | |||
gpu=2080Ti | |||
name=crackMeasurement | |||
nclass=2 | |||
mWidth=0 | |||
mHeight=0 | |||
python toTrt.py --weights /mnt/thsw2/DSP2/weights/${name}/stdc_360X640.pth --nclass ${nclass} --mWidth ${mWidth} --mHeight ${mHeight} | |||
mv /mnt/thsw2/DSP2/weights/${name}/stdc_${mWidth}X${mHeight}.engine /mnt/thsw2/DSP2/weights/${name}/stdc_${mHeight}X${mWidth}_${gpu}_fp16.engine |
@@ -29,7 +29,7 @@ class SegModel(object): | |||
time0 = time.time() | |||
imageH, imageW, _ = image.shape | |||
image = self.RB_convert(image) | |||
#print('###line28: image:',image[10:12,10:12,0]) | |||
print('line32: image:',image[100,100,:],image.shape ) | |||
img = self.preprocess_image(image) | |||
if self.device != 'cpu': | |||
imgs = img.to(self.device) | |||
@@ -37,7 +37,7 @@ class SegModel(object): | |||
time1 = time.time() | |||
self.model.eval() | |||
with torch.no_grad(): | |||
#print('#### segmodel.py line35:',len(imgs),imgs[0].shape , imgs[0][0,10:12,10:12]) | |||
print(' segmodel.py line35:',len(imgs),imgs[0].shape , imgs[0,:,100,100]) | |||
output = self.model(imgs) | |||
time2 = time.time() |
@@ -0,0 +1,64 @@ | |||
from pathlib import Path | |||
import torch | |||
import os,sys | |||
import argparse | |||
sys.path.extend(['segutils']) | |||
from model_stages import BiSeNet_STDC | |||
from trtUtils2 import pth2onnx,onnx2engine,onnx_inference | |||
def main(opt): | |||
if opt.mWidth ==0 or opt.mHeight==0: | |||
modelSize=None | |||
else: | |||
modelSize = ( int(opt.mHeight), int(opt.mWidth) ) | |||
model = BiSeNet_STDC(backbone='STDCNet813', n_classes=int(opt.nclass), | |||
use_boundary_2=False, use_boundary_4=False, | |||
use_boundary_8=True, use_boundary_16=False, | |||
use_conv_last=False, | |||
modelSize=modelSize | |||
) | |||
model.load_state_dict(torch.load(opt.weights.strip(), map_location='cuda:0' )) | |||
#model= model.to(device) | |||
#pth_model='../weights/best_mae.pth' | |||
pth_model=opt.weights.strip() | |||
onnx_name = pth_model.replace('.pth','_dynamic.onnx') | |||
trt_name = onnx_name.replace('.onnx','.engine') | |||
dynamic_hw ={'input':{0:'batch',2:'H',3:'W'}, | |||
'output0':{1:'C',2:'H',3:'W'}, | |||
'output1':{1:'C',2:'H',3:'W'}, | |||
} | |||
inputShape =(1, 3, 128*4,128*4)#(bs,channels,height,width) | |||
input_profile_shapes = [(1,3,256,256),(1,3,1024,1024),(1,3,2048,2048)] | |||
pth2onnx(model,onnx_name,input_shape=(1,3,512,512),input_names=['input'],output_names=[ 'output0' ,'output1'],dynamix_axis=dynamic_hw) | |||
onnx2engine(onnx_name,trt_name,input_shape=[1,3,-1,-1],half=True,max_batch_size=1,input_profile_shapes=input_profile_shapes) | |||
if __name__ == '__main__': | |||
parser = argparse.ArgumentParser() | |||
parser.add_argument('--weights', type=str, default='stdc_360X640.pth', help='model path(s)') | |||
parser.add_argument('--nclass', type=int, default=2, help='segmodel nclass') | |||
parser.add_argument('--mWidth', type=int, default=640, help='segmodel mWdith') | |||
parser.add_argument('--mHeight', type=int, default=360, help='segmodel mHeight') | |||
opt = parser.parse_args() | |||
main(opt) |
@@ -3,18 +3,21 @@ import tensorrt as trt | |||
import torch | |||
import sys | |||
from segutils.trtUtils import segPreProcess_image,segTrtForward,segPreProcess_image_torch | |||
from segutils.segmodel import SegModel | |||
from segutils.model_stages import BiSeNet_STDC | |||
import time,cv2 | |||
import numpy as np | |||
class stdcModel(object): | |||
def __init__(self, weights=None, | |||
par={'modelSize':(640,360),'nclass':2,'predResize':True,'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'numpy':False, 'RGB_convert_first':True} | |||
par={'modelSize':(640,360),'dynamic':False,'nclass':2,'predResize':True,'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'numpy':False, 'RGB_convert_first':True} | |||
): | |||
self.par = par | |||
self.device = 'cuda:0' | |||
self.half =True | |||
self.half =True | |||
if 'dynamic' not in par.keys(): | |||
self.dynamic=False | |||
else: self.dynamic=par['dynamic'] | |||
if weights.endswith('.engine'): | |||
self. infer_type ='trt' | |||
@@ -25,49 +28,94 @@ class stdcModel(object): | |||
sys.exit(0) | |||
if self.infer_type=='trt': | |||
if self.dynamic : | |||
print('####################ERROR##########,STDC动态模型不能采用trt格式########') | |||
logger = trt.Logger(trt.Logger.ERROR) | |||
with open(weights, "rb") as f, trt.Runtime(logger) as runtime: | |||
self.model=runtime.deserialize_cuda_engine(f.read())# 输入trt本地文件,返回ICudaEngine对象 | |||
elif self.infer_type=='pth': | |||
self.model = SegModel(nclass=par['seg_nclass'],weights=weights,device=self.device) | |||
print('############load seg model pth success:',weights,self.model,par['seg_nclass'] ) | |||
if self.dynamic: modelSize=None | |||
else: modelSize=( self.par['modelSize'][1], self.par['modelSize'][0] ) | |||
self.model = BiSeNet_STDC(backbone='STDCNet813', n_classes=par['seg_nclass'], | |||
use_boundary_2=False, use_boundary_4=False, | |||
use_boundary_8=True, use_boundary_16=False, | |||
use_conv_last=False, | |||
modelSize = modelSize | |||
) | |||
self.model.load_state_dict(torch.load(weights, map_location=torch.device(self.device) )) | |||
self.model= self.model.to(self.device) | |||
print('#########加载模型:',weights,' 类型:',self.infer_type) | |||
def eval(self,image): | |||
if self.infer_type=='trt': | |||
seg_pred,segstr = self.segtrtEval(image) | |||
else: | |||
def preprocess_image(self,image): | |||
image = self.RB_convert(image) | |||
seg_pred,segstr = self.model.eval(image ) | |||
return seg_pred,segstr | |||
if self.dynamic: | |||
H,W=image.shape[0:2]; | |||
yscale = self.par['modelSize'][1]/H | |||
xscale = self.par['modelSize'][0]/W | |||
dscale = min(yscale,xscale) | |||
re_size = ( int((dscale*W)//4*4), int( (dscale*H)//4*4 ) ) | |||
else: re_size = self.par['modelSize'] | |||
#print('####line 58:,', re_size,image.shape) | |||
image = cv2.resize(image,re_size, interpolation=cv2.INTER_LINEAR) | |||
image = image.astype(np.float32) | |||
image /= 255.0 | |||
image[:, :, 0] -= self.par['mean'][0] | |||
image[:, :, 1] -= self.par['mean'][1] | |||
image[:, :, 2] -= self.par['mean'][2] | |||
image[:, :, 0] /= self.par['std'][0] | |||
image[:, :, 1] /= self.par['std'][1] | |||
image[:, :, 2] /= self.par['std'][2] | |||
image = np.transpose(image, (2, 0, 1)) | |||
image = torch.from_numpy(image).float() | |||
image = image.unsqueeze(0) | |||
if self.device != 'cpu': | |||
image = image.to(self.device) | |||
return image | |||
def RB_convert(self,image): | |||
image_c = image.copy() | |||
image_c[:,:,0] = image[:,:,2] | |||
image_c[:,:,2] = image[:,:,0] | |||
return image_c | |||
def get_ms(self,t1,t0): | |||
return (t1-t0)*1000.0 | |||
def pthEval(self,image_array0): | |||
seg_pred,segstr = self.model.eval(image_array0 ) | |||
return | |||
def segtrtEval(self,image_array0): | |||
time0_0=time.time() | |||
H,W,C=image_array0.shape | |||
#img_input = segPreProcess_image(image_array0,modelSize=self.par['modelSize'],mean=self.par['mean'],std =self.par['std'],numpy=self.par['numpy'], RGB_convert_first=self.par['RGB_convert_first'] ) | |||
#img_input = img_input.to(self.device) | |||
#print('###line56:',img_input.size()) | |||
img_input = segPreProcess_image_torch(image_array0,modelSize=self.par['modelSize'],mean=self.par['mean'],std =self.par['std'],numpy=self.par['numpy'], RGB_convert_first=self.par['RGB_convert_first'] ) | |||
def eval(self,image): | |||
time0 = time.time() | |||
imageH, imageW, _ = image.shape | |||
img = self.preprocess_image(image) | |||
time1 = time.time() | |||
time1_0=time.time() | |||
pred=segTrtForward(self.model,[img_input]) | |||
time2_0=time.time() | |||
if self.infer_type=='trt': | |||
pred=segTrtForward(self.model,[img]) | |||
elif self.infer_type=='pth': | |||
self.model.eval() | |||
with torch.no_grad(): | |||
pred = self.model(img) | |||
time2 = time.time() | |||
pred=torch.argmax(pred,dim=1).cpu().numpy()[0] | |||
time3_0 = time.time() | |||
if 'predResize' in self.par.keys(): | |||
if self.par['predResize']: | |||
pred = cv2.resize(pred.astype(np.uint8),(W,H)) | |||
else: | |||
pred = cv2.resize(pred.astype(np.uint8),(W,H)) | |||
time4_0 = time.time() | |||
segInfoStr= 'stdc:%.1f (pre-precess:%.1f ,infer:%.1f ,post-cpu-argmax:%.1f ,post-resize:%.1f) '%(self.get_ms(time4_0,time0_0), self.get_ms(time1_0,time0_0),self.get_ms(time2_0,time1_0),self.get_ms(time3_0,time2_0),self.get_ms(time4_0,time3_0) ) | |||
return pred,segInfoStr | |||
time3 = time.time() | |||
pred = cv2.resize(pred.astype(np.uint8),(imageW,imageH)) | |||
time4 = time.time() | |||
outstr= 'pre-precess:%.1f ,infer:%.1f ,post-cpu-argmax:%.1f ,post-resize:%.1f, total:%.1f \n '%( self.get_ms(time1,time0),self.get_ms(time2,time1),self.get_ms(time3,time2),self.get_ms(time4,time3),self.get_ms(time4,time0) ) | |||
return pred,outstr | |||
@@ -410,6 +410,7 @@ class Sort(object): | |||
for t in reversed(to_del): | |||
self.trackers.pop(t) | |||
# 将目标检测框与卡尔曼滤波器预测的跟踪框关联获取跟踪成功的目标,新增的目标,离开画面的目标 | |||
matched, unmatched_dets, unmatched_trks = associate_detections_to_trackers(dets, trks, self.iou_threshold) | |||
# 将跟踪成功的目标框更新到对应的卡尔曼滤波器 |
@@ -0,0 +1,36 @@ | |||
import numpy as np | |||
from skimage.morphology import medial_axis | |||
def Crack_measure(_mask_cv_gray,par={'dsx':(123-30)*1000/35*0.004387636 } ): | |||
'''裂缝实际尺寸测量''' | |||
'''输入:单个裂缝分割图像 | |||
过程:。 | |||
返回:最终绘制的结果图、最终落水人员(坐标、类别、置信度), | |||
''' | |||
# 图像转化 | |||
dsx = par['dsx'] | |||
###READ | |||
img = np.array(_mask_cv_gray.astype(np.int32)) | |||
image0 = binary = img | |||
###SKELETONIZATION | |||
img_skeletonized, distance = medial_axis(image0, return_distance=True) | |||
#print(img_skeletonized) | |||
img_skeletonized = np.array(img_skeletonized.astype(np.int32)) | |||
###COMPUTING WIDTH | |||
dist_on_skel = distance * img_skeletonized | |||
width = dist_on_skel[dist_on_skel != 0] * 2 | |||
for i in range(len(width)): | |||
if width[i] <= 2.0: | |||
width[i] = width[i] | |||
else: | |||
width[i] = width[i] - 2 | |||
###OUTPUT | |||
real_length = np.count_nonzero(img_skeletonized) *dsx # Each pixel remaining after | |||
if len(width)==0: | |||
return [0,0,0,0] | |||
real_mean_width = np.mean(width)*dsx | |||
real_max_width = np.max(width)*dsx | |||
real_min_width = np.min(width)*dsx | |||
return [real_length,real_mean_width,real_max_width,real_min_width] |
@@ -0,0 +1,4 @@ | |||
{ | |||
"labelnames":[ "纵向裂缝","横向裂缝","网状裂缝" ], | |||
"labelIndexs":["SL01","SL02","SL03"] | |||
} |
@@ -0,0 +1,5 @@ | |||
crack_yolov5_202302.pt对应类别['pedestrian', 'vehicle', 'D00', 'D10', 'Repair', 'D20', 'D40', 'Block crack', 'JiShui'] | |||
roaddamage20231028.pt对应类别[ 'D00','D10','D20','D40','D44','D50','Repair','D43','D01','D11','D0w0','Block crack' ] | |||
[ 'D00':纵向裂缝, | |||
'D10':横向裂缝, | |||
'D20':网状裂缝 ] |