18 changed files with 954 additions and 389 deletions
@ -0,0 +1,226 @@ |
|||||
|
""" |
||||
|
Copyright 2022 Huawei Technologies Co., Ltd |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
""" |
||||
|
|
||||
|
import time |
||||
|
|
||||
|
import cv2 |
||||
|
import numpy as np |
||||
|
import torch |
||||
|
import torchvision |
||||
|
|
||||
|
|
||||
|
def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=False, scaleFill=False, scaleup=True): |
||||
|
# Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 |
||||
|
shape = img.shape[:2] # current shape [height, width] |
||||
|
if isinstance(new_shape, int): |
||||
|
new_shape = (new_shape, new_shape) |
||||
|
|
||||
|
# Scale ratio (new / old) |
||||
|
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) |
||||
|
if not scaleup: # only scale down, do not scale up (for better test mAP) |
||||
|
r = min(r, 1.0) |
||||
|
|
||||
|
# Compute padding |
||||
|
ratio = r, r # width, height ratios |
||||
|
new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) |
||||
|
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding |
||||
|
if auto: # minimum rectangle |
||||
|
dw, dh = np.mod(dw, 64), np.mod(dh, 64) # wh padding |
||||
|
elif scaleFill: # stretch |
||||
|
dw, dh = 0.0, 0.0 |
||||
|
new_unpad = (new_shape[1], new_shape[0]) |
||||
|
ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios |
||||
|
|
||||
|
dw /= 2 # divide padding into 2 sides |
||||
|
dh /= 2 |
||||
|
|
||||
|
if shape[::-1] != new_unpad: # resize |
||||
|
img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) |
||||
|
top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) |
||||
|
left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) |
||||
|
img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border |
||||
|
return img, ratio, (dw, dh) |
||||
|
|
||||
|
|
||||
|
def non_max_suppression( |
||||
|
prediction, |
||||
|
conf_thres=0.25, |
||||
|
iou_thres=0.45, |
||||
|
classes=None, |
||||
|
agnostic=False, |
||||
|
multi_label=False, |
||||
|
labels=(), |
||||
|
max_det=300, |
||||
|
nm=0, # number of masks |
||||
|
): |
||||
|
"""Non-Maximum Suppression (NMS) on inference results to reject overlapping detections |
||||
|
|
||||
|
Returns: |
||||
|
list of detections, on (n,6) tensor per image [xyxy, conf, cls] |
||||
|
""" |
||||
|
|
||||
|
if isinstance(prediction, (list, tuple)): # YOLOv5 model in validation model, output = (inference_out, loss_out) |
||||
|
prediction = prediction[0] # select only inference output |
||||
|
|
||||
|
device = prediction.device |
||||
|
mps = 'mps' in device.type # Apple MPS |
||||
|
if mps: # MPS not fully supported yet, convert tensors to CPU before NMS |
||||
|
prediction = prediction.cpu() |
||||
|
bs = prediction.shape[0] # batch size |
||||
|
nc = prediction.shape[2] - nm - 5 # number of classes |
||||
|
xc = prediction[..., 4] > conf_thres # candidates |
||||
|
|
||||
|
# Checks |
||||
|
assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0' |
||||
|
assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0' |
||||
|
|
||||
|
# Settings |
||||
|
# min_wh = 2 # (pixels) minimum box width and height |
||||
|
max_wh = 7680 # (pixels) maximum box width and height |
||||
|
max_nms = 30000 # maximum number of boxes into torchvision.ops.nms() |
||||
|
time_limit = 0.5 + 0.05 * bs # seconds to quit after |
||||
|
multi_label &= nc > 1 # multiple labels per box (adds 0.5ms/img) |
||||
|
|
||||
|
t = time.time() |
||||
|
mi = 5 + nc # mask start index |
||||
|
output = [torch.zeros((0, 6 + nm), device=prediction.device)] * bs |
||||
|
for xi, x in enumerate(prediction): # image index, image inference |
||||
|
# Apply constraints |
||||
|
# x[((x[..., 2:4] < min_wh) | (x[..., 2:4] > max_wh)).any(1), 4] = 0 # width-height |
||||
|
x = x[xc[xi]] # confidence |
||||
|
|
||||
|
# Cat apriori labels if autolabelling |
||||
|
if labels and len(labels[xi]): |
||||
|
lb = labels[xi] |
||||
|
v = torch.zeros((len(lb), nc + nm + 5), device=x.device) |
||||
|
v[:, :4] = lb[:, 1:5] # box |
||||
|
v[:, 4] = 1.0 # conf |
||||
|
v[range(len(lb)), lb[:, 0].long() + 5] = 1.0 # cls |
||||
|
x = torch.cat((x, v), 0) |
||||
|
|
||||
|
# If none remain process next image |
||||
|
if not x.shape[0]: |
||||
|
continue |
||||
|
|
||||
|
# Compute conf |
||||
|
x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf |
||||
|
|
||||
|
# Box/Mask |
||||
|
box = xywh2xyxy(x[:, :4]) # center_x, center_y, width, height) to (x1, y1, x2, y2) |
||||
|
mask = x[:, mi:] # zero columns if no masks |
||||
|
|
||||
|
# Detections matrix nx6 (xyxy, conf, cls) |
||||
|
if multi_label: |
||||
|
i, j = (x[:, 5:mi] > conf_thres).nonzero(as_tuple=False).T |
||||
|
x = torch.cat((box[i], x[i, 5 + j, None], j[:, None].float(), mask[i]), 1) |
||||
|
else: # best class only |
||||
|
conf, j = x[:, 5:mi].max(1, keepdim=True) |
||||
|
x = torch.cat((box, conf, j.float(), mask), 1)[conf.view(-1) > conf_thres] |
||||
|
|
||||
|
# Filter by class |
||||
|
if classes is not None: |
||||
|
x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)] |
||||
|
|
||||
|
# Check shape |
||||
|
n = x.shape[0] # number of boxes |
||||
|
if not n: # no boxes |
||||
|
continue |
||||
|
elif n > max_nms: # excess boxes |
||||
|
x = x[x[:, 4].argsort(descending=True)[:max_nms]] # sort by confidence |
||||
|
else: |
||||
|
x = x[x[:, 4].argsort(descending=True)] # sort by confidence |
||||
|
|
||||
|
# Batched NMS |
||||
|
c = x[:, 5:6] * (0 if agnostic else max_wh) # classes |
||||
|
boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores |
||||
|
i = torchvision.ops.nms(boxes, scores, iou_thres) # NMS |
||||
|
if i.shape[0] > max_det: # limit detections |
||||
|
i = i[:max_det] |
||||
|
|
||||
|
output[xi] = x[i] |
||||
|
if mps: |
||||
|
output[xi] = output[xi].to(device) |
||||
|
if (time.time() - t) > time_limit: |
||||
|
print(f'WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded') |
||||
|
break # time limit exceeded |
||||
|
|
||||
|
return output |
||||
|
|
||||
|
|
||||
|
def xywh2xyxy(x): |
||||
|
# Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right |
||||
|
y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) |
||||
|
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x |
||||
|
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y |
||||
|
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x |
||||
|
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y |
||||
|
return y |
||||
|
|
||||
|
|
||||
|
def get_labels_from_txt(path): |
||||
|
labels_dict = dict() |
||||
|
with open(path) as f: |
||||
|
for cat_id, label in enumerate(f.readlines()): |
||||
|
labels_dict[cat_id] = label.strip() |
||||
|
return labels_dict |
||||
|
|
||||
|
|
||||
|
def scale_coords(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]] -= pad[0] # x padding |
||||
|
coords[:, [1, 3]] -= pad[1] # y padding |
||||
|
coords[:, :4] /= gain |
||||
|
clip_coords(coords, img0_shape) |
||||
|
return coords |
||||
|
|
||||
|
|
||||
|
def clip_coords(boxes, shape): |
||||
|
# Clip bounding xyxy bounding boxes to image shape (height, width) |
||||
|
if isinstance(boxes, torch.Tensor): # faster individually |
||||
|
boxes[:, 0].clamp_(0, shape[1]) # x1 |
||||
|
boxes[:, 1].clamp_(0, shape[0]) # y1 |
||||
|
boxes[:, 2].clamp_(0, shape[1]) # x2 |
||||
|
boxes[:, 3].clamp_(0, shape[0]) # y2 |
||||
|
else: # np.array (faster grouped) |
||||
|
boxes[:, [0, 2]] = boxes[:, [0, 2]].clip(0, shape[1]) # x1, x2 |
||||
|
boxes[:, [1, 3]] = boxes[:, [1, 3]].clip(0, shape[0]) # y1, y2 |
||||
|
|
||||
|
|
||||
|
def nms(box_out, conf_thres=0.4, iou_thres=0.5): |
||||
|
try: |
||||
|
boxout = non_max_suppression(box_out, conf_thres=conf_thres, iou_thres=iou_thres, multi_label=True) |
||||
|
except: |
||||
|
boxout = non_max_suppression(box_out, conf_thres=conf_thres, iou_thres=iou_thres) |
||||
|
return boxout |
||||
|
|
||||
|
|
||||
|
def draw_bbox(bbox, img0, color, wt, names): |
||||
|
det_result_str = '' |
||||
|
for idx, class_id in enumerate(bbox[:, 5]): |
||||
|
if float(bbox[idx][4] < float(0.05)): |
||||
|
continue |
||||
|
img0 = cv2.rectangle(img0, (int(bbox[idx][0]), int(bbox[idx][1])), (int(bbox[idx][2]), int(bbox[idx][3])), color, wt) |
||||
|
img0 = cv2.putText(img0, str(idx) + ' ' + names[int(class_id)], (int(bbox[idx][0]), int(bbox[idx][1] + 16)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) |
||||
|
img0 = cv2.putText(img0, '{:.4f}'.format(bbox[idx][4]), (int(bbox[idx][0]), int(bbox[idx][1] + 32)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) |
||||
|
det_result_str += '{} {} {} {} {} {}\n'.format(names[bbox[idx][5]], str(bbox[idx][4]), bbox[idx][0], bbox[idx][1], bbox[idx][2], bbox[idx][3]) |
||||
|
return img0 |
@ -0,0 +1,50 @@ |
|||||
|
import os.path |
||||
|
|
||||
|
from model.plugins.ModelBase import ModelBase |
||||
|
from myutils.ConfigManager import myCongif |
||||
|
import torch |
||||
|
import cv2 |
||||
|
class Model(ModelBase): |
||||
|
def __init__(self,path): |
||||
|
super().__init__() |
||||
|
self.name = "人员入侵(ACL)" |
||||
|
self.version = "V1.0" |
||||
|
self.model_type = 2 |
||||
|
#找pt模型路径 -- 一个约束py文件和模型文件的路径关系需要固定, -- 上传模型时,要解压好路径 |
||||
|
dirpath,filename = os.path.split(path) |
||||
|
model_file = os.path.join(dirpath,"yolov5s.pt") #目前约束模型文件和py文件在同一目录 |
||||
|
yolov5_path = myCongif.get_data("yolov5_path") |
||||
|
print(f"************{model_file},{yolov5_path}") |
||||
|
#实例化模型 |
||||
|
self.model = torch.hub.load(yolov5_path, 'custom', path=model_file, source='local') |
||||
|
|
||||
|
|
||||
|
def verify(self,image,data,isdraw=1): |
||||
|
results = self.model(image) # 进行模型检测 --- 需要统一接口 |
||||
|
detections = results.pandas().xyxy[0].to_dict(orient="records") |
||||
|
bwarn = False |
||||
|
warn_text = "" |
||||
|
#是否有检测区域,有先绘制检测区域 由于在该函数生成了polygon对象,所有需要在检测区域前调用。 |
||||
|
if data[1] == 1: |
||||
|
self.draw_polygon(image,data[2],(0, 255, 0)) |
||||
|
# 绘制检测结果 --- 也需要封装在类里, |
||||
|
for det in detections: |
||||
|
if det['name'] == 'person': #标签是人 |
||||
|
x1, y1, x2, y2 = int(det['xmin']), int(det['ymin']), int(det['xmax']), int(det['ymax']) |
||||
|
# 绘制目标识别的锚框 |
||||
|
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) |
||||
|
if data[1] == 1: # 指定了检测区域 |
||||
|
x_center = (x1 + x2) / 2 |
||||
|
y_center = (y1 + y2) / 2 |
||||
|
#绘制中心点? |
||||
|
cv2.circle(image, (int(x_center), int(y_center)), 5, (0, 0, 255), -1) |
||||
|
#判断是否区域点 |
||||
|
if not self.is_point_in_region((x_center, y_center)): |
||||
|
continue #没产生报警-继续 |
||||
|
#产生报警 |
||||
|
bwarn = True |
||||
|
warn_text = "Intruder detected!" |
||||
|
return detections,bwarn,warn_text |
||||
|
|
||||
|
def testRun(self): |
||||
|
print("1111") |
@ -0,0 +1,80 @@ |
|||||
|
person |
||||
|
bicycle |
||||
|
car |
||||
|
motorcycle |
||||
|
airplane |
||||
|
bus |
||||
|
train |
||||
|
truck |
||||
|
boat |
||||
|
traffic_light |
||||
|
fire_hydrant |
||||
|
stop_sign |
||||
|
parking_meter |
||||
|
bench |
||||
|
bird |
||||
|
cat |
||||
|
dog |
||||
|
horse |
||||
|
sheep |
||||
|
cow |
||||
|
elephant |
||||
|
bear |
||||
|
zebra |
||||
|
giraffe |
||||
|
backpack |
||||
|
umbrella |
||||
|
handbag |
||||
|
tie |
||||
|
suitcase |
||||
|
frisbee |
||||
|
skis |
||||
|
snowboard |
||||
|
sports_ball |
||||
|
kite |
||||
|
baseball_bat |
||||
|
baseball_glove |
||||
|
skateboard |
||||
|
surfboard |
||||
|
tennis_racket |
||||
|
bottle |
||||
|
wine_glass |
||||
|
cup |
||||
|
fork |
||||
|
knife |
||||
|
spoon |
||||
|
bowl |
||||
|
banana |
||||
|
apple |
||||
|
sandwich |
||||
|
orange |
||||
|
broccoli |
||||
|
carrot |
||||
|
hot_dog |
||||
|
pizza |
||||
|
donut |
||||
|
cake |
||||
|
chair |
||||
|
couch |
||||
|
potted_plant |
||||
|
bed |
||||
|
dining_table |
||||
|
toilet |
||||
|
tv |
||||
|
laptop |
||||
|
mouse |
||||
|
remote |
||||
|
keyboard |
||||
|
cell_phone |
||||
|
microwave |
||||
|
oven |
||||
|
toaster |
||||
|
sink |
||||
|
refrigerator |
||||
|
book |
||||
|
clock |
||||
|
vase |
||||
|
scissors |
||||
|
teddy_bear |
||||
|
hair_drier |
||||
|
toothbrush |
After Width: | Height: | Size: 64 KiB |
Binary file not shown.
Binary file not shown.
@ -1,17 +1,31 @@ |
|||||
|
import platform |
||||
|
|
||||
from myutils.ConfigManager import myCongif |
from myutils.ConfigManager import myCongif |
||||
from myutils.MyLogger_logger import LogHandler |
from myutils.MyLogger_logger import LogHandler |
||||
from core.ViewManager import mVManager |
from core.ViewManager import mVManager |
||||
from web import create_app |
from web import create_app |
||||
|
from core.ModelManager import mMM |
||||
import os |
import os |
||||
|
import platform |
||||
|
import shutil |
||||
|
|
||||
|
|
||||
#print(f"Current working directory (run.py): {os.getcwd()}") |
print(f"Current working directory (run.py): {os.getcwd()}") |
||||
web = create_app() |
web = create_app() |
||||
|
|
||||
if __name__ == '__main__': |
if __name__ == '__main__': |
||||
# logger = LogHandler().get_logger("main") |
system = platform.system() |
||||
# logger.debug("debug") |
if system == "Windows": |
||||
# logger.info("info") |
total, used, free = shutil.disk_usage("/") |
||||
mVManager.start_check_rtsp() |
elif system == "Linux": |
||||
|
"""获取Linux系统的剩余存储空间""" |
||||
|
statvfs = os.statvfs(os.getcwd()) |
||||
|
free = statvfs.f_bavail * statvfs.f_frsize |
||||
|
else: |
||||
|
raise NotImplementedError(f"Unsupported operating system: {system}") |
||||
|
print(free/(1024*1024)) |
||||
|
|
||||
|
mMM.start_work() # 启动所有通道的处理 |
||||
|
mVManager.start_check_rtsp() #线程更新视频在线情况 |
||||
web.run(debug=True,port=5001) |
web.run(debug=True,port=5001) |
||||
|
|
||||
|
Binary file not shown.
Loading…
Reference in new issue