dataloaders.py 139 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964
  1. # YOLOv5 🚀 by Ultralytics, AGPL-3.0 license
  2. """
  3. Dataloaders and dataset utils
  4. """
  5. import contextlib
  6. import glob
  7. import hashlib
  8. import json
  9. import math
  10. import os
  11. import random
  12. import shutil
  13. import time
  14. from itertools import repeat
  15. from multiprocessing.pool import Pool, ThreadPool
  16. from pathlib import Path
  17. from threading import Thread
  18. from urllib.parse import urlparse
  19. import sqlite3
  20. import numpy as np
  21. import psutil
  22. import torch
  23. import torch.nn.functional as F
  24. import torchvision
  25. import yaml
  26. from PIL import ExifTags, Image, ImageOps
  27. from torch.utils.data import DataLoader, Dataset, dataloader, distributed
  28. from tqdm import tqdm
  29. import requests
  30. from utils.augmentations import (Albumentations, augment_hsv, classify_albumentations, classify_transforms, copy_paste,
  31. letterbox, mixup, random_perspective)
  32. from utils.general import (DATASETS_DIR, LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, check_dataset, check_requirements,
  33. check_yaml, clean_str, cv2, is_colab, is_kaggle, segments2boxes, unzip_file, xyn2xy,
  34. xywh2xyxy, xywhn2xyxy, xyxy2xywhn)
  35. from utils.torch_utils import torch_distributed_zero_first
  36. urlrtsp = "http://172.19.152.231/open/api/operate/previewURLs"
  37. # Parameters
  38. HELP_URL = 'See https://docs.ultralytics.com/yolov5/tutorials/train_custom_data'
  39. IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm' # include image suffixes
  40. VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv' # include video suffixes
  41. LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html
  42. RANK = int(os.getenv('RANK', -1))
  43. PIN_MEMORY = str(os.getenv('PIN_MEMORY', True)).lower() == 'true' # global pin_memory for dataloaders
  44. # Get orientation exif tag
  45. for orientation in ExifTags.TAGS.keys():
  46. if ExifTags.TAGS[orientation] == 'Orientation':
  47. break
  48. def get_hash(paths):
  49. # Returns a single hash value of a list of paths (files or dirs)
  50. size = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) # sizes
  51. h = hashlib.sha256(str(size).encode()) # hash sizes
  52. h.update(''.join(paths).encode()) # hash paths
  53. return h.hexdigest() # return hash
  54. def exif_size(img):
  55. # Returns exif-corrected PIL size
  56. s = img.size # (width, height)
  57. with contextlib.suppress(Exception):
  58. rotation = dict(img._getexif().items())[orientation]
  59. if rotation in [6, 8]: # rotation 270 or 90
  60. s = (s[1], s[0])
  61. return s
  62. def exif_transpose(image):
  63. """
  64. Transpose a PIL image accordingly if it has an EXIF Orientation tag.
  65. Inplace version of https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py exif_transpose()
  66. :param image: The image to transpose.
  67. :return: An image.
  68. """
  69. exif = image.getexif()
  70. orientation = exif.get(0x0112, 1) # default 1
  71. if orientation > 1:
  72. method = {
  73. 2: Image.FLIP_LEFT_RIGHT,
  74. 3: Image.ROTATE_180,
  75. 4: Image.FLIP_TOP_BOTTOM,
  76. 5: Image.TRANSPOSE,
  77. 6: Image.ROTATE_270,
  78. 7: Image.TRANSVERSE,
  79. 8: Image.ROTATE_90}.get(orientation)
  80. if method is not None:
  81. image = image.transpose(method)
  82. del exif[0x0112]
  83. image.info['exif'] = exif.tobytes()
  84. return image
  85. def seed_worker(worker_id):
  86. # Set dataloader worker seed https://pytorch.org/docs/stable/notes/randomness.html#dataloader
  87. worker_seed = torch.initial_seed() % 2 ** 32
  88. np.random.seed(worker_seed)
  89. random.seed(worker_seed)
  90. def create_dataloader(path,
  91. imgsz,
  92. batch_size,
  93. stride,
  94. single_cls=False,
  95. hyp=None,
  96. augment=False,
  97. cache=False,
  98. pad=0.0,
  99. rect=False,
  100. rank=-1,
  101. workers=8,
  102. image_weights=False,
  103. quad=False,
  104. prefix='',
  105. shuffle=False,
  106. seed=0):
  107. if rect and shuffle:
  108. LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False')
  109. shuffle = False
  110. with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP
  111. dataset = LoadImagesAndLabels(
  112. path,
  113. imgsz,
  114. batch_size,
  115. augment=augment, # augmentation
  116. hyp=hyp, # hyperparameters
  117. rect=rect, # rectangular batches
  118. cache_images=cache,
  119. single_cls=single_cls,
  120. stride=int(stride),
  121. pad=pad,
  122. image_weights=image_weights,
  123. prefix=prefix)
  124. batch_size = min(batch_size, len(dataset))
  125. nd = torch.cuda.device_count() # number of CUDA devices
  126. nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) # number of workers
  127. sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle)
  128. loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates
  129. generator = torch.Generator()
  130. generator.manual_seed(6148914691236517205 + seed + RANK)
  131. return loader(dataset,
  132. batch_size=batch_size,
  133. shuffle=shuffle and sampler is None,
  134. num_workers=nw,
  135. sampler=sampler,
  136. pin_memory=PIN_MEMORY,
  137. collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn,
  138. worker_init_fn=seed_worker,
  139. generator=generator), dataset
  140. class InfiniteDataLoader(dataloader.DataLoader):
  141. """ Dataloader that reuses workers
  142. Uses same syntax as vanilla DataLoader
  143. """
  144. def __init__(self, *args, **kwargs):
  145. super().__init__(*args, **kwargs)
  146. object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler))
  147. self.iterator = super().__iter__()
  148. def __len__(self):
  149. return len(self.batch_sampler.sampler)
  150. def __iter__(self):
  151. for _ in range(len(self)):
  152. yield next(self.iterator)
  153. class _RepeatSampler:
  154. """ Sampler that repeats forever
  155. Args:
  156. sampler (Sampler)
  157. """
  158. def __init__(self, sampler):
  159. self.sampler = sampler
  160. def __iter__(self):
  161. while True:
  162. yield from iter(self.sampler)
  163. class LoadScreenshots:
  164. # YOLOv5 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"`
  165. def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None):
  166. # source = [screen_number left top width height] (pixels)
  167. check_requirements('mss')
  168. import mss
  169. source, *params = source.split()
  170. self.screen, left, top, width, height = 0, None, None, None, None # default to full screen 0
  171. if len(params) == 1:
  172. self.screen = int(params[0])
  173. elif len(params) == 4:
  174. left, top, width, height = (int(x) for x in params)
  175. elif len(params) == 5:
  176. self.screen, left, top, width, height = (int(x) for x in params)
  177. self.img_size = img_size
  178. self.stride = stride
  179. self.transforms = transforms
  180. self.auto = auto
  181. self.mode = 'stream'
  182. self.frame = 0
  183. self.sct = mss.mss()
  184. # Parse monitor shape
  185. monitor = self.sct.monitors[self.screen]
  186. self.top = monitor['top'] if top is None else (monitor['top'] + top)
  187. self.left = monitor['left'] if left is None else (monitor['left'] + left)
  188. self.width = width or monitor['width']
  189. self.height = height or monitor['height']
  190. self.monitor = {'left': self.left, 'top': self.top, 'width': self.width, 'height': self.height}
  191. def __iter__(self):
  192. return self
  193. def __next__(self):
  194. # mss screen capture: get raw pixels from the screen as np array
  195. im0 = np.array(self.sct.grab(self.monitor))[:, :, :3] # [:, :, :3] BGRA to BGR
  196. s = f'screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: '
  197. if self.transforms:
  198. im = self.transforms(im0) # transforms
  199. else:
  200. im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize
  201. im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB
  202. im = np.ascontiguousarray(im) # contiguous
  203. self.frame += 1
  204. return str(self.screen), im, im0, None, s # screen, img, original img, im0s, s
  205. class LoadImages:
  206. # YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4`
  207. def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1):
  208. if isinstance(path, str) and Path(path).suffix == '.txt': # *.txt file with img/vid/dir on each line
  209. path = Path(path).read_text().rsplit()
  210. files = []
  211. for p in sorted(path) if isinstance(path, (list, tuple)) else [path]:
  212. p = str(Path(p).resolve())
  213. if '*' in p:
  214. files.extend(sorted(glob.glob(p, recursive=True))) # glob
  215. elif os.path.isdir(p):
  216. files.extend(sorted(glob.glob(os.path.join(p, '*.*')))) # dir
  217. elif os.path.isfile(p):
  218. files.append(p) # files
  219. else:
  220. raise FileNotFoundError(f'{p} does not exist')
  221. images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS]
  222. videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS]
  223. ni, nv = len(images), len(videos)
  224. self.img_size = img_size
  225. self.stride = stride
  226. self.files = images + videos
  227. self.nf = ni + nv # number of files
  228. self.video_flag = [False] * ni + [True] * nv
  229. self.mode = 'image'
  230. self.auto = auto
  231. self.transforms = transforms # optional
  232. self.vid_stride = vid_stride # video frame-rate stride
  233. if any(videos):
  234. self._new_video(videos[0]) # new video
  235. else:
  236. self.cap = None
  237. assert self.nf > 0, f'No images or videos found in {p}. ' \
  238. f'Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}'
  239. def __iter__(self):
  240. self.count = 0
  241. return self
  242. def __next__(self):
  243. if self.count == self.nf:
  244. raise StopIteration
  245. path = self.files[self.count]
  246. if self.video_flag[self.count]:
  247. # Read video
  248. self.mode = 'video'
  249. for _ in range(self.vid_stride):
  250. self.cap.grab()
  251. ret_val, im0 = self.cap.retrieve()
  252. while not ret_val:
  253. self.count += 1
  254. self.cap.release()
  255. if self.count == self.nf: # last video
  256. raise StopIteration
  257. path = self.files[self.count]
  258. self._new_video(path)
  259. ret_val, im0 = self.cap.read()
  260. self.frame += 1
  261. # im0 = self._cv2_rotate(im0) # for use if cv2 autorotation is False
  262. s = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: '
  263. else:
  264. # Read image
  265. self.count += 1
  266. im0 = cv2.imread(path) # BGR
  267. assert im0 is not None, f'Image Not Found {path}'
  268. s = f'image {self.count}/{self.nf} {path}: '
  269. if self.transforms:
  270. im = self.transforms(im0) # transforms
  271. else:
  272. im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize
  273. im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB
  274. im = np.ascontiguousarray(im) # contiguous
  275. return path, im, im0, self.cap, s
  276. def _new_video(self, path):
  277. # Create a new video capture object
  278. self.frame = 0
  279. self.cap = cv2.VideoCapture(path)
  280. self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.vid_stride)
  281. self.orientation = int(self.cap.get(cv2.CAP_PROP_ORIENTATION_META)) # rotation degrees
  282. # self.cap.set(cv2.CAP_PROP_ORIENTATION_AUTO, 0) # disable https://github.com/ultralytics/yolov5/issues/8493
  283. def _cv2_rotate(self, im):
  284. # Rotate a cv2 video manually
  285. if self.orientation == 0:
  286. return cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE)
  287. elif self.orientation == 180:
  288. return cv2.rotate(im, cv2.ROTATE_90_COUNTERCLOCKWISE)
  289. elif self.orientation == 90:
  290. return cv2.rotate(im, cv2.ROTATE_180)
  291. return im
  292. def __len__(self):
  293. return self.nf # number of files
  294. class LoadStreams:
  295. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  296. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1):
  297. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  298. self.mode = 'stream'
  299. self.img_size = img_size
  300. self.stride = stride
  301. self.vid_stride = vid_stride # video frame-rate stride
  302. sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  303. n = len(sources)
  304. self.sources = sources
  305. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  306. self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n
  307. for i, s in enumerate(sources): # index, source
  308. # Start thread to read frames from video stream
  309. st = f'{i + 1}/{n}: {s}... '
  310. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  311. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  312. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  313. import pafy
  314. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  315. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  316. if s == 0:
  317. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  318. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  319. cap = cv2.VideoCapture(s)
  320. assert cap.isOpened(), f'{st}Failed to open {s}'
  321. w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  322. h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  323. fps = cap.get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  324. self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  325. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  326. _, self.imgs[i] = cap.read() # guarantee first frame
  327. self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True)
  328. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  329. self.threads[i].start()
  330. LOGGER.info('') # newline
  331. # check for common shapes
  332. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  333. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  334. self.auto = auto and self.rect
  335. self.transforms = transforms # optional
  336. if not self.rect:
  337. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  338. def update(self, i, cap, stream):
  339. # Read stream `i` frames in daemon thread
  340. n, f = 0, self.frames[i] # frame number, frame array
  341. while cap.isOpened() and n < f:
  342. n += 1
  343. cap.grab() # .read() = .grab() followed by .retrieve()
  344. if n % self.vid_stride == 0:
  345. success, im = cap.retrieve()
  346. if success:
  347. self.imgs[i] = im
  348. else:
  349. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  350. self.imgs[i] = np.zeros_like(self.imgs[i])
  351. cap.open(stream) # re-open stream if signal was lost
  352. time.sleep(0.0) # wait time
  353. def __iter__(self):
  354. self.count = -1
  355. return self
  356. def __next__(self):
  357. self.count += 1
  358. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  359. cv2.destroyAllWindows()
  360. raise StopIteration
  361. im0 = self.imgs.copy()
  362. if self.transforms:
  363. im = np.stack([self.transforms(x) for x in im0]) # transforms
  364. else:
  365. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  366. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  367. im = np.ascontiguousarray(im) # contiguous
  368. return self.sources, im, im0, None, ''
  369. def __len__(self):
  370. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  371. class LoadStreamsNR:
  372. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  373. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1):
  374. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  375. self.mode = 'stream'
  376. self.img_size = img_size
  377. self.stride = stride
  378. self.vid_stride = vid_stride # video frame-rate stride
  379. sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  380. self.running = True
  381. # print(f'orisource= {sources}')
  382. # sources = sources[::4]
  383. # print(f'source= {sources}')
  384. n = len(sources)
  385. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  386. self.sources = sources
  387. print(f'self.sources {self.sources}')
  388. self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n
  389. self.caps = [None] * n
  390. for i, s in enumerate(sources): # index, source
  391. # Start thread to read frames from video stream
  392. st = f'{i + 1}/{n}: {s}... '
  393. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  394. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  395. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  396. import pafy
  397. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  398. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  399. if s == 0:
  400. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  401. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  402. print(f's= {s}')
  403. try:
  404. self.caps[i] = cv2.VideoCapture(s)
  405. except Exception:
  406. print('read error')
  407. print('hello')
  408. #assert self.caps[i].isOpened(), f'{st}Failed to open {s}'
  409. if not self.caps[i].isOpened():
  410. #self.cap[i].set(cv2.CAP_PROP_TIMEOUT, 1000)
  411. #w = 1280
  412. #h = 720
  413. w = 704
  414. h = 576
  415. fps = 25 # warning: may return 0 or nan
  416. self.frames[i] = float('inf') # infinite stream fallback
  417. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  418. self.imgs[i] = np.zeros((h,w,3),dtype=np.uint8) # guarantee first frame
  419. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  420. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  421. self.threads[i].start()
  422. else:
  423. #self.cap[i].set(cv2.CAP_PROP_TIMEOUT, 1000)
  424. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  425. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  426. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  427. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float(
  428. 'inf') # infinite stream fallback
  429. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  430. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  431. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  432. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  433. self.threads[i].start()
  434. LOGGER.info('') # newline
  435. # check for common shapes
  436. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  437. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  438. self.auto = auto and self.rect
  439. self.transforms = transforms # optional
  440. if not self.rect:
  441. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  442. def update(self, i, cap, stream):
  443. # Read stream `i` frames in daemon thread
  444. n, f = 0, self.frames[i] # frame number, frame array
  445. while self.running:
  446. if cap.isOpened() and n < f:
  447. #print("capread")
  448. n += 1
  449. cap.grab() # .read() = .grab() followed by .retrieve()
  450. if n % self.vid_stride == 0:
  451. success, im = cap.retrieve()
  452. if success:
  453. self.imgs[i] = im
  454. else:
  455. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  456. self.imgs[i] = np.zeros_like(self.imgs[i])
  457. cap.open(stream) # re-open stream if signal was lost
  458. else:
  459. try:
  460. cap.open(stream)
  461. time.sleep(3) # wait time
  462. except Exception:
  463. print('readerror')
  464. time.sleep(0)
  465. def close(self):
  466. """Close stream loader and release resources."""
  467. self.running = False # stop flag for Thread
  468. for thread in self.threads:
  469. if thread.is_alive():
  470. thread.join(timeout=5) # Add timeout
  471. for cap in self.caps: # Iterate through the stored VideoCapture objects
  472. try:
  473. cap.release() # release video capture
  474. except Exception as e:
  475. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  476. cv2.destroyAllWindows()
  477. def __iter__(self):
  478. self.count = -1
  479. return self
  480. def __next__(self):
  481. self.count += 1
  482. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  483. cv2.destroyAllWindows()
  484. raise StopIteration
  485. im0 = self.imgs.copy()
  486. if self.transforms:
  487. im = np.stack([self.transforms(x) for x in im0]) # transforms
  488. else:
  489. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  490. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  491. im = np.ascontiguousarray(im) # contiguous
  492. return self.sources, im, im0, None, ''
  493. def __len__(self):
  494. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  495. class LoadStreamsSQLNEWN:
  496. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  497. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,weights=''):
  498. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  499. self.mode = 'stream'
  500. self.img_size = img_size
  501. self.stride = stride
  502. self.vid_stride = vid_stride # video frame-rate stride
  503. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  504. sourcelist = []
  505. conn = sqlite3.connect(sources)
  506. c = conn.cursor()
  507. print("sqlite")
  508. print(Path(weights).stem)
  509. cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?)",(Path(weights).stem,))
  510. for i in cursor:
  511. print(i[1])
  512. sourcelist.append(i[1])
  513. conn.commit()
  514. c.close()
  515. conn.close()
  516. # print(f'orisource= {sources}')
  517. # sources = sources[::4]
  518. # print(f'source= {sources}')
  519. sources = sourcelist
  520. n = len(sources)
  521. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  522. self.sources = sources
  523. print(f'self.sources {self.sources}')
  524. self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n
  525. self.caps = [None] * n
  526. for i, s in enumerate(sources): # index, source
  527. # Start thread to read frames from video stream
  528. st = f'{i + 1}/{n}: {s}... '
  529. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  530. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  531. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  532. import pafy
  533. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  534. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  535. if s == 0:
  536. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  537. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  538. print(f's= {s}')
  539. self.caps[i] = cv2.VideoCapture(s)
  540. print('cap')
  541. assert self.caps[i].isOpened(), f'{st}Failed to open {s}'
  542. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  543. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  544. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  545. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  546. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  547. self.running = True
  548. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  549. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  550. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  551. self.threads[i].start()
  552. LOGGER.info('') # newline
  553. # check for common shapes
  554. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  555. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  556. self.auto = auto and self.rect
  557. self.running = True
  558. self.transforms = transforms # optional
  559. if not self.rect:
  560. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  561. def update(self, i, cap, stream):
  562. # Read stream `i` frames in daemon thread
  563. n, f = 0, self.frames[i] # frame number, frame array
  564. while self.running and cap.isOpened() and n < f:
  565. n += 1
  566. cap.grab() # .read() = .grab() followed by .retrieve()
  567. if n % self.vid_stride == 0:
  568. success, im = cap.retrieve()
  569. if success:
  570. self.imgs[i] = im
  571. else:
  572. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  573. self.imgs[i] = np.zeros_like(self.imgs[i])
  574. cap.open(stream) # re-open stream if signal was lost
  575. time.sleep(0.0) # wait time
  576. def close(self):
  577. """Close stream loader and release resources."""
  578. self.running = False # stop flag for Thread
  579. for thread in self.threads:
  580. if thread.is_alive():
  581. thread.join(timeout=5) # Add timeout
  582. for cap in self.caps: # Iterate through the stored VideoCapture objects
  583. print('close cap')
  584. try:
  585. cap.release() # release video capture
  586. except Exception as e:
  587. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  588. cv2.destroyAllWindows()
  589. def __iter__(self):
  590. self.count = -1
  591. return self
  592. def __next__(self):
  593. self.count += 1
  594. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  595. cv2.destroyAllWindows()
  596. raise StopIteration
  597. im0 = self.imgs.copy()
  598. if self.transforms:
  599. im = np.stack([self.transforms(x) for x in im0]) # transforms
  600. else:
  601. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  602. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  603. im = np.ascontiguousarray(im) # contiguous
  604. return self.sources, im, im0, None, ''
  605. def __len__(self):
  606. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  607. class LoadStreamsSQLNRE:
  608. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  609. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,weights=''):
  610. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  611. self.mode = 'stream'
  612. self.img_size = img_size
  613. self.stride = stride
  614. self.vid_stride = vid_stride # video frame-rate stride
  615. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  616. sourcelist = []
  617. conn = sqlite3.connect(sources)
  618. c = conn.cursor()
  619. print("sqlite")
  620. print(Path(weights).stem)
  621. cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ",(Path(weights).stem,))
  622. for i in cursor:
  623. print(i[1])
  624. sourcelist.append(i[1])
  625. sourcelist = set(sourcelist)
  626. conn.commit()
  627. c.close()
  628. conn.close()
  629. # print(f'orisource= {sources}')
  630. # sources = sources[::4]
  631. # print(f'source= {sources}')
  632. sources = list(sourcelist)
  633. n = len(sources)
  634. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  635. self.sources = sources
  636. print(f'self.sources {self.sources}')
  637. self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n
  638. self.caps = [None] * n
  639. for i, s in enumerate(sources): # index, source
  640. # Start thread to read frames from video stream
  641. st = f'{i + 1}/{n}: {s}... '
  642. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  643. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  644. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  645. import pafy
  646. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  647. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  648. if s == 0:
  649. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  650. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  651. print(f's= {s}')
  652. self.caps[i] = cv2.VideoCapture(s)
  653. print('cap')
  654. assert self.caps[i].isOpened(), f'{st}Failed to open {s}'
  655. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  656. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  657. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  658. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  659. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  660. self.running = True
  661. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  662. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  663. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  664. self.threads[i].start()
  665. LOGGER.info('') # newline
  666. # check for common shapes
  667. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  668. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  669. self.auto = auto and self.rect
  670. self.running = True
  671. self.transforms = transforms # optional
  672. if not self.rect:
  673. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  674. def update(self, i, cap, stream):
  675. # Read stream `i` frames in daemon thread
  676. n, f = 0, self.frames[i] # frame number, frame array
  677. while self.running:
  678. if cap.isOpened() and n < f:
  679. n += 1
  680. cap.grab() # .read() = .grab() followed by .retrieve()
  681. if n % self.vid_stride == 0:
  682. success, im = cap.retrieve()
  683. if success:
  684. self.imgs[i] = im
  685. else:
  686. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  687. self.imgs[i] = np.zeros_like(self.imgs[i])
  688. try:
  689. cap.open(stream) # re-open stream if signal was lost
  690. except Exception:
  691. print(f'readerror {stream}')
  692. time.sleep(0.0) # wait time
  693. elif not cap.isOpened() and n < f:
  694. try:
  695. cap.open(stream) # re-open stream if signal was lost
  696. except Exception:
  697. print(f'readerror {stream}')
  698. def close(self):
  699. """Close stream loader and release resources."""
  700. self.running = False # stop flag for Thread
  701. for thread in self.threads:
  702. if thread.is_alive():
  703. thread.join(timeout=5) # Add timeout
  704. for cap in self.caps: # Iterate through the stored VideoCapture objects
  705. print('close cap')
  706. try:
  707. cap.release() # release video capture
  708. except Exception as e:
  709. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  710. cv2.destroyAllWindows()
  711. def __iter__(self):
  712. self.count = -1
  713. return self
  714. def __next__(self):
  715. self.count += 1
  716. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  717. cv2.destroyAllWindows()
  718. raise StopIteration
  719. im0 = self.imgs.copy()
  720. if self.transforms:
  721. im = np.stack([self.transforms(x) for x in im0]) # transforms
  722. else:
  723. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  724. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  725. im = np.ascontiguousarray(im) # contiguous
  726. return self.sources, im, im0, None, ''
  727. def __len__(self):
  728. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  729. class LoadStreamsSQLNRER:
  730. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  731. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,weights=''):
  732. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  733. self.mode = 'stream'
  734. self.img_size = img_size
  735. self.stride = stride
  736. self.running = True
  737. self.vid_stride = vid_stride # video frame-rate stride
  738. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  739. sourcelist = []
  740. conn = sqlite3.connect(sources)
  741. c = conn.cursor()
  742. print("sqlite")
  743. print(Path(weights).stem)
  744. cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ",(Path(weights).stem,))
  745. for i in cursor:
  746. print(i[1])
  747. sourcelist.append(i[1])
  748. sourcelist = set(sourcelist)
  749. conn.commit()
  750. c.close()
  751. conn.close()
  752. # print(f'orisource= {sources}')
  753. # sources = sources[::4]
  754. # print(f'source= {sources}')
  755. sources = list(sourcelist)
  756. n = len(sources)
  757. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  758. self.sources = sources
  759. print(f'self.sources {self.sources}')
  760. self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n
  761. self.caps = [None] * n
  762. for i, s in enumerate(sources): # index, source
  763. # Start thread to read frames from video stream
  764. st = f'{i + 1}/{n}: {s}... '
  765. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  766. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  767. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  768. import pafy
  769. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  770. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  771. if s == 0:
  772. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  773. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  774. print(f's= {s}')
  775. self.caps[i] = cv2.VideoCapture(s)
  776. print('cap')
  777. if not self.caps[i].isOpened():
  778. if Path(weights).stem == 'smoke':
  779. w,h= 2688 , 1520
  780. elif Path(weights).stem == 'liquid' or Path(weights).stem == 'pressure':
  781. w,h = 2560,1440
  782. elif Path(weights).stem == 'helmet' or Path(weights).stem == 'fire':
  783. w,h = 1280,720
  784. else:
  785. w,h = 704,576
  786. #w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  787. #h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  788. fps = 25 # warning: may return 0 or nan
  789. self.frames[i] = float('inf') # infinite stream fallback
  790. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  791. self.imgs[i] = np.zeros((h,w,3)) # guarantee first frame
  792. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  793. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  794. self.threads[i].start()
  795. else:
  796. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  797. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  798. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  799. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  800. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  801. #self.running = True
  802. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  803. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  804. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  805. self.threads[i].start()
  806. LOGGER.info('') # newline
  807. # check for common shapes
  808. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  809. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  810. self.auto = auto and self.rect
  811. self.running = True
  812. self.transforms = transforms # optional
  813. if not self.rect:
  814. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  815. def update(self, i, cap, stream):
  816. # Read stream `i` frames in daemon thread
  817. n, f = 0, self.frames[i] # frame number, frame array
  818. while self.running:
  819. if cap.isOpened() and n < f:
  820. n += 1
  821. cap.grab() # .read() = .grab() followed by .retrieve()
  822. if n % self.vid_stride == 0:
  823. success, im = cap.retrieve()
  824. if success:
  825. self.imgs[i] = im
  826. else:
  827. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  828. self.imgs[i] = np.zeros_like(self.imgs[i])
  829. try:
  830. cap.open(stream) # re-open stream if signal was lost
  831. except Exception:
  832. print(f'readerror {stream}')
  833. time.sleep(0.0) # wait time
  834. elif not cap.isOpened() and n < f:
  835. try:
  836. cap.open(stream) # re-open stream if signal was lost
  837. except Exception:
  838. print(f'readerror {stream}')
  839. def close(self):
  840. """Close stream loader and release resources."""
  841. self.running = False # stop flag for Thread
  842. for thread in self.threads:
  843. if thread.is_alive():
  844. thread.join(timeout=5) # Add timeout
  845. for cap in self.caps: # Iterate through the stored VideoCapture objects
  846. print('close cap')
  847. try:
  848. cap.release() # release video capture
  849. except Exception as e:
  850. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  851. cv2.destroyAllWindows()
  852. def __iter__(self):
  853. self.count = -1
  854. return self
  855. def __next__(self):
  856. self.count += 1
  857. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  858. cv2.destroyAllWindows()
  859. raise StopIteration
  860. im0 = self.imgs.copy()
  861. if self.transforms:
  862. im = np.stack([self.transforms(x) for x in im0]) # transforms
  863. else:
  864. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  865. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  866. im = np.ascontiguousarray(im) # contiguous
  867. return self.sources, im, im0, None, ''
  868. def __len__(self):
  869. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  870. class LoadStreamsSQLNRERT:
  871. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  872. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,weights=''):
  873. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  874. self.mode = 'stream'
  875. self.img_size = img_size
  876. self.stride = stride
  877. self.running = True
  878. self.vid_stride = vid_stride # video frame-rate stride
  879. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  880. sourcelist = []
  881. conn = sqlite3.connect(sources)
  882. c = conn.cursor()
  883. print("sqlite")
  884. print(Path(weights).stem)
  885. cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ",(Path(weights).stem,))
  886. for i in cursor:
  887. #print(f'typei1{type(i[1])}')
  888. #rt = f'{i[1][:-1]}0'
  889. #print(i[1])
  890. sourcelist.append(i[1])
  891. sourcelist = set(sourcelist)
  892. conn.commit()
  893. c.close()
  894. conn.close()
  895. # print(f'orisource= {sources}')
  896. # sources = sources[::4]
  897. # print(f'source= {sources}')
  898. sources = list(sourcelist)
  899. n = len(sources)
  900. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  901. self.sources = sources
  902. print(f'self.sources {self.sources}')
  903. self.imgs, self.fps, self.frames, self.threads,self.videotime = [None] * n, [0] * n, [0] * n, [None] * n, [None]*n
  904. self.caps = [None] * n
  905. for i, s in enumerate(sources): # index, source
  906. # Start thread to read frames from video stream
  907. st = f'{i + 1}/{n}: {s}... '
  908. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  909. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  910. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  911. import pafy
  912. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  913. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  914. if s == 0:
  915. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  916. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  917. print(f's= {s}')
  918. self.caps[i] = cv2.VideoCapture(s)
  919. self.caps[i] = cv2.VideoCapture(s)
  920. self.caps[i] = cv2.VideoCapture(s)
  921. print('cap')
  922. if not self.caps[i].isOpened():
  923. if Path(weights).stem == 'smoke':
  924. w,h= 2688 , 1520
  925. elif Path(weights).stem == 'liquid' or Path(weights).stem == 'pressure':
  926. w,h = 2560,1440
  927. elif Path(weights).stem == 'helmet' or Path(weights).stem == 'fire':
  928. w,h = 1280,720
  929. else:
  930. w,h = 1280,720
  931. #w,h = 1280,720
  932. #w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  933. #h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  934. fps = 25 # warning: may return 0 or nan
  935. self.frames[i] = float('inf') # infinite stream fallback
  936. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  937. self.imgs[i] = np.zeros((h,w,3)) # guarantee first frame
  938. self.videotime[i] = time.localtime()
  939. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  940. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h}e at {self.fps[i]:.2f} FPS)')
  941. self.threads[i].start()
  942. else:
  943. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  944. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  945. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  946. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  947. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  948. #self.running = True
  949. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  950. self.videotime[i] = time.localtime()
  951. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  952. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  953. self.threads[i].start()
  954. LOGGER.info('') # newline
  955. # check for common shapes
  956. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  957. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  958. self.auto = auto and self.rect
  959. self.running = True
  960. self.transforms = transforms # optional
  961. if not self.rect:
  962. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  963. def update(self, i, cap, stream):
  964. # Read stream `i` frames in daemon thread
  965. n, f = 0, self.frames[i] # frame number, frame array
  966. while self.running:
  967. if cap.isOpened() and n < f:
  968. n += 1
  969. cap.grab() # .read() = .grab() followed by .retrieve()
  970. if n % self.vid_stride == 0:
  971. success, im = cap.retrieve()
  972. if success:
  973. self.imgs[i] = im
  974. timesta = time.time()-5
  975. self.videotime[i] = time.localtime(timesta)
  976. else:
  977. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  978. self.imgs[i] = np.zeros_like(self.imgs[i])
  979. self.videotime[i] = time.localtime()
  980. try:
  981. time.sleep(300)
  982. cap.open(stream) # re-open stream if signal was lost
  983. print('read')
  984. except Exception:
  985. print(f'readerror {stream}')
  986. time.sleep(0.0) # wait time
  987. elif not cap.isOpened() and n < f:
  988. try:
  989. time.sleep(300)
  990. cap.open(stream) # re-open stream if signal was lost
  991. print('read')
  992. except Exception:
  993. print(f'readerror {stream}')
  994. def close(self):
  995. """Close stream loader and release resources."""
  996. self.running = False # stop flag for Thread
  997. for thread in self.threads:
  998. if thread.is_alive():
  999. thread.join(timeout=5) # Add timeout
  1000. for cap in self.caps: # Iterate through the stored VideoCapture objects
  1001. print('close cap')
  1002. try:
  1003. cap.release() # release video capture
  1004. except Exception as e:
  1005. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  1006. cv2.destroyAllWindows()
  1007. def __iter__(self):
  1008. self.count = -1
  1009. return self
  1010. def __next__(self):
  1011. self.count += 1
  1012. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  1013. cv2.destroyAllWindows()
  1014. raise StopIteration
  1015. im0 = self.imgs.copy()
  1016. if self.transforms:
  1017. im = np.stack([self.transforms(x) for x in im0]) # transforms
  1018. else:
  1019. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  1020. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  1021. im = np.ascontiguousarray(im) # contiguous
  1022. return self.sources, im, im0, None, '',self.videotime
  1023. def __len__(self):
  1024. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  1025. class LoadStreamsSQLT:
  1026. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  1027. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,tt=0,numworks=3):
  1028. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  1029. self.mode = 'stream'
  1030. self.img_size = img_size
  1031. self.stride = stride
  1032. self.running = True
  1033. self.vid_stride = vid_stride # video frame-rate stride
  1034. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  1035. # print(f'orisource= {sources}')
  1036. # sources = sources[::4]
  1037. # print(f'source= {sources}')
  1038. # sourcelist = []
  1039. # conn = sqlite3.connect(sources)
  1040. # c = conn.cursor()
  1041. # print("sqlite")
  1042. # print(Path(weights).stem)
  1043. # cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ", (Path(weights).stem,))
  1044. # for i in cursor:
  1045. # # print(f'typei1{type(i[1])}')
  1046. # # rt = f'{i[1][:-1]}0'
  1047. # # print(i[1])
  1048. # sourcelist.append(i[1])
  1049. # sourcelist = set(sourcelist)
  1050. # conn.commit()
  1051. # c.close()
  1052. # conn.close()
  1053. # # print(f'orisource= {sources}')
  1054. # # sources = sources[::4]
  1055. # # print(f'source= {sources}')
  1056. # sources = list(sourcelist)
  1057. # sources.sort()
  1058. print(sources)
  1059. sources = sources[tt::numworks]
  1060. n = len(sources)
  1061. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  1062. self.sources = sources
  1063. print(f'self.sources {self.sources}')
  1064. self.imgs, self.fps, self.frames, self.threads,self.videotime = [None] * n, [0] * n, [0] * n, [None] * n, [None]*n
  1065. self.caps = [None] * n
  1066. for i, s in enumerate(sources): # index, source
  1067. # Start thread to read frames from video stream
  1068. st = f'{i + 1}/{n}: {s}... '
  1069. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  1070. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  1071. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  1072. import pafy
  1073. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  1074. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  1075. if s == 0:
  1076. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  1077. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  1078. print(f's= {s}')
  1079. self.caps[i] = cv2.VideoCapture(s)
  1080. print('cap')
  1081. if not self.caps[i].isOpened():
  1082. #if Path(weights).stem == 'smoke':
  1083. # w,h= 2688 , 1520
  1084. #elif Path(weights).stem == 'liquid' or Path(weights).stem == 'pressure':
  1085. # w,h = 2560,1440
  1086. #elif Path(weights).stem == 'helmet' or Path(weights).stem == 'fire':
  1087. # w,h = 1280,720
  1088. #else:
  1089. w,h = 1280,720
  1090. #w,h = 1280,720
  1091. #w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  1092. #h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  1093. fps = 25 # warning: may return 0 or nan
  1094. self.frames[i] = float('inf') # infinite stream fallback
  1095. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1096. self.imgs[i] = np.zeros((h,w,3)) # guarantee first frame
  1097. self.videotime[i] = time.localtime()
  1098. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1099. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1100. self.threads[i].start()
  1101. else:
  1102. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  1103. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  1104. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  1105. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  1106. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1107. #self.running = True
  1108. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  1109. self.videotime[i] = time.localtime()
  1110. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1111. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1112. self.threads[i].start()
  1113. LOGGER.info('') # newline
  1114. # check for common shapes
  1115. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  1116. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  1117. self.auto = auto and self.rect
  1118. self.running = True
  1119. self.transforms = transforms # optional
  1120. if not self.rect:
  1121. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  1122. def update(self, i, cap, stream):
  1123. # Read stream `i` frames in daemon thread
  1124. n, f = 0, self.frames[i] # frame number, frame array
  1125. while self.running:
  1126. if cap.isOpened() and n < f:
  1127. n += 1
  1128. cap.grab() # .read() = .grab() followed by .retrieve()
  1129. if n % self.vid_stride == 0:
  1130. success, im = cap.retrieve()
  1131. if success:
  1132. self.imgs[i] = im
  1133. timesta = time.time()-5
  1134. self.videotime[i] = time.localtime(timesta)
  1135. else:
  1136. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  1137. self.imgs[i] = np.zeros_like(self.imgs[i])
  1138. self.videotime[i] = time.localtime()
  1139. try:
  1140. cap.open(stream) # re-open stream if signal was lost
  1141. except Exception:
  1142. print(f'readerror {stream}')
  1143. time.sleep(0.0) # wait time
  1144. elif not cap.isOpened() and n < f:
  1145. try:
  1146. cap.open(stream) # re-open stream if signal was lost
  1147. except Exception:
  1148. print(f'readerror {stream}')
  1149. def close(self):
  1150. """Close stream loader and release resources."""
  1151. self.running = False # stop flag for Thread
  1152. for thread in self.threads:
  1153. if thread.is_alive():
  1154. thread.join(timeout=5) # Add timeout
  1155. for cap in self.caps: # Iterate through the stored VideoCapture objects
  1156. print('close cap')
  1157. try:
  1158. cap.release() # release video capture
  1159. except Exception as e:
  1160. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  1161. cv2.destroyAllWindows()
  1162. def __iter__(self):
  1163. self.count = -1
  1164. return self
  1165. def __next__(self):
  1166. self.count += 1
  1167. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  1168. cv2.destroyAllWindows()
  1169. raise StopIteration
  1170. im0 = self.imgs.copy()
  1171. if self.transforms:
  1172. im = np.stack([self.transforms(x) for x in im0]) # transforms
  1173. else:
  1174. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  1175. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  1176. im = np.ascontiguousarray(im) # contiguous
  1177. return self.sources, im, im0, None, '',self.videotime
  1178. def __len__(self):
  1179. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  1180. class LoadStreamsVEight:
  1181. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  1182. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,weights=''):
  1183. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  1184. self.mode = 'stream'
  1185. self.img_size = img_size
  1186. self.stride = stride
  1187. self.running = True
  1188. self.vid_stride = vid_stride # video frame-rate stride
  1189. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  1190. sourcelist = []
  1191. conn = sqlite3.connect(sources)
  1192. c = conn.cursor()
  1193. print("sqlite")
  1194. print(Path(weights).stem)
  1195. cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ",(Path(weights).stem,))
  1196. for i in cursor:
  1197. #print(f'typei1{type(i[1])}')
  1198. #rt = f'{i[1][:-1]}0'
  1199. #print(i[1])
  1200. sourcelist.append(i[1])
  1201. sourcelist = set(sourcelist)
  1202. conn.commit()
  1203. c.close()
  1204. conn.close()
  1205. # print(f'orisource= {sources}')
  1206. # sources = sources[::4]
  1207. # print(f'source= {sources}')
  1208. sources = list(sourcelist)
  1209. n = len(sources)
  1210. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  1211. self.sources = sources
  1212. print(f'self.sources {self.sources}')
  1213. self.imgs, self.fps, self.frames, self.threads,self.videotime = [[]] * n, [0] * n, [0] * n, [None] * n, [None]*n
  1214. self.caps = [None] * n
  1215. for i, s in enumerate(sources): # index, source
  1216. # Start thread to read frames from video stream
  1217. st = f'{i + 1}/{n}: {s}... '
  1218. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  1219. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  1220. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  1221. import pafy
  1222. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  1223. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  1224. if s == 0:
  1225. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  1226. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  1227. print(f's= {s}')
  1228. self.caps[i] = cv2.VideoCapture(s)
  1229. print('cap')
  1230. if not self.caps[i].isOpened():
  1231. if Path(weights).stem == 'smoke':
  1232. w,h= 2688 , 1520
  1233. elif Path(weights).stem == 'liquid' or Path(weights).stem == 'pressure':
  1234. w,h = 2560,1440
  1235. elif Path(weights).stem == 'helmet' or Path(weights).stem == 'fire':
  1236. w,h = 1280,720
  1237. else:
  1238. w,h = 704,576
  1239. #w,h = 1280,720
  1240. #w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  1241. #h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  1242. fps = 25 # warning: may return 0 or nan
  1243. self.frames[i] = float('inf') # infinite stream fallback
  1244. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1245. self.imgs[i].append(np.zeros((h,w,3))) # guarantee first frame
  1246. self.videotime[i] = time.localtime()
  1247. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1248. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1249. self.threads[i].start()
  1250. else:
  1251. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  1252. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  1253. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  1254. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  1255. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1256. #self.running = True
  1257. _, im = self.caps[i].read() # guarantee first frame
  1258. self.imgs[i].append(im)
  1259. self.videotime[i] = time.localtime()
  1260. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1261. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1262. self.threads[i].start()
  1263. LOGGER.info('') # newline
  1264. # check for common shapes
  1265. s = np.stack([letterbox(x[0], img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  1266. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  1267. self.auto = auto and self.rect
  1268. self.running = True
  1269. self.transforms = transforms # optional
  1270. if not self.rect:
  1271. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  1272. def update(self, i, cap, stream):
  1273. # Read stream `i` frames in daemon thread
  1274. n, f = 0, self.frames[i] # frame number, frame array
  1275. while self.running:
  1276. if cap.isOpened() and n < f:
  1277. n += 1
  1278. cap.grab() # .read() = .grab() followed by .retrieve()
  1279. if n % self.vid_stride == 0:
  1280. success, im = cap.retrieve()
  1281. if success:
  1282. self.imgs[i] = [im]
  1283. self.videotime[i] = time.localtime()
  1284. else:
  1285. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  1286. self.imgs[i] = [np.zeros_like(self.imgs[i])]
  1287. self.videotime[i] = time.localtime()
  1288. try:
  1289. cap.open(stream) # re-open stream if signal was lost
  1290. except Exception:
  1291. print(f'readerror {stream}')
  1292. time.sleep(0.0) # wait time
  1293. elif not cap.isOpened() and n < f:
  1294. try:
  1295. cap.open(stream) # re-open stream if signal was lost
  1296. except Exception:
  1297. print(f'readerror {stream}')
  1298. def close(self):
  1299. """Close stream loader and release resources."""
  1300. self.running = False # stop flag for Thread
  1301. for thread in self.threads:
  1302. if thread.is_alive():
  1303. thread.join(timeout=5) # Add timeout
  1304. for cap in self.caps: # Iterate through the stored VideoCapture objects
  1305. print('close cap')
  1306. try:
  1307. cap.release() # release video capture
  1308. except Exception as e:
  1309. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  1310. cv2.destroyAllWindows()
  1311. def __iter__(self):
  1312. self.count = -1
  1313. return self
  1314. def __next__(self):
  1315. self.count += 1
  1316. # Wait until a frame is available in each buffer
  1317. images = []
  1318. for i, x in enumerate(self.imgs):
  1319. while not x:
  1320. if not self.threads[i].is_alive() or cv2.waitKey(1) == ord('q'): # q to quit
  1321. self.close()
  1322. raise StopIteration
  1323. time.sleep(1 / min(self.fps))
  1324. x = self.imgs[i]
  1325. if not x:
  1326. LOGGER.warning(f'WARNING ⚠️ Waiting for stream {i}')
  1327. # Get and remove the first frame from imgs buffer
  1328. # Get the last frame, and clear the rest from the imgs buffer
  1329. images.append(x.pop(-1) if x else np.zeros_like(self.imgs[i][0], dtype=np.uint8))
  1330. x.clear()
  1331. im0 = images
  1332. if self.transforms:
  1333. im = np.stack([self.transforms(x) for x in im0]) # transforms
  1334. else:
  1335. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  1336. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  1337. im = np.ascontiguousarray(im) # contiguous
  1338. return self.sources, im, im0, None, '',self.videotime
  1339. def __len__(self):
  1340. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  1341. class LoadStreamsSQL:
  1342. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  1343. def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,weights=''):
  1344. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  1345. self.mode = 'stream'
  1346. self.img_size = img_size
  1347. self.stride = stride
  1348. self.vid_stride = vid_stride # video frame-rate stride
  1349. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  1350. sourcelist = []
  1351. conn = sqlite3.connect(sources)
  1352. c = conn.cursor()
  1353. print("sqlite")
  1354. print(Path(weights).stem)
  1355. cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?)",(Path(weights).stem,))
  1356. for i in cursor:
  1357. print(i[1])
  1358. sourcelist.append(i[1])
  1359. conn.commit()
  1360. c.close()
  1361. conn.close()
  1362. # print(f'orisource= {sources}')
  1363. # sources = sources[::4]
  1364. # print(f'source= {sources}')
  1365. sources = sourcelist
  1366. n = len(sources)
  1367. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  1368. self.sources = sources
  1369. print(f'self.sources {self.sources}')
  1370. self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n
  1371. for i, s in enumerate(sources): # index, source
  1372. # Start thread to read frames from video stream
  1373. st = f'{i + 1}/{n}: {s}... '
  1374. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  1375. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  1376. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  1377. import pafy
  1378. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  1379. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  1380. if s == 0:
  1381. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  1382. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  1383. print(f's= {s}')
  1384. cap = cv2.VideoCapture(s)
  1385. print('cap')
  1386. assert cap.isOpened(), f'{st}Failed to open {s}'
  1387. w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  1388. h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  1389. fps = cap.get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  1390. self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  1391. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1392. _, self.imgs[i] = cap.read() # guarantee first frame
  1393. self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True)
  1394. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1395. self.threads[i].start()
  1396. LOGGER.info('') # newline
  1397. # check for common shapes
  1398. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  1399. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  1400. self.auto = auto and self.rect
  1401. self.transforms = transforms # optional
  1402. if not self.rect:
  1403. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  1404. def update(self, i, cap, stream):
  1405. # Read stream `i` frames in daemon thread
  1406. n, f = 0, self.frames[i] # frame number, frame array
  1407. while cap.isOpened() and n < f:
  1408. n += 1
  1409. cap.grab() # .read() = .grab() followed by .retrieve()
  1410. if n % self.vid_stride == 0:
  1411. success, im = cap.retrieve()
  1412. if success:
  1413. self.imgs[i] = im
  1414. else:
  1415. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  1416. self.imgs[i] = np.zeros_like(self.imgs[i])
  1417. cap.open(stream) # re-open stream if signal was lost
  1418. time.sleep(0.0) # wait time
  1419. def __iter__(self):
  1420. self.count = -1
  1421. return self
  1422. def __next__(self):
  1423. self.count += 1
  1424. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  1425. cv2.destroyAllWindows()
  1426. raise StopIteration
  1427. im0 = self.imgs.copy()
  1428. if self.transforms:
  1429. im = np.stack([self.transforms(x) for x in im0]) # transforms
  1430. else:
  1431. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  1432. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  1433. im = np.ascontiguousarray(im) # contiguous
  1434. return self.sources, im, im0, None, ''
  1435. def __len__(self):
  1436. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  1437. class LoadStreamsSQLTN:
  1438. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  1439. def __init__(self, channellist = [],sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,tt=0,numworks=3):
  1440. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  1441. self.mode = 'stream'
  1442. self.img_size = img_size
  1443. self.stride = stride
  1444. self.running = True
  1445. self.vid_stride = vid_stride # video frame-rate stride
  1446. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  1447. # print(f'orisource= {sources}')
  1448. # sources = sources[::4]
  1449. # print(f'source= {sources}')
  1450. # sourcelist = []
  1451. # conn = sqlite3.connect(sources)
  1452. # c = conn.cursor()
  1453. # print("sqlite")
  1454. # print(Path(weights).stem)
  1455. # cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ", (Path(weights).stem,))
  1456. # for i in cursor:
  1457. # # print(f'typei1{type(i[1])}')
  1458. # # rt = f'{i[1][:-1]}0'
  1459. # # print(i[1])
  1460. # sourcelist.append(i[1])
  1461. # sourcelist = set(sourcelist)
  1462. # conn.commit()
  1463. # c.close()
  1464. # conn.close()
  1465. # # print(f'orisource= {sources}')
  1466. # # sources = sources[::4]
  1467. # # print(f'source= {sources}')
  1468. # sources = list(sourcelist)
  1469. # sources.sort()
  1470. print(sources)
  1471. sources = sources[tt::numworks]
  1472. channellist = channellist[tt::numworks]
  1473. n = len(sources)
  1474. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  1475. self.sources = sources
  1476. self.channellist = channellist
  1477. print(f'self.sources {self.sources}')
  1478. self.imgs, self.fps, self.frames, self.threads,self.videotime = [None] * n, [0] * n, [0] * n, [None] * n, [None]*n
  1479. self.caps = [None] * n
  1480. self.pretime = [0]*n
  1481. for i, s in enumerate(sources): # index, source
  1482. # Start thread to read frames from video stream
  1483. st = f'{i + 1}/{n}: {s}... '
  1484. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  1485. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  1486. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  1487. import pafy
  1488. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  1489. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  1490. if s == 0:
  1491. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  1492. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  1493. print(f's= {s}')
  1494. self.caps[i] = cv2.VideoCapture(s)
  1495. self.caps[i] = cv2.VideoCapture(s)
  1496. self.caps[i] = cv2.VideoCapture(s)
  1497. print('cap')
  1498. if not self.caps[i].isOpened():
  1499. #if Path(weights).stem == 'smoke':
  1500. # w,h= 2688 , 1520
  1501. #elif Path(weights).stem == 'liquid' or Path(weights).stem == 'pressure':
  1502. # w,h = 2560,1440
  1503. #elif Path(weights).stem == 'helmet' or Path(weights).stem == 'fire':
  1504. # w,h = 1280,720
  1505. #else:
  1506. w,h = 1280,720
  1507. #w,h = 1280,720
  1508. #w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  1509. #h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  1510. fps = 25 # warning: may return 0 or nan
  1511. self.frames[i] = float('inf') # infinite stream fallback
  1512. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1513. self.imgs[i] = np.zeros((h,w,3)) # guarantee first frame
  1514. self.videotime[i] = time.localtime()
  1515. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1516. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h}e at {self.fps[i]:.2f} FPS)')
  1517. self.threads[i].start()
  1518. else:
  1519. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  1520. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  1521. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  1522. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  1523. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1524. #self.running = True
  1525. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  1526. self.videotime[i] = time.localtime()
  1527. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1528. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1529. self.threads[i].start()
  1530. LOGGER.info('') # newline
  1531. # check for common shapes
  1532. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  1533. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  1534. self.auto = auto and self.rect
  1535. self.running = True
  1536. self.transforms = transforms # optional
  1537. if not self.rect:
  1538. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  1539. def update(self, i, cap, stream):
  1540. # Read stream `i` frames in daemon thread
  1541. n, f = 0, self.frames[i] # frame number, frame array
  1542. while self.running:
  1543. if cap.isOpened() and n < f:
  1544. n += 1
  1545. cap.grab() # .read() = .grab() followed by .retrieve()
  1546. if n % self.vid_stride == 0:
  1547. success, im = cap.retrieve()
  1548. if success:
  1549. self.imgs[i] = im
  1550. timesta = time.time()-5
  1551. self.videotime[i] = time.localtime(timesta)
  1552. else:
  1553. if time.time()-self.pretime[i]>300:
  1554. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  1555. self.imgs[i] = np.zeros_like(self.imgs[i])
  1556. self.videotime[i] = time.localtime()
  1557. #try:
  1558. channel = self.channellist[i]
  1559. data = {
  1560. "channel": channel,
  1561. "ip":"172.19.152.231"
  1562. }
  1563. stream = requests.post(url=urlrtsp,data=data).json()['msg']
  1564. cap.open(stream) # re-open stream if signal was lost
  1565. cap.open(stream)
  1566. cap.open(stream)
  1567. print('reread')
  1568. #except Exception:
  1569. # print(f'readerror {stream}')
  1570. self.pretime[i] = time.time()
  1571. #time.sleep(300)
  1572. time.sleep(0.0) # wait time
  1573. elif not cap.isOpened() and n < f:
  1574. if time.time()-self.pretime[i]>300:
  1575. #try:
  1576. channel = self.channellist[i]
  1577. data = {
  1578. "channel": channel,
  1579. "ip":"172.19.152.231"
  1580. }
  1581. stream = requests.post(url=urlrtsp,data=data).json()['msg']
  1582. cap.open(stream) # re-open stream if signal was lost
  1583. cap.open(stream)
  1584. cap.open(stream)
  1585. print('reread1')
  1586. #except Exception:
  1587. # print(f'readerror {stream}')
  1588. #time.sleep(300)
  1589. self.pretime[i] = time.time()
  1590. def close(self):
  1591. """Close stream loader and release resources."""
  1592. self.running = False # stop flag for Thread
  1593. for thread in self.threads:
  1594. if thread.is_alive():
  1595. thread.join(timeout=5) # Add timeout
  1596. for cap in self.caps: # Iterate through the stored VideoCapture objects
  1597. print('close cap')
  1598. try:
  1599. cap.release() # release video capture
  1600. except Exception as e:
  1601. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  1602. cv2.destroyAllWindows()
  1603. def __iter__(self):
  1604. self.count = -1
  1605. return self
  1606. def __next__(self):
  1607. self.count += 1
  1608. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  1609. cv2.destroyAllWindows()
  1610. raise StopIteration
  1611. im0 = self.imgs.copy()
  1612. if self.transforms:
  1613. im = np.stack([self.transforms(x) for x in im0]) # transforms
  1614. else:
  1615. im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  1616. im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  1617. im = np.ascontiguousarray(im) # contiguous
  1618. return self.sources, im, im0, None, '',self.videotime,self.channellist
  1619. def __len__(self):
  1620. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  1621. class LoadStreamsSQLTND:
  1622. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  1623. def __init__(self, channellist = [],sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,tt=0,numworks=3,boxdir=None):
  1624. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  1625. self.mode = 'stream'
  1626. self.img_size = img_size
  1627. self.stride = stride
  1628. self.running = True
  1629. self.vid_stride = vid_stride # video frame-rate stride
  1630. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  1631. # print(f'orisource= {sources}')
  1632. # sources = sources[::4]
  1633. # print(f'source= {sources}')
  1634. # sourcelist = []
  1635. # conn = sqlite3.connect(sources)
  1636. # c = conn.cursor()
  1637. # print("sqlite")
  1638. # print(Path(weights).stem)
  1639. # cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ", (Path(weights).stem,))
  1640. # for i in cursor:
  1641. # # print(f'typei1{type(i[1])}')
  1642. # # rt = f'{i[1][:-1]}0'
  1643. # # print(i[1])
  1644. # sourcelist.append(i[1])
  1645. # sourcelist = set(sourcelist)
  1646. # conn.commit()
  1647. # c.close()
  1648. # conn.close()
  1649. # # print(f'orisource= {sources}')
  1650. # # sources = sources[::4]
  1651. # # print(f'source= {sources}')
  1652. # sources = list(sourcelist)
  1653. # sources.sort()
  1654. print(sources)
  1655. sources = sources[tt::numworks]
  1656. channellist = channellist[tt::numworks]
  1657. n = len(sources)
  1658. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  1659. self.sources = sources
  1660. self.channellist = channellist
  1661. print(f'self.sources {self.sources}')
  1662. self.imgs, self.fps, self.frames, self.threads,self.videotime = [None] * n, [0] * n, [0] * n, [None] * n, [None]*n
  1663. self.caps = [None] * n
  1664. self.pretime = [0]*n
  1665. for i, s in enumerate(sources): # index, source
  1666. # Start thread to read frames from video stream
  1667. st = f'{i + 1}/{n}: {s}... '
  1668. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  1669. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  1670. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  1671. import pafy
  1672. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  1673. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  1674. if s == 0:
  1675. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  1676. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  1677. print(f's= {s}')
  1678. self.caps[i] = cv2.VideoCapture(s)
  1679. self.caps[i] = cv2.VideoCapture(s)
  1680. self.caps[i] = cv2.VideoCapture(s)
  1681. print('cap')
  1682. if not self.caps[i].isOpened():
  1683. #if Path(weights).stem == 'smoke':
  1684. # w,h= 2688 , 1520
  1685. #elif Path(weights).stem == 'liquid' or Path(weights).stem == 'pressure':
  1686. # w,h = 2560,1440
  1687. #elif Path(weights).stem == 'helmet' or Path(weights).stem == 'fire':
  1688. # w,h = 1280,720
  1689. #else:
  1690. w,h = 1280,720
  1691. #w,h = 1280,720
  1692. #w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  1693. #h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  1694. fps = 25 # warning: may return 0 or nan
  1695. self.frames[i] = float('inf') # infinite stream fallback
  1696. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1697. self.imgs[i] = np.zeros((h,w,3)) # guarantee first frame
  1698. self.videotime[i] = time.localtime()
  1699. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1700. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h}e at {self.fps[i]:.2f} FPS)')
  1701. self.threads[i].start()
  1702. else:
  1703. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  1704. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  1705. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  1706. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  1707. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1708. #self.running = True
  1709. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  1710. self.videotime[i] = time.localtime()
  1711. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1712. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1713. self.threads[i].start()
  1714. LOGGER.info('') # newline
  1715. # check for common shapes
  1716. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  1717. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  1718. self.auto = auto and self.rect
  1719. self.running = True
  1720. self.transforms = transforms # optional
  1721. self.boxdir = boxdir
  1722. if not self.rect:
  1723. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  1724. def update(self, i, cap, stream):
  1725. # Read stream `i` frames in daemon thread
  1726. n, f = 0, self.frames[i] # frame number, frame array
  1727. while self.running:
  1728. if cap.isOpened() and n < f:
  1729. n += 1
  1730. cap.grab() # .read() = .grab() followed by .retrieve()
  1731. if n % self.vid_stride == 0:
  1732. success, im = cap.retrieve()
  1733. if success:
  1734. self.imgs[i] = im
  1735. timesta = time.time()-5
  1736. self.videotime[i] = time.localtime(timesta)
  1737. else:
  1738. if time.time()-self.pretime[i]>300:
  1739. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  1740. self.imgs[i] = np.zeros_like(self.imgs[i])
  1741. self.videotime[i] = time.localtime()
  1742. try:
  1743. cap.open(stream) # re-open stream if signal was lost
  1744. cap.open(stream)
  1745. cap.open(stream)
  1746. print('reread')
  1747. except Exception:
  1748. print(f'readerror {stream}')
  1749. self.pretime[i] = time.time()
  1750. #time.sleep(300)
  1751. time.sleep(0.0) # wait time
  1752. elif not cap.isOpened() and n < f:
  1753. if time.time()-self.pretime[i]>300:
  1754. try:
  1755. cap.open(stream) # re-open stream if signal was lost
  1756. cap.open(stream)
  1757. cap.open(stream)
  1758. print('reread1')
  1759. except Exception:
  1760. print(f'readerror {stream}')
  1761. #time.sleep(300)
  1762. self.pretime[i] = time.time()
  1763. def close(self):
  1764. """Close stream loader and release resources."""
  1765. self.running = False # stop flag for Thread
  1766. for thread in self.threads:
  1767. if thread.is_alive():
  1768. thread.join(timeout=5) # Add timeout
  1769. for cap in self.caps: # Iterate through the stored VideoCapture objects
  1770. print('close cap')
  1771. try:
  1772. cap.release() # release video capture
  1773. except Exception as e:
  1774. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  1775. cv2.destroyAllWindows()
  1776. def __iter__(self):
  1777. self.count = -1
  1778. return self
  1779. def __next__(self):
  1780. self.count += 1
  1781. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  1782. cv2.destroyAllWindows()
  1783. raise StopIteration
  1784. im0 = self.imgs.copy()
  1785. for channel,ima in zip(self.channellist,im0):
  1786. if channel in self.boxdir:
  1787. if len(self.boxdir[channel])>0:
  1788. print('find-----------------------------------box')
  1789. for box in self.boxdir[channel]:
  1790. cv2.rectangle(ima,(box[0],box[1]),(box[2],box[3]),(0,0,255),3)
  1791. #cv2.imwrite(f'data/images/{time.time()}.jpg',ima)
  1792. return self.sources, im0, None, '',self.videotime,self.channellist
  1793. def __len__(self):
  1794. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  1795. def img2label_paths(img_paths):
  1796. # Define label paths as a function of image paths
  1797. sa, sb = f'{os.sep}images{os.sep}', f'{os.sep}labels{os.sep}' # /images/, /labels/ substrings
  1798. return [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths]
  1799. class LoadStreamsTN:
  1800. # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams`
  1801. def __init__(self, channellist = [],sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1,tt=0,numworks=3):
  1802. torch.backends.cudnn.benchmark = True # faster for fixed-size inference
  1803. self.mode = 'stream'
  1804. self.img_size = img_size
  1805. self.stride = stride
  1806. self.running = True
  1807. self.vid_stride = vid_stride # video frame-rate stride
  1808. #sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources]
  1809. # print(f'orisource= {sources}')
  1810. # sources = sources[::4]
  1811. # print(f'source= {sources}')
  1812. # sourcelist = []
  1813. # conn = sqlite3.connect(sources)
  1814. # c = conn.cursor()
  1815. # print("sqlite")
  1816. # print(Path(weights).stem)
  1817. # cursor = c.execute("SELECT modelname, address from STREAM WHERE modelname = (?) ", (Path(weights).stem,))
  1818. # for i in cursor:
  1819. # # print(f'typei1{type(i[1])}')
  1820. # # rt = f'{i[1][:-1]}0'
  1821. # # print(i[1])
  1822. # sourcelist.append(i[1])
  1823. # sourcelist = set(sourcelist)
  1824. # conn.commit()
  1825. # c.close()
  1826. # conn.close()
  1827. # # print(f'orisource= {sources}')
  1828. # # sources = sources[::4]
  1829. # # print(f'source= {sources}')
  1830. # sources = list(sourcelist)
  1831. # sources.sort()
  1832. print(sources)
  1833. sources = sources[tt::numworks]
  1834. channellist = channellist[tt::numworks]
  1835. n = len(sources)
  1836. #self.sources = [clean_str(x) for x in sources] # clean source names for later
  1837. self.sources = sources
  1838. self.channellist = channellist
  1839. print(f'self.sources {self.sources}')
  1840. self.imgs, self.fps, self.frames, self.threads,self.videotime = [None] * n, [0] * n, [0] * n, [None] * n, [None]*n
  1841. self.caps = [None] * n
  1842. self.pretime = [0]*n
  1843. for i, s in enumerate(sources): # index, source
  1844. # Start thread to read frames from video stream
  1845. st = f'{i + 1}/{n}: {s}... '
  1846. if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video
  1847. # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc'
  1848. check_requirements(('pafy', 'youtube_dl==2020.12.2'))
  1849. import pafy
  1850. s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL
  1851. s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam
  1852. if s == 0:
  1853. assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.'
  1854. assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.'
  1855. print(f's= {s}')
  1856. self.caps[i] = cv2.VideoCapture(s)
  1857. self.caps[i] = cv2.VideoCapture(s)
  1858. self.caps[i] = cv2.VideoCapture(s)
  1859. print('cap')
  1860. if not self.caps[i].isOpened():
  1861. #if Path(weights).stem == 'smoke':
  1862. # w,h= 2688 , 1520
  1863. #elif Path(weights).stem == 'liquid' or Path(weights).stem == 'pressure':
  1864. # w,h = 2560,1440
  1865. #elif Path(weights).stem == 'helmet' or Path(weights).stem == 'fire':
  1866. # w,h = 1280,720
  1867. #else:
  1868. w,h = 1280,720
  1869. #w,h = 1280,720
  1870. #w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  1871. #h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  1872. fps = 25 # warning: may return 0 or nan
  1873. self.frames[i] = float('inf') # infinite stream fallback
  1874. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1875. self.imgs[i] = np.zeros((h,w,3)) # guarantee first frame
  1876. self.videotime[i] = time.localtime()
  1877. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1878. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h}e at {self.fps[i]:.2f} FPS)')
  1879. self.threads[i].start()
  1880. else:
  1881. w = int(self.caps[i].get(cv2.CAP_PROP_FRAME_WIDTH))
  1882. h = int(self.caps[i].get(cv2.CAP_PROP_FRAME_HEIGHT))
  1883. fps = self.caps[i].get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan
  1884. self.frames[i] = max(int(self.caps[i].get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback
  1885. self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback
  1886. #self.running = True
  1887. _, self.imgs[i] = self.caps[i].read() # guarantee first frame
  1888. self.videotime[i] = time.localtime()
  1889. self.threads[i] = Thread(target=self.update, args=([i, self.caps[i], s]), daemon=True)
  1890. LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)')
  1891. self.threads[i].start()
  1892. LOGGER.info('') # newline
  1893. # check for common shapes
  1894. s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs])
  1895. self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal
  1896. self.auto = auto and self.rect
  1897. self.running = True
  1898. self.transforms = transforms # optional
  1899. if not self.rect:
  1900. LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.')
  1901. def update(self, i, cap, stream):
  1902. # Read stream `i` frames in daemon thread
  1903. n, f = 0, self.frames[i] # frame number, frame array
  1904. while self.running:
  1905. if cap.isOpened() and n < f:
  1906. n += 1
  1907. cap.grab() # .read() = .grab() followed by .retrieve()
  1908. if n % self.vid_stride == 0:
  1909. success, im = cap.retrieve()
  1910. if success:
  1911. self.imgs[i] = im
  1912. timesta = time.time()-5
  1913. self.videotime[i] = time.localtime(timesta)
  1914. else:
  1915. if time.time()-self.pretime[i]>300:
  1916. LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.')
  1917. self.imgs[i] = np.zeros_like(self.imgs[i])
  1918. self.videotime[i] = time.localtime()
  1919. #try:
  1920. channel = self.channellist[i]
  1921. data = {
  1922. "channel": channel,
  1923. "ip":"172.19.152.231"
  1924. }
  1925. stream = requests.post(url=urlrtsp,data=data).json()['msg']
  1926. cap.open(stream) # re-open stream if signal was lost
  1927. cap.open(stream)
  1928. cap.open(stream)
  1929. print('reread')
  1930. #except Exception:
  1931. # print(f'readerror {stream}')
  1932. self.pretime[i] = time.time()
  1933. #time.sleep(300)
  1934. time.sleep(0.0) # wait time
  1935. elif not cap.isOpened() and n < f:
  1936. if time.time()-self.pretime[i]>300:
  1937. #try:
  1938. channel = self.channellist[i]
  1939. data = {
  1940. "channel": channel,
  1941. "ip":"172.19.152.231"
  1942. }
  1943. stream = requests.post(url=urlrtsp,data=data).json()['msg']
  1944. cap.open(stream) # re-open stream if signal was lost
  1945. cap.open(stream)
  1946. cap.open(stream)
  1947. print('reread1')
  1948. #except Exception:
  1949. # print(f'readerror {stream}')
  1950. #time.sleep(300)
  1951. self.pretime[i] = time.time()
  1952. def close(self):
  1953. """Close stream loader and release resources."""
  1954. self.running = False # stop flag for Thread
  1955. for thread in self.threads:
  1956. if thread.is_alive():
  1957. thread.join(timeout=5) # Add timeout
  1958. for cap in self.caps: # Iterate through the stored VideoCapture objects
  1959. print('close cap')
  1960. try:
  1961. cap.release() # release video capture
  1962. except Exception as e:
  1963. LOGGER.warning(f'WARNING ⚠️ Could not release VideoCapture object: {e}')
  1964. cv2.destroyAllWindows()
  1965. def __iter__(self):
  1966. self.count = -1
  1967. return self
  1968. def __next__(self):
  1969. self.count += 1
  1970. if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
  1971. cv2.destroyAllWindows()
  1972. raise StopIteration
  1973. im0 = self.imgs.copy()
  1974. # if self.transforms:
  1975. # im = np.stack([self.transforms(x) for x in im0]) # transforms
  1976. # else:
  1977. # im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize
  1978. # im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW
  1979. # im = np.ascontiguousarray(im) # contiguous
  1980. return self.sources, '', im0, None, '',self.videotime,self.channellist
  1981. def __len__(self):
  1982. return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years
  1983. class LoadImagesAndLabels(Dataset):
  1984. # YOLOv5 train_loader/val_loader, loads images and labels for training and validation
  1985. cache_version = 0.6 # dataset labels *.cache version
  1986. rand_interp_methods = [cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_LANCZOS4]
  1987. def __init__(self,
  1988. path,
  1989. img_size=640,
  1990. batch_size=16,
  1991. augment=False,
  1992. hyp=None,
  1993. rect=False,
  1994. image_weights=False,
  1995. cache_images=False,
  1996. single_cls=False,
  1997. stride=32,
  1998. pad=0.0,
  1999. min_items=0,
  2000. prefix=''):
  2001. self.img_size = img_size
  2002. self.augment = augment
  2003. self.hyp = hyp
  2004. self.image_weights = image_weights
  2005. self.rect = False if image_weights else rect
  2006. self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training)
  2007. self.mosaic_border = [-img_size // 2, -img_size // 2]
  2008. self.stride = stride
  2009. self.path = path
  2010. self.albumentations = Albumentations(size=img_size) if augment else None
  2011. try:
  2012. f = [] # image files
  2013. for p in path if isinstance(path, list) else [path]:
  2014. p = Path(p) # os-agnostic
  2015. if p.is_dir(): # dir
  2016. f += glob.glob(str(p / '**' / '*.*'), recursive=True)
  2017. # f = list(p.rglob('*.*')) # pathlib
  2018. elif p.is_file(): # file
  2019. with open(p) as t:
  2020. t = t.read().strip().splitlines()
  2021. parent = str(p.parent) + os.sep
  2022. f += [x.replace('./', parent, 1) if x.startswith('./') else x for x in t] # to global path
  2023. # f += [p.parent / x.lstrip(os.sep) for x in t] # to global path (pathlib)
  2024. else:
  2025. raise FileNotFoundError(f'{prefix}{p} does not exist')
  2026. self.im_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS)
  2027. # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS]) # pathlib
  2028. assert self.im_files, f'{prefix}No images found'
  2029. except Exception as e:
  2030. raise Exception(f'{prefix}Error loading data from {path}: {e}\n{HELP_URL}') from e
  2031. # Check cache
  2032. self.label_files = img2label_paths(self.im_files) # labels
  2033. cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache')
  2034. try:
  2035. cache, exists = np.load(cache_path, allow_pickle=True).item(), True # load dict
  2036. assert cache['version'] == self.cache_version # matches current version
  2037. assert cache['hash'] == get_hash(self.label_files + self.im_files) # identical hash
  2038. except Exception:
  2039. cache, exists = self.cache_labels(cache_path, prefix), False # run cache ops
  2040. # Display cache
  2041. nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupt, total
  2042. if exists and LOCAL_RANK in {-1, 0}:
  2043. d = f'Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt'
  2044. tqdm(None, desc=prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT) # display cache results
  2045. if cache['msgs']:
  2046. LOGGER.info('\n'.join(cache['msgs'])) # display warnings
  2047. assert nf > 0 or not augment, f'{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}'
  2048. # Read cache
  2049. [cache.pop(k) for k in ('hash', 'version', 'msgs')] # remove items
  2050. labels, shapes, self.segments = zip(*cache.values())
  2051. nl = len(np.concatenate(labels, 0)) # number of labels
  2052. assert nl > 0 or not augment, f'{prefix}All labels empty in {cache_path}, can not start training. {HELP_URL}'
  2053. self.labels = list(labels)
  2054. self.shapes = np.array(shapes)
  2055. self.im_files = list(cache.keys()) # update
  2056. self.label_files = img2label_paths(cache.keys()) # update
  2057. # Filter images
  2058. if min_items:
  2059. include = np.array([len(x) >= min_items for x in self.labels]).nonzero()[0].astype(int)
  2060. LOGGER.info(f'{prefix}{n - len(include)}/{n} images filtered from dataset')
  2061. self.im_files = [self.im_files[i] for i in include]
  2062. self.label_files = [self.label_files[i] for i in include]
  2063. self.labels = [self.labels[i] for i in include]
  2064. self.segments = [self.segments[i] for i in include]
  2065. self.shapes = self.shapes[include] # wh
  2066. # Create indices
  2067. n = len(self.shapes) # number of images
  2068. bi = np.floor(np.arange(n) / batch_size).astype(int) # batch index
  2069. nb = bi[-1] + 1 # number of batches
  2070. self.batch = bi # batch index of image
  2071. self.n = n
  2072. self.indices = range(n)
  2073. # Update labels
  2074. include_class = [] # filter labels to include only these classes (optional)
  2075. self.segments = list(self.segments)
  2076. include_class_array = np.array(include_class).reshape(1, -1)
  2077. for i, (label, segment) in enumerate(zip(self.labels, self.segments)):
  2078. if include_class:
  2079. j = (label[:, 0:1] == include_class_array).any(1)
  2080. self.labels[i] = label[j]
  2081. if segment:
  2082. self.segments[i] = [segment[idx] for idx, elem in enumerate(j) if elem]
  2083. if single_cls: # single-class training, merge all classes into 0
  2084. self.labels[i][:, 0] = 0
  2085. # Rectangular Training
  2086. if self.rect:
  2087. # Sort by aspect ratio
  2088. s = self.shapes # wh
  2089. ar = s[:, 1] / s[:, 0] # aspect ratio
  2090. irect = ar.argsort()
  2091. self.im_files = [self.im_files[i] for i in irect]
  2092. self.label_files = [self.label_files[i] for i in irect]
  2093. self.labels = [self.labels[i] for i in irect]
  2094. self.segments = [self.segments[i] for i in irect]
  2095. self.shapes = s[irect] # wh
  2096. ar = ar[irect]
  2097. # Set training image shapes
  2098. shapes = [[1, 1]] * nb
  2099. for i in range(nb):
  2100. ari = ar[bi == i]
  2101. mini, maxi = ari.min(), ari.max()
  2102. if maxi < 1:
  2103. shapes[i] = [maxi, 1]
  2104. elif mini > 1:
  2105. shapes[i] = [1, 1 / mini]
  2106. self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(int) * stride
  2107. # Cache images into RAM/disk for faster training
  2108. if cache_images == 'ram' and not self.check_cache_ram(prefix=prefix):
  2109. cache_images = False
  2110. self.ims = [None] * n
  2111. self.npy_files = [Path(f).with_suffix('.npy') for f in self.im_files]
  2112. if cache_images:
  2113. b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes
  2114. self.im_hw0, self.im_hw = [None] * n, [None] * n
  2115. fcn = self.cache_images_to_disk if cache_images == 'disk' else self.load_image
  2116. results = ThreadPool(NUM_THREADS).imap(fcn, range(n))
  2117. pbar = tqdm(enumerate(results), total=n, bar_format=TQDM_BAR_FORMAT, disable=LOCAL_RANK > 0)
  2118. for i, x in pbar:
  2119. if cache_images == 'disk':
  2120. b += self.npy_files[i].stat().st_size
  2121. else: # 'ram'
  2122. self.ims[i], self.im_hw0[i], self.im_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i)
  2123. b += self.ims[i].nbytes
  2124. pbar.desc = f'{prefix}Caching images ({b / gb:.1f}GB {cache_images})'
  2125. pbar.close()
  2126. def check_cache_ram(self, safety_margin=0.1, prefix=''):
  2127. # Check image caching requirements vs available memory
  2128. b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes
  2129. n = min(self.n, 30) # extrapolate from 30 random images
  2130. for _ in range(n):
  2131. im = cv2.imread(random.choice(self.im_files)) # sample image
  2132. ratio = self.img_size / max(im.shape[0], im.shape[1]) # max(h, w) # ratio
  2133. b += im.nbytes * ratio ** 2
  2134. mem_required = b * self.n / n # GB required to cache dataset into RAM
  2135. mem = psutil.virtual_memory()
  2136. cache = mem_required * (1 + safety_margin) < mem.available # to cache or not to cache, that is the question
  2137. if not cache:
  2138. LOGGER.info(f'{prefix}{mem_required / gb:.1f}GB RAM required, '
  2139. f'{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, '
  2140. f"{'caching images ✅' if cache else 'not caching images ⚠️'}")
  2141. return cache
  2142. def cache_labels(self, path=Path('./labels.cache'), prefix=''):
  2143. # Cache dataset labels, check images and read shapes
  2144. x = {} # dict
  2145. nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages
  2146. desc = f'{prefix}Scanning {path.parent / path.stem}...'
  2147. with Pool(NUM_THREADS) as pool:
  2148. pbar = tqdm(pool.imap(verify_image_label, zip(self.im_files, self.label_files, repeat(prefix))),
  2149. desc=desc,
  2150. total=len(self.im_files),
  2151. bar_format=TQDM_BAR_FORMAT)
  2152. for im_file, lb, shape, segments, nm_f, nf_f, ne_f, nc_f, msg in pbar:
  2153. nm += nm_f
  2154. nf += nf_f
  2155. ne += ne_f
  2156. nc += nc_f
  2157. if im_file:
  2158. x[im_file] = [lb, shape, segments]
  2159. if msg:
  2160. msgs.append(msg)
  2161. pbar.desc = f'{desc} {nf} images, {nm + ne} backgrounds, {nc} corrupt'
  2162. pbar.close()
  2163. if msgs:
  2164. LOGGER.info('\n'.join(msgs))
  2165. if nf == 0:
  2166. LOGGER.warning(f'{prefix}WARNING ⚠️ No labels found in {path}. {HELP_URL}')
  2167. x['hash'] = get_hash(self.label_files + self.im_files)
  2168. x['results'] = nf, nm, ne, nc, len(self.im_files)
  2169. x['msgs'] = msgs # warnings
  2170. x['version'] = self.cache_version # cache version
  2171. try:
  2172. np.save(path, x) # save cache for next time
  2173. path.with_suffix('.cache.npy').rename(path) # remove .npy suffix
  2174. LOGGER.info(f'{prefix}New cache created: {path}')
  2175. except Exception as e:
  2176. LOGGER.warning(f'{prefix}WARNING ⚠️ Cache directory {path.parent} is not writeable: {e}') # not writeable
  2177. return x
  2178. def __len__(self):
  2179. return len(self.im_files)
  2180. # def __iter__(self):
  2181. # self.count = -1
  2182. # print('ran dataset iter')
  2183. # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF)
  2184. # return self
  2185. def __getitem__(self, index):
  2186. index = self.indices[index] # linear, shuffled, or image_weights
  2187. hyp = self.hyp
  2188. mosaic = self.mosaic and random.random() < hyp['mosaic']
  2189. if mosaic:
  2190. # Load mosaic
  2191. img, labels = self.load_mosaic(index)
  2192. shapes = None
  2193. # MixUp augmentation
  2194. if random.random() < hyp['mixup']:
  2195. img, labels = mixup(img, labels, *self.load_mosaic(random.randint(0, self.n - 1)))
  2196. else:
  2197. # Load image
  2198. img, (h0, w0), (h, w) = self.load_image(index)
  2199. # Letterbox
  2200. shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape
  2201. img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment)
  2202. shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling
  2203. labels = self.labels[index].copy()
  2204. if labels.size: # normalized xywh to pixel xyxy format
  2205. labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1])
  2206. if self.augment:
  2207. img, labels = random_perspective(img,
  2208. labels,
  2209. degrees=hyp['degrees'],
  2210. translate=hyp['translate'],
  2211. scale=hyp['scale'],
  2212. shear=hyp['shear'],
  2213. perspective=hyp['perspective'])
  2214. nl = len(labels) # number of labels
  2215. if nl:
  2216. labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1E-3)
  2217. if self.augment:
  2218. # Albumentations
  2219. img, labels = self.albumentations(img, labels)
  2220. nl = len(labels) # update after albumentations
  2221. # HSV color-space
  2222. augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v'])
  2223. # Flip up-down
  2224. if random.random() < hyp['flipud']:
  2225. img = np.flipud(img)
  2226. if nl:
  2227. labels[:, 2] = 1 - labels[:, 2]
  2228. # Flip left-right
  2229. if random.random() < hyp['fliplr']:
  2230. img = np.fliplr(img)
  2231. if nl:
  2232. labels[:, 1] = 1 - labels[:, 1]
  2233. # Cutouts
  2234. # labels = cutout(img, labels, p=0.5)
  2235. # nl = len(labels) # update after cutout
  2236. labels_out = torch.zeros((nl, 6))
  2237. if nl:
  2238. labels_out[:, 1:] = torch.from_numpy(labels)
  2239. # Convert
  2240. img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB
  2241. img = np.ascontiguousarray(img)
  2242. return torch.from_numpy(img), labels_out, self.im_files[index], shapes
  2243. def load_image(self, i):
  2244. # Loads 1 image from dataset index 'i', returns (im, original hw, resized hw)
  2245. im, f, fn = self.ims[i], self.im_files[i], self.npy_files[i],
  2246. if im is None: # not cached in RAM
  2247. if fn.exists(): # load npy
  2248. im = np.load(fn)
  2249. else: # read image
  2250. im = cv2.imread(f) # BGR
  2251. assert im is not None, f'Image Not Found {f}'
  2252. h0, w0 = im.shape[:2] # orig hw
  2253. r = self.img_size / max(h0, w0) # ratio
  2254. if r != 1: # if sizes are not equal
  2255. interp = cv2.INTER_LINEAR if (self.augment or r > 1) else cv2.INTER_AREA
  2256. im = cv2.resize(im, (math.ceil(w0 * r), math.ceil(h0 * r)), interpolation=interp)
  2257. return im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized
  2258. return self.ims[i], self.im_hw0[i], self.im_hw[i] # im, hw_original, hw_resized
  2259. def cache_images_to_disk(self, i):
  2260. # Saves an image as an *.npy file for faster loading
  2261. f = self.npy_files[i]
  2262. if not f.exists():
  2263. np.save(f.as_posix(), cv2.imread(self.im_files[i]))
  2264. def load_mosaic(self, index):
  2265. # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic
  2266. labels4, segments4 = [], []
  2267. s = self.img_size
  2268. yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y
  2269. indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices
  2270. random.shuffle(indices)
  2271. for i, index in enumerate(indices):
  2272. # Load image
  2273. img, _, (h, w) = self.load_image(index)
  2274. # place img in img4
  2275. if i == 0: # top left
  2276. img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles
  2277. x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image)
  2278. x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image)
  2279. elif i == 1: # top right
  2280. x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc
  2281. x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h
  2282. elif i == 2: # bottom left
  2283. x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)
  2284. x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h)
  2285. elif i == 3: # bottom right
  2286. x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h)
  2287. x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h)
  2288. img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax]
  2289. padw = x1a - x1b
  2290. padh = y1a - y1b
  2291. # Labels
  2292. labels, segments = self.labels[index].copy(), self.segments[index].copy()
  2293. if labels.size:
  2294. labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format
  2295. segments = [xyn2xy(x, w, h, padw, padh) for x in segments]
  2296. labels4.append(labels)
  2297. segments4.extend(segments)
  2298. # Concat/clip labels
  2299. labels4 = np.concatenate(labels4, 0)
  2300. for x in (labels4[:, 1:], *segments4):
  2301. np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective()
  2302. # img4, labels4 = replicate(img4, labels4) # replicate
  2303. # Augment
  2304. img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste'])
  2305. img4, labels4 = random_perspective(img4,
  2306. labels4,
  2307. segments4,
  2308. degrees=self.hyp['degrees'],
  2309. translate=self.hyp['translate'],
  2310. scale=self.hyp['scale'],
  2311. shear=self.hyp['shear'],
  2312. perspective=self.hyp['perspective'],
  2313. border=self.mosaic_border) # border to remove
  2314. return img4, labels4
  2315. def load_mosaic9(self, index):
  2316. # YOLOv5 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic
  2317. labels9, segments9 = [], []
  2318. s = self.img_size
  2319. indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices
  2320. random.shuffle(indices)
  2321. hp, wp = -1, -1 # height, width previous
  2322. for i, index in enumerate(indices):
  2323. # Load image
  2324. img, _, (h, w) = self.load_image(index)
  2325. # place img in img9
  2326. if i == 0: # center
  2327. img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles
  2328. h0, w0 = h, w
  2329. c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates
  2330. elif i == 1: # top
  2331. c = s, s - h, s + w, s
  2332. elif i == 2: # top right
  2333. c = s + wp, s - h, s + wp + w, s
  2334. elif i == 3: # right
  2335. c = s + w0, s, s + w0 + w, s + h
  2336. elif i == 4: # bottom right
  2337. c = s + w0, s + hp, s + w0 + w, s + hp + h
  2338. elif i == 5: # bottom
  2339. c = s + w0 - w, s + h0, s + w0, s + h0 + h
  2340. elif i == 6: # bottom left
  2341. c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h
  2342. elif i == 7: # left
  2343. c = s - w, s + h0 - h, s, s + h0
  2344. elif i == 8: # top left
  2345. c = s - w, s + h0 - hp - h, s, s + h0 - hp
  2346. padx, pady = c[:2]
  2347. x1, y1, x2, y2 = (max(x, 0) for x in c) # allocate coords
  2348. # Labels
  2349. labels, segments = self.labels[index].copy(), self.segments[index].copy()
  2350. if labels.size:
  2351. labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady) # normalized xywh to pixel xyxy format
  2352. segments = [xyn2xy(x, w, h, padx, pady) for x in segments]
  2353. labels9.append(labels)
  2354. segments9.extend(segments)
  2355. # Image
  2356. img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax]
  2357. hp, wp = h, w # height, width previous
  2358. # Offset
  2359. yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y
  2360. img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s]
  2361. # Concat/clip labels
  2362. labels9 = np.concatenate(labels9, 0)
  2363. labels9[:, [1, 3]] -= xc
  2364. labels9[:, [2, 4]] -= yc
  2365. c = np.array([xc, yc]) # centers
  2366. segments9 = [x - c for x in segments9]
  2367. for x in (labels9[:, 1:], *segments9):
  2368. np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective()
  2369. # img9, labels9 = replicate(img9, labels9) # replicate
  2370. # Augment
  2371. img9, labels9, segments9 = copy_paste(img9, labels9, segments9, p=self.hyp['copy_paste'])
  2372. img9, labels9 = random_perspective(img9,
  2373. labels9,
  2374. segments9,
  2375. degrees=self.hyp['degrees'],
  2376. translate=self.hyp['translate'],
  2377. scale=self.hyp['scale'],
  2378. shear=self.hyp['shear'],
  2379. perspective=self.hyp['perspective'],
  2380. border=self.mosaic_border) # border to remove
  2381. return img9, labels9
  2382. @staticmethod
  2383. def collate_fn(batch):
  2384. im, label, path, shapes = zip(*batch) # transposed
  2385. for i, lb in enumerate(label):
  2386. lb[:, 0] = i # add target image index for build_targets()
  2387. return torch.stack(im, 0), torch.cat(label, 0), path, shapes
  2388. @staticmethod
  2389. def collate_fn4(batch):
  2390. im, label, path, shapes = zip(*batch) # transposed
  2391. n = len(shapes) // 4
  2392. im4, label4, path4, shapes4 = [], [], path[:n], shapes[:n]
  2393. ho = torch.tensor([[0.0, 0, 0, 1, 0, 0]])
  2394. wo = torch.tensor([[0.0, 0, 1, 0, 0, 0]])
  2395. s = torch.tensor([[1, 1, 0.5, 0.5, 0.5, 0.5]]) # scale
  2396. for i in range(n): # zidane torch.zeros(16,3,720,1280) # BCHW
  2397. i *= 4
  2398. if random.random() < 0.5:
  2399. im1 = F.interpolate(im[i].unsqueeze(0).float(), scale_factor=2.0, mode='bilinear',
  2400. align_corners=False)[0].type(im[i].type())
  2401. lb = label[i]
  2402. else:
  2403. im1 = torch.cat((torch.cat((im[i], im[i + 1]), 1), torch.cat((im[i + 2], im[i + 3]), 1)), 2)
  2404. lb = torch.cat((label[i], label[i + 1] + ho, label[i + 2] + wo, label[i + 3] + ho + wo), 0) * s
  2405. im4.append(im1)
  2406. label4.append(lb)
  2407. for i, lb in enumerate(label4):
  2408. lb[:, 0] = i # add target image index for build_targets()
  2409. return torch.stack(im4, 0), torch.cat(label4, 0), path4, shapes4
  2410. # Ancillary functions --------------------------------------------------------------------------------------------------
  2411. def flatten_recursive(path=DATASETS_DIR / 'coco128'):
  2412. # Flatten a recursive directory by bringing all files to top level
  2413. new_path = Path(f'{str(path)}_flat')
  2414. if os.path.exists(new_path):
  2415. shutil.rmtree(new_path) # delete output folder
  2416. os.makedirs(new_path) # make new output folder
  2417. for file in tqdm(glob.glob(f'{str(Path(path))}/**/*.*', recursive=True)):
  2418. shutil.copyfile(file, new_path / Path(file).name)
  2419. def extract_boxes(path=DATASETS_DIR / 'coco128'): # from utils.dataloaders import *; extract_boxes()
  2420. # Convert detection dataset into classification dataset, with one directory per class
  2421. path = Path(path) # images dir
  2422. shutil.rmtree(path / 'classification') if (path / 'classification').is_dir() else None # remove existing
  2423. files = list(path.rglob('*.*'))
  2424. n = len(files) # number of files
  2425. for im_file in tqdm(files, total=n):
  2426. if im_file.suffix[1:] in IMG_FORMATS:
  2427. # image
  2428. im = cv2.imread(str(im_file))[..., ::-1] # BGR to RGB
  2429. h, w = im.shape[:2]
  2430. # labels
  2431. lb_file = Path(img2label_paths([str(im_file)])[0])
  2432. if Path(lb_file).exists():
  2433. with open(lb_file) as f:
  2434. lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels
  2435. for j, x in enumerate(lb):
  2436. c = int(x[0]) # class
  2437. f = (path / 'classifier') / f'{c}' / f'{path.stem}_{im_file.stem}_{j}.jpg' # new filename
  2438. if not f.parent.is_dir():
  2439. f.parent.mkdir(parents=True)
  2440. b = x[1:] * [w, h, w, h] # box
  2441. # b[2:] = b[2:].max() # rectangle to square
  2442. b[2:] = b[2:] * 1.2 + 3 # pad
  2443. b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(int)
  2444. b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image
  2445. b[[1, 3]] = np.clip(b[[1, 3]], 0, h)
  2446. assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}'
  2447. def autosplit(path=DATASETS_DIR / 'coco128/images', weights=(0.9, 0.1, 0.0), annotated_only=False):
  2448. """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files
  2449. Usage: from utils.dataloaders import *; autosplit()
  2450. Arguments
  2451. path: Path to images directory
  2452. weights: Train, val, test weights (list, tuple)
  2453. annotated_only: Only use images with an annotated txt file
  2454. """
  2455. path = Path(path) # images dir
  2456. files = sorted(x for x in path.rglob('*.*') if x.suffix[1:].lower() in IMG_FORMATS) # image files only
  2457. n = len(files) # number of files
  2458. random.seed(0) # for reproducibility
  2459. indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split
  2460. txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files
  2461. for x in txt:
  2462. if (path.parent / x).exists():
  2463. (path.parent / x).unlink() # remove existing
  2464. print(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only)
  2465. for i, img in tqdm(zip(indices, files), total=n):
  2466. if not annotated_only or Path(img2label_paths([str(img)])[0]).exists(): # check label
  2467. with open(path.parent / txt[i], 'a') as f:
  2468. f.write(f'./{img.relative_to(path.parent).as_posix()}' + '\n') # add image to txt file
  2469. def verify_image_label(args):
  2470. # Verify one image-label pair
  2471. im_file, lb_file, prefix = args
  2472. nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, '', [] # number (missing, found, empty, corrupt), message, segments
  2473. try:
  2474. # verify images
  2475. im = Image.open(im_file)
  2476. im.verify() # PIL verify
  2477. shape = exif_size(im) # image size
  2478. assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels'
  2479. assert im.format.lower() in IMG_FORMATS, f'invalid image format {im.format}'
  2480. if im.format.lower() in ('jpg', 'jpeg'):
  2481. with open(im_file, 'rb') as f:
  2482. f.seek(-2, 2)
  2483. if f.read() != b'\xff\xd9': # corrupt JPEG
  2484. ImageOps.exif_transpose(Image.open(im_file)).save(im_file, 'JPEG', subsampling=0, quality=100)
  2485. msg = f'{prefix}WARNING ⚠️ {im_file}: corrupt JPEG restored and saved'
  2486. # verify labels
  2487. if os.path.isfile(lb_file):
  2488. nf = 1 # label found
  2489. with open(lb_file) as f:
  2490. lb = [x.split() for x in f.read().strip().splitlines() if len(x)]
  2491. if any(len(x) > 6 for x in lb): # is segment
  2492. classes = np.array([x[0] for x in lb], dtype=np.float32)
  2493. segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in lb] # (cls, xy1...)
  2494. lb = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh)
  2495. lb = np.array(lb, dtype=np.float32)
  2496. nl = len(lb)
  2497. if nl:
  2498. assert lb.shape[1] == 5, f'labels require 5 columns, {lb.shape[1]} columns detected'
  2499. assert (lb >= 0).all(), f'negative label values {lb[lb < 0]}'
  2500. assert (lb[:, 1:] <= 1).all(), f'non-normalized or out of bounds coordinates {lb[:, 1:][lb[:, 1:] > 1]}'
  2501. _, i = np.unique(lb, axis=0, return_index=True)
  2502. if len(i) < nl: # duplicate row check
  2503. lb = lb[i] # remove duplicates
  2504. if segments:
  2505. segments = [segments[x] for x in i]
  2506. msg = f'{prefix}WARNING ⚠️ {im_file}: {nl - len(i)} duplicate labels removed'
  2507. else:
  2508. ne = 1 # label empty
  2509. lb = np.zeros((0, 5), dtype=np.float32)
  2510. else:
  2511. nm = 1 # label missing
  2512. lb = np.zeros((0, 5), dtype=np.float32)
  2513. return im_file, lb, shape, segments, nm, nf, ne, nc, msg
  2514. except Exception as e:
  2515. nc = 1
  2516. msg = f'{prefix}WARNING ⚠️ {im_file}: ignoring corrupt image/label: {e}'
  2517. return [None, None, None, None, nm, nf, ne, nc, msg]
  2518. class HUBDatasetStats():
  2519. """ Class for generating HUB dataset JSON and `-hub` dataset directory
  2520. Arguments
  2521. path: Path to data.yaml or data.zip (with data.yaml inside data.zip)
  2522. autodownload: Attempt to download dataset if not found locally
  2523. Usage
  2524. from utils.dataloaders import HUBDatasetStats
  2525. stats = HUBDatasetStats('coco128.yaml', autodownload=True) # usage 1
  2526. stats = HUBDatasetStats('path/to/coco128.zip') # usage 2
  2527. stats.get_json(save=False)
  2528. stats.process_images()
  2529. """
  2530. def __init__(self, path='coco128.yaml', autodownload=False):
  2531. # Initialize class
  2532. zipped, data_dir, yaml_path = self._unzip(Path(path))
  2533. try:
  2534. with open(check_yaml(yaml_path), errors='ignore') as f:
  2535. data = yaml.safe_load(f) # data dict
  2536. if zipped:
  2537. data['path'] = data_dir
  2538. except Exception as e:
  2539. raise Exception('error/HUB/dataset_stats/yaml_load') from e
  2540. check_dataset(data, autodownload) # download dataset if missing
  2541. self.hub_dir = Path(data['path'] + '-hub')
  2542. self.im_dir = self.hub_dir / 'images'
  2543. self.im_dir.mkdir(parents=True, exist_ok=True) # makes /images
  2544. self.stats = {'nc': data['nc'], 'names': list(data['names'].values())} # statistics dictionary
  2545. self.data = data
  2546. @staticmethod
  2547. def _find_yaml(dir):
  2548. # Return data.yaml file
  2549. files = list(dir.glob('*.yaml')) or list(dir.rglob('*.yaml')) # try root level first and then recursive
  2550. assert files, f'No *.yaml file found in {dir}'
  2551. if len(files) > 1:
  2552. files = [f for f in files if f.stem == dir.stem] # prefer *.yaml files that match dir name
  2553. assert files, f'Multiple *.yaml files found in {dir}, only 1 *.yaml file allowed'
  2554. assert len(files) == 1, f'Multiple *.yaml files found: {files}, only 1 *.yaml file allowed in {dir}'
  2555. return files[0]
  2556. def _unzip(self, path):
  2557. # Unzip data.zip
  2558. if not str(path).endswith('.zip'): # path is data.yaml
  2559. return False, None, path
  2560. assert Path(path).is_file(), f'Error unzipping {path}, file not found'
  2561. unzip_file(path, path=path.parent)
  2562. dir = path.with_suffix('') # dataset directory == zip name
  2563. assert dir.is_dir(), f'Error unzipping {path}, {dir} not found. path/to/abc.zip MUST unzip to path/to/abc/'
  2564. return True, str(dir), self._find_yaml(dir) # zipped, data_dir, yaml_path
  2565. def _hub_ops(self, f, max_dim=1920):
  2566. # HUB ops for 1 image 'f': resize and save at reduced quality in /dataset-hub for web/app viewing
  2567. f_new = self.im_dir / Path(f).name # dataset-hub image filename
  2568. try: # use PIL
  2569. im = Image.open(f)
  2570. r = max_dim / max(im.height, im.width) # ratio
  2571. if r < 1.0: # image too large
  2572. im = im.resize((int(im.width * r), int(im.height * r)))
  2573. im.save(f_new, 'JPEG', quality=50, optimize=True) # save
  2574. except Exception as e: # use OpenCV
  2575. LOGGER.info(f'WARNING ⚠️ HUB ops PIL failure {f}: {e}')
  2576. im = cv2.imread(f)
  2577. im_height, im_width = im.shape[:2]
  2578. r = max_dim / max(im_height, im_width) # ratio
  2579. if r < 1.0: # image too large
  2580. im = cv2.resize(im, (int(im_width * r), int(im_height * r)), interpolation=cv2.INTER_AREA)
  2581. cv2.imwrite(str(f_new), im)
  2582. def get_json(self, save=False, verbose=False):
  2583. # Return dataset JSON for Ultralytics HUB
  2584. def _round(labels):
  2585. # Update labels to integer class and 6 decimal place floats
  2586. return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels]
  2587. for split in 'train', 'val', 'test':
  2588. if self.data.get(split) is None:
  2589. self.stats[split] = None # i.e. no test set
  2590. continue
  2591. dataset = LoadImagesAndLabels(self.data[split]) # load dataset
  2592. x = np.array([
  2593. np.bincount(label[:, 0].astype(int), minlength=self.data['nc'])
  2594. for label in tqdm(dataset.labels, total=dataset.n, desc='Statistics')]) # shape(128x80)
  2595. self.stats[split] = {
  2596. 'instance_stats': {
  2597. 'total': int(x.sum()),
  2598. 'per_class': x.sum(0).tolist()},
  2599. 'image_stats': {
  2600. 'total': dataset.n,
  2601. 'unlabelled': int(np.all(x == 0, 1).sum()),
  2602. 'per_class': (x > 0).sum(0).tolist()},
  2603. 'labels': [{
  2604. str(Path(k).name): _round(v.tolist())} for k, v in zip(dataset.im_files, dataset.labels)]}
  2605. # Save, print and return
  2606. if save:
  2607. stats_path = self.hub_dir / 'stats.json'
  2608. print(f'Saving {stats_path.resolve()}...')
  2609. with open(stats_path, 'w') as f:
  2610. json.dump(self.stats, f) # save stats.json
  2611. if verbose:
  2612. print(json.dumps(self.stats, indent=2, sort_keys=False))
  2613. return self.stats
  2614. def process_images(self):
  2615. # Compress images for Ultralytics HUB
  2616. for split in 'train', 'val', 'test':
  2617. if self.data.get(split) is None:
  2618. continue
  2619. dataset = LoadImagesAndLabels(self.data[split]) # load dataset
  2620. desc = f'{split} images'
  2621. for _ in tqdm(ThreadPool(NUM_THREADS).imap(self._hub_ops, dataset.im_files), total=dataset.n, desc=desc):
  2622. pass
  2623. print(f'Done. All images saved to {self.im_dir}')
  2624. return self.im_dir
  2625. # Classification dataloaders -------------------------------------------------------------------------------------------
  2626. class ClassificationDataset(torchvision.datasets.ImageFolder):
  2627. """
  2628. YOLOv5 Classification Dataset.
  2629. Arguments
  2630. root: Dataset path
  2631. transform: torchvision transforms, used by default
  2632. album_transform: Albumentations transforms, used if installed
  2633. """
  2634. def __init__(self, root, augment, imgsz, cache=False):
  2635. super().__init__(root=root)
  2636. self.torch_transforms = classify_transforms(imgsz)
  2637. self.album_transforms = classify_albumentations(augment, imgsz) if augment else None
  2638. self.cache_ram = cache is True or cache == 'ram'
  2639. self.cache_disk = cache == 'disk'
  2640. self.samples = [list(x) + [Path(x[0]).with_suffix('.npy'), None] for x in self.samples] # file, index, npy, im
  2641. def __getitem__(self, i):
  2642. f, j, fn, im = self.samples[i] # filename, index, filename.with_suffix('.npy'), image
  2643. if self.cache_ram and im is None:
  2644. im = self.samples[i][3] = cv2.imread(f)
  2645. elif self.cache_disk:
  2646. if not fn.exists(): # load npy
  2647. np.save(fn.as_posix(), cv2.imread(f))
  2648. im = np.load(fn)
  2649. else: # read image
  2650. im = cv2.imread(f) # BGR
  2651. if self.album_transforms:
  2652. sample = self.album_transforms(image=cv2.cvtColor(im, cv2.COLOR_BGR2RGB))['image']
  2653. else:
  2654. sample = self.torch_transforms(im)
  2655. return sample, j
  2656. def create_classification_dataloader(path,
  2657. imgsz=224,
  2658. batch_size=16,
  2659. augment=True,
  2660. cache=False,
  2661. rank=-1,
  2662. workers=8,
  2663. shuffle=True):
  2664. # Returns Dataloader object to be used with YOLOv5 Classifier
  2665. with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP
  2666. dataset = ClassificationDataset(root=path, imgsz=imgsz, augment=augment, cache=cache)
  2667. batch_size = min(batch_size, len(dataset))
  2668. nd = torch.cuda.device_count()
  2669. nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers])
  2670. sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle)
  2671. generator = torch.Generator()
  2672. generator.manual_seed(6148914691236517205 + RANK)
  2673. return InfiniteDataLoader(dataset,
  2674. batch_size=batch_size,
  2675. shuffle=shuffle and sampler is None,
  2676. num_workers=nw,
  2677. sampler=sampler,
  2678. pin_memory=PIN_MEMORY,
  2679. worker_init_fn=seed_worker,
  2680. generator=generator) # or DataLoader(persistent_workers=True)