detectopencvmut0113auta.py 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. # YOLOv5 �� by Ultralytics, AGPL-3.0 license
  2. """
  3. Run YOLOv5 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc.
  4. Usage - sources:
  5. $ python detect.py --weights yolov5s.pt --source 0 # webcam
  6. img.jpg # image
  7. vid.mp4 # video
  8. screen # screenshot
  9. path/ # directory
  10. list.txt # list of images
  11. list.streams # list of streams
  12. 'path/*.jpg' # glob
  13. 'https://youtu.be/Zgi9g1ksQHc' # YouTube
  14. 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream
  15. Usage - formats:
  16. $ python detect.py --weights yolov5s.pt # PyTorch
  17. yolov5s.torchscript # TorchScript
  18. yolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnn
  19. yolov5s_openvino_model # OpenVINO
  20. yolov5s.engine # TensorRT
  21. yolov5s.mlmodel # CoreML (macOS-only)
  22. yolov5s_saved_model # TensorFlow SavedModel
  23. yolov5s.pb # TensorFlow GraphDef
  24. yolov5s.tflite # TensorFlow Lite
  25. yolov5s_edgetpu.tflite # TensorFlow Edge TPU
  26. yolov5s_paddle_model # PaddlePaddle
  27. """
  28. import matplotlib.path as mat
  29. import requests
  30. import argparse
  31. import os
  32. import platform
  33. import sqlite3
  34. import sys
  35. import threading
  36. import time
  37. from pathlib import Path
  38. import signal
  39. import torch
  40. from concurrent.futures import ThreadPoolExecutor
  41. from concurrent.futures import ProcessPoolExecutor
  42. from multiprocessing import Process, Manager, Value
  43. from multiprocessing import Queue
  44. from multiprocessing import set_start_method
  45. import multiprocessing
  46. import multiprocessing as mp
  47. import numpy as np
  48. from torchvision import transforms
  49. FILE = Path(__file__).resolve()
  50. ROOT = FILE.parents[0] # YOLOv5 root directory
  51. if str(ROOT) not in sys.path:
  52. sys.path.append(str(ROOT)) # add ROOT to PATH
  53. ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative
  54. from models.common import DetectMultiBackend
  55. from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams, LoadStreamsSQLNEWN, LoadStreamsSQL, \
  56. LoadStreamsSQLNRERT, LoadStreamsVEight, LoadStreamsSQLT, LoadStreamsSQLTN
  57. from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2,
  58. increment_path, non_max_suppression, print_args, scale_boxes, strip_optimizer, xyxy2xywh,
  59. strtolst, apply_classifier1, apply_classifieruniform, compute_IOU, task, apply_classifierarm)
  60. from utils.plots import Annotator, colors, save_one_box
  61. from utils.torch_utils import select_device, smart_inference_mode
  62. from utils.renwu import newHelmet, newUniform, newFall, Personcount, Arm, Bag, Cross, Extinguisher, newPersontre, Bag, Danager,CarHelmetBelt
  63. # from testpool import func1,TestA
  64. # def my_handler(signum, frame):
  65. # exit(0)
  66. # url = "http://36.7.84.146:18802/ai-service/open/api/operate/upload"
  67. url = "http://172.19.152.231/open/api/operate/upload"
  68. urlrtsp = "http://172.19.152.231/open/api/operate/previewURLs"
  69. urlt = "http://172.19.152.231/open/api/operate/taskList"
  70. urla = "http://172.19.152.231/open/api/operate/algorithmList"
  71. urlele = "http://172.19.152.231/open/api/operate/fence"
  72. urltime = "http://172.19.152.231/open/api/operate/getTime"
  73. urlperson = "http://172.19.152.231/open/api/operate/getPersonLimitNum"
  74. # modellabeldir = {'0':'head','8':'person','10':'other','14':'smoke','16':'fire','21':'cross','25':'fall','29':'car','30':'liquid','31':'pressure','32':'sleep','33':'conveyor','34':'personcount','35':'gloves','36':'sit','37':'other','38':'person','98':'face','51':'person'}
  75. # algmodel = {'helmet': '0','danager': '8','uniform': '10','smoke': '14','fire': '16','cross': '21','fall': '25','occupancy': '29','liquid': '30','pressure': '31','sleep': '32','conveyor': '33','personcount': '34','gloves': '35','sit': '36','other': '37','duty': '38','face': '98','run': '51'}
  76. modelnamedir = {'0': 'helmet', '8': 'danager', '10': 'uniform', '14': 'smoke', '16': 'fire', '21': 'cross',
  77. '25': 'fall', '29': 'occupancy', '30': 'liquid', '31': 'pressure', '32': 'sleep', '34': 'personcount',
  78. '37': 'other', '38': 'duty', '98': 'face', '55': 'oil', '52': 'jingdian', '53': 'rope',
  79. '54': 'personcar', '39': 'inspection', '11': 'reflective', '12': 'phone', '66': 'extinguisher',
  80. '67': 'belt', '68': 'menjin', '35': 'arm', '36': 'persontre', '33': 'bag'}
  81. modellabeldir = {'0': 'head,person', '8': 'person', '10': 'black_work_clothes,blue_work_clothes,person', '14': 'smoke',
  82. '16': 'fire', '21': 'cross', '25': 'fall', '29': 'car', '30': 'liquid', '31': 'pressure',
  83. '32': 'sleep', '34': 'personcount', '37': 'other', '38': 'person', '98': 'face', '55': 'oil',
  84. '52': 'person,hand,ball', '53': 'rope', '54': 'person', '39': 'person',
  85. '11': 'blue,greent,whitet,bluecoat,whitebarcoat,graycoat,baoan,chenyi,other', '12': 'phone',
  86. '66': 'extinguisher', '67': 'person,head,helmet,belt', '68': 'person', '35': 'barearm,arm',
  87. '36': 'person,foot,cart,bag,box', '33': 'handbox,handbag'}
  88. modelalgdir = {}
  89. personcountdir = {}
  90. for key, value in modelnamedir.items():
  91. modelalgdir[value] = key
  92. taskmap = {'helmet': newHelmet, 'uniform': newUniform, 'fall': newFall, 'personcount': Personcount, 'arm': Arm, 'bag': Bag,
  93. 'cross': Cross, 'extinguisher': Extinguisher, 'persontre': newPersontre, 'bag': Bag, 'danager': Danager,'belt':CarHelmetBelt}
  94. mean, std = [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
  95. test = transforms.Compose([transforms.Resize((224, 224)),
  96. # transforms.CenterCrop(224),
  97. transforms.ToTensor(),
  98. transforms.Normalize(mean=mean, std=std)
  99. ])
  100. def clapre(modelcla, claimg, clapoint):
  101. imgten = torch.stack(claimg, dim=0)
  102. clapoint = torch.stack(clapoint, dim=0)
  103. imgten = imgten.to(0)
  104. result = modelcla(imgten)
  105. result = F.softmax(result)
  106. print(result)
  107. index = result.argmax(1)
  108. index = index.cpu().numpy()
  109. index = np.argwhere(index < 5)
  110. index = index.reshape(-1)
  111. print(index)
  112. if len(index) > 0:
  113. print(clapoint[index])
  114. return clapoint[index]
  115. else:
  116. return None
  117. class YoloOpt:
  118. def __init__(self, weights=ROOT / 'yolov5s.pt', source=ROOT / 'data/images', data=ROOT / 'data/coco128.yaml',
  119. imgsz=(640, 640),
  120. conf_thres=0.25,
  121. iou_thres=0.45,
  122. max_det=1000,
  123. device='',
  124. view_img=False,
  125. save_txt=False,
  126. save_conf=False,
  127. save_crop=False,
  128. nosave=True,
  129. classes=None,
  130. agnostic_nms=False,
  131. augment=False,
  132. visualize=False,
  133. update=False,
  134. project=ROOT / 'runs/detect',
  135. name='exp',
  136. exist_ok=False,
  137. line_thickness=1,
  138. hide_labels=False,
  139. hide_conf=False,
  140. half=False,
  141. dnn=False,
  142. vid_stride=10,
  143. classify=False,
  144. v8=False):
  145. self.weights = weights # 权重文件地址
  146. self.source = source # 待识别的图像
  147. self.data = data
  148. if imgsz is None:
  149. self.imgsz = (640, 640)
  150. self.imgsz = imgsz # 输入图片的大小,默认 (640,640)
  151. self.conf_thres = conf_thres # object置信度阈值 默认0.25 用在nms中
  152. self.iou_thres = iou_thres # 做nms的iou阈值 默认0.45 用在nms中
  153. self.device = device # 执行代码的设备,由于项目只能用 CPU,这里只封装了 CPU 的方法
  154. self.view_img = view_img # 是否展示预测之后的图片或视频 默认False
  155. self.classes = classes # 只保留一部分的类别,默认是全部保留
  156. self.agnostic_nms = agnostic_nms # 进行NMS去除不同类别之间的框, 默认False
  157. self.augment = augment # augmented inference TTA测试时增强/多尺度预测,可以提分
  158. self.update = update # 如果为True,则对所有模型进行strip_optimizer操作,去除pt文件中的优化器等信息,默认为False
  159. self.exist_ok = exist_ok # 如果为True,则对所有模型进行strip_optimizer操作,去除pt文件中的优化器等信息,默认为False
  160. self.project = project # 保存测试日志的参数,本程序没有用到
  161. self.name = name # 每次实验的名称,本程序也没有用到
  162. self.max_det = max_det
  163. self.save_txt = save_txt
  164. self.save_conf = save_conf
  165. self.save_crop = save_crop
  166. self.nosave = nosave
  167. self.visualize = visualize
  168. self.line_thickness = line_thickness
  169. self.hide_labels = hide_labels
  170. self.hide_conf = hide_conf
  171. self.half = half
  172. self.dnn = dnn
  173. self.vid_stride = vid_stride
  174. self.classify = classify
  175. self.v8 = v8
  176. class Detect:
  177. def __init__(self, weights=ROOT / 'yolov5s.pt', imgsz=(640, 640), source="changshusql1103.db", classes=None,
  178. device=None, classify=False, conf_thres=0.25, v8=False):
  179. print(f'detectweights = {weights}')
  180. if v8:
  181. from ultralytics.nn.autobackend import AutoBackend
  182. from ultralytics.utils.ops import non_max_suppression
  183. else:
  184. from utils.general import non_max_suppression
  185. self.opt = YoloOpt(weights=weights, imgsz=imgsz, source=source, classes=classes, device=device,
  186. classify=classify, conf_thres=conf_thres, v8=v8)
  187. self.source = str(self.opt.source)
  188. self.save_img = not self.opt.nosave and not source.endswith('.txt') # save inference images
  189. is_file = Path(self.source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
  190. is_url = self.source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://'))
  191. self.webcam = self.source.isnumeric() or source.endswith('.db') or (is_url and not is_file)
  192. screenshot = self.source.lower().startswith('screen')
  193. if is_url and is_file:
  194. self.source = check_file(self.source) # download
  195. self.save_dir = increment_path(Path(self.opt.project) / self.opt.name,
  196. exist_ok=self.opt.exist_ok) # increment run
  197. # self.save_dir = self.save_dir / Path(self.opt.weights).stem
  198. # self.save_dir.mkdir(parents=True, exist_ok=True)
  199. (self.save_dir / 'labels' if self.opt.save_txt else self.save_dir).mkdir(parents=True,
  200. exist_ok=True) # make dir
  201. print(f'device = {self.opt.device}')
  202. device = select_device(self.opt.device)
  203. if v8:
  204. self.model = AutoBackend(self.opt.weights, device=device, dnn=self.opt.dnn, data=self.opt.data,
  205. fp16=self.opt.half)
  206. if Path(weights).stem in ['arm', 'uniform','fall']:
  207. if Path(weights).stem == 'arm':
  208. self.personmodel = AutoBackend('yolov8m.pt', device=device, dnn=self.opt.dnn, data=self.opt.data,
  209. fp16=self.opt.half)
  210. elif Path(weights).stem in ['uniform','fall']:
  211. self.personmodel = AutoBackend('yolo11m.pt', device=device, dnn=self.opt.dnn, data=self.opt.data,
  212. fp16=self.opt.half)
  213. else:
  214. self.model = DetectMultiBackend(self.opt.weights, device=device, dnn=self.opt.dnn, data=self.opt.data,
  215. fp16=self.opt.half)
  216. if Path(weights).stem in ['helmet', 'arm']:
  217. self.personmodel = DetectMultiBackend('personcount.pt', device=device, dnn=self.opt.dnn,
  218. data=self.opt.data, fp16=self.opt.half)
  219. self.stride, self.names, self.pt = self.model.stride, self.model.names, self.model.pt
  220. self.classify = classify
  221. if self.classify:
  222. if Path(weights).stem != "arm":
  223. classifier_model = torch.load(f"{Path(weights).stem}cls.pt")
  224. self.classifier_model = classifier_model.to(device)
  225. self.classifier_model.eval()
  226. else:
  227. self.classifier_model = AutoBackend(f"{Path(weights).stem}cls.pt", device=device, dnn=self.opt.dnn,
  228. data=self.opt.data, fp16=self.opt.half)
  229. self.imgsz = check_img_size(self.opt.imgsz, s=self.stride)
  230. self.model.warmup(imgsz=(1, 3, *self.imgsz))
  231. self.readpoint()
  232. print(self.imgsz)
  233. self.updatetime = time.time()
  234. self.updatemtime = time.time()
  235. self.filetime = os.path.getmtime(self.opt.weights)
  236. self.taskname = taskmap[Path(self.opt.weights).stem]()
  237. t1 = threading.Thread(target=self.load, daemon=True)
  238. t1.start()
  239. @smart_inference_mode()
  240. def infer(self, queue, runmodel):
  241. pretime = time.time()
  242. seen, windows, self.dt = 0, [], (Profile(), Profile(), Profile())
  243. #
  244. # print ("数据库打开成功")
  245. while True:
  246. if time.localtime().tm_hour not in range(7, 20):
  247. time.sleep(30)
  248. continue
  249. # print('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
  250. if time.time() - pretime > 300:
  251. ret = self.readpoint()
  252. pretime = time.time()
  253. if not ret:
  254. print(f'{Path(self.opt.weights).stem} {runmodel}')
  255. runmodel.pop(Path(self.opt.weights).stem)
  256. print(f'{Path(self.opt.weights).stem} {runmodel}')
  257. break
  258. print(f'queuelen = {len(queue)}')
  259. for que in queue:
  260. if que.qsize() == 0:
  261. print('queuezero')
  262. time.sleep(0.01)
  263. if que.qsize() > 0:
  264. # if time.time()-pretime>300:
  265. # ret = self.readpoint()
  266. # pretime = time.time()
  267. # if not ret:
  268. # print(f'{Path(self.opt.weights).stem} {runmodel}')
  269. # runmodel.pop(Path(self.opt.weights).stem)
  270. # print(f'{Path(self.opt.weights).stem} {runmodel}')
  271. # break
  272. setframe = que.get()
  273. # print('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
  274. # if setframe is not None
  275. path, im, im0s, vid_cap, s, videotime, channels = setframe
  276. algchannel = list(self.dirmodel.keys())
  277. print(algchannel)
  278. print(path)
  279. algchannel = np.array(algchannel)
  280. channelsnp = np.array(channels)
  281. algindex = np.where(np.in1d(channelsnp, algchannel))[0]
  282. algindex = list(algindex)
  283. path = np.array(path)
  284. path = path[algindex]
  285. path = path.tolist()
  286. channels = np.array(channels)
  287. channels = channels[algindex]
  288. channels = channels.tolist()
  289. # print(algindex)
  290. if len(algindex) == 0:
  291. continue
  292. # for ia in algindex:
  293. # print(type(im0s[ia]))
  294. # print(im0s[ia].shape)
  295. im = im[algindex]
  296. # for ia in algindex:
  297. # print(type(ia))
  298. try:
  299. im0s = np.asarray(im0s)
  300. except Exception:
  301. im0s = np.asarray(im0s, dtype=object)
  302. print(im0s.shape)
  303. im0s = im0s[algindex]
  304. # im0s = im0s.tolist()
  305. print(f'algindex = {algindex}')
  306. print(f'im0s ={im0s[0].shape}')
  307. videotime = np.array(videotime)
  308. videotime = videotime[algindex]
  309. videotime = tuple(map(tuple, videotime))
  310. with self.dt[0]:
  311. im = torch.from_numpy(im).to(self.model.device)
  312. im = im.half() if self.model.fp16 else im.float() # uint8 to fp16/32
  313. im /= 255 # 0 - 255 to 0.0 - 1.0
  314. if len(im.shape) == 3:
  315. im = im[None] # expand for batch dim
  316. # Inference
  317. with self.dt[1]:
  318. visualize = increment_path(self.save_dir / Path(path).stem,
  319. mkdir=True) if self.opt.visualize else False
  320. # print('error')
  321. # print(self.model)
  322. pred = self.model(im, augment=self.opt.augment, visualize=visualize)
  323. self.postprocess(pred, path, im0s, im, s, videotime, channels)
  324. def postprocess(self, pred, path, im0s, im, s, videotime, channels):
  325. if time.time() - self.updatemtime > 300:
  326. if self.filetime != os.path.getmtime(self.opt.weights):
  327. device = select_device(self.opt.device)
  328. print("load new load")
  329. self.model = DetectMultiBackend(self.opt.weights, device=device, dnn=self.opt.dnn, data=self.opt.data,
  330. fp16=self.opt.half)
  331. self.stride, self.names, self.pt = self.model.stride, self.model.names, self.model.pt
  332. self.filetime = os.path.getmtime(self.opt.weights)
  333. # try:
  334. # if modelalgdir[Path(self.opt.weights).stem]!='0':
  335. print(modelalgdir[Path(self.opt.weights).stem])
  336. try:
  337. rea = requests.post(url=urla, data={'algorithmCode': modelalgdir[Path(self.opt.weights).stem]}).json()[
  338. 'data']
  339. con = rea[0]['confidence']
  340. self.opt.conf_thres = con
  341. except Exception:
  342. print('error')
  343. self.updatemtime = time.time()
  344. seen = 0
  345. # dt = (Profile(), Profile(), Profile())
  346. print(f'senn = {seen}')
  347. windows = []
  348. if Path(self.opt.weights).stem:
  349. labelnamelist = []
  350. with self.dt[2]:
  351. # print(f'cropshape={pred.shape}')
  352. if self.opt.v8:
  353. from ultralytics.utils.ops import non_max_suppression
  354. else:
  355. from utils.general import non_max_suppression
  356. if Path(self.opt.weights).stem == "fall":
  357. pred = non_max_suppression(pred, self.opt.conf_thres, self.opt.iou_thres, self.opt.classes,
  358. self.opt.agnostic_nms, max_det=self.opt.max_det,nc=1)
  359. else:
  360. pred = non_max_suppression(pred, self.opt.conf_thres, self.opt.iou_thres, self.opt.classes,
  361. self.opt.agnostic_nms, max_det=self.opt.max_det)
  362. # Second-stage classifier (optional)
  363. # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)
  364. if self.classify and Path(self.opt.weights).stem != 'persontre':
  365. if Path(self.opt.weights).stem == 'arm':
  366. pred = apply_classifierarm(pred, self.classifier_model, im, im0s, Path(self.opt.weights).stem)
  367. else:
  368. pred = apply_classifier1(pred, self.classifier_model, im, im0s, Path(self.opt.weights).stem)
  369. # Process predictions
  370. # print(f'predshape={pred.shape}')
  371. for i, det in enumerate(pred): # per image
  372. if time.time() - self.updatetime > 300:
  373. dataele = {
  374. "algorithmCode": self.dirmodel[channels[i]]['classindex'],
  375. "algorithmIp": self.dirmodel[channels[i]]['algip'],
  376. "channel": self.dirmodel[channels[i]]['channel']
  377. }
  378. try:
  379. resultele = requests.post(url=urlele, data=dataele).json()['data']['pointCollections']
  380. resultele = resultele.split(',||')
  381. resultele = tuple(resultele)
  382. point = '%s:' * len(resultele) % resultele
  383. if len(point[:-2]) > 1:
  384. self.dirmodel[channels[i]]['point'] = point[:-2]
  385. except Exception:
  386. print('post error')
  387. if Path(self.opt.weights).stem == 'personcount':
  388. try:
  389. resultper = requests.post(url=urlperson, data=dataele).json()['data']
  390. personcountdir[channels[i]] = int(resultper)
  391. except Exception:
  392. print('urlpersonerror')
  393. if Path(self.opt.weights).stem == 'sleep' or Path(self.opt.weights).stem == 'duty':
  394. datatime = {
  395. "algorithmCode": self.dirmodel[channels[i]]['classindex'],
  396. "algorithmIp": self.dirmodel[channels[i]]['algip'],
  397. "channel": self.dirmodel[channels[i]]['channel']
  398. }
  399. try:
  400. resulttime = requests.post(url=urltime, data=dataele).json()['data']
  401. self.dirmodel[channel]['durtime'] = int(resulttime)
  402. except Exception:
  403. print('posttime error')
  404. self.updatetime = time.time()
  405. seen += 1
  406. if self.webcam: # batch_size >= 1
  407. p, im0 = path[i], im0s[i].copy()
  408. s += f'{i}: '
  409. else:
  410. p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)
  411. p = Path(p) # to Path
  412. save_path = str(self.save_dir / p.name) # im.jpg
  413. # txt_path = str(self.save_dir / 'labels' / p.stem) + (
  414. # '' #if dataset.mode == 'image' else f'_{frame}') # im.txt
  415. s += '%gx%g ' % im.shape[2:] # print string
  416. gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh
  417. imc = im0.copy() # for save_crop
  418. annotator = Annotator(im0, line_width=self.opt.line_thickness, example=str(self.names))
  419. flag = False
  420. if len(det) and Path(self.opt.weights).stem != 'duty':
  421. # flag = True
  422. # Rescale boxes from img_size to im0 size
  423. det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round()
  424. # Print results
  425. for c in det[:, 5].unique():
  426. n = (det[:, 5] == c).sum() # detections per class
  427. s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string
  428. # Write results
  429. if Path(self.opt.weights).stem in ['arm', 'uniform','fall']:
  430. personpred = self.personmodel(im[i][None], None, None)
  431. personpred = non_max_suppression(personpred, 0.7, self.opt.iou_thres, 0,
  432. self.opt.agnostic_nms, max_det=self.opt.max_det)
  433. if len(personpred[0]) == 0:
  434. flag = False
  435. elif Path(self.opt.weights).stem == 'other':
  436. persondet = []
  437. personpred = personpred[0]
  438. personpred[:, :4] = scale_boxes(im.shape[2:], personpred[:, :4], im0.shape).round()
  439. for *perxyxy, conf, cls in reversed(personpred):
  440. print(perxyxy)
  441. x1, y1, x3, y3 = perxyxy
  442. x1, y1, x3, y3 = int(x1), int(y1), int(x3), int(y3)
  443. x2, y2 = x3, y1
  444. x4, y4 = x1, y3
  445. flag = self.taskname.getflag(det, persondet, annotator, self.dirmodel[channels[i]]['fence'],
  446. self.dirmodel[channels[i]]['point'], self.names,
  447. self.dirmodel[channels[i]]['label'],channel=channls[i])
  448. else:
  449. persondet = []
  450. personpred = personpred[0]
  451. personpred[:, :4] = scale_boxes(im.shape[2:], personpred[:, :4], im0.shape).round()
  452. for *perxyxy, conf, cls in reversed(personpred):
  453. print(perxyxy)
  454. if conf < 0.8:
  455. continue
  456. x1, y1, x3, y3 = perxyxy
  457. x1, y1, x3, y3 = int(x1), int(y1), int(x3), int(y3)
  458. x2, y2 = x3, y1
  459. x4, y4 = x1, y3
  460. persondet.append([x1, y1, x2, y2, x3, y3, x4, y4])
  461. if Path(self.opt.weights).stem == "fall":
  462. flag = self.taskname.getflag(det, persondet, annotator, self.dirmodel[channels[i]]['fence'],
  463. self.dirmodel[channels[i]]['point'], self.names,
  464. self.dirmodel[channels[i]]['label'],imshape=im.shape[2:],channel=channels[i])
  465. else:
  466. flag = self.taskname.getflag(det, persondet, annotator, self.dirmodel[channels[i]]['fence'],
  467. self.dirmodel[channels[i]]['point'], self.names,
  468. self.dirmodel[channels[i]]['label'],channel=channels[i])
  469. else:
  470. if Path(self.opt.weights).stem in ['personcount']:
  471. flag = self.taskname.getflag(det, None, annotator, self.dirmodel[channels[i]]['fence'],
  472. self.dirmodel[channels[i]]['point'], self.names,
  473. self.dirmodel[channels[i]]['label'], personcountdir[channels[i]],channel=channels[i])
  474. elif Path(self.opt.weights).stem in ['persontre']:
  475. flag = self.taskname.getflag(det, None, annotator, self.dirmodel[channels[i]]['fence'],
  476. self.dirmodel[channels[i]]['point'], self.names,
  477. self.dirmodel[channels[i]]['label'], 1, imc,channel=channels[i])
  478. else:
  479. flag = self.taskname.getflag(det, None, annotator, self.dirmodel[channels[i]]['fence'],
  480. self.dirmodel[channels[i]]['point'], self.names,
  481. self.dirmodel[channels[i]]['label'],channel=channels[i])
  482. if flag:
  483. # if self.dirmodel[channels[i]]['imgtime'] != videotime[i]:
  484. self.dirmodel[channels[i]]['detframe'].pop(0)
  485. self.dirmodel[channels[i]]['detframe'].append(1)
  486. self.dirmodel[channels[i]]['preim'] = annotator.result()
  487. self.dirmodel[channels[i]]['oripreim'] = imc
  488. self.dirmodel[channels[i]]['posttime'] = videotime[i]
  489. print(self.dirmodel[channels[i]]['detframe'])
  490. # self.dirmodel[channels[i]]['imgtime'] = videotime[i]
  491. else:
  492. # print(f'deti= {i}')
  493. # print(detframe[i])
  494. # if self.dirmodel[channels[i]]['imgtime'] != videotime[i]:
  495. self.dirmodel[channels[i]]['detframe'].pop(0)
  496. self.dirmodel[channels[i]]['detframe'].append(0)
  497. print(self.dirmodel[channels[i]]['detframe'])
  498. if not self.dirmodel[channels[i]]['detflag'] and self.dirmodel[channels[i]]['detframe'].count(1) >= 1:
  499. self.dirmodel[channels[i]]['detflag'] = True
  500. self.dirmodel[channels[i]]['detpretime'] = time.time()
  501. elif self.dirmodel[channels[i]]['detframe'].count(1) == 0:
  502. self.dirmodel[channels[i]]['detflag'] = False
  503. self.dirmodel[channels[i]]['detpretime'] = float('inf')
  504. # Stream results
  505. # im0 = annotator.result()
  506. if time.time() - self.dirmodel[channels[i]]['postpretime'] > 30 and time.time() - \
  507. self.dirmodel[channels[i]]['detpretime'] > self.dirmodel[channels[i]]['durtime'] and \
  508. self.dirmodel[channels[i]]['detflag']:
  509. print('post-------------------------------------------------------------------------')
  510. # time.sleep(30)
  511. # print(time.time() - postpretime[i])
  512. # print('111111111111111111111111111111111111111111111111')
  513. # print(dirmodel[channels[i]]['preim'].shape)
  514. success, encoded_image = cv2.imencode('.jpg', self.dirmodel[channels[i]]['preim'])
  515. content = encoded_image.tobytes()
  516. successori, encoded_imageori = cv2.imencode('.jpg', self.dirmodel[channels[i]]['oripreim'])
  517. contentori = encoded_imageori.tobytes()
  518. filename = f'{p.stem}_{int(time.time())}.jpg'
  519. filenameori = f'ori{p.stem}_{int(time.time())}.jpg'
  520. print(f'str(p) {p.name}')
  521. print(channels[i])
  522. payload = {'channel': self.dirmodel[channels[i]]['channel'],
  523. 'classIndex': self.dirmodel[channels[i]]['classindex'],
  524. 'ip': self.dirmodel[channels[i]]['algip'],
  525. 'videoTime': time.strftime('%Y-%m-%d %H:%M:%S', self.dirmodel[channels[i]]['posttime']),
  526. 'videoUrl': channels[i]}
  527. files = [
  528. ('file', (filename, content, 'image/jpeg')),
  529. ('oldFile', (filenameori, contentori, 'image/jpeg')),
  530. ]
  531. try:
  532. result = requests.post(url, data=payload, files=files)
  533. print(result)
  534. except Exception:
  535. print('posterror')
  536. # time.sleep(3000)
  537. self.dirmodel[channels[i]]['postpretime'] = time.time()
  538. self.dirmodel[channels[i]]['detflag'] = False
  539. timesave = time.strftime('%Y-%m-%d-%H:%M:%S', self.dirmodel[channels[i]]['posttime'])
  540. year = time.strftime('%Y', time.localtime(time.time()))
  541. month = time.strftime('%m', time.localtime(time.time()))
  542. day = time.strftime('%d', time.localtime(time.time()))
  543. savefold = f'/mnt/project/images/{Path(self.opt.weights).stem}/{year}/{month}/{day}'
  544. savefold = Path(savefold)
  545. savefold.mkdir(parents=True, exist_ok=True)
  546. detsavefold = f'/mnt/project/detimages/{Path(self.opt.weights).stem}/{year}/{month}/{day}'
  547. detsavefold = Path(detsavefold)
  548. detsavefold.mkdir(parents=True, exist_ok=True)
  549. cv2.imwrite(f'{savefold}/{timesave}.jpg', self.dirmodel[channels[i]]['oripreim'])
  550. cv2.imwrite(f'{detsavefold}/{timesave}det.jpg', self.dirmodel[channels[i]]['preim'])
  551. # if self.dirmodel[channels[i]]['detframe'].count(1)==0:
  552. # self.dirmodel[channels[i]]['detflag'] = False
  553. # time.sleep(1)
  554. self.view_img = False
  555. if self.view_img:
  556. if platform.system() == 'Linux' and p not in windows:
  557. windows.append(p)
  558. cv2.namedWindow(f'{str(p)}-{Path(self.opt.weights).stem}',
  559. cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux)
  560. cv2.resizeWindow(f'{str(p)}-{Path(self.opt.weights).stem}', im0.shape[1], im0.shape[0])
  561. im1 = cv2.resize(im0, (1280, 720))
  562. cv2.imshow(f'{str(p)}-{Path(self.opt.weights).stem}', im1)
  563. cv2.waitKey(1) # 1 millisecond
  564. # Save results (image with detections)
  565. # Print time (inference-only)
  566. print(f'channels[i]={channels[i]}')
  567. LOGGER.info(
  568. f"{s}{'' if len(det) else '(no detections), '}{self.dt[1].dt * 1E3:.1f}ms {str(p)}-{Path(self.opt.weights).stem}")
  569. def load(self):
  570. conn = sqlite3.connect(self.source)
  571. c = conn.cursor()
  572. while True:
  573. #
  574. # print ("数据库打开成功")
  575. cursor = c.execute(
  576. "SELECT modelname, addstream,delstream,streaming from CHANGESTREAM WHERE modelname= (?)",
  577. (Path(self.opt.weights).stem,))
  578. self.contentid = cursor.fetchall()
  579. # global tag
  580. # tag = Value('i', self.contentid[0][3])
  581. # print(tag.value==1)
  582. print(f'loadcontent={self.contentid[0][3]}')
  583. time.sleep(3)
  584. c.close()
  585. conn.close()
  586. def readpoint(self):
  587. data = {
  588. "algorithmCode": modelalgdir[Path(self.opt.weights).stem],
  589. "deviceIp": None,
  590. 'fwqCode': None
  591. }
  592. self.dirmodel = {}
  593. result = requests.post(url=urlt, data=data).json()['data']
  594. channell = []
  595. for info in result:
  596. # content = cursor.fetchall()
  597. # self.dirmodel = {}
  598. # for address,fence,point,channel,classindex,ip ,algip,label,durtime in content:
  599. # address = f'{address[:-1]}0'
  600. channel = info["deviceChannel"]
  601. if Path(self.opt.weights).stem == "danager" and channel == '45':
  602. continue
  603. channell.append(channel)
  604. self.dirmodel[channel] = {}
  605. self.dirmodel[channel]['fence'] = 1 if len(info["electricFence"]) > 0 else 0
  606. if Path(self.opt.weights).stem == "uniform":
  607. self.dirmodel[channel]['fence'] = 1
  608. # self.dirmodel[channel]['point'] = point
  609. self.dirmodel[channel]['channel'] = info['deviceChannel']
  610. self.dirmodel[channel]['classindex'] = info['algorithmCode']
  611. self.dirmodel[channel]['ip'] = info['deviceIp']
  612. self.dirmodel[channel]['algip'] = info['deviceAlgorithmIp']
  613. dataele = {
  614. "algorithmCode": self.dirmodel[channel]['classindex'],
  615. "algorithmIp": self.dirmodel[channel]['algip'],
  616. "channel": self.dirmodel[channel]['channel']
  617. }
  618. resultele = requests.post(url=urlele, data=dataele).json()['data']['pointCollections']
  619. resultele = resultele.split(',||')
  620. resultele = tuple(resultele)
  621. point = '%s:' * len(resultele) % resultele
  622. if Path(self.opt.weights).stem == 'personcount':
  623. resultper = requests.post(url=urlperson, data=dataele).json()['data']
  624. personcountdir[channel] = int(resultper)
  625. if (Path(self.opt.weights).stem == "uniform") and len(
  626. point[:-2]) <= 1:
  627. self.dirmodel[channel]['point'] = "150#144,1100#144,1100#550,150#550"
  628. else:
  629. self.dirmodel[channel]['point'] = point[:-2]
  630. self.dirmodel[channel]['preim'] = None
  631. self.dirmodel[channel]['oripreim'] = None
  632. self.dirmodel[channel]['detframe'] = [0 for _ in range(2)]
  633. self.dirmodel[channel]['postpretime'] = 0
  634. self.dirmodel[channel]['detflag'] = False
  635. self.dirmodel[channel]['detpretime'] = float('inf')
  636. self.dirmodel[channel]['label'] = modellabeldir[data['algorithmCode']]
  637. if Path(self.opt.weights).stem == 'sleep' or Path(self.opt.weights).stem == 'duty':
  638. datatime = {
  639. "algorithmCode": self.dirmodel[channel]['classindex'],
  640. "algorithmIp": self.dirmodel[channel]['algip'],
  641. "channel": self.dirmodel[channel]['channel']
  642. }
  643. resulttime = requests.post(url=urltime, data=dataele).json()['data']
  644. self.dirmodel[channel]['durtime'] = int(resulttime)
  645. else:
  646. self.dirmodel[channel]['durtime'] = 0
  647. self.dirmodel[channel]['posttime'] = 0
  648. return sorted(channell)
  649. def getframe(queuelist, channelsl, source, tt, numworks, lock, numworkv):
  650. while True:
  651. print("dataloader")
  652. imgsz = [768, 768]
  653. print(f'source = {source}')
  654. dataset = LoadStreamsSQLTN(channelsl, source, img_size=832,
  655. auto=True, vid_stride=20, tt=tt, numworks=numworks)
  656. bs = len(dataset)
  657. vid_path, vid_writer = [None] * bs, [None] * bs
  658. # self.detframe = [[0 for _ in range(8)] for i in range(bs)]
  659. # self.postpretime = [0]*bs
  660. # Run inference
  661. # imgsz = (1 , 3, *self.imgsz)
  662. print(imgsz)
  663. # self.model.warmup(imgsz=(1 , 3, *imgsz)) # warmup
  664. seen, windows, dt = 0, [], (Profile(), Profile(), Profile())
  665. #
  666. # print ("数据库打开成功")
  667. pretime = time.time()
  668. tag = 0
  669. sourcebase = 'project0117.db'
  670. for path, im, im0s, vid_cap, s, videotime, channels in dataset:
  671. if time.time() - pretime > 300:
  672. channellist = []
  673. pretime = time.time()
  674. data = {
  675. "algorithmCode": None,
  676. "deviceIp": None,
  677. "fwqCode": None
  678. }
  679. try:
  680. result = requests.post(url=urlt, data=data).json()['data']
  681. except Exception:
  682. result = []
  683. for info in result:
  684. data = {
  685. "channel": info["deviceChannel"],
  686. "ip": info["deviceAlgorithmIp"]
  687. }
  688. chaflag = any(info["deviceChannel"] in t for t in channellist)
  689. # personcountdir[channel] = num
  690. if not chaflag:
  691. address = requests.post(url=urlrtsp, data=data).json()['msg']
  692. channellist.append((info['deviceChannel'], address))
  693. channelsa = []
  694. sourcea = []
  695. channellist = set(channellist)
  696. channellist = sorted(channellist, key=lambda x: x[0])
  697. # channellist = set(channellist)
  698. for cha, add in channellist:
  699. channelsa.append(cha)
  700. sourcea.append(add)
  701. channelsl = sorted(channelsl)
  702. # channelsa = sorted(channelsa)
  703. if channelsa != channelsl and len(channelsa) > 0:
  704. print(f'channelsa = {channelsa}')
  705. print(f'channelsl = {channelsl}')
  706. dataset.close()
  707. channelsl = channelsa
  708. source = sourcea
  709. break;
  710. for key, value in queuelist.items():
  711. hour = time.localtime(time.time()).tm_hour
  712. if hour in range(7, 21):
  713. value[-1].put((path, im, im0s, vid_cap, s, videotime, channels))
  714. value[-1].get() if value[-1].qsize() == 10 else time.sleep(0.001)
  715. def getmutpro(channels, source, streamlist, numworkv, lock, numworks=1, modellen=None):
  716. processlist = []
  717. queuelist = {}
  718. for i in range(numworks):
  719. for model in modellen:
  720. queue = Queue(maxsize=10)
  721. queuelist.setdefault(model, [])
  722. queuelist[model].append(queue)
  723. process = Process(target=getframe,
  724. args=(queuelist, channels, source, i, numworks, lock, numworkv))
  725. processlist.append(process)
  726. process.start()
  727. # queuelist.append(queue)
  728. return queuelist
  729. def modelfun(queue, weights, sourcedb, classes, device, classify, conf_thres, runmodel, v8=False):
  730. print(weights)
  731. detectdemo = Detect(weights=weights, source=sourcedb, classes=classes, device=device, classify=classify,
  732. conf_thres=conf_thres, v8=v8)
  733. detectdemo.infer(queue, runmodel)
  734. def parse_opt():
  735. parser = argparse.ArgumentParser()
  736. parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s.pt', help='model path or triton URL')
  737. opt = parser.parse_args()
  738. return opt
  739. def main(opt):
  740. check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop'))
  741. run(**vars(opt))
  742. if __name__ == '__main__':
  743. # torch.multiprocessing.set_start_method('spawn')
  744. # set_start_method('spawn')
  745. opt = parse_opt()
  746. dbpath = 'projectnew.db'
  747. conn = sqlite3.connect(dbpath)
  748. #
  749. # print ("数据库打开成功")
  750. c = conn.cursor()
  751. task(c, conn, urlt, urla)
  752. cursor = c.execute('select channel,algip from stream ')
  753. result = cursor.fetchall()
  754. for channel, algip in result:
  755. data = {
  756. "channel": channel,
  757. "ip": algip
  758. }
  759. # personcountdir[channel] = num
  760. address = requests.post(url=urlrtsp, data=data).json()['msg']
  761. c.execute('UPDATE STREAM set address= (?) where channel =(?)', (address, channel))
  762. conn.commit()
  763. cursor = c.execute(
  764. "SELECT modelname from CHANGESTREAM where modelname = 'helmet' or modelname = 'smoke' or modelname = 'uniform' or modelname = 'fire' or modelname ='duty' or modelname = 'sleep' or modelname='occupancy' or modelname = 'personcar' or modelname = 'phone' or modelname = 'reflective' or modelname = 'extinguisher' or modelname = 'danager' or modelname = 'inspection' or modelname = 'cross' or modelname = 'personcount' or modelname= 'arm' or modelname = 'persontre' or modelname = 'bag' or modelname = 'fall' or modelname = 'belt'")
  765. # cursor = c.execute("SELECT modelname from CHANGESTREAM where modelname = 'helmet'")
  766. content = cursor.fetchall()
  767. cursor = c.execute("SELECT address,channel from STREAM ")
  768. # cursor = c.execute("SELECT address from STREAM where modelname = 'helmet'")
  769. contenta = cursor.fetchall()
  770. source = []
  771. modellist = []
  772. addcha = []
  773. channellist = []
  774. for i in contenta:
  775. addcha.append((i[0], i[1]))
  776. # modellist.append(i[1])
  777. addcha = set(addcha)
  778. addcha = sorted(addcha, key=lambda x: x[1])
  779. for add, cha in addcha:
  780. source.append(add)
  781. channellist.append(cha)
  782. # source = set(source)
  783. print(addcha)
  784. source = list(source)
  785. cursor = c.execute(
  786. "SELECT modelname from STREAM where (modelname ='helmet' or modelname = 'smoke' or modelname = 'uniform' or modelname = 'fire' or modelname = 'duty' or modelname = 'sleep' or modelname='occupancy' or modelname = 'personcar' or modelname = 'phone' or modelname = 'reflective' or modelname = 'extinguisher' or modelname = 'danager' or modelname = 'inspection' or modelname = 'cross' or modelname = 'personcount' or modelname = 'arm' or modelname = 'persontre' or modelname = 'bag' or modelname = 'fall' or modelname = 'belt')")
  787. contentm = cursor.fetchall()
  788. for m in contentm:
  789. modellist.append(m[0])
  790. modellist = set(modellist)
  791. modellist = list(modellist)
  792. contentlist = []
  793. for i in content:
  794. contentlist.append(i[0])
  795. # source.sort()
  796. n = len(content)
  797. print(f'modelname={n}')
  798. print(content)
  799. # content.reverse()
  800. print(content)
  801. print(source)
  802. # main(opt)
  803. # processes = []
  804. streamqueue = Queue(maxsize=4)
  805. numworkv = Value('i', 0)
  806. manager = Manager()
  807. lock = multiprocessing.Lock()
  808. streamlist = manager.list()
  809. numworks = 7
  810. modellen = []
  811. for i in modellist:
  812. if i in contentlist:
  813. modellen.append(i)
  814. queuelist = getmutpro(channellist, source, streamlist, numworkv, lock, numworks, modellen)
  815. deid = 0
  816. # pool = ThreadPoolExecutor(max_workers=n)
  817. runmodel = manager.dict()
  818. while True:
  819. for i in modellist:
  820. if i in contentlist:
  821. if i not in runmodel:
  822. # print(i)
  823. # detectdemo=Detect(weights=f'/mnt/project/yolodemo/yolov5-master/{i[0]}.pt')
  824. c.execute('select conf,cla from changestream where modelname = (?)', (i,))
  825. rea = c.fetchall()
  826. print(f'weights ={i[0]}.pt')
  827. if i in ['duty', 'danager', 'inspection', 'cross', 'personcount']:
  828. process = Process(target=modelfun, args=(
  829. queuelist[i], f'{i}.pt', dbpath, [0], 0, rea[0][1], rea[0][0], runmodel, True))
  830. else:
  831. if i in ['fall', 'extinguisher']:
  832. process = Process(target=modelfun, args=(
  833. queuelist[i], f'{i}.pt', dbpath, None, 0, rea[0][1], rea[0][0], runmodel,True))
  834. else:
  835. process = Process(target=modelfun, args=(
  836. queuelist[i], f'{i}.pt', dbpath, None, 0, rea[0][1], rea[0][0], runmodel, True))
  837. time.sleep(3)
  838. process.start()
  839. deid = deid + 1
  840. runmodel[i] = 1
  841. time.sleep(600)
  842. task(c, conn, urlt, urla)
  843. cursor = c.execute(
  844. "SELECT modelname from CHANGESTREAM where modelname = 'helmet' or modelname = 'smoke' or modelname = 'uniform' or modelname = 'fire' or modelname ='duty' or modelname = 'sleep' or modelname='occupancy' or modelname = 'personcar' or modelname = 'phone' or modelname = 'reflective' or modelname = 'extinguisher' or modelname = 'danager' or modelname = 'inspection' or modelname = 'cross' or modelname = 'personcount' or modelname = 'arm' or modelname = 'persontre' or modelname = 'bag' or modelname = 'fall' or modelname = 'belt'")
  845. content = cursor.fetchall()
  846. contentlist = []
  847. for con in content:
  848. contentlist.append(con[0])
  849. cursor = c.execute("SELECT address,channel from STREAM ")
  850. contenta = cursor.fetchall()
  851. source = []
  852. modellist = []
  853. addcha = []
  854. channellist = []
  855. for i in contenta:
  856. addcha.append((i[0], i[1]))
  857. # modellist.append(i[1])
  858. addcha = set(addcha)
  859. addcha = sorted(addcha)
  860. for a, cha in addcha:
  861. source.append(a)
  862. channellist.append(cha)
  863. print(addcha)
  864. source = list(source)
  865. # source.sort()
  866. cursor = c.execute(
  867. "SELECT modelname from STREAM where (modelname = 'helmet' or modelname = 'smoke' or modelname = 'uniform' or modelname = 'fire' or modelname = 'duty' or modelname = 'sleep' or modelname='occupancy' or modelname = 'personcar' or modelname = 'phone' or modelname = 'reflective' or modelname = 'extinguisher' or modelname = 'danager' or modelname = 'inspection' or modelname = 'cross' or modelname = 'personcount' or modelname = 'arm' or modelname = 'persontre' or modelname = 'bag' or modelname = 'fall' or modelname = 'belt')")
  868. contentm = cursor.fetchall()
  869. for m in contentm:
  870. modellist.append(m[0])
  871. modellist = set(modellist)
  872. n = len(content)
  873. print(f'modelname={n}')
  874. print(content)
  875. # content.reverse()
  876. print(content)