├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── coco_classes.json ├── configs ├── deep_sort.yaml ├── fastreid.yaml ├── mask_rcnn.yaml ├── mmdet.yaml ├── yolov3.yaml ├── yolov3_tiny.yaml ├── yolov5l.yaml ├── yolov5m.yaml ├── yolov5n.yaml ├── yolov5s.yaml └── yolov5x.yaml ├── deep_sort ├── README.md ├── __init__.py ├── deep │ ├── GETTING_STARTED.md │ ├── __init__.py │ ├── checkpoint │ │ └── .gitkeep │ ├── datasets.py │ ├── evaluate.py │ ├── feature_extractor.py │ ├── model.py │ ├── multi_train_utils │ │ ├── distributed_utils.py │ │ └── train_eval_utils.py │ ├── resnet.py │ ├── test.py │ ├── train.jpg │ ├── train.py │ └── train_multiGPU.py ├── deep_sort.py └── sort │ ├── __init__.py │ ├── detection.py │ ├── iou_matching.py │ ├── kalman_filter.py │ ├── linear_assignment.py │ ├── nn_matching.py │ ├── preprocessing.py │ ├── track.py │ └── tracker.py ├── deepsort.py ├── demo ├── 1.jpg ├── 2.jpg ├── demo.gif └── demo2.gif ├── detector ├── MMDet │ ├── __init__.py │ ├── detector.py │ └── mmdet_utils.py ├── Mask_RCNN │ ├── README.md │ ├── __init__.py │ ├── backbone │ │ ├── __init__.py │ │ ├── feature_pyramid_network.py │ │ └── resnet50_fpn_model.py │ ├── coco_classes.json │ ├── draw_box_utils.py │ ├── maskrcnn.py │ ├── network_files │ │ ├── __init__.py │ │ ├── boxes.py │ │ ├── det_utils.py │ │ ├── faster_rcnn_framework.py │ │ ├── image_list.py │ │ ├── mask_rcnn.py │ │ ├── roi_head.py │ │ ├── rpn_function.py │ │ └── transform.py │ ├── test.jpg │ ├── test_result.jpg │ └── train_utils │ │ ├── __init__.py │ │ ├── coco_eval.py │ │ ├── coco_utils.py │ │ ├── distributed_utils.py │ │ ├── group_by_aspect_ratio.py │ │ └── train_eval_utils.py ├── YOLOv3 │ ├── README.md │ ├── __init__.py │ ├── cfg.py │ ├── cfg │ │ ├── coco.data │ │ ├── coco.names │ │ ├── darknet19_448.cfg │ │ ├── tiny-yolo-voc.cfg │ │ ├── tiny-yolo.cfg │ │ ├── voc.data │ │ ├── voc.names │ │ ├── voc_gaotie.data │ │ ├── yolo-voc.cfg │ │ ├── yolo.cfg │ │ ├── yolo_v3.cfg │ │ └── yolov3-tiny.cfg │ ├── darknet.py │ ├── demo │ │ ├── 004545.jpg │ │ └── results │ │ │ └── 004545.jpg │ ├── detect.py │ ├── detector.py │ ├── nms │ │ ├── __init__.py │ │ ├── build.sh │ │ ├── ext │ │ │ ├── __init__.py │ │ │ ├── build.py │ │ │ ├── cpu │ │ │ │ ├── nms_cpu.cpp │ │ │ │ └── vision.h │ │ │ ├── cuda │ │ │ │ ├── nms.cu │ │ │ │ └── vision.h │ │ │ ├── nms.h │ │ │ └── vision.cpp │ │ ├── nms.py │ │ └── python_nms.py │ ├── region_layer.py │ ├── weight │ │ └── .gitkeep │ ├── yolo_layer.py │ └── yolo_utils.py ├── YOLOv5 │ ├── .dockerignore │ ├── .gitattributes │ ├── .gitignore │ ├── .pre-commit-config.yaml │ ├── CONTRIBUTING.md │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── __init__.py │ ├── data │ │ ├── Argoverse.yaml │ │ ├── GlobalWheat2020.yaml │ │ ├── Objects365.yaml │ │ ├── SKU-110K.yaml │ │ ├── VOC.yaml │ │ ├── VisDrone.yaml │ │ ├── coco.yaml │ │ ├── coco128.yaml │ │ ├── hyps │ │ │ ├── hyp.Objects365.yaml │ │ │ ├── hyp.VOC.yaml │ │ │ ├── hyp.scratch-high.yaml │ │ │ ├── hyp.scratch-low.yaml │ │ │ └── hyp.scratch-med.yaml │ │ ├── images │ │ │ ├── bus.jpg │ │ │ └── zidane.jpg │ │ ├── scripts │ │ │ ├── download_weights.sh │ │ │ ├── get_coco.sh │ │ │ └── get_coco128.sh │ │ └── xView.yaml │ ├── detector.py │ ├── export.py │ ├── hubconf.py │ ├── models │ │ ├── __init__.py │ │ ├── common.py │ │ ├── experimental.py │ │ ├── hub │ │ │ ├── anchors.yaml │ │ │ ├── yolov3-spp.yaml │ │ │ ├── yolov3-tiny.yaml │ │ │ ├── yolov3.yaml │ │ │ ├── yolov5-bifpn.yaml │ │ │ ├── yolov5-fpn.yaml │ │ │ ├── yolov5-p2.yaml │ │ │ ├── yolov5-p34.yaml │ │ │ ├── yolov5-p6.yaml │ │ │ ├── yolov5-p7.yaml │ │ │ ├── yolov5-panet.yaml │ │ │ ├── yolov5l6.yaml │ │ │ ├── yolov5m6.yaml │ │ │ ├── yolov5n6.yaml │ │ │ ├── yolov5s-ghost.yaml │ │ │ ├── yolov5s-transformer.yaml │ │ │ ├── yolov5s6.yaml │ │ │ └── yolov5x6.yaml │ │ ├── tf.py │ │ ├── yolo.py │ │ ├── yolov5l.yaml │ │ ├── yolov5m.yaml │ │ ├── yolov5n.yaml │ │ ├── yolov5s.yaml │ │ └── yolov5x.yaml │ ├── setup.cfg │ └── utils │ │ ├── __init__.py │ │ ├── activations.py │ │ ├── augmentations.py │ │ ├── autoanchor.py │ │ ├── autobatch.py │ │ ├── aws │ │ ├── __init__.py │ │ ├── mime.sh │ │ ├── resume.py │ │ └── userdata.sh │ │ ├── benchmarks.py │ │ ├── callbacks.py │ │ ├── datasets.py │ │ ├── downloads.py │ │ ├── flask_rest_api │ │ ├── README.md │ │ ├── example_request.py │ │ └── restapi.py │ │ ├── general.py │ │ ├── google_app_engine │ │ ├── Dockerfile │ │ └── app.yaml │ │ ├── loggers │ │ ├── __init__.py │ │ └── wandb │ │ │ ├── README.md │ │ │ ├── __init__.py │ │ │ ├── log_dataset.py │ │ │ ├── sweep.py │ │ │ ├── sweep.yaml │ │ │ └── wandb_utils.py │ │ ├── loss.py │ │ ├── metrics.py │ │ ├── plots.py │ │ └── torch_utils.py └── __init__.py ├── ped_det_server.py ├── requirements.txt ├── scripts ├── yolov3_deepsort.sh └── yolov3_tiny_deepsort.sh ├── utils ├── __init__.py ├── asserts.py ├── draw.py ├── evaluation.py ├── io.py ├── json_logger.py ├── log.py ├── parser.py └── tools.py ├── webserver ├── .env ├── __init__.py ├── config │ └── config.py ├── images │ ├── Thumbs.db │ ├── arc.png │ └── request.png ├── readme.md ├── rtsp_threaded_tracker.py ├── rtsp_webserver.py ├── server_cfg.py └── templates │ └── index.html └── yolov3_deepsort_eval.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Folders 2 | __pycache__/ 3 | build/ 4 | *.egg-info 5 | .idea/ 6 | 7 | 8 | # Files 9 | *.weights 10 | *.pth 11 | *.pt 12 | *.t7 13 | *.mp4 14 | *.avi 15 | *.so 16 | *.txt 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/fast-reid"] 2 | path = thirdparty/fast-reid 3 | url = https://github.com/JDAI-CV/fast-reid.git 4 | [submodule "thirdparty/mmdetection"] 5 | path = thirdparty/mmdetection 6 | url = https://github.com/open-mmlab/mmdetection.git 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ziqiang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /coco_classes.json: -------------------------------------------------------------------------------- 1 | { 2 | "0": "person", 3 | "1": "bicycle", 4 | "10": "fire hydrant", 5 | "11": "stop sign", 6 | "12": "parking meter", 7 | "13": "bench", 8 | "14": "bird", 9 | "15": "cat", 10 | "16": "dog", 11 | "17": "horse", 12 | "18": "sheep", 13 | "19": "cow", 14 | "2": "car", 15 | "20": "elephant", 16 | "21": "bear", 17 | "22": "zebra", 18 | "23": "giraffe", 19 | "24": "backpack", 20 | "25": "umbrella", 21 | "26": "handbag", 22 | "27": "tie", 23 | "28": "suitcase", 24 | "29": "frisbee", 25 | "3": "motorcycle", 26 | "30": "skis", 27 | "31": "snowboard", 28 | "32": "sports ball", 29 | "33": "kite", 30 | "34": "baseball bat", 31 | "35": "baseball glove", 32 | "36": "skateboard", 33 | "37": "surfboard", 34 | "38": "tennis racket", 35 | "39": "bottle", 36 | "4": "airplane", 37 | "40": "wine glass", 38 | "41": "cup", 39 | "42": "fork", 40 | "43": "knife", 41 | "44": "spoon", 42 | "45": "bowl", 43 | "46": "banana", 44 | "47": "apple", 45 | "48": "sandwich", 46 | "49": "orange", 47 | "5": "bus", 48 | "50": "broccoli", 49 | "51": "carrot", 50 | "52": "hot dog", 51 | "53": "pizza", 52 | "54": "donut", 53 | "55": "cake", 54 | "56": "chair", 55 | "57": "couch", 56 | "58": "potted plant", 57 | "59": "bed", 58 | "6": "train", 59 | "60": "dining table", 60 | "61": "toilet", 61 | "62": "tv", 62 | "63": "laptop", 63 | "64": "mouse", 64 | "65": "remote", 65 | "66": "keyboard", 66 | "67": "cell phone", 67 | "68": "microwave", 68 | "69": "oven", 69 | "7": "truck", 70 | "70": "toaster", 71 | "71": "sink", 72 | "72": "refrigerator", 73 | "73": "book", 74 | "74": "clock", 75 | "75": "vase", 76 | "76": "scissors", 77 | "77": "teddy bear", 78 | "78": "hair drier", 79 | "79": "toothbrush", 80 | "8": "boat", 81 | "9": "traffic light" 82 | } -------------------------------------------------------------------------------- /configs/deep_sort.yaml: -------------------------------------------------------------------------------- 1 | DEEPSORT: 2 | REID_CKPT: "./deep_sort/deep/checkpoint/ckpt.t7" 3 | MAX_DIST: 0.2 4 | MIN_CONFIDENCE: 0.5 5 | NMS_MAX_OVERLAP: 0.5 6 | MAX_IOU_DISTANCE: 0.7 7 | MAX_AGE: 70 8 | N_INIT: 3 9 | NN_BUDGET: 100 10 | -------------------------------------------------------------------------------- /configs/fastreid.yaml: -------------------------------------------------------------------------------- 1 | FASTREID: 2 | CFG: "thirdparty/fast-reid/configs/Market1501/bagtricks_R50.yml" 3 | CHECKPOINT: "deep_sort/deep/checkpoint/market_bot_R50.pth" -------------------------------------------------------------------------------- /configs/mask_rcnn.yaml: -------------------------------------------------------------------------------- 1 | MASKRCNN: 2 | LABEL: "./coco_classes.json" 3 | WEIGHT: "./detector/Mask_RCNN/save_weights/maskrcnn_resnet50_fpn_coco.pth" 4 | 5 | NUM_CLASSES: 90 6 | BOX_THRESH: 0.5 -------------------------------------------------------------------------------- /configs/mmdet.yaml: -------------------------------------------------------------------------------- 1 | MMDET: 2 | CFG: "thirdparty/mmdetection/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py" 3 | CHECKPOINT: "detector/MMDet/weight/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth" 4 | 5 | SCORE_THRESH: 0.5 -------------------------------------------------------------------------------- /configs/yolov3.yaml: -------------------------------------------------------------------------------- 1 | YOLOV3: 2 | CFG: "./detector/YOLOv3/cfg/yolo_v3.cfg" 3 | WEIGHT: "./detector/YOLOv3/weight/yolov3.weights" 4 | CLASS_NAMES: "./detector/YOLOv3/cfg/coco.names" 5 | 6 | SCORE_THRESH: 0.5 7 | NMS_THRESH: 0.4 8 | -------------------------------------------------------------------------------- /configs/yolov3_tiny.yaml: -------------------------------------------------------------------------------- 1 | YOLOV3: 2 | CFG: "./detector/YOLOv3/cfg/yolov3-tiny.cfg" 3 | WEIGHT: "./detector/YOLOv3/weight/yolov3-tiny.weights" 4 | CLASS_NAMES: "./detector/YOLOv3/cfg/coco.names" 5 | 6 | SCORE_THRESH: 0.5 7 | NMS_THRESH: 0.4 -------------------------------------------------------------------------------- /configs/yolov5l.yaml: -------------------------------------------------------------------------------- 1 | YOLOV5: 2 | CFG: "./detector/YOLOv5/models/yolov5l.yaml" 3 | WEIGHT: "./detector/YOLOv5/yolov5l.pt" 4 | DATA: './detector/YOLOv5/data/coco128.yaml' 5 | 6 | IMGSZ: [640, 640] 7 | SCORE_THRESH: 0.25 8 | NMS_THRESH: 0.45 9 | MAX_DET: 100 10 | -------------------------------------------------------------------------------- /configs/yolov5m.yaml: -------------------------------------------------------------------------------- 1 | YOLOV5: 2 | CFG: "./detector/YOLOv5/models/yolov5m.yaml" 3 | WEIGHT: "./detector/YOLOv5/yolov5m.pt" 4 | DATA: './detector/YOLOv5/data/coco128.yaml' 5 | 6 | IMGSZ: [640, 640] 7 | SCORE_THRESH: 0.25 8 | NMS_THRESH: 0.45 9 | MAX_DET: 100 10 | -------------------------------------------------------------------------------- /configs/yolov5n.yaml: -------------------------------------------------------------------------------- 1 | YOLOV5: 2 | CFG: "./detector/YOLOv5/models/yolov5n.yaml" 3 | WEIGHT: "./detector/YOLOv5/yolov5n.pt" 4 | DATA: './detector/YOLOv5/data/coco128.yaml' 5 | 6 | IMGSZ: [640, 640] 7 | SCORE_THRESH: 0.25 8 | NMS_THRESH: 0.45 9 | MAX_DET: 100 10 | -------------------------------------------------------------------------------- /configs/yolov5s.yaml: -------------------------------------------------------------------------------- 1 | YOLOV5: 2 | CFG: "./detector/YOLOv5/models/yolov5s.yaml" 3 | WEIGHT: "./detector/YOLOv5/yolov5s.pt" 4 | DATA: './detector/YOLOv5/data/coco128.yaml' 5 | 6 | IMGSZ: [640, 640] 7 | SCORE_THRESH: 0.25 8 | NMS_THRESH: 0.45 9 | MAX_DET: 100 10 | -------------------------------------------------------------------------------- /configs/yolov5x.yaml: -------------------------------------------------------------------------------- 1 | YOLOV5: 2 | CFG: "./detector/YOLOv5/models/yolov5x.yaml" 3 | WEIGHT: "./detector/YOLOv5/yolov5x.pt" 4 | DATA: './detector/YOLOv5/data/coco128.yaml' 5 | 6 | IMGSZ: [640, 640] 7 | SCORE_THRESH: 0.25 8 | NMS_THRESH: 0.45 9 | MAX_DET: 100 10 | -------------------------------------------------------------------------------- /deep_sort/README.md: -------------------------------------------------------------------------------- 1 | # Deep Sort 2 | 3 | This is the implemention of deep sort with pytorch. -------------------------------------------------------------------------------- /deep_sort/__init__.py: -------------------------------------------------------------------------------- 1 | from .deep_sort import DeepSort 2 | 3 | __all__ = ['DeepSort', 'build_tracker'] 4 | 5 | 6 | def build_tracker(cfg, use_cuda): 7 | if cfg.USE_FASTREID: 8 | return DeepSort(model_path=cfg.FASTREID.CHECKPOINT, model_config=cfg.FASTREID.CFG, 9 | max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE, 10 | nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE, 11 | max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET, 12 | use_cuda=use_cuda) 13 | 14 | else: 15 | return DeepSort(model_path=cfg.DEEPSORT.REID_CKPT, 16 | max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE, 17 | nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE, 18 | max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET, 19 | use_cuda=use_cuda) 20 | -------------------------------------------------------------------------------- /deep_sort/deep/GETTING_STARTED.md: -------------------------------------------------------------------------------- 1 | In deepsort algorithm, appearance feature extraction network used to extract features from **image_crops** for matching purpose.The original model used in paper is in `model.py`, and its parameter here [ckpt.t7](https://drive.google.com/drive/folders/1xhG0kRH1EX5B9_Iz8gQJb7UNnn_riXi6). This repository also provides a `resnet.py` script and its pre-training weights on Imagenet here. 2 | 3 | ``` 4 | # resnet18 5 | https://download.pytorch.org/models/resnet18-5c106cde.pth 6 | # resnet34 7 | https://download.pytorch.org/models/resnet34-333f7ec4.pth 8 | # resnet50 9 | https://download.pytorch.org/models/resnet50-19c8e357.pth 10 | # resnext50_32x4d 11 | https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth 12 | ``` 13 | 14 | ## Dataset PrePare 15 | 16 | To train the model, first you need download [Market1501](http://www.liangzheng.com.cn/Project/project_reid.html) dataset or [Mars](http://www.liangzheng.com.cn/Project/project_mars.html) dataset. 17 | 18 | If you want to train on your **own dataset**, assuming you have already downloaded the dataset.The dataset should be arranged in the following way. 19 | 20 | ``` 21 | ├── dataset_root: The root dir of the dataset. 22 | ├── class1: Category 1 is located in the folder dir. 23 | ├── xxx1.jpg: Image belonging to category 1. 24 | ├── xxx2.jpg: Image belonging to category 1. 25 | ├── class2: Category 2 is located in the folder dir. 26 | ├── xxx3.jpg: Image belonging to category 2. 27 | ├── xxx4.jpg: Image belonging to category 2. 28 | ├── class3: Category 3 is located in the folder dir. 29 | ... 30 | ... 31 | ``` 32 | 33 | ## Training the RE-ID model 34 | 35 | Assuming you have already prepare the dataset. Then you can use the following command to start your training progress. 36 | 37 | #### training on a single GPU 38 | 39 | ```python 40 | usage: train.py [--data-dir] 41 | [--epochs] 42 | [--batch_size] 43 | [--lr] 44 | [--lrf] 45 | [--weights] 46 | [--freeze-layers] 47 | [--gpu_id] 48 | 49 | # default use cuda:0, use Net in `model.py` 50 | python train.py --data-dir [dataset/root/path] --weights [(optional)pre-train/weight/path] 51 | # you can use `--freeze-layers` option to freeze full convolutional layer parameters except fc layers parameters 52 | python train.py --data-dir [dataset/root/path] --weights [(optional)pre-train/weight/path] --freeze-layers 53 | ``` 54 | 55 | #### training on multiple GPU 56 | 57 | ```python 58 | usage: train_multiGPU.py [--data-dir] 59 | [--epochs] 60 | [--batch_size] 61 | [--lr] 62 | [--lrf] 63 | [--syncBN] 64 | [--weights] 65 | [--freeze-layers] 66 | # not change the following parameters, the system will automatically assignment 67 | [--device] 68 | [--world_size] 69 | [--dist_url] 70 | 71 | # default use cuda:0, cuda:1, cuda:2, cuda:3, use resnet18 in `resnet.py` 72 | CUDA_VISIBLE_DEVICES=0,1,2,3 torchrun --nproc_per_node=4 train_multiGPU.py --data-dir [dataset/root/path] --weights [(optional)pre-train/weight/path] 73 | # you can use `--freeze-layers` option to freeze full convolutional layer parameters except fc layers parameters 74 | CUDA_VISIBLE_DEVICES=0,1,2,3 torchrun --nproc_per_node=4 train_multiGPU.py --data-dir [dataset/root/path] --weights [(optional)pre-train/weight/path] --freeze-layers 75 | ``` 76 | 77 | An example of training progress is as follows: 78 | 79 | ![train.jpg](./train.jpg) 80 | 81 | The last, you can evaluate it using [test.py](deep_sort/deep/test.py) and [evaluate.py](deep_sort/deep/evalute.py). 82 | 83 | -------------------------------------------------------------------------------- /deep_sort/deep/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/deep_sort/deep/__init__.py -------------------------------------------------------------------------------- /deep_sort/deep/checkpoint/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/deep_sort/deep/checkpoint/.gitkeep -------------------------------------------------------------------------------- /deep_sort/deep/datasets.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import random 4 | 5 | import cv2 6 | from PIL import Image 7 | import torch 8 | from torch.utils.data import Dataset 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | class ClsDataset(Dataset): 13 | def __init__(self, images_path, images_labels, transform=None): 14 | self.images_path = images_path 15 | self.images_labels = images_labels 16 | self.transform = transform 17 | 18 | def __len__(self): 19 | return len(self.images_path) 20 | 21 | def __getitem__(self, idx): 22 | img = cv2.imread(self.images_path[idx]) 23 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 24 | img = Image.fromarray(img) 25 | label = self.images_labels[idx] 26 | 27 | if self.transform is not None: 28 | img = self.transform(img) 29 | return img, label 30 | 31 | @staticmethod 32 | def collate_fn(batch): 33 | images, labels = tuple(zip(*batch)) 34 | images = torch.stack(images, dim=0) 35 | labels = torch.as_tensor(labels) 36 | return images, labels 37 | 38 | 39 | def read_split_data(root, valid_rate=0.2): 40 | assert os.path.exists(root), 'dataset root: {} does not exist.'.format(root) 41 | 42 | class_names = [cls for cls in os.listdir(root) if os.path.isdir(os.path.join(root, cls))] 43 | class_names.sort() 44 | 45 | class_indices = {name: i for i, name in enumerate(class_names)} 46 | json_str = json.dumps({v: k for k, v in class_indices.items()}, indent=4) 47 | with open('class_indices.json', 'w') as f: 48 | f.write(json_str) 49 | 50 | train_images_path = [] 51 | train_labels = [] 52 | val_images_path = [] 53 | val_labels = [] 54 | per_class_num = [] 55 | 56 | supported = ['.jpg', '.JPG', '.png', '.PNG'] 57 | for cls in class_names: 58 | cls_path = os.path.join(root, cls) 59 | images_path = [os.path.join(cls_path, i) for i in os.listdir(cls_path) 60 | if os.path.splitext(i)[-1] in supported] 61 | images_label = class_indices[cls] 62 | per_class_num.append(len(images_path)) 63 | 64 | val_path = random.sample(images_path, int(len(images_path) * valid_rate)) 65 | for img_path in images_path: 66 | if img_path in val_path: 67 | val_images_path.append(img_path) 68 | val_labels.append(images_label) 69 | else: 70 | train_images_path.append(img_path) 71 | train_labels.append(images_label) 72 | 73 | print("{} images were found in the dataset.".format(sum(per_class_num))) 74 | print("{} images for training.".format(len(train_images_path))) 75 | print("{} images for validation.".format(len(val_images_path))) 76 | 77 | assert len(train_images_path) > 0, "number of training images must greater than zero" 78 | assert len(val_images_path) > 0, "number of validation images must greater than zero" 79 | 80 | plot_distribution = False 81 | if plot_distribution: 82 | plt.bar(range(len(class_names)), per_class_num, align='center') 83 | plt.xticks(range(len(class_names)), class_names) 84 | 85 | for i, v in enumerate(per_class_num): 86 | plt.text(x=i, y=v + 5, s=str(v), ha='center') 87 | 88 | plt.xlabel('classes') 89 | plt.ylabel('numbers') 90 | plt.title('the distribution of dataset') 91 | plt.show() 92 | return [train_images_path, train_labels], [val_images_path, val_labels], len(class_names) 93 | -------------------------------------------------------------------------------- /deep_sort/deep/evaluate.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | features = torch.load("features.pth") 4 | qf = features["qf"] 5 | ql = features["ql"] 6 | gf = features["gf"] 7 | gl = features["gl"] 8 | 9 | scores = qf.mm(gf.t()) 10 | res = scores.topk(5, dim=1)[1][:,0] 11 | top1correct = gl[res].eq(ql).sum().item() 12 | 13 | print("Acc top1:{:.3f}".format(top1correct/ql.size(0))) 14 | 15 | 16 | -------------------------------------------------------------------------------- /deep_sort/deep/feature_extractor.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torchvision.transforms as transforms 3 | import numpy as np 4 | import cv2 5 | import logging 6 | 7 | from .model import Net 8 | from .resnet import resnet18 9 | # from fastreid.config import get_cfg 10 | # from fastreid.engine import DefaultTrainer 11 | # from fastreid.utils.checkpoint import Checkpointer 12 | 13 | 14 | class Extractor(object): 15 | def __init__(self, model_path, use_cuda=True): 16 | self.net = Net(reid=True) 17 | # self.net = resnet18(reid=True) 18 | self.device = "cuda" if torch.cuda.is_available() and use_cuda else "cpu" 19 | state_dict = torch.load(model_path, map_location=lambda storage, loc: storage) 20 | self.net.load_state_dict(state_dict if 'net_dict' not in state_dict else state_dict['net_dict'], strict=False) 21 | logger = logging.getLogger("root.tracker") 22 | logger.info("Loading weights from {}... Done!".format(model_path)) 23 | self.net.to(self.device) 24 | self.size = (64, 128) 25 | self.norm = transforms.Compose([ 26 | transforms.ToTensor(), 27 | transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 28 | ]) 29 | 30 | def _preprocess(self, im_crops): 31 | """ 32 | TODO: 33 | 1. to float with scale from 0 to 1 34 | 2. resize to (64, 128) as Market1501 dataset did 35 | 3. concatenate to a numpy array 36 | 3. to torch Tensor 37 | 4. normalize 38 | """ 39 | 40 | def _resize(im, size): 41 | return cv2.resize(im.astype(np.float32) / 255., size) 42 | 43 | im_batch = torch.cat([self.norm(_resize(im, self.size)).unsqueeze(0) for im in im_crops], dim=0).float() 44 | return im_batch 45 | 46 | def __call__(self, im_crops): 47 | im_batch = self._preprocess(im_crops) 48 | with torch.no_grad(): 49 | im_batch = im_batch.to(self.device) 50 | features = self.net(im_batch) 51 | return features.cpu().numpy() 52 | 53 | 54 | class FastReIDExtractor(object): 55 | def __init__(self, model_config, model_path, use_cuda=True): 56 | cfg = get_cfg() 57 | cfg.merge_from_file(model_config) 58 | cfg.MODEL.BACKBONE.PRETRAIN = False 59 | self.net = DefaultTrainer.build_model(cfg) 60 | self.device = "cuda" if torch.cuda.is_available() and use_cuda else "cpu" 61 | 62 | Checkpointer(self.net).load(model_path) 63 | logger = logging.getLogger("root.tracker") 64 | logger.info("Loading weights from {}... Done!".format(model_path)) 65 | self.net.to(self.device) 66 | self.net.eval() 67 | height, width = cfg.INPUT.SIZE_TEST 68 | self.size = (width, height) 69 | self.norm = transforms.Compose([ 70 | transforms.ToTensor(), 71 | transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), 72 | ]) 73 | 74 | def _preprocess(self, im_crops): 75 | def _resize(im, size): 76 | return cv2.resize(im.astype(np.float32) / 255., size) 77 | 78 | im_batch = torch.cat([self.norm(_resize(im, self.size)).unsqueeze(0) for im in im_crops], dim=0).float() 79 | return im_batch 80 | 81 | def __call__(self, im_crops): 82 | im_batch = self._preprocess(im_crops) 83 | with torch.no_grad(): 84 | im_batch = im_batch.to(self.device) 85 | features = self.net(im_batch) 86 | return features.cpu().numpy() 87 | 88 | 89 | if __name__ == '__main__': 90 | img = cv2.imread("demo.jpg")[:, :, (2, 1, 0)] 91 | extr = Extractor("checkpoint/ckpt.t7") 92 | feature = extr(img) 93 | print(feature.shape) 94 | -------------------------------------------------------------------------------- /deep_sort/deep/model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | class BasicBlock(nn.Module): 7 | def __init__(self, c_in, c_out, is_downsample=False): 8 | super(BasicBlock, self).__init__() 9 | self.is_downsample = is_downsample 10 | if is_downsample: 11 | self.conv1 = nn.Conv2d(c_in, c_out, 3, stride=2, padding=1, bias=False) 12 | else: 13 | self.conv1 = nn.Conv2d(c_in, c_out, 3, stride=1, padding=1, bias=False) 14 | self.bn1 = nn.BatchNorm2d(c_out) 15 | self.relu = nn.ReLU(True) 16 | self.conv2 = nn.Conv2d(c_out, c_out, 3, stride=1, padding=1, bias=False) 17 | self.bn2 = nn.BatchNorm2d(c_out) 18 | if is_downsample: 19 | self.downsample = nn.Sequential( 20 | nn.Conv2d(c_in, c_out, 1, stride=2, bias=False), 21 | nn.BatchNorm2d(c_out) 22 | ) 23 | elif c_in != c_out: 24 | self.downsample = nn.Sequential( 25 | nn.Conv2d(c_in, c_out, 1, stride=1, bias=False), 26 | nn.BatchNorm2d(c_out) 27 | ) 28 | self.is_downsample = True 29 | 30 | def forward(self, x): 31 | y = self.conv1(x) 32 | y = self.bn1(y) 33 | y = self.relu(y) 34 | y = self.conv2(y) 35 | y = self.bn2(y) 36 | if self.is_downsample: 37 | x = self.downsample(x) 38 | return F.relu(x.add(y), True) 39 | 40 | 41 | def make_layers(c_in, c_out, repeat_times, is_downsample=False): 42 | blocks = [] 43 | for i in range(repeat_times): 44 | if i == 0: 45 | blocks += [BasicBlock(c_in, c_out, is_downsample=is_downsample), ] 46 | else: 47 | blocks += [BasicBlock(c_out, c_out), ] 48 | return nn.Sequential(*blocks) 49 | 50 | 51 | class Net(nn.Module): 52 | def __init__(self, num_classes=751, reid=False): 53 | super(Net, self).__init__() 54 | # 3 128 64 55 | self.conv = nn.Sequential( 56 | nn.Conv2d(3, 64, 3, stride=1, padding=1), 57 | nn.BatchNorm2d(64), 58 | nn.ReLU(inplace=True), 59 | # nn.Conv2d(32,32,3,stride=1,padding=1), 60 | # nn.BatchNorm2d(32), 61 | # nn.ReLU(inplace=True), 62 | nn.MaxPool2d(3, 2, padding=1), 63 | ) 64 | # 32 64 32 65 | self.layer1 = make_layers(64, 64, 2, False) 66 | # 32 64 32 67 | self.layer2 = make_layers(64, 128, 2, True) 68 | # 64 32 16 69 | self.layer3 = make_layers(128, 256, 2, True) 70 | # 128 16 8 71 | self.layer4 = make_layers(256, 512, 2, True) 72 | # 256 8 4 73 | self.avgpool = nn.AdaptiveAvgPool2d(1) 74 | # 256 1 1 75 | self.reid = reid 76 | self.classifier = nn.Sequential( 77 | nn.Linear(512, 256), 78 | nn.BatchNorm1d(256), 79 | nn.ReLU(inplace=True), 80 | nn.Dropout(), 81 | nn.Linear(256, num_classes), 82 | ) 83 | 84 | def forward(self, x): 85 | x = self.conv(x) 86 | x = self.layer1(x) 87 | x = self.layer2(x) 88 | x = self.layer3(x) 89 | x = self.layer4(x) 90 | x = self.avgpool(x) 91 | x = x.view(x.size(0), -1) 92 | # B x 128 93 | if self.reid: 94 | x = x.div(x.norm(p=2, dim=1, keepdim=True)) 95 | return x 96 | # classifier 97 | x = self.classifier(x) 98 | return x 99 | 100 | 101 | if __name__ == '__main__': 102 | net = Net() 103 | x = torch.randn(4, 3, 128, 64) 104 | y = net(x) 105 | 106 | -------------------------------------------------------------------------------- /deep_sort/deep/multi_train_utils/distributed_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import torch 4 | import torch.distributed as dist 5 | 6 | 7 | def init_distributed_mode(args): 8 | if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ: 9 | args.rank = int(os.environ['RANK']) 10 | args.world_size = int(os.environ['WORLD_SIZE']) 11 | args.gpu = int(os.environ['LOCAL_RANK']) 12 | elif 'SLURM_PROCID' in os.environ: 13 | args.rank = int(os.environ['SLURM_PROCID']) 14 | args.gpu = args.rank % torch.cuda.device_count() 15 | else: 16 | print("Not using distributed mode") 17 | args.distributed = False 18 | return 19 | 20 | args.distributed = True 21 | 22 | torch.cuda.set_device(args.gpu) 23 | args.dist_backend = 'nccl' 24 | print('| distributed init (rank {}): {}'.format(args.rank, args.dist_url), flush=True) 25 | dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, 26 | world_size=args.world_size, rank=args.rank) 27 | dist.barrier() 28 | 29 | 30 | def cleanup(): 31 | dist.destroy_process_group() 32 | 33 | 34 | def is_dist_avail_and_initialized(): 35 | if not dist.is_available(): 36 | return False 37 | if not dist.is_initialized(): 38 | return False 39 | return True 40 | 41 | 42 | def get_world_size(): 43 | if not is_dist_avail_and_initialized(): 44 | return 1 45 | return dist.get_world_size() 46 | 47 | 48 | def get_rank(): 49 | if not is_dist_avail_and_initialized(): 50 | return 0 51 | return dist.get_rank() 52 | 53 | 54 | def is_main_process(): 55 | return get_rank() == 0 56 | 57 | 58 | def reduce_value(value, average=True): 59 | world_size = get_world_size() 60 | if world_size < 2: 61 | return value 62 | with torch.no_grad(): 63 | dist.all_reduce(value) 64 | if average: 65 | value /= world_size 66 | 67 | return value 68 | -------------------------------------------------------------------------------- /deep_sort/deep/multi_train_utils/train_eval_utils.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from tqdm import tqdm 4 | import torch 5 | 6 | from .distributed_utils import reduce_value, is_main_process 7 | 8 | 9 | def load_model(state_dict, model_state_dict, model): 10 | for k in state_dict: 11 | if k in model_state_dict: 12 | if state_dict[k].shape != model_state_dict[k].shape: 13 | print('Skip loading parameter {}, required shape {}, ' \ 14 | 'loaded shape {}.'.format( 15 | k, model_state_dict[k].shape, state_dict[k].shape)) 16 | state_dict[k] = model_state_dict[k] 17 | else: 18 | print('Drop parameter {}.'.format(k)) 19 | for k in model_state_dict: 20 | if not (k in state_dict): 21 | print('No param {}.'.format(k)) 22 | state_dict[k] = model_state_dict[k] 23 | model.load_state_dict(state_dict, strict=False) 24 | return model 25 | 26 | 27 | def train_one_epoch(model, optimizer, data_loader, device, epoch): 28 | model.train() 29 | criterion = torch.nn.CrossEntropyLoss() 30 | mean_loss = torch.zeros(1).to(device) 31 | sum_num = torch.zeros(1).to(device) 32 | optimizer.zero_grad() 33 | 34 | if is_main_process(): 35 | data_loader = tqdm(data_loader, file=sys.stdout) 36 | 37 | for idx, (images, labels) in enumerate(data_loader): 38 | # forward 39 | images, labels = images.to(device), labels.to(device) 40 | outputs = model(images) 41 | loss = criterion(outputs, labels) 42 | 43 | # backward 44 | loss.backward() 45 | loss = reduce_value(loss, average=True) 46 | mean_loss = (mean_loss * idx + loss.detach()) / (idx + 1) 47 | pred = torch.max(outputs, dim=1)[1] 48 | sum_num += torch.eq(pred, labels).sum() 49 | 50 | if is_main_process(): 51 | data_loader.desc = '[epoch {}] mean loss {}'.format(epoch, mean_loss.item()) 52 | 53 | if not torch.isfinite(loss): 54 | print('loss is infinite, ending training') 55 | sys.exit(1) 56 | 57 | optimizer.step() 58 | optimizer.zero_grad() 59 | if device != torch.device('cpu'): 60 | torch.cuda.synchronize(device) 61 | sum_num = reduce_value(sum_num, average=False) 62 | 63 | return sum_num.item(), mean_loss.item() 64 | 65 | 66 | @torch.no_grad() 67 | def evaluate(model, data_loader, device): 68 | model.eval() 69 | criterion = torch.nn.CrossEntropyLoss() 70 | test_loss = torch.zeros(1).to(device) 71 | sum_num = torch.zeros(1).to(device) 72 | if is_main_process(): 73 | data_loader = tqdm(data_loader, file=sys.stdout) 74 | 75 | for idx, (inputs, labels) in enumerate(data_loader): 76 | inputs, labels = inputs.to(device), labels.to(device) 77 | outputs = model(inputs) 78 | loss = criterion(outputs, labels) 79 | loss = reduce_value(loss, average=True) 80 | 81 | test_loss = (test_loss * idx + loss.detach()) / (idx + 1) 82 | pred = torch.max(outputs, dim=1)[1] 83 | sum_num += torch.eq(pred, labels).sum() 84 | 85 | if device != torch.device('cpu'): 86 | torch.cuda.synchronize(device) 87 | 88 | sum_num = reduce_value(sum_num, average=False) 89 | 90 | return sum_num.item(), test_loss.item() 91 | -------------------------------------------------------------------------------- /deep_sort/deep/test.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.backends.cudnn as cudnn 3 | import torchvision 4 | 5 | import argparse 6 | import os 7 | 8 | from model import Net 9 | 10 | parser = argparse.ArgumentParser(description="Train on market1501") 11 | parser.add_argument("--data-dir", default='data', type=str) 12 | parser.add_argument("--no-cuda", action="store_true") 13 | parser.add_argument("--gpu-id", default=0, type=int) 14 | args = parser.parse_args() 15 | 16 | # device 17 | device = "cuda:{}".format(args.gpu_id) if torch.cuda.is_available() and not args.no_cuda else "cpu" 18 | if torch.cuda.is_available() and not args.no_cuda: 19 | cudnn.benchmark = True 20 | 21 | # data loader 22 | root = args.data_dir 23 | query_dir = os.path.join(root, "query") 24 | gallery_dir = os.path.join(root, "gallery") 25 | transform = torchvision.transforms.Compose([ 26 | torchvision.transforms.Resize((128, 64)), 27 | torchvision.transforms.ToTensor(), 28 | torchvision.transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 29 | ]) 30 | queryloader = torch.utils.data.DataLoader( 31 | torchvision.datasets.ImageFolder(query_dir, transform=transform), 32 | batch_size=64, shuffle=False 33 | ) 34 | galleryloader = torch.utils.data.DataLoader( 35 | torchvision.datas0ets.ImageFolder(gallery_dir, transform=transform), 36 | batch_size=64, shuffle=False 37 | ) 38 | 39 | # net definition 40 | net = Net(reid=True) 41 | assert os.path.isfile("./checkpoint/ckpt.t7"), "Error: no checkpoint file found!" 42 | print('Loading from checkpoint/ckpt.t7') 43 | checkpoint = torch.load("./checkpoint/ckpt.t7") 44 | net_dict = checkpoint['net_dict'] 45 | net.load_state_dict(net_dict, strict=False) 46 | net.eval() 47 | net.to(device) 48 | 49 | # compute features 50 | query_features = torch.tensor([]).float() 51 | query_labels = torch.tensor([]).long() 52 | gallery_features = torch.tensor([]).float() 53 | gallery_labels = torch.tensor([]).long() 54 | 55 | with torch.no_grad(): 56 | for idx, (inputs, labels) in enumerate(queryloader): 57 | inputs = inputs.to(device) 58 | features = net(inputs).cpu() 59 | query_features = torch.cat((query_features, features), dim=0) 60 | query_labels = torch.cat((query_labels, labels)) 61 | 62 | for idx, (inputs, labels) in enumerate(galleryloader): 63 | inputs = inputs.to(device) 64 | features = net(inputs).cpu() 65 | gallery_features = torch.cat((gallery_features, features), dim=0) 66 | gallery_labels = torch.cat((gallery_labels, labels)) 67 | 68 | gallery_labels -= 2 69 | 70 | # save features 71 | features = { 72 | "qf": query_features, 73 | "ql": query_labels, 74 | "gf": gallery_features, 75 | "gl": gallery_labels 76 | } 77 | torch.save(features, "features.pth") 78 | -------------------------------------------------------------------------------- /deep_sort/deep/train.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/deep_sort/deep/train.jpg -------------------------------------------------------------------------------- /deep_sort/sort/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/deep_sort/sort/__init__.py -------------------------------------------------------------------------------- /deep_sort/sort/detection.py: -------------------------------------------------------------------------------- 1 | # vim: expandtab:ts=4:sw=4 2 | import numpy as np 3 | 4 | 5 | class Detection(object): 6 | """ 7 | This class represents a bounding box detection in a single image. 8 | 9 | Parameters 10 | ---------- 11 | tlwh : array_like 12 | Bounding box in format `(x, y, w, h)`. 13 | confidence : float 14 | Detector confidence score. 15 | feature : array_like 16 | A feature vector that describes the object contained in this image. 17 | 18 | Attributes 19 | ---------- 20 | tlwh : ndarray 21 | Bounding box in format `(top left x, top left y, width, height)`. 22 | confidence : ndarray 23 | Detector confidence score. 24 | feature : ndarray | NoneType 25 | A feature vector that describes the object contained in this image. 26 | 27 | """ 28 | 29 | def __init__(self, tlwh, confidence, label, feature, mask=None): 30 | self.tlwh = np.asarray(tlwh, dtype=np.float32) 31 | self.confidence = float(confidence) 32 | self.cls = int(label) 33 | self.feature = np.asarray(feature, dtype=np.float32) 34 | self.mask = mask 35 | 36 | def to_tlbr(self): 37 | """Convert bounding box to format `(min x, min y, max x, max y)`, i.e., 38 | `(top left, bottom right)`. 39 | """ 40 | ret = self.tlwh.copy() 41 | ret[2:] += ret[:2] 42 | return ret 43 | 44 | def to_xyah(self): 45 | """Convert bounding box to format `(center x, center y, aspect ratio, 46 | height)`, where the aspect ratio is `width / height`. 47 | """ 48 | ret = self.tlwh.copy() 49 | ret[:2] += ret[2:] / 2 50 | ret[2] /= ret[3] 51 | return ret 52 | -------------------------------------------------------------------------------- /deep_sort/sort/iou_matching.py: -------------------------------------------------------------------------------- 1 | # vim: expandtab:ts=4:sw=4 2 | from __future__ import absolute_import 3 | import numpy as np 4 | from . import linear_assignment 5 | 6 | 7 | def iou(bbox, candidates): 8 | """Computer intersection over union. 9 | 10 | Parameters 11 | ---------- 12 | bbox : ndarray 13 | A bounding box in format `(top left x, top left y, width, height)`. 14 | candidates : ndarray 15 | A matrix of candidate bounding boxes (one per row) in the same format 16 | as `bbox`. 17 | 18 | Returns 19 | ------- 20 | ndarray 21 | The intersection over union in [0, 1] between the `bbox` and each 22 | candidate. A higher score means a larger fraction of the `bbox` is 23 | occluded by the candidate. 24 | 25 | """ 26 | bbox_tl, bbox_br = bbox[:2], bbox[:2] + bbox[2:] 27 | candidates_tl = candidates[:, :2] 28 | candidates_br = candidates[:, :2] + candidates[:, 2:] 29 | 30 | tl = np.c_[np.maximum(bbox_tl[0], candidates_tl[:, 0])[:, np.newaxis], 31 | np.maximum(bbox_tl[1], candidates_tl[:, 1])[:, np.newaxis]] 32 | br = np.c_[np.minimum(bbox_br[0], candidates_br[:, 0])[:, np.newaxis], 33 | np.minimum(bbox_br[1], candidates_br[:, 1])[:, np.newaxis]] 34 | wh = np.maximum(0., br - tl) 35 | 36 | area_intersection = wh.prod(axis=1) 37 | area_bbox = bbox[2:].prod() 38 | area_candidates = candidates[:, 2:].prod(axis=1) 39 | return area_intersection / (area_bbox + area_candidates - area_intersection) 40 | 41 | 42 | def iou_cost(tracks, detections, track_indices=None, 43 | detection_indices=None): 44 | """An intersection over union distance metric. 45 | 46 | Parameters 47 | ---------- 48 | tracks : List[deep_sort.track.Track] 49 | A list of tracks. 50 | detections : List[deep_sort.detection.Detection] 51 | A list of detections. 52 | track_indices : Optional[List[int]] 53 | A list of indices to tracks that should be matched. Defaults to 54 | all `tracks`. 55 | detection_indices : Optional[List[int]] 56 | A list of indices to detections that should be matched. Defaults 57 | to all `detections`. 58 | 59 | Returns 60 | ------- 61 | ndarray 62 | Returns a cost matrix of shape 63 | len(track_indices), len(detection_indices) where entry (i, j) is 64 | `1 - iou(tracks[track_indices[i]], detections[detection_indices[j]])`. 65 | 66 | """ 67 | if track_indices is None: 68 | track_indices = np.arange(len(tracks)) 69 | if detection_indices is None: 70 | detection_indices = np.arange(len(detections)) 71 | 72 | cost_matrix = np.zeros((len(track_indices), len(detection_indices))) 73 | for row, track_idx in enumerate(track_indices): 74 | if tracks[track_idx].time_since_update > 1: 75 | cost_matrix[row, :] = linear_assignment.INFTY_COST 76 | continue 77 | 78 | bbox = tracks[track_idx].to_tlwh() 79 | candidates = np.asarray([detections[i].tlwh for i in detection_indices]) 80 | cost_matrix[row, :] = 1. - iou(bbox, candidates) 81 | return cost_matrix 82 | -------------------------------------------------------------------------------- /deep_sort/sort/preprocessing.py: -------------------------------------------------------------------------------- 1 | # vim: expandtab:ts=4:sw=4 2 | import numpy as np 3 | import cv2 4 | 5 | 6 | def non_max_suppression(boxes, max_bbox_overlap, scores=None): 7 | """Suppress overlapping detections. 8 | 9 | Original code from [1]_ has been adapted to include confidence score. 10 | 11 | .. [1] http://www.pyimagesearch.com/2015/02/16/ 12 | faster-non-maximum-suppression-python/ 13 | 14 | Examples 15 | -------- 16 | 17 | >>> boxes = [d.roi for d in detections] 18 | >>> scores = [d.confidence for d in detections] 19 | >>> indices = non_max_suppression(boxes, max_bbox_overlap, scores) 20 | >>> detections = [detections[i] for i in indices] 21 | 22 | Parameters 23 | ---------- 24 | boxes : ndarray 25 | Array of ROIs (x, y, width, height). 26 | max_bbox_overlap : float 27 | ROIs that overlap more than this values are suppressed. 28 | scores : Optional[array_like] 29 | Detector confidence score. 30 | 31 | Returns 32 | ------- 33 | List[int] 34 | Returns indices of detections that have survived non-maxima suppression. 35 | 36 | """ 37 | if len(boxes) == 0: 38 | return [] 39 | 40 | boxes = boxes.astype(np.float32) 41 | pick = [] 42 | 43 | x1 = boxes[:, 0] 44 | y1 = boxes[:, 1] 45 | x2 = boxes[:, 2] + boxes[:, 0] 46 | y2 = boxes[:, 3] + boxes[:, 1] 47 | 48 | area = (x2 - x1 + 1) * (y2 - y1 + 1) 49 | if scores is not None: 50 | idxs = np.argsort(scores) 51 | else: 52 | idxs = np.argsort(y2) 53 | 54 | while len(idxs) > 0: 55 | last = len(idxs) - 1 56 | i = idxs[last] 57 | pick.append(i) 58 | 59 | xx1 = np.maximum(x1[i], x1[idxs[:last]]) 60 | yy1 = np.maximum(y1[i], y1[idxs[:last]]) 61 | xx2 = np.minimum(x2[i], x2[idxs[:last]]) 62 | yy2 = np.minimum(y2[i], y2[idxs[:last]]) 63 | 64 | w = np.maximum(0, xx2 - xx1 + 1) 65 | h = np.maximum(0, yy2 - yy1 + 1) 66 | 67 | overlap = (w * h) / (area[idxs[:last]] + area[idxs[last]] - w * h) 68 | 69 | idxs = np.delete( 70 | idxs, np.concatenate( 71 | ([last], np.where(overlap > max_bbox_overlap)[0]))) 72 | 73 | return pick 74 | -------------------------------------------------------------------------------- /demo/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/demo/1.jpg -------------------------------------------------------------------------------- /demo/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/demo/2.jpg -------------------------------------------------------------------------------- /demo/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/demo/demo.gif -------------------------------------------------------------------------------- /demo/demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/demo/demo2.gif -------------------------------------------------------------------------------- /detector/MMDet/__init__.py: -------------------------------------------------------------------------------- 1 | from .detector import MMDet 2 | __all__ = ['MMDet'] -------------------------------------------------------------------------------- /detector/MMDet/detector.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import numpy as np 3 | import torch 4 | 5 | from mmdet.apis import init_detector, inference_detector 6 | from .mmdet_utils import xyxy_to_xywh 7 | 8 | 9 | class MMDet(object): 10 | def __init__(self, cfg_file, checkpoint_file, score_thresh=0.7, 11 | is_xywh=False, use_cuda=True): 12 | # net definition 13 | self.device = "cuda" if use_cuda else "cpu" 14 | self.net = init_detector(cfg_file, checkpoint_file, device=self.device) 15 | logger = logging.getLogger("root.detector") 16 | logger.info('Loading weights from %s... Done!' % (checkpoint_file)) 17 | 18 | #constants 19 | self.score_thresh = score_thresh 20 | self.use_cuda = use_cuda 21 | self.is_xywh = is_xywh 22 | self.class_names = self.net.CLASSES 23 | self.num_classes = len(self.class_names) 24 | 25 | def __call__(self, ori_img): 26 | # forward 27 | bbox_result = inference_detector(self.net, ori_img) 28 | bboxes = np.vstack(bbox_result) 29 | 30 | if len(bboxes) == 0: 31 | bbox = np.array([]).reshape([0, 4]) 32 | cls_conf = np.array([]) 33 | cls_ids = np.array([]) 34 | return bbox, cls_conf, cls_ids 35 | 36 | bbox = bboxes[:, :4] 37 | cls_conf = bboxes[:, 4] 38 | cls_ids = [ 39 | np.full(bbox.shape[0], i, dtype=np.int32) 40 | for i, bbox in enumerate(bbox_result) 41 | ] 42 | cls_ids = np.concatenate(cls_ids) 43 | 44 | selected_idx = cls_conf > self.score_thresh 45 | bbox = bbox[selected_idx, :] 46 | cls_conf = cls_conf[selected_idx] 47 | cls_ids = cls_ids[selected_idx] 48 | 49 | if self.is_xywh: 50 | bbox = xyxy_to_xywh(bbox) 51 | 52 | return bbox, cls_conf, cls_ids 53 | -------------------------------------------------------------------------------- /detector/MMDet/mmdet_utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | 4 | def xyxy_to_xywh(boxes_xyxy): 5 | if isinstance(boxes_xyxy, torch.Tensor): 6 | boxes_xywh = boxes_xyxy.clone() 7 | elif isinstance(boxes_xyxy, np.ndarray): 8 | boxes_xywh = boxes_xyxy.copy() 9 | 10 | boxes_xywh[:, 0] = (boxes_xyxy[:, 0] + boxes_xyxy[:, 2]) / 2. 11 | boxes_xywh[:, 1] = (boxes_xyxy[:, 1] + boxes_xyxy[:, 3]) / 2. 12 | boxes_xywh[:, 2] = boxes_xyxy[:, 2] - boxes_xyxy[:, 0] 13 | boxes_xywh[:, 3] = boxes_xyxy[:, 3] - boxes_xyxy[:, 1] 14 | 15 | return boxes_xywh -------------------------------------------------------------------------------- /detector/Mask_RCNN/__init__.py: -------------------------------------------------------------------------------- 1 | from .maskrcnn import Mask_RCNN 2 | -------------------------------------------------------------------------------- /detector/Mask_RCNN/backbone/__init__.py: -------------------------------------------------------------------------------- 1 | from .resnet50_fpn_model import resnet50_fpn_backbone 2 | -------------------------------------------------------------------------------- /detector/Mask_RCNN/coco_classes.json: -------------------------------------------------------------------------------- 1 | { 2 | "0": "person", 3 | "1": "bicycle", 4 | "10": "fire hydrant", 5 | "11": "stop sign", 6 | "12": "parking meter", 7 | "13": "bench", 8 | "14": "bird", 9 | "15": "cat", 10 | "16": "dog", 11 | "17": "horse", 12 | "18": "sheep", 13 | "19": "cow", 14 | "2": "car", 15 | "20": "elephant", 16 | "21": "bear", 17 | "22": "zebra", 18 | "23": "giraffe", 19 | "24": "backpack", 20 | "25": "umbrella", 21 | "26": "handbag", 22 | "27": "tie", 23 | "28": "suitcase", 24 | "29": "frisbee", 25 | "3": "motorcycle", 26 | "30": "skis", 27 | "31": "snowboard", 28 | "32": "sports ball", 29 | "33": "kite", 30 | "34": "baseball bat", 31 | "35": "baseball glove", 32 | "36": "skateboard", 33 | "37": "surfboard", 34 | "38": "tennis racket", 35 | "39": "bottle", 36 | "4": "airplane", 37 | "40": "wine glass", 38 | "41": "cup", 39 | "42": "fork", 40 | "43": "knife", 41 | "44": "spoon", 42 | "45": "bowl", 43 | "46": "banana", 44 | "47": "apple", 45 | "48": "sandwich", 46 | "49": "orange", 47 | "5": "bus", 48 | "50": "broccoli", 49 | "51": "carrot", 50 | "52": "hot dog", 51 | "53": "pizza", 52 | "54": "donut", 53 | "55": "cake", 54 | "56": "chair", 55 | "57": "couch", 56 | "58": "potted plant", 57 | "59": "bed", 58 | "6": "train", 59 | "60": "dining table", 60 | "61": "toilet", 61 | "62": "tv", 62 | "63": "laptop", 63 | "64": "mouse", 64 | "65": "remote", 65 | "66": "keyboard", 66 | "67": "cell phone", 67 | "68": "microwave", 68 | "69": "oven", 69 | "7": "truck", 70 | "70": "toaster", 71 | "71": "sink", 72 | "72": "refrigerator", 73 | "73": "book", 74 | "74": "clock", 75 | "75": "vase", 76 | "76": "scissors", 77 | "77": "teddy bear", 78 | "78": "hair drier", 79 | "79": "toothbrush", 80 | "8": "boat", 81 | "9": "traffic light" 82 | } -------------------------------------------------------------------------------- /detector/Mask_RCNN/network_files/__init__.py: -------------------------------------------------------------------------------- 1 | from .faster_rcnn_framework import FasterRCNN, FastRCNNPredictor 2 | from .rpn_function import AnchorsGenerator 3 | from .mask_rcnn import MaskRCNN 4 | -------------------------------------------------------------------------------- /detector/Mask_RCNN/network_files/image_list.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | from torch import Tensor 3 | 4 | 5 | class ImageList(object): 6 | """ 7 | Structure that holds a list of images (of possibly 8 | varying sizes) as a single tensor. 9 | This works by padding the images to the same size, 10 | and storing in a field the original sizes of each image 11 | """ 12 | 13 | def __init__(self, tensors, image_sizes): 14 | # type: (Tensor, List[Tuple[int, int]]) -> None 15 | """ 16 | Arguments: 17 | tensors (tensor) padding后的图像数据 18 | image_sizes (list[tuple[int, int]]) padding前的图像尺寸 19 | """ 20 | self.tensors = tensors 21 | self.image_sizes = image_sizes 22 | 23 | def to(self, device): 24 | # type: (Device) -> ImageList # noqa 25 | cast_tensor = self.tensors.to(device) 26 | return ImageList(cast_tensor, self.image_sizes) 27 | 28 | -------------------------------------------------------------------------------- /detector/Mask_RCNN/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/Mask_RCNN/test.jpg -------------------------------------------------------------------------------- /detector/Mask_RCNN/test_result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/Mask_RCNN/test_result.jpg -------------------------------------------------------------------------------- /detector/Mask_RCNN/train_utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .group_by_aspect_ratio import GroupedBatchSampler, create_aspect_ratio_groups 2 | from .distributed_utils import init_distributed_mode, save_on_master, mkdir 3 | from .coco_eval import EvalCOCOMetric 4 | from .coco_utils import coco_remove_images_without_annotations, convert_coco_poly_mask, convert_to_coco_api 5 | -------------------------------------------------------------------------------- /detector/Mask_RCNN/train_utils/coco_utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.utils.data 3 | from pycocotools import mask as coco_mask 4 | from pycocotools.coco import COCO 5 | 6 | 7 | def coco_remove_images_without_annotations(dataset, ids): 8 | """ 9 | 删除coco数据集中没有目标,或者目标面积非常小的数据 10 | refer to: 11 | https://github.com/pytorch/vision/blob/master/references/detection/coco_utils.py 12 | :param dataset: 13 | :param cat_list: 14 | :return: 15 | """ 16 | def _has_only_empty_bbox(anno): 17 | return all(any(o <= 1 for o in obj["bbox"][2:]) for obj in anno) 18 | 19 | def _has_valid_annotation(anno): 20 | # if it's empty, there is no annotation 21 | if len(anno) == 0: 22 | return False 23 | # if all boxes have close to zero area, there is no annotation 24 | if _has_only_empty_bbox(anno): 25 | return False 26 | 27 | return True 28 | 29 | valid_ids = [] 30 | for ds_idx, img_id in enumerate(ids): 31 | ann_ids = dataset.getAnnIds(imgIds=img_id, iscrowd=None) 32 | anno = dataset.loadAnns(ann_ids) 33 | 34 | if _has_valid_annotation(anno): 35 | valid_ids.append(img_id) 36 | 37 | return valid_ids 38 | 39 | 40 | def convert_coco_poly_mask(segmentations, height, width): 41 | masks = [] 42 | for polygons in segmentations: 43 | rles = coco_mask.frPyObjects(polygons, height, width) 44 | mask = coco_mask.decode(rles) 45 | if len(mask.shape) < 3: 46 | mask = mask[..., None] 47 | mask = torch.as_tensor(mask, dtype=torch.uint8) 48 | mask = mask.any(dim=2) 49 | masks.append(mask) 50 | if masks: 51 | masks = torch.stack(masks, dim=0) 52 | else: 53 | # 如果mask为空,则说明没有目标,直接返回数值为0的mask 54 | masks = torch.zeros((0, height, width), dtype=torch.uint8) 55 | return masks 56 | 57 | 58 | def convert_to_coco_api(self): 59 | coco_ds = COCO() 60 | # annotation IDs need to start at 1, not 0, see torchvision issue #1530 61 | ann_id = 1 62 | dataset = {"images": [], "categories": [], "annotations": []} 63 | categories = set() 64 | for img_idx in range(len(self)): 65 | targets, h, w = self.get_annotations(img_idx) 66 | img_id = targets["image_id"].item() 67 | img_dict = {"id": img_id, 68 | "height": h, 69 | "width": w} 70 | dataset["images"].append(img_dict) 71 | bboxes = targets["boxes"].clone() 72 | # convert (x_min, ymin, xmax, ymax) to (xmin, ymin, w, h) 73 | bboxes[:, 2:] -= bboxes[:, :2] 74 | bboxes = bboxes.tolist() 75 | labels = targets["labels"].tolist() 76 | areas = targets["area"].tolist() 77 | iscrowd = targets["iscrowd"].tolist() 78 | if "masks" in targets: 79 | masks = targets["masks"] 80 | # make masks Fortran contiguous for coco_mask 81 | masks = masks.permute(0, 2, 1).contiguous().permute(0, 2, 1) 82 | num_objs = len(bboxes) 83 | for i in range(num_objs): 84 | ann = {"image_id": img_id, 85 | "bbox": bboxes[i], 86 | "category_id": labels[i], 87 | "area": areas[i], 88 | "iscrowd": iscrowd[i], 89 | "id": ann_id} 90 | categories.add(labels[i]) 91 | if "masks" in targets: 92 | ann["segmentation"] = coco_mask.encode(masks[i].numpy()) 93 | dataset["annotations"].append(ann) 94 | ann_id += 1 95 | dataset["categories"] = [{"id": i} for i in sorted(categories)] 96 | coco_ds.dataset = dataset 97 | coco_ds.createIndex() 98 | return coco_ds 99 | -------------------------------------------------------------------------------- /detector/YOLOv3/README.md: -------------------------------------------------------------------------------- 1 | # YOLOv3 for detection 2 | 3 | This is an implemention of YOLOv3 with only the forward part. 4 | 5 | If you want to train YOLOv3 on your custom dataset, please search `YOLOv3` on github. 6 | 7 | ## Quick forward 8 | ```bash 9 | cd YOLOv3 10 | python 11 | ``` -------------------------------------------------------------------------------- /detector/YOLOv3/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.append("detector/YOLOv3") 4 | 5 | from .detector import YOLOv3 6 | 7 | __all__ = ['YOLOv3'] 8 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/coco.data: -------------------------------------------------------------------------------- 1 | train = coco_train.txt 2 | valid = coco_test.txt 3 | names = data/coco.names 4 | backup = backup 5 | gpus = 0,1,2,3 6 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/coco.names: -------------------------------------------------------------------------------- 1 | person 2 | bicycle 3 | car 4 | motorbike 5 | aeroplane 6 | bus 7 | train 8 | truck 9 | boat 10 | traffic light 11 | fire hydrant 12 | stop sign 13 | parking meter 14 | bench 15 | bird 16 | cat 17 | dog 18 | horse 19 | sheep 20 | cow 21 | elephant 22 | bear 23 | zebra 24 | giraffe 25 | backpack 26 | umbrella 27 | handbag 28 | tie 29 | suitcase 30 | frisbee 31 | skis 32 | snowboard 33 | sports ball 34 | kite 35 | baseball bat 36 | baseball glove 37 | skateboard 38 | surfboard 39 | tennis racket 40 | bottle 41 | wine glass 42 | cup 43 | fork 44 | knife 45 | spoon 46 | bowl 47 | banana 48 | apple 49 | sandwich 50 | orange 51 | broccoli 52 | carrot 53 | hot dog 54 | pizza 55 | donut 56 | cake 57 | chair 58 | sofa 59 | pottedplant 60 | bed 61 | diningtable 62 | toilet 63 | tvmonitor 64 | laptop 65 | mouse 66 | remote 67 | keyboard 68 | cell phone 69 | microwave 70 | oven 71 | toaster 72 | sink 73 | refrigerator 74 | book 75 | clock 76 | vase 77 | scissors 78 | teddy bear 79 | hair drier 80 | toothbrush 81 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/darknet19_448.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | batch=128 3 | subdivisions=4 4 | height=448 5 | width=448 6 | max_crop=512 7 | channels=3 8 | momentum=0.9 9 | decay=0.0005 10 | 11 | learning_rate=0.001 12 | policy=poly 13 | power=4 14 | max_batches=100000 15 | 16 | angle=7 17 | hue = .1 18 | saturation=.75 19 | exposure=.75 20 | aspect=.75 21 | 22 | [convolutional] 23 | batch_normalize=1 24 | filters=32 25 | size=3 26 | stride=1 27 | pad=1 28 | activation=leaky 29 | 30 | [maxpool] 31 | size=2 32 | stride=2 33 | 34 | [convolutional] 35 | batch_normalize=1 36 | filters=64 37 | size=3 38 | stride=1 39 | pad=1 40 | activation=leaky 41 | 42 | [maxpool] 43 | size=2 44 | stride=2 45 | 46 | [convolutional] 47 | batch_normalize=1 48 | filters=128 49 | size=3 50 | stride=1 51 | pad=1 52 | activation=leaky 53 | 54 | [convolutional] 55 | batch_normalize=1 56 | filters=64 57 | size=1 58 | stride=1 59 | pad=1 60 | activation=leaky 61 | 62 | [convolutional] 63 | batch_normalize=1 64 | filters=128 65 | size=3 66 | stride=1 67 | pad=1 68 | activation=leaky 69 | 70 | [maxpool] 71 | size=2 72 | stride=2 73 | 74 | [convolutional] 75 | batch_normalize=1 76 | filters=256 77 | size=3 78 | stride=1 79 | pad=1 80 | activation=leaky 81 | 82 | [convolutional] 83 | batch_normalize=1 84 | filters=128 85 | size=1 86 | stride=1 87 | pad=1 88 | activation=leaky 89 | 90 | [convolutional] 91 | batch_normalize=1 92 | filters=256 93 | size=3 94 | stride=1 95 | pad=1 96 | activation=leaky 97 | 98 | [maxpool] 99 | size=2 100 | stride=2 101 | 102 | [convolutional] 103 | batch_normalize=1 104 | filters=512 105 | size=3 106 | stride=1 107 | pad=1 108 | activation=leaky 109 | 110 | [convolutional] 111 | batch_normalize=1 112 | filters=256 113 | size=1 114 | stride=1 115 | pad=1 116 | activation=leaky 117 | 118 | [convolutional] 119 | batch_normalize=1 120 | filters=512 121 | size=3 122 | stride=1 123 | pad=1 124 | activation=leaky 125 | 126 | [convolutional] 127 | batch_normalize=1 128 | filters=256 129 | size=1 130 | stride=1 131 | pad=1 132 | activation=leaky 133 | 134 | [convolutional] 135 | batch_normalize=1 136 | filters=512 137 | size=3 138 | stride=1 139 | pad=1 140 | activation=leaky 141 | 142 | [maxpool] 143 | size=2 144 | stride=2 145 | 146 | [convolutional] 147 | batch_normalize=1 148 | filters=1024 149 | size=3 150 | stride=1 151 | pad=1 152 | activation=leaky 153 | 154 | [convolutional] 155 | batch_normalize=1 156 | filters=512 157 | size=1 158 | stride=1 159 | pad=1 160 | activation=leaky 161 | 162 | [convolutional] 163 | batch_normalize=1 164 | filters=1024 165 | size=3 166 | stride=1 167 | pad=1 168 | activation=leaky 169 | 170 | [convolutional] 171 | batch_normalize=1 172 | filters=512 173 | size=1 174 | stride=1 175 | pad=1 176 | activation=leaky 177 | 178 | [convolutional] 179 | batch_normalize=1 180 | filters=1024 181 | size=3 182 | stride=1 183 | pad=1 184 | activation=leaky 185 | 186 | [convolutional] 187 | filters=1000 188 | size=1 189 | stride=1 190 | pad=1 191 | activation=linear 192 | 193 | [avgpool] 194 | 195 | [softmax] 196 | groups=1 197 | 198 | [cost] 199 | type=sse 200 | 201 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/tiny-yolo-voc.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | batch=64 3 | subdivisions=8 4 | width=416 5 | height=416 6 | channels=3 7 | momentum=0.9 8 | decay=0.0005 9 | angle=0 10 | saturation = 1.5 11 | exposure = 1.5 12 | hue=.1 13 | 14 | learning_rate=0.001 15 | max_batches = 40200 16 | policy=steps 17 | steps=-1,100,20000,30000 18 | scales=.1,10,.1,.1 19 | 20 | [convolutional] 21 | batch_normalize=1 22 | filters=16 23 | size=3 24 | stride=1 25 | pad=1 26 | activation=leaky 27 | 28 | [maxpool] 29 | size=2 30 | stride=2 31 | 32 | [convolutional] 33 | batch_normalize=1 34 | filters=32 35 | size=3 36 | stride=1 37 | pad=1 38 | activation=leaky 39 | 40 | [maxpool] 41 | size=2 42 | stride=2 43 | 44 | [convolutional] 45 | batch_normalize=1 46 | filters=64 47 | size=3 48 | stride=1 49 | pad=1 50 | activation=leaky 51 | 52 | [maxpool] 53 | size=2 54 | stride=2 55 | 56 | [convolutional] 57 | batch_normalize=1 58 | filters=128 59 | size=3 60 | stride=1 61 | pad=1 62 | activation=leaky 63 | 64 | [maxpool] 65 | size=2 66 | stride=2 67 | 68 | [convolutional] 69 | batch_normalize=1 70 | filters=256 71 | size=3 72 | stride=1 73 | pad=1 74 | activation=leaky 75 | 76 | [maxpool] 77 | size=2 78 | stride=2 79 | 80 | [convolutional] 81 | batch_normalize=1 82 | filters=512 83 | size=3 84 | stride=1 85 | pad=1 86 | activation=leaky 87 | 88 | [maxpool] 89 | size=2 90 | stride=1 91 | 92 | [convolutional] 93 | batch_normalize=1 94 | filters=1024 95 | size=3 96 | stride=1 97 | pad=1 98 | activation=leaky 99 | 100 | ########### 101 | 102 | [convolutional] 103 | batch_normalize=1 104 | size=3 105 | stride=1 106 | pad=1 107 | filters=1024 108 | activation=leaky 109 | 110 | [convolutional] 111 | size=1 112 | stride=1 113 | pad=1 114 | filters=125 115 | activation=linear 116 | 117 | [region] 118 | anchors = 1.08,1.19, 3.42,4.41, 6.63,11.38, 9.42,5.11, 16.62,10.52 119 | bias_match=1 120 | classes=20 121 | coords=4 122 | num=5 123 | softmax=1 124 | jitter=.2 125 | rescore=1 126 | 127 | object_scale=5 128 | noobject_scale=1 129 | class_scale=1 130 | coord_scale=1 131 | 132 | absolute=1 133 | thresh = .6 134 | random=1 135 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/tiny-yolo.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Training 3 | # batch=64 4 | # subdivisions=2 5 | # Testing 6 | batch=1 7 | subdivisions=1 8 | width=416 9 | height=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 500200 21 | policy=steps 22 | steps=400000,450000 23 | scales=.1,.1 24 | 25 | [convolutional] 26 | batch_normalize=1 27 | filters=16 28 | size=3 29 | stride=1 30 | pad=1 31 | activation=leaky 32 | 33 | [maxpool] 34 | size=2 35 | stride=2 36 | 37 | [convolutional] 38 | batch_normalize=1 39 | filters=32 40 | size=3 41 | stride=1 42 | pad=1 43 | activation=leaky 44 | 45 | [maxpool] 46 | size=2 47 | stride=2 48 | 49 | [convolutional] 50 | batch_normalize=1 51 | filters=64 52 | size=3 53 | stride=1 54 | pad=1 55 | activation=leaky 56 | 57 | [maxpool] 58 | size=2 59 | stride=2 60 | 61 | [convolutional] 62 | batch_normalize=1 63 | filters=128 64 | size=3 65 | stride=1 66 | pad=1 67 | activation=leaky 68 | 69 | [maxpool] 70 | size=2 71 | stride=2 72 | 73 | [convolutional] 74 | batch_normalize=1 75 | filters=256 76 | size=3 77 | stride=1 78 | pad=1 79 | activation=leaky 80 | 81 | [maxpool] 82 | size=2 83 | stride=2 84 | 85 | [convolutional] 86 | batch_normalize=1 87 | filters=512 88 | size=3 89 | stride=1 90 | pad=1 91 | activation=leaky 92 | 93 | [maxpool] 94 | size=2 95 | stride=1 96 | 97 | [convolutional] 98 | batch_normalize=1 99 | filters=1024 100 | size=3 101 | stride=1 102 | pad=1 103 | activation=leaky 104 | 105 | ########### 106 | 107 | [convolutional] 108 | batch_normalize=1 109 | size=3 110 | stride=1 111 | pad=1 112 | filters=512 113 | activation=leaky 114 | 115 | [convolutional] 116 | size=1 117 | stride=1 118 | pad=1 119 | filters=425 120 | activation=linear 121 | 122 | [region] 123 | anchors = 0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828 124 | bias_match=1 125 | classes=80 126 | coords=4 127 | num=5 128 | softmax=1 129 | jitter=.2 130 | rescore=0 131 | 132 | object_scale=5 133 | noobject_scale=1 134 | class_scale=1 135 | coord_scale=1 136 | 137 | absolute=1 138 | thresh = .6 139 | random=1 140 | 141 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/voc.data: -------------------------------------------------------------------------------- 1 | train = data/voc_train.txt 2 | valid = data/2007_test.txt 3 | names = data/voc.names 4 | backup = backup 5 | gpus = 3 6 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/voc.names: -------------------------------------------------------------------------------- 1 | aeroplane 2 | bicycle 3 | bird 4 | boat 5 | bottle 6 | bus 7 | car 8 | cat 9 | chair 10 | cow 11 | diningtable 12 | dog 13 | horse 14 | motorbike 15 | person 16 | pottedplant 17 | sheep 18 | sofa 19 | train 20 | tvmonitor 21 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/voc_gaotie.data: -------------------------------------------------------------------------------- 1 | train = data/gaotie_trainval.txt 2 | valid = data/gaotie_test.txt 3 | names = data/voc.names 4 | backup = backup 5 | gpus = 3 -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/yolo-voc.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | batch=64 4 | subdivisions=8 5 | # Training 6 | # batch=64 7 | # subdivisions=8 8 | height=416 9 | width=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 80200 21 | policy=steps 22 | steps=-1,500,40000,60000 23 | scales=0.1,10,.1,.1 24 | 25 | [convolutional] 26 | batch_normalize=1 27 | filters=32 28 | size=3 29 | stride=1 30 | pad=1 31 | activation=leaky 32 | 33 | [maxpool] 34 | size=2 35 | stride=2 36 | 37 | [convolutional] 38 | batch_normalize=1 39 | filters=64 40 | size=3 41 | stride=1 42 | pad=1 43 | activation=leaky 44 | 45 | [maxpool] 46 | size=2 47 | stride=2 48 | 49 | [convolutional] 50 | batch_normalize=1 51 | filters=128 52 | size=3 53 | stride=1 54 | pad=1 55 | activation=leaky 56 | 57 | [convolutional] 58 | batch_normalize=1 59 | filters=64 60 | size=1 61 | stride=1 62 | pad=1 63 | activation=leaky 64 | 65 | [convolutional] 66 | batch_normalize=1 67 | filters=128 68 | size=3 69 | stride=1 70 | pad=1 71 | activation=leaky 72 | 73 | [maxpool] 74 | size=2 75 | stride=2 76 | 77 | [convolutional] 78 | batch_normalize=1 79 | filters=256 80 | size=3 81 | stride=1 82 | pad=1 83 | activation=leaky 84 | 85 | [convolutional] 86 | batch_normalize=1 87 | filters=128 88 | size=1 89 | stride=1 90 | pad=1 91 | activation=leaky 92 | 93 | [convolutional] 94 | batch_normalize=1 95 | filters=256 96 | size=3 97 | stride=1 98 | pad=1 99 | activation=leaky 100 | 101 | [maxpool] 102 | size=2 103 | stride=2 104 | 105 | [convolutional] 106 | batch_normalize=1 107 | filters=512 108 | size=3 109 | stride=1 110 | pad=1 111 | activation=leaky 112 | 113 | [convolutional] 114 | batch_normalize=1 115 | filters=256 116 | size=1 117 | stride=1 118 | pad=1 119 | activation=leaky 120 | 121 | [convolutional] 122 | batch_normalize=1 123 | filters=512 124 | size=3 125 | stride=1 126 | pad=1 127 | activation=leaky 128 | 129 | [convolutional] 130 | batch_normalize=1 131 | filters=256 132 | size=1 133 | stride=1 134 | pad=1 135 | activation=leaky 136 | 137 | [convolutional] 138 | batch_normalize=1 139 | filters=512 140 | size=3 141 | stride=1 142 | pad=1 143 | activation=leaky 144 | 145 | [maxpool] 146 | size=2 147 | stride=2 148 | 149 | [convolutional] 150 | batch_normalize=1 151 | filters=1024 152 | size=3 153 | stride=1 154 | pad=1 155 | activation=leaky 156 | 157 | [convolutional] 158 | batch_normalize=1 159 | filters=512 160 | size=1 161 | stride=1 162 | pad=1 163 | activation=leaky 164 | 165 | [convolutional] 166 | batch_normalize=1 167 | filters=1024 168 | size=3 169 | stride=1 170 | pad=1 171 | activation=leaky 172 | 173 | [convolutional] 174 | batch_normalize=1 175 | filters=512 176 | size=1 177 | stride=1 178 | pad=1 179 | activation=leaky 180 | 181 | [convolutional] 182 | batch_normalize=1 183 | filters=1024 184 | size=3 185 | stride=1 186 | pad=1 187 | activation=leaky 188 | 189 | 190 | ####### 191 | 192 | [convolutional] 193 | batch_normalize=1 194 | size=3 195 | stride=1 196 | pad=1 197 | filters=1024 198 | activation=leaky 199 | 200 | [convolutional] 201 | batch_normalize=1 202 | size=3 203 | stride=1 204 | pad=1 205 | filters=1024 206 | activation=leaky 207 | 208 | [route] 209 | layers=-9 210 | 211 | [convolutional] 212 | batch_normalize=1 213 | size=1 214 | stride=1 215 | pad=1 216 | filters=64 217 | activation=leaky 218 | 219 | [reorg] 220 | stride=2 221 | 222 | [route] 223 | layers=-1,-4 224 | 225 | [convolutional] 226 | batch_normalize=1 227 | size=3 228 | stride=1 229 | pad=1 230 | filters=1024 231 | activation=leaky 232 | 233 | [convolutional] 234 | size=1 235 | stride=1 236 | pad=1 237 | filters=125 238 | activation=linear 239 | 240 | 241 | [region] 242 | anchors = 1.3221, 1.73145, 3.19275, 4.00944, 5.05587, 8.09892, 9.47112, 4.84053, 11.2364, 10.0071 243 | bias_match=1 244 | classes=20 245 | coords=4 246 | num=5 247 | softmax=1 248 | jitter=.3 249 | rescore=1 250 | 251 | object_scale=5 252 | noobject_scale=1 253 | class_scale=1 254 | coord_scale=1 255 | 256 | absolute=1 257 | thresh = .6 258 | random=1 259 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/yolo.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | batch=1 4 | subdivisions=1 5 | # Training 6 | # batch=64 7 | # subdivisions=8 8 | width=416 9 | height=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 500200 21 | policy=steps 22 | steps=400000,450000 23 | scales=.1,.1 24 | 25 | [convolutional] 26 | batch_normalize=1 27 | filters=32 28 | size=3 29 | stride=1 30 | pad=1 31 | activation=leaky 32 | 33 | [maxpool] 34 | size=2 35 | stride=2 36 | 37 | [convolutional] 38 | batch_normalize=1 39 | filters=64 40 | size=3 41 | stride=1 42 | pad=1 43 | activation=leaky 44 | 45 | [maxpool] 46 | size=2 47 | stride=2 48 | 49 | [convolutional] 50 | batch_normalize=1 51 | filters=128 52 | size=3 53 | stride=1 54 | pad=1 55 | activation=leaky 56 | 57 | [convolutional] 58 | batch_normalize=1 59 | filters=64 60 | size=1 61 | stride=1 62 | pad=1 63 | activation=leaky 64 | 65 | [convolutional] 66 | batch_normalize=1 67 | filters=128 68 | size=3 69 | stride=1 70 | pad=1 71 | activation=leaky 72 | 73 | [maxpool] 74 | size=2 75 | stride=2 76 | 77 | [convolutional] 78 | batch_normalize=1 79 | filters=256 80 | size=3 81 | stride=1 82 | pad=1 83 | activation=leaky 84 | 85 | [convolutional] 86 | batch_normalize=1 87 | filters=128 88 | size=1 89 | stride=1 90 | pad=1 91 | activation=leaky 92 | 93 | [convolutional] 94 | batch_normalize=1 95 | filters=256 96 | size=3 97 | stride=1 98 | pad=1 99 | activation=leaky 100 | 101 | [maxpool] 102 | size=2 103 | stride=2 104 | 105 | [convolutional] 106 | batch_normalize=1 107 | filters=512 108 | size=3 109 | stride=1 110 | pad=1 111 | activation=leaky 112 | 113 | [convolutional] 114 | batch_normalize=1 115 | filters=256 116 | size=1 117 | stride=1 118 | pad=1 119 | activation=leaky 120 | 121 | [convolutional] 122 | batch_normalize=1 123 | filters=512 124 | size=3 125 | stride=1 126 | pad=1 127 | activation=leaky 128 | 129 | [convolutional] 130 | batch_normalize=1 131 | filters=256 132 | size=1 133 | stride=1 134 | pad=1 135 | activation=leaky 136 | 137 | [convolutional] 138 | batch_normalize=1 139 | filters=512 140 | size=3 141 | stride=1 142 | pad=1 143 | activation=leaky 144 | 145 | [maxpool] 146 | size=2 147 | stride=2 148 | 149 | [convolutional] 150 | batch_normalize=1 151 | filters=1024 152 | size=3 153 | stride=1 154 | pad=1 155 | activation=leaky 156 | 157 | [convolutional] 158 | batch_normalize=1 159 | filters=512 160 | size=1 161 | stride=1 162 | pad=1 163 | activation=leaky 164 | 165 | [convolutional] 166 | batch_normalize=1 167 | filters=1024 168 | size=3 169 | stride=1 170 | pad=1 171 | activation=leaky 172 | 173 | [convolutional] 174 | batch_normalize=1 175 | filters=512 176 | size=1 177 | stride=1 178 | pad=1 179 | activation=leaky 180 | 181 | [convolutional] 182 | batch_normalize=1 183 | filters=1024 184 | size=3 185 | stride=1 186 | pad=1 187 | activation=leaky 188 | 189 | 190 | ####### 191 | 192 | [convolutional] 193 | batch_normalize=1 194 | size=3 195 | stride=1 196 | pad=1 197 | filters=1024 198 | activation=leaky 199 | 200 | [convolutional] 201 | batch_normalize=1 202 | size=3 203 | stride=1 204 | pad=1 205 | filters=1024 206 | activation=leaky 207 | 208 | [route] 209 | layers=-9 210 | 211 | [convolutional] 212 | batch_normalize=1 213 | size=1 214 | stride=1 215 | pad=1 216 | filters=64 217 | activation=leaky 218 | 219 | [reorg] 220 | stride=2 221 | 222 | [route] 223 | layers=-1,-4 224 | 225 | [convolutional] 226 | batch_normalize=1 227 | size=3 228 | stride=1 229 | pad=1 230 | filters=1024 231 | activation=leaky 232 | 233 | [convolutional] 234 | size=1 235 | stride=1 236 | pad=1 237 | filters=425 238 | activation=linear 239 | 240 | 241 | [region] 242 | anchors = 0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828 243 | bias_match=1 244 | classes=80 245 | coords=4 246 | num=5 247 | softmax=1 248 | jitter=.3 249 | rescore=1 250 | 251 | object_scale=5 252 | noobject_scale=1 253 | class_scale=1 254 | coord_scale=1 255 | 256 | absolute=1 257 | thresh = .6 258 | random=1 259 | -------------------------------------------------------------------------------- /detector/YOLOv3/cfg/yolov3-tiny.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | batch=1 4 | subdivisions=1 5 | # Training 6 | # batch=64 7 | # subdivisions=2 8 | width=416 9 | height=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 500200 21 | policy=steps 22 | steps=400000,450000 23 | scales=.1,.1 24 | 25 | [convolutional] 26 | batch_normalize=1 27 | filters=16 28 | size=3 29 | stride=1 30 | pad=1 31 | activation=leaky 32 | 33 | [maxpool] 34 | size=2 35 | stride=2 36 | 37 | [convolutional] 38 | batch_normalize=1 39 | filters=32 40 | size=3 41 | stride=1 42 | pad=1 43 | activation=leaky 44 | 45 | [maxpool] 46 | size=2 47 | stride=2 48 | 49 | [convolutional] 50 | batch_normalize=1 51 | filters=64 52 | size=3 53 | stride=1 54 | pad=1 55 | activation=leaky 56 | 57 | [maxpool] 58 | size=2 59 | stride=2 60 | 61 | [convolutional] 62 | batch_normalize=1 63 | filters=128 64 | size=3 65 | stride=1 66 | pad=1 67 | activation=leaky 68 | 69 | [maxpool] 70 | size=2 71 | stride=2 72 | 73 | [convolutional] 74 | batch_normalize=1 75 | filters=256 76 | size=3 77 | stride=1 78 | pad=1 79 | activation=leaky 80 | 81 | [maxpool] 82 | size=2 83 | stride=2 84 | 85 | [convolutional] 86 | batch_normalize=1 87 | filters=512 88 | size=3 89 | stride=1 90 | pad=1 91 | activation=leaky 92 | 93 | [maxpool] 94 | size=2 95 | stride=1 96 | 97 | [convolutional] 98 | batch_normalize=1 99 | filters=1024 100 | size=3 101 | stride=1 102 | pad=1 103 | activation=leaky 104 | 105 | ########### 106 | 107 | [convolutional] 108 | batch_normalize=1 109 | filters=256 110 | size=1 111 | stride=1 112 | pad=1 113 | activation=leaky 114 | 115 | [convolutional] 116 | batch_normalize=1 117 | filters=512 118 | size=3 119 | stride=1 120 | pad=1 121 | activation=leaky 122 | 123 | [convolutional] 124 | size=1 125 | stride=1 126 | pad=1 127 | filters=255 128 | activation=linear 129 | 130 | 131 | 132 | [yolo] 133 | mask = 3,4,5 134 | anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 135 | classes=80 136 | num=6 137 | jitter=.3 138 | ignore_thresh = .7 139 | truth_thresh = 1 140 | random=1 141 | 142 | [route] 143 | layers = -4 144 | 145 | [convolutional] 146 | batch_normalize=1 147 | filters=128 148 | size=1 149 | stride=1 150 | pad=1 151 | activation=leaky 152 | 153 | [upsample] 154 | stride=2 155 | 156 | [route] 157 | layers = -1, 8 158 | 159 | [convolutional] 160 | batch_normalize=1 161 | filters=256 162 | size=3 163 | stride=1 164 | pad=1 165 | activation=leaky 166 | 167 | [convolutional] 168 | size=1 169 | stride=1 170 | pad=1 171 | filters=255 172 | activation=linear 173 | 174 | [yolo] 175 | mask = 0,1,2 176 | anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 177 | classes=80 178 | num=6 179 | jitter=.3 180 | ignore_thresh = .7 181 | truth_thresh = 1 182 | random=1 183 | -------------------------------------------------------------------------------- /detector/YOLOv3/demo/004545.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/YOLOv3/demo/004545.jpg -------------------------------------------------------------------------------- /detector/YOLOv3/demo/results/004545.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/YOLOv3/demo/results/004545.jpg -------------------------------------------------------------------------------- /detector/YOLOv3/detector.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import logging 3 | import numpy as np 4 | import cv2 5 | 6 | from .darknet import Darknet 7 | from .yolo_utils import get_all_boxes, nms, post_process, xywh_to_xyxy, xyxy_to_xywh 8 | from .nms import boxes_nms 9 | 10 | 11 | class YOLOv3(object): 12 | def __init__(self, cfgfile, weightfile, namesfile, score_thresh=0.7, conf_thresh=0.01, nms_thresh=0.45, 13 | is_xywh=False, use_cuda=True): 14 | # net definition 15 | self.net = Darknet(cfgfile) 16 | self.net.load_weights(weightfile) 17 | logger = logging.getLogger("root.detector") 18 | logger.info('Loading weights from %s... Done!' % (weightfile)) 19 | self.device = "cuda" if use_cuda else "cpu" 20 | self.net.eval() 21 | self.net.to(self.device) 22 | 23 | # constants 24 | self.size = self.net.width, self.net.height 25 | self.score_thresh = score_thresh 26 | self.conf_thresh = conf_thresh 27 | self.nms_thresh = nms_thresh 28 | self.use_cuda = use_cuda 29 | self.is_xywh = is_xywh 30 | self.num_classes = self.net.num_classes 31 | self.class_names = self.load_class_names(namesfile) 32 | 33 | def __call__(self, ori_img): 34 | # img to tensor 35 | assert isinstance(ori_img, np.ndarray), "input must be a numpy array!" 36 | img = ori_img.astype(np.float) / 255. 37 | 38 | img = cv2.resize(img, self.size) 39 | img = torch.from_numpy(img).float().permute(2, 0, 1).unsqueeze(0) 40 | 41 | # forward 42 | with torch.no_grad(): 43 | img = img.to(self.device) 44 | out_boxes = self.net(img) 45 | boxes = get_all_boxes(out_boxes, self.conf_thresh, self.num_classes, 46 | use_cuda=self.use_cuda) # batch size is 1 47 | # boxes = nms(boxes, self.nms_thresh) 48 | 49 | boxes = post_process(boxes, self.net.num_classes, self.conf_thresh, self.nms_thresh)[0].cpu() 50 | boxes = boxes[boxes[:, -2] > self.score_thresh, :] # bbox xmin ymin xmax ymax 51 | 52 | if len(boxes) == 0: 53 | bbox = torch.FloatTensor([]).reshape([0, 4]) 54 | cls_conf = torch.FloatTensor([]) 55 | cls_ids = torch.LongTensor([]) 56 | else: 57 | height, width = ori_img.shape[:2] 58 | bbox = boxes[:, :4] 59 | if self.is_xywh: 60 | # bbox x y w h 61 | bbox = xyxy_to_xywh(bbox) 62 | 63 | bbox *= torch.FloatTensor([[width, height, width, height]]) 64 | cls_conf = boxes[:, 5] 65 | cls_ids = boxes[:, 6].long() 66 | return bbox.numpy(), cls_conf.numpy(), cls_ids.numpy() 67 | 68 | def load_class_names(self, namesfile): 69 | with open(namesfile, 'r', encoding='utf8') as fp: 70 | class_names = [line.strip() for line in fp.readlines()] 71 | return class_names 72 | 73 | 74 | def demo(): 75 | import os 76 | from vizer.draw import draw_boxes 77 | 78 | yolo = YOLOv3("cfg/yolo_v3.cfg", "weight/yolov3.weights", "cfg/coco.names") 79 | print("yolo.size =", yolo.size) 80 | root = "./demo" 81 | resdir = os.path.join(root, "results") 82 | os.makedirs(resdir, exist_ok=True) 83 | files = [os.path.join(root, file) for file in os.listdir(root) if file.endswith('.jpg')] 84 | files.sort() 85 | for filename in files: 86 | img = cv2.imread(filename) 87 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 88 | bbox, cls_conf, cls_ids = yolo(img) 89 | 90 | if bbox is not None: 91 | img = draw_boxes(img, bbox, cls_ids, cls_conf, class_name_map=yolo.class_names) 92 | # save results 93 | cv2.imwrite(os.path.join(resdir, os.path.basename(filename)), img[:, :, (2, 1, 0)]) 94 | # imshow 95 | # cv2.namedWindow("yolo", cv2.WINDOW_NORMAL) 96 | # cv2.resizeWindow("yolo", 600,600) 97 | # cv2.imshow("yolo",res[:,:,(2,1,0)]) 98 | # cv2.waitKey(0) 99 | 100 | 101 | if __name__ == "__main__": 102 | demo() 103 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/__init__.py: -------------------------------------------------------------------------------- 1 | from .nms import boxes_nms -------------------------------------------------------------------------------- /detector/YOLOv3/nms/build.sh: -------------------------------------------------------------------------------- 1 | cd ext 2 | 3 | python build.py build_ext develop 4 | 5 | cd .. 6 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/YOLOv3/nms/ext/__init__.py -------------------------------------------------------------------------------- /detector/YOLOv3/nms/ext/build.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | 4 | import torch 5 | from setuptools import setup 6 | from torch.utils.cpp_extension import CUDA_HOME 7 | from torch.utils.cpp_extension import CppExtension 8 | from torch.utils.cpp_extension import CUDAExtension 9 | 10 | requirements = ["torch"] 11 | 12 | 13 | def get_extensions(): 14 | extensions_dir = os.path.dirname(os.path.abspath(__file__)) 15 | 16 | main_file = glob.glob(os.path.join(extensions_dir, "*.cpp")) 17 | source_cpu = glob.glob(os.path.join(extensions_dir, "cpu", "*.cpp")) 18 | source_cuda = glob.glob(os.path.join(extensions_dir, "cuda", "*.cu")) 19 | 20 | sources = main_file + source_cpu 21 | extension = CppExtension 22 | 23 | extra_compile_args = {"cxx": []} 24 | define_macros = [] 25 | 26 | if torch.cuda.is_available() and CUDA_HOME is not None: 27 | extension = CUDAExtension 28 | sources += source_cuda 29 | define_macros += [("WITH_CUDA", None)] 30 | extra_compile_args["nvcc"] = [ 31 | "-DCUDA_HAS_FP16=1", 32 | "-D__CUDA_NO_HALF_OPERATORS__", 33 | "-D__CUDA_NO_HALF_CONVERSIONS__", 34 | "-D__CUDA_NO_HALF2_OPERATORS__", 35 | ] 36 | 37 | sources = [os.path.join(extensions_dir, s) for s in sources] 38 | 39 | include_dirs = [extensions_dir] 40 | 41 | ext_modules = [ 42 | extension( 43 | "torch_extension", 44 | sources, 45 | include_dirs=include_dirs, 46 | define_macros=define_macros, 47 | extra_compile_args=extra_compile_args, 48 | ) 49 | ] 50 | 51 | return ext_modules 52 | 53 | 54 | setup( 55 | name="torch_extension", 56 | version="0.1", 57 | ext_modules=get_extensions(), 58 | cmdclass={"build_ext": torch.utils.cpp_extension.BuildExtension}) 59 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/ext/cpu/nms_cpu.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #include "cpu/vision.h" 3 | 4 | 5 | template 6 | at::Tensor nms_cpu_kernel(const at::Tensor& dets, 7 | const at::Tensor& scores, 8 | const float threshold) { 9 | AT_ASSERTM(!dets.type().is_cuda(), "dets must be a CPU tensor"); 10 | AT_ASSERTM(!scores.type().is_cuda(), "scores must be a CPU tensor"); 11 | AT_ASSERTM(dets.type() == scores.type(), "dets should have the same type as scores"); 12 | 13 | if (dets.numel() == 0) { 14 | return at::empty({0}, dets.options().dtype(at::kLong).device(at::kCPU)); 15 | } 16 | 17 | auto x1_t = dets.select(1, 0).contiguous(); 18 | auto y1_t = dets.select(1, 1).contiguous(); 19 | auto x2_t = dets.select(1, 2).contiguous(); 20 | auto y2_t = dets.select(1, 3).contiguous(); 21 | 22 | at::Tensor areas_t = (x2_t - x1_t) * (y2_t - y1_t); 23 | 24 | auto order_t = std::get<1>(scores.sort(0, /* descending=*/true)); 25 | 26 | auto ndets = dets.size(0); 27 | at::Tensor suppressed_t = at::zeros({ndets}, dets.options().dtype(at::kByte).device(at::kCPU)); 28 | 29 | auto suppressed = suppressed_t.data(); 30 | auto order = order_t.data(); 31 | auto x1 = x1_t.data(); 32 | auto y1 = y1_t.data(); 33 | auto x2 = x2_t.data(); 34 | auto y2 = y2_t.data(); 35 | auto areas = areas_t.data(); 36 | 37 | for (int64_t _i = 0; _i < ndets; _i++) { 38 | auto i = order[_i]; 39 | if (suppressed[i] == 1) 40 | continue; 41 | auto ix1 = x1[i]; 42 | auto iy1 = y1[i]; 43 | auto ix2 = x2[i]; 44 | auto iy2 = y2[i]; 45 | auto iarea = areas[i]; 46 | 47 | for (int64_t _j = _i + 1; _j < ndets; _j++) { 48 | auto j = order[_j]; 49 | if (suppressed[j] == 1) 50 | continue; 51 | auto xx1 = std::max(ix1, x1[j]); 52 | auto yy1 = std::max(iy1, y1[j]); 53 | auto xx2 = std::min(ix2, x2[j]); 54 | auto yy2 = std::min(iy2, y2[j]); 55 | 56 | auto w = std::max(static_cast(0), xx2 - xx1); 57 | auto h = std::max(static_cast(0), yy2 - yy1); 58 | auto inter = w * h; 59 | auto ovr = inter / (iarea + areas[j] - inter); 60 | if (ovr >= threshold) 61 | suppressed[j] = 1; 62 | } 63 | } 64 | return at::nonzero(suppressed_t == 0).squeeze(1); 65 | } 66 | 67 | at::Tensor nms_cpu(const at::Tensor& dets, 68 | const at::Tensor& scores, 69 | const float threshold) { 70 | at::Tensor result; 71 | AT_DISPATCH_FLOATING_TYPES(dets.type(), "nms", [&] { 72 | result = nms_cpu_kernel(dets, scores, threshold); 73 | }); 74 | return result; 75 | } -------------------------------------------------------------------------------- /detector/YOLOv3/nms/ext/cpu/vision.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #pragma once 3 | #include 4 | 5 | at::Tensor nms_cpu(const at::Tensor& dets, 6 | const at::Tensor& scores, 7 | const float threshold); 8 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/ext/cuda/vision.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #pragma once 3 | #include 4 | 5 | at::Tensor nms_cuda(const at::Tensor boxes, float nms_overlap_thresh); 6 | 7 | 8 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/ext/nms.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #pragma once 3 | #include "cpu/vision.h" 4 | 5 | #ifdef WITH_CUDA 6 | #include "cuda/vision.h" 7 | #endif 8 | 9 | 10 | at::Tensor nms(const at::Tensor& dets, 11 | const at::Tensor& scores, 12 | const float threshold) { 13 | 14 | if (dets.type().is_cuda()) { 15 | #ifdef WITH_CUDA 16 | // TODO raise error if not compiled with CUDA 17 | if (dets.numel() == 0) 18 | return at::empty({0}, dets.options().dtype(at::kLong).device(at::kCPU)); 19 | auto b = at::cat({dets, scores.unsqueeze(1)}, 1); 20 | return nms_cuda(b, threshold); 21 | #else 22 | AT_ERROR("Not compiled with GPU support"); 23 | #endif 24 | } 25 | 26 | at::Tensor result = nms_cpu(dets, scores, threshold); 27 | return result; 28 | } 29 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/ext/vision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #include "nms.h" 3 | 4 | 5 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 6 | m.def("nms", &nms, "non-maximum suppression"); 7 | } 8 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/nms.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | import torchvision 3 | 4 | try: 5 | import torch 6 | import torch_extension 7 | 8 | _nms = torch_extension.nms 9 | except ImportError: 10 | # if torchvision.__version__ >= '0.3.0': 11 | # _nms = torchvision.ops.nms 12 | # else: 13 | # from .python_nms import python_nms 14 | # 15 | # _nms = python_nms 16 | # warnings.warn('You are using python version NMS, which is very very slow. Try compile c++ NMS ' 17 | # 'using `cd ext & python build.py build_ext develop`') 18 | _nms = torchvision.ops.nms 19 | 20 | 21 | def boxes_nms(boxes, scores, nms_thresh, max_count=-1): 22 | """ Performs non-maximum suppression, run on GPU or CPU according to 23 | boxes's device. 24 | Args: 25 | boxes(Tensor): `xyxy` mode boxes, use absolute coordinates(or relative coordinates), shape is (n, 4) 26 | scores(Tensor): scores, shape is (n, ) 27 | nms_thresh(float): thresh 28 | max_count (int): if > 0, then only the top max_proposals are kept after non-maximum suppression 29 | Returns: 30 | indices kept. 31 | """ 32 | keep = _nms(boxes, scores, nms_thresh) 33 | if max_count > 0: 34 | keep = keep[:max_count] 35 | return keep 36 | -------------------------------------------------------------------------------- /detector/YOLOv3/nms/python_nms.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | 4 | 5 | def python_nms(boxes, scores, nms_thresh): 6 | """ Performs non-maximum suppression using numpy 7 | Args: 8 | boxes(Tensor): `xyxy` mode boxes, use absolute coordinates(not support relative coordinates), 9 | shape is (n, 4) 10 | scores(Tensor): scores, shape is (n, ) 11 | nms_thresh(float): thresh 12 | Returns: 13 | indices kept. 14 | """ 15 | if boxes.numel() == 0: 16 | return torch.empty((0,), dtype=torch.long) 17 | # Use numpy to run nms. Running nms in PyTorch code on CPU is really slow. 18 | origin_device = boxes.device 19 | cpu_device = torch.device('cpu') 20 | boxes = boxes.to(cpu_device).numpy() 21 | scores = scores.to(cpu_device).numpy() 22 | 23 | x1 = boxes[:, 0] 24 | y1 = boxes[:, 1] 25 | x2 = boxes[:, 2] 26 | y2 = boxes[:, 3] 27 | areas = (x2 - x1) * (y2 - y1) 28 | order = np.argsort(scores)[::-1] 29 | num_detections = boxes.shape[0] 30 | suppressed = np.zeros((num_detections,), dtype=np.bool) 31 | for _i in range(num_detections): 32 | i = order[_i] 33 | if suppressed[i]: 34 | continue 35 | ix1 = x1[i] 36 | iy1 = y1[i] 37 | ix2 = x2[i] 38 | iy2 = y2[i] 39 | iarea = areas[i] 40 | 41 | for _j in range(_i + 1, num_detections): 42 | j = order[_j] 43 | if suppressed[j]: 44 | continue 45 | 46 | xx1 = max(ix1, x1[j]) 47 | yy1 = max(iy1, y1[j]) 48 | xx2 = min(ix2, x2[j]) 49 | yy2 = min(iy2, y2[j]) 50 | w = max(0, xx2 - xx1) 51 | h = max(0, yy2 - yy1) 52 | 53 | inter = w * h 54 | ovr = inter / (iarea + areas[j] - inter) 55 | if ovr >= nms_thresh: 56 | suppressed[j] = True 57 | keep = np.nonzero(suppressed == 0)[0] 58 | keep = torch.from_numpy(keep).to(origin_device) 59 | return keep 60 | -------------------------------------------------------------------------------- /detector/YOLOv3/weight/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/YOLOv3/weight/.gitkeep -------------------------------------------------------------------------------- /detector/YOLOv5/.gitattributes: -------------------------------------------------------------------------------- 1 | # this drop notebooks from GitHub language stats 2 | *.ipynb linguist-vendored 3 | -------------------------------------------------------------------------------- /detector/YOLOv5/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # Define hooks for code formations 2 | # Will be applied on any updated commit files if a user has installed and linked commit hook 3 | 4 | default_language_version: 5 | python: python3.8 6 | 7 | # Define bot property if installed via https://github.com/marketplace/pre-commit-ci 8 | ci: 9 | autofix_prs: true 10 | autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions' 11 | autoupdate_schedule: quarterly 12 | # submodules: true 13 | 14 | repos: 15 | - repo: https://github.com/pre-commit/pre-commit-hooks 16 | rev: v4.1.0 17 | hooks: 18 | - id: end-of-file-fixer 19 | - id: trailing-whitespace 20 | - id: check-case-conflict 21 | - id: check-yaml 22 | - id: check-toml 23 | - id: pretty-format-json 24 | - id: check-docstring-first 25 | 26 | - repo: https://github.com/asottile/pyupgrade 27 | rev: v2.31.0 28 | hooks: 29 | - id: pyupgrade 30 | args: [--py36-plus] 31 | name: Upgrade code 32 | 33 | - repo: https://github.com/PyCQA/isort 34 | rev: 5.10.1 35 | hooks: 36 | - id: isort 37 | name: Sort imports 38 | 39 | # TODO 40 | #- repo: https://github.com/pre-commit/mirrors-yapf 41 | # rev: v0.31.0 42 | # hooks: 43 | # - id: yapf 44 | # name: formatting 45 | 46 | # TODO 47 | #- repo: https://github.com/executablebooks/mdformat 48 | # rev: 0.7.7 49 | # hooks: 50 | # - id: mdformat 51 | # additional_dependencies: 52 | # - mdformat-gfm 53 | # - mdformat-black 54 | # - mdformat_frontmatter 55 | 56 | # TODO 57 | #- repo: https://github.com/asottile/yesqa 58 | # rev: v1.2.3 59 | # hooks: 60 | # - id: yesqa 61 | 62 | - repo: https://github.com/PyCQA/flake8 63 | rev: 4.0.1 64 | hooks: 65 | - id: flake8 66 | name: PEP8 67 | -------------------------------------------------------------------------------- /detector/YOLOv5/Dockerfile: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | 3 | # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch 4 | FROM nvcr.io/nvidia/pytorch:21.10-py3 5 | 6 | # Install linux packages 7 | RUN apt update && apt install -y zip htop screen libgl1-mesa-glx 8 | 9 | # Install python dependencies 10 | COPY requirements.txt . 11 | RUN python -m pip install --upgrade pip 12 | RUN pip uninstall -y torch torchvision torchtext 13 | RUN pip install --no-cache -r requirements.txt albumentations wandb gsutil notebook \ 14 | torch==1.10.2+cu113 torchvision==0.11.3+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html 15 | # RUN pip install --no-cache -U torch torchvision 16 | 17 | # Create working directory 18 | RUN mkdir -p /usr/src/app 19 | WORKDIR /usr/src/app 20 | 21 | # Copy contents 22 | COPY . /usr/src/app 23 | 24 | # Downloads to user config dir 25 | ADD https://ultralytics.com/assets/Arial.ttf /root/.config/Ultralytics/ 26 | 27 | # Set environment variables 28 | # ENV HOME=/usr/src/app 29 | 30 | 31 | # Usage Examples ------------------------------------------------------------------------------------------------------- 32 | 33 | # Build and Push 34 | # t=ultralytics/yolov5:latest && sudo docker build -t $t . && sudo docker push $t 35 | 36 | # Pull and Run 37 | # t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t 38 | 39 | # Pull and Run with local directory access 40 | # t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/datasets:/usr/src/datasets $t 41 | 42 | # Kill all 43 | # sudo docker kill $(sudo docker ps -q) 44 | 45 | # Kill all image-based 46 | # sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov5:latest) 47 | 48 | # Bash into running container 49 | # sudo docker exec -it 5a9b5863d93d bash 50 | 51 | # Bash into stopped container 52 | # id=$(sudo docker ps -qa) && sudo docker start $id && sudo docker exec -it $id bash 53 | 54 | # Clean up 55 | # docker system prune -a --volumes 56 | 57 | # Update Ubuntu drivers 58 | # https://www.maketecheasier.com/install-nvidia-drivers-ubuntu/ 59 | 60 | # DDP test 61 | # python -m torch.distributed.run --nproc_per_node 2 --master_port 1 train.py --epochs 3 62 | 63 | # GCP VM from Image 64 | # docker.io/ultralytics/yolov5:latest 65 | -------------------------------------------------------------------------------- /detector/YOLOv5/__init__.py: -------------------------------------------------------------------------------- 1 | from .detector import YOLOv5 2 | 3 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/Argoverse.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ by Argo AI 3 | # Example usage: python train.py --data Argoverse.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── Argoverse ← downloads here 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/Argoverse # dataset root dir 12 | train: Argoverse-1.1/images/train/ # train images (relative to 'path') 39384 images 13 | val: Argoverse-1.1/images/val/ # val images (relative to 'path') 15062 images 14 | test: Argoverse-1.1/images/test/ # test images (optional) https://eval.ai/web/challenges/challenge-page/800/overview 15 | 16 | # Classes 17 | nc: 8 # number of classes 18 | names: ['person', 'bicycle', 'car', 'motorcycle', 'bus', 'truck', 'traffic_light', 'stop_sign'] # class names 19 | 20 | 21 | # Download script/URL (optional) --------------------------------------------------------------------------------------- 22 | download: | 23 | import json 24 | 25 | from tqdm import tqdm 26 | from utils.general import download, Path 27 | 28 | 29 | def argoverse2yolo(set): 30 | labels = {} 31 | a = json.load(open(set, "rb")) 32 | for annot in tqdm(a['annotations'], desc=f"Converting {set} to YOLOv5 format..."): 33 | img_id = annot['image_id'] 34 | img_name = a['images'][img_id]['name'] 35 | img_label_name = img_name[:-3] + "txt" 36 | 37 | cls = annot['category_id'] # instance class id 38 | x_center, y_center, width, height = annot['bbox'] 39 | x_center = (x_center + width / 2) / 1920.0 # offset and scale 40 | y_center = (y_center + height / 2) / 1200.0 # offset and scale 41 | width /= 1920.0 # scale 42 | height /= 1200.0 # scale 43 | 44 | img_dir = set.parents[2] / 'Argoverse-1.1' / 'labels' / a['seq_dirs'][a['images'][annot['image_id']]['sid']] 45 | if not img_dir.exists(): 46 | img_dir.mkdir(parents=True, exist_ok=True) 47 | 48 | k = str(img_dir / img_label_name) 49 | if k not in labels: 50 | labels[k] = [] 51 | labels[k].append(f"{cls} {x_center} {y_center} {width} {height}\n") 52 | 53 | for k in labels: 54 | with open(k, "w") as f: 55 | f.writelines(labels[k]) 56 | 57 | 58 | # Download 59 | dir = Path('../datasets/Argoverse') # dataset root dir 60 | urls = ['https://argoverse-hd.s3.us-east-2.amazonaws.com/Argoverse-HD-Full.zip'] 61 | download(urls, dir=dir, delete=False) 62 | 63 | # Convert 64 | annotations_dir = 'Argoverse-HD/annotations/' 65 | (dir / 'Argoverse-1.1' / 'tracking').rename(dir / 'Argoverse-1.1' / 'images') # rename 'tracking' to 'images' 66 | for d in "train.json", "val.json": 67 | argoverse2yolo(dir / annotations_dir / d) # convert VisDrone annotations to YOLO labels 68 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/GlobalWheat2020.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # Global Wheat 2020 dataset http://www.global-wheat.com/ by University of Saskatchewan 3 | # Example usage: python train.py --data GlobalWheat2020.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── GlobalWheat2020 ← downloads here 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/GlobalWheat2020 # dataset root dir 12 | train: # train images (relative to 'path') 3422 images 13 | - images/arvalis_1 14 | - images/arvalis_2 15 | - images/arvalis_3 16 | - images/ethz_1 17 | - images/rres_1 18 | - images/inrae_1 19 | - images/usask_1 20 | val: # val images (relative to 'path') 748 images (WARNING: train set contains ethz_1) 21 | - images/ethz_1 22 | test: # test images (optional) 1276 images 23 | - images/utokyo_1 24 | - images/utokyo_2 25 | - images/nau_1 26 | - images/uq_1 27 | 28 | # Classes 29 | nc: 1 # number of classes 30 | names: ['wheat_head'] # class names 31 | 32 | 33 | # Download script/URL (optional) --------------------------------------------------------------------------------------- 34 | download: | 35 | from utils.general import download, Path 36 | 37 | # Download 38 | dir = Path(yaml['path']) # dataset root dir 39 | urls = ['https://zenodo.org/record/4298502/files/global-wheat-codalab-official.zip', 40 | 'https://github.com/ultralytics/yolov5/releases/download/v1.0/GlobalWheat2020_labels.zip'] 41 | download(urls, dir=dir) 42 | 43 | # Make Directories 44 | for p in 'annotations', 'images', 'labels': 45 | (dir / p).mkdir(parents=True, exist_ok=True) 46 | 47 | # Move 48 | for p in 'arvalis_1', 'arvalis_2', 'arvalis_3', 'ethz_1', 'rres_1', 'inrae_1', 'usask_1', \ 49 | 'utokyo_1', 'utokyo_2', 'nau_1', 'uq_1': 50 | (dir / p).rename(dir / 'images' / p) # move to /images 51 | f = (dir / p).with_suffix('.json') # json file 52 | if f.exists(): 53 | f.rename((dir / 'annotations' / p).with_suffix('.json')) # move to /annotations 54 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/SKU-110K.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 by Trax Retail 3 | # Example usage: python train.py --data SKU-110K.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── SKU-110K ← downloads here 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/SKU-110K # dataset root dir 12 | train: train.txt # train images (relative to 'path') 8219 images 13 | val: val.txt # val images (relative to 'path') 588 images 14 | test: test.txt # test images (optional) 2936 images 15 | 16 | # Classes 17 | nc: 1 # number of classes 18 | names: ['object'] # class names 19 | 20 | 21 | # Download script/URL (optional) --------------------------------------------------------------------------------------- 22 | download: | 23 | import shutil 24 | from tqdm import tqdm 25 | from utils.general import np, pd, Path, download, xyxy2xywh 26 | 27 | # Download 28 | dir = Path(yaml['path']) # dataset root dir 29 | parent = Path(dir.parent) # download dir 30 | urls = ['http://trax-geometry.s3.amazonaws.com/cvpr_challenge/SKU110K_fixed.tar.gz'] 31 | download(urls, dir=parent, delete=False) 32 | 33 | # Rename directories 34 | if dir.exists(): 35 | shutil.rmtree(dir) 36 | (parent / 'SKU110K_fixed').rename(dir) # rename dir 37 | (dir / 'labels').mkdir(parents=True, exist_ok=True) # create labels dir 38 | 39 | # Convert labels 40 | names = 'image', 'x1', 'y1', 'x2', 'y2', 'class', 'image_width', 'image_height' # column names 41 | for d in 'annotations_train.csv', 'annotations_val.csv', 'annotations_test.csv': 42 | x = pd.read_csv(dir / 'annotations' / d, names=names).values # annotations 43 | images, unique_images = x[:, 0], np.unique(x[:, 0]) 44 | with open((dir / d).with_suffix('.txt').__str__().replace('annotations_', ''), 'w') as f: 45 | f.writelines(f'./images/{s}\n' for s in unique_images) 46 | for im in tqdm(unique_images, desc=f'Converting {dir / d}'): 47 | cls = 0 # single-class dataset 48 | with open((dir / 'labels' / im).with_suffix('.txt'), 'a') as f: 49 | for r in x[images == im]: 50 | w, h = r[6], r[7] # image width, height 51 | xywh = xyxy2xywh(np.array([[r[1] / w, r[2] / h, r[3] / w, r[4] / h]]))[0] # instance 52 | f.write(f"{cls} {xywh[0]:.5f} {xywh[1]:.5f} {xywh[2]:.5f} {xywh[3]:.5f}\n") # write label 53 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/VOC.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC by University of Oxford 3 | # Example usage: python train.py --data VOC.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── VOC ← downloads here 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/VOC 12 | train: # train images (relative to 'path') 16551 images 13 | - images/train2012 14 | - images/train2007 15 | - images/val2012 16 | - images/val2007 17 | val: # val images (relative to 'path') 4952 images 18 | - images/test2007 19 | test: # test images (optional) 20 | - images/test2007 21 | 22 | # Classes 23 | nc: 20 # number of classes 24 | names: ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 25 | 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] # class names 26 | 27 | 28 | # Download script/URL (optional) --------------------------------------------------------------------------------------- 29 | download: | 30 | import xml.etree.ElementTree as ET 31 | 32 | from tqdm import tqdm 33 | from utils.general import download, Path 34 | 35 | 36 | def convert_label(path, lb_path, year, image_id): 37 | def convert_box(size, box): 38 | dw, dh = 1. / size[0], 1. / size[1] 39 | x, y, w, h = (box[0] + box[1]) / 2.0 - 1, (box[2] + box[3]) / 2.0 - 1, box[1] - box[0], box[3] - box[2] 40 | return x * dw, y * dh, w * dw, h * dh 41 | 42 | in_file = open(path / f'VOC{year}/Annotations/{image_id}.xml') 43 | out_file = open(lb_path, 'w') 44 | tree = ET.parse(in_file) 45 | root = tree.getroot() 46 | size = root.find('size') 47 | w = int(size.find('width').text) 48 | h = int(size.find('height').text) 49 | 50 | for obj in root.iter('object'): 51 | cls = obj.find('name').text 52 | if cls in yaml['names'] and not int(obj.find('difficult').text) == 1: 53 | xmlbox = obj.find('bndbox') 54 | bb = convert_box((w, h), [float(xmlbox.find(x).text) for x in ('xmin', 'xmax', 'ymin', 'ymax')]) 55 | cls_id = yaml['names'].index(cls) # class id 56 | out_file.write(" ".join([str(a) for a in (cls_id, *bb)]) + '\n') 57 | 58 | 59 | # Download 60 | dir = Path(yaml['path']) # dataset root dir 61 | url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/' 62 | urls = [url + 'VOCtrainval_06-Nov-2007.zip', # 446MB, 5012 images 63 | url + 'VOCtest_06-Nov-2007.zip', # 438MB, 4953 images 64 | url + 'VOCtrainval_11-May-2012.zip'] # 1.95GB, 17126 images 65 | download(urls, dir=dir / 'images', delete=False) 66 | 67 | # Convert 68 | path = dir / f'images/VOCdevkit' 69 | for year, image_set in ('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test'): 70 | imgs_path = dir / 'images' / f'{image_set}{year}' 71 | lbs_path = dir / 'labels' / f'{image_set}{year}' 72 | imgs_path.mkdir(exist_ok=True, parents=True) 73 | lbs_path.mkdir(exist_ok=True, parents=True) 74 | 75 | image_ids = open(path / f'VOC{year}/ImageSets/Main/{image_set}.txt').read().strip().split() 76 | for id in tqdm(image_ids, desc=f'{image_set}{year}'): 77 | f = path / f'VOC{year}/JPEGImages/{id}.jpg' # old img path 78 | lb_path = (lbs_path / f.name).with_suffix('.txt') # new label path 79 | f.rename(imgs_path / f.name) # move image 80 | convert_label(path, lb_path, year, id) # convert labels to YOLO format 81 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/VisDrone.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset by Tianjin University 3 | # Example usage: python train.py --data VisDrone.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── VisDrone ← downloads here 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/VisDrone # dataset root dir 12 | train: VisDrone2019-DET-train/images # train images (relative to 'path') 6471 images 13 | val: VisDrone2019-DET-val/images # val images (relative to 'path') 548 images 14 | test: VisDrone2019-DET-test-dev/images # test images (optional) 1610 images 15 | 16 | # Classes 17 | nc: 10 # number of classes 18 | names: ['pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning-tricycle', 'bus', 'motor'] 19 | 20 | 21 | # Download script/URL (optional) --------------------------------------------------------------------------------------- 22 | download: | 23 | from utils.general import download, os, Path 24 | 25 | def visdrone2yolo(dir): 26 | from PIL import Image 27 | from tqdm import tqdm 28 | 29 | def convert_box(size, box): 30 | # Convert VisDrone box to YOLO xywh box 31 | dw = 1. / size[0] 32 | dh = 1. / size[1] 33 | return (box[0] + box[2] / 2) * dw, (box[1] + box[3] / 2) * dh, box[2] * dw, box[3] * dh 34 | 35 | (dir / 'labels').mkdir(parents=True, exist_ok=True) # make labels directory 36 | pbar = tqdm((dir / 'annotations').glob('*.txt'), desc=f'Converting {dir}') 37 | for f in pbar: 38 | img_size = Image.open((dir / 'images' / f.name).with_suffix('.jpg')).size 39 | lines = [] 40 | with open(f, 'r') as file: # read annotation.txt 41 | for row in [x.split(',') for x in file.read().strip().splitlines()]: 42 | if row[4] == '0': # VisDrone 'ignored regions' class 0 43 | continue 44 | cls = int(row[5]) - 1 45 | box = convert_box(img_size, tuple(map(int, row[:4]))) 46 | lines.append(f"{cls} {' '.join(f'{x:.6f}' for x in box)}\n") 47 | with open(str(f).replace(os.sep + 'annotations' + os.sep, os.sep + 'labels' + os.sep), 'w') as fl: 48 | fl.writelines(lines) # write label.txt 49 | 50 | 51 | # Download 52 | dir = Path(yaml['path']) # dataset root dir 53 | urls = ['https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-train.zip', 54 | 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-val.zip', 55 | 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-dev.zip', 56 | 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-challenge.zip'] 57 | download(urls, dir=dir) 58 | 59 | # Convert 60 | for d in 'VisDrone2019-DET-train', 'VisDrone2019-DET-val', 'VisDrone2019-DET-test-dev': 61 | visdrone2yolo(dir / d) # convert VisDrone annotations to YOLO labels 62 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/coco.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # COCO 2017 dataset http://cocodataset.org by Microsoft 3 | # Example usage: python train.py --data coco.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── coco ← downloads here 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/coco # dataset root dir 12 | train: train2017.txt # train images (relative to 'path') 118287 images 13 | val: val2017.txt # val images (relative to 'path') 5000 images 14 | test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 15 | 16 | # Classes 17 | nc: 80 # number of classes 18 | names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 19 | 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 20 | 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 21 | 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 22 | 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 23 | 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 24 | 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 25 | 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 26 | 'hair drier', 'toothbrush'] # class names 27 | 28 | 29 | # Download script/URL (optional) 30 | download: | 31 | from utils.general import download, Path 32 | 33 | # Download labels 34 | segments = False # segment or box labels 35 | dir = Path(yaml['path']) # dataset root dir 36 | url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/' 37 | urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')] # labels 38 | download(urls, dir=dir.parent) 39 | 40 | # Download data 41 | urls = ['http://images.cocodataset.org/zips/train2017.zip', # 19G, 118k images 42 | 'http://images.cocodataset.org/zips/val2017.zip', # 1G, 5k images 43 | 'http://images.cocodataset.org/zips/test2017.zip'] # 7G, 41k images (optional) 44 | download(urls, dir=dir / 'images', threads=3) 45 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/coco128.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics 3 | # Example usage: python train.py --data coco128.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── coco128 ← downloads here 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/coco128 # dataset root dir 12 | train: images/train2017 # train images (relative to 'path') 128 images 13 | val: images/train2017 # val images (relative to 'path') 128 images 14 | test: # test images (optional) 15 | 16 | # Classes 17 | nc: 80 # number of classes 18 | names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 19 | 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 20 | 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 21 | 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 22 | 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 23 | 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 24 | 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 25 | 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 26 | 'hair drier', 'toothbrush'] # class names 27 | 28 | 29 | # Download script/URL (optional) 30 | download: https://ultralytics.com/assets/coco128.zip 31 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/hyps/hyp.Objects365.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # Hyperparameters for Objects365 training 3 | # python train.py --weights yolov5m.pt --data Objects365.yaml --evolve 4 | # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials 5 | 6 | lr0: 0.00258 7 | lrf: 0.17 8 | momentum: 0.779 9 | weight_decay: 0.00058 10 | warmup_epochs: 1.33 11 | warmup_momentum: 0.86 12 | warmup_bias_lr: 0.0711 13 | box: 0.0539 14 | cls: 0.299 15 | cls_pw: 0.825 16 | obj: 0.632 17 | obj_pw: 1.0 18 | iou_t: 0.2 19 | anchor_t: 3.44 20 | anchors: 3.2 21 | fl_gamma: 0.0 22 | hsv_h: 0.0188 23 | hsv_s: 0.704 24 | hsv_v: 0.36 25 | degrees: 0.0 26 | translate: 0.0902 27 | scale: 0.491 28 | shear: 0.0 29 | perspective: 0.0 30 | flipud: 0.0 31 | fliplr: 0.5 32 | mosaic: 1.0 33 | mixup: 0.0 34 | copy_paste: 0.0 35 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/hyps/hyp.VOC.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # Hyperparameters for VOC training 3 | # python train.py --batch 128 --weights yolov5m6.pt --data VOC.yaml --epochs 50 --img 512 --hyp hyp.scratch-med.yaml --evolve 4 | # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials 5 | 6 | # YOLOv5 Hyperparameter Evolution Results 7 | # Best generation: 319 8 | # Last generation: 434 9 | # metrics/precision, metrics/recall, metrics/mAP_0.5, metrics/mAP_0.5:0.95, val/box_loss, val/obj_loss, val/cls_loss 10 | # 0.86236, 0.86184, 0.91274, 0.72647, 0.0077056, 0.0042449, 0.0013846 11 | 12 | lr0: 0.0033 13 | lrf: 0.15184 14 | momentum: 0.74747 15 | weight_decay: 0.00025 16 | warmup_epochs: 3.4278 17 | warmup_momentum: 0.59032 18 | warmup_bias_lr: 0.18742 19 | box: 0.02 20 | cls: 0.21563 21 | cls_pw: 0.5 22 | obj: 0.50843 23 | obj_pw: 0.6729 24 | iou_t: 0.2 25 | anchor_t: 3.4172 26 | fl_gamma: 0.0 27 | hsv_h: 0.01032 28 | hsv_s: 0.5562 29 | hsv_v: 0.28255 30 | degrees: 0.0 31 | translate: 0.04575 32 | scale: 0.73711 33 | shear: 0.0 34 | perspective: 0.0 35 | flipud: 0.0 36 | fliplr: 0.5 37 | mosaic: 0.87158 38 | mixup: 0.04294 39 | copy_paste: 0.0 40 | anchors: 3.3556 41 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/hyps/hyp.scratch-high.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # Hyperparameters for high-augmentation COCO training from scratch 3 | # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 4 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials 5 | 6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) 7 | lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) 8 | momentum: 0.937 # SGD momentum/Adam beta1 9 | weight_decay: 0.0005 # optimizer weight decay 5e-4 10 | warmup_epochs: 3.0 # warmup epochs (fractions ok) 11 | warmup_momentum: 0.8 # warmup initial momentum 12 | warmup_bias_lr: 0.1 # warmup initial bias lr 13 | box: 0.05 # box loss gain 14 | cls: 0.3 # cls loss gain 15 | cls_pw: 1.0 # cls BCELoss positive_weight 16 | obj: 0.7 # obj loss gain (scale with pixels) 17 | obj_pw: 1.0 # obj BCELoss positive_weight 18 | iou_t: 0.20 # IoU training threshold 19 | anchor_t: 4.0 # anchor-multiple threshold 20 | # anchors: 3 # anchors per output layer (0 to ignore) 21 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) 22 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction) 23 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) 24 | hsv_v: 0.4 # image HSV-Value augmentation (fraction) 25 | degrees: 0.0 # image rotation (+/- deg) 26 | translate: 0.1 # image translation (+/- fraction) 27 | scale: 0.9 # image scale (+/- gain) 28 | shear: 0.0 # image shear (+/- deg) 29 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 30 | flipud: 0.0 # image flip up-down (probability) 31 | fliplr: 0.5 # image flip left-right (probability) 32 | mosaic: 1.0 # image mosaic (probability) 33 | mixup: 0.1 # image mixup (probability) 34 | copy_paste: 0.1 # segment copy-paste (probability) 35 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/hyps/hyp.scratch-low.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # Hyperparameters for low-augmentation COCO training from scratch 3 | # python train.py --batch 64 --cfg yolov5n6.yaml --weights '' --data coco.yaml --img 640 --epochs 300 --linear 4 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials 5 | 6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) 7 | lrf: 0.01 # final OneCycleLR learning rate (lr0 * lrf) 8 | momentum: 0.937 # SGD momentum/Adam beta1 9 | weight_decay: 0.0005 # optimizer weight decay 5e-4 10 | warmup_epochs: 3.0 # warmup epochs (fractions ok) 11 | warmup_momentum: 0.8 # warmup initial momentum 12 | warmup_bias_lr: 0.1 # warmup initial bias lr 13 | box: 0.05 # box loss gain 14 | cls: 0.5 # cls loss gain 15 | cls_pw: 1.0 # cls BCELoss positive_weight 16 | obj: 1.0 # obj loss gain (scale with pixels) 17 | obj_pw: 1.0 # obj BCELoss positive_weight 18 | iou_t: 0.20 # IoU training threshold 19 | anchor_t: 4.0 # anchor-multiple threshold 20 | # anchors: 3 # anchors per output layer (0 to ignore) 21 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) 22 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction) 23 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) 24 | hsv_v: 0.4 # image HSV-Value augmentation (fraction) 25 | degrees: 0.0 # image rotation (+/- deg) 26 | translate: 0.1 # image translation (+/- fraction) 27 | scale: 0.5 # image scale (+/- gain) 28 | shear: 0.0 # image shear (+/- deg) 29 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 30 | flipud: 0.0 # image flip up-down (probability) 31 | fliplr: 0.5 # image flip left-right (probability) 32 | mosaic: 1.0 # image mosaic (probability) 33 | mixup: 0.0 # image mixup (probability) 34 | copy_paste: 0.0 # segment copy-paste (probability) 35 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/hyps/hyp.scratch-med.yaml: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | # Hyperparameters for medium-augmentation COCO training from scratch 3 | # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 4 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials 5 | 6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) 7 | lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) 8 | momentum: 0.937 # SGD momentum/Adam beta1 9 | weight_decay: 0.0005 # optimizer weight decay 5e-4 10 | warmup_epochs: 3.0 # warmup epochs (fractions ok) 11 | warmup_momentum: 0.8 # warmup initial momentum 12 | warmup_bias_lr: 0.1 # warmup initial bias lr 13 | box: 0.05 # box loss gain 14 | cls: 0.3 # cls loss gain 15 | cls_pw: 1.0 # cls BCELoss positive_weight 16 | obj: 0.7 # obj loss gain (scale with pixels) 17 | obj_pw: 1.0 # obj BCELoss positive_weight 18 | iou_t: 0.20 # IoU training threshold 19 | anchor_t: 4.0 # anchor-multiple threshold 20 | # anchors: 3 # anchors per output layer (0 to ignore) 21 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) 22 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction) 23 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) 24 | hsv_v: 0.4 # image HSV-Value augmentation (fraction) 25 | degrees: 0.0 # image rotation (+/- deg) 26 | translate: 0.1 # image translation (+/- fraction) 27 | scale: 0.9 # image scale (+/- gain) 28 | shear: 0.0 # image shear (+/- deg) 29 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 30 | flipud: 0.0 # image flip up-down (probability) 31 | fliplr: 0.5 # image flip left-right (probability) 32 | mosaic: 1.0 # image mosaic (probability) 33 | mixup: 0.1 # image mixup (probability) 34 | copy_paste: 0.0 # segment copy-paste (probability) 35 | -------------------------------------------------------------------------------- /detector/YOLOv5/data/images/bus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/YOLOv5/data/images/bus.jpg -------------------------------------------------------------------------------- /detector/YOLOv5/data/images/zidane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/YOLOv5/data/images/zidane.jpg -------------------------------------------------------------------------------- /detector/YOLOv5/data/scripts/download_weights.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 3 | # Download latest models from https://github.com/ultralytics/yolov5/releases 4 | # Example usage: bash path/to/download_weights.sh 5 | # parent 6 | # └── yolov5 7 | # ├── yolov5s.pt ← downloads here 8 | # ├── yolov5m.pt 9 | # └── ... 10 | 11 | python - < 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel 31 | 32 | if ddp: # multi-GPU 33 | port += 1 34 | cmd = f'python -m torch.distributed.run --nproc_per_node {nd} --master_port {port} train.py --resume {last}' 35 | else: # single-GPU 36 | cmd = f'python train.py --resume {last}' 37 | 38 | cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread 39 | print(cmd) 40 | os.system(cmd) 41 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/aws/userdata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html 3 | # This script will run only once on first instance start (for a re-start script see mime.sh) 4 | # /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir 5 | # Use >300 GB SSD 6 | 7 | cd home/ubuntu 8 | if [ ! -d yolov5 ]; then 9 | echo "Running first-time script." # install dependencies, download COCO, pull Docker 10 | git clone https://github.com/ultralytics/yolov5 -b master && sudo chmod -R 777 yolov5 11 | cd yolov5 12 | bash data/scripts/get_coco.sh && echo "COCO done." & 13 | sudo docker pull ultralytics/yolov5:latest && echo "Docker done." & 14 | python -m pip install --upgrade pip && pip install -r requirements.txt && python detect.py && echo "Requirements done." & 15 | wait && echo "All tasks done." # finish background tasks 16 | else 17 | echo "Running re-start script." # resume interrupted runs 18 | i=0 19 | list=$(sudo docker ps -qa) # container list i.e. $'one\ntwo\nthree\nfour' 20 | while IFS= read -r id; do 21 | ((i++)) 22 | echo "restarting container $i: $id" 23 | sudo docker start $id 24 | # sudo docker exec -it $id python train.py --resume # single-GPU 25 | sudo docker exec -d $id python utils/aws/resume.py # multi-scenario 26 | done <<<"$list" 27 | fi 28 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/benchmarks.py: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | """ 3 | Run YOLOv5 benchmarks on all supported export formats 4 | 5 | Format | `export.py --include` | Model 6 | --- | --- | --- 7 | PyTorch | - | yolov5s.pt 8 | TorchScript | `torchscript` | yolov5s.torchscript 9 | ONNX | `onnx` | yolov5s.onnx 10 | OpenVINO | `openvino` | yolov5s_openvino_model/ 11 | TensorRT | `engine` | yolov5s.engine 12 | CoreML | `coreml` | yolov5s.mlmodel 13 | TensorFlow SavedModel | `saved_model` | yolov5s_saved_model/ 14 | TensorFlow GraphDef | `pb` | yolov5s.pb 15 | TensorFlow Lite | `tflite` | yolov5s.tflite 16 | TensorFlow Edge TPU | `edgetpu` | yolov5s_edgetpu.tflite 17 | TensorFlow.js | `tfjs` | yolov5s_web_model/ 18 | 19 | Requirements: 20 | $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime openvino-dev tensorflow-cpu # CPU 21 | $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime-gpu openvino-dev tensorflow # GPU 22 | 23 | Usage: 24 | $ python utils/benchmarks.py --weights yolov5s.pt --img 640 25 | """ 26 | 27 | import argparse 28 | import sys 29 | import time 30 | from pathlib import Path 31 | 32 | import pandas as pd 33 | 34 | FILE = Path(__file__).resolve() 35 | ROOT = FILE.parents[1] # YOLOv5 root directory 36 | if str(ROOT) not in sys.path: 37 | sys.path.append(str(ROOT)) # add ROOT to PATH 38 | # ROOT = ROOT.relative_to(Path.cwd()) # relative 39 | 40 | import export 41 | import val 42 | from detector.YOLOv5.utils import notebook_init 43 | from detector.YOLOv5.utils.general import LOGGER, print_args 44 | s 45 | 46 | def run(weights=ROOT / 'yolov5s.pt', # weights path 47 | imgsz=640, # inference size (pixels) 48 | batch_size=1, # batch size 49 | data=ROOT / 'data/coco128.yaml', # dataset.yaml path 50 | ): 51 | y, t = [], time.time() 52 | formats = export.export_formats() 53 | for i, (name, f, suffix) in formats.iterrows(): # index, (name, file, suffix) 54 | try: 55 | w = weights if f == '-' else export.run(weights=weights, imgsz=[imgsz], include=[f], device='cpu')[-1] 56 | assert suffix in str(w), 'export failed' 57 | result = val.run(data, w, batch_size, imgsz=imgsz, plots=False, device='cpu', task='benchmark') 58 | metrics = result[0] # metrics (mp, mr, map50, map, *losses(box, obj, cls)) 59 | speeds = result[2] # times (preprocess, inference, postprocess) 60 | y.append([name, metrics[3], speeds[1]]) # mAP, t_inference 61 | except Exception as e: 62 | LOGGER.warning(f'WARNING: Benchmark failure for {name}: {e}') 63 | y.append([name, None, None]) # mAP, t_inference 64 | 65 | # Print results 66 | LOGGER.info('\n') 67 | parse_opt() 68 | notebook_init() # print system info 69 | py = pd.DataFrame(y, columns=['Format', 'mAP@0.5:0.95', 'Inference time (ms)']) 70 | LOGGER.info(f'\nBenchmarks complete ({time.time() - t:.2f}s)') 71 | LOGGER.info(str(py)) 72 | return py 73 | 74 | 75 | def parse_opt(): 76 | parser = argparse.ArgumentParser() 77 | parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path') 78 | parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') 79 | parser.add_argument('--batch-size', type=int, default=1, help='batch size') 80 | parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') 81 | opt = parser.parse_args() 82 | print_args(FILE.stem, opt) 83 | return opt 84 | 85 | 86 | def main(opt): 87 | run(**vars(opt)) 88 | 89 | 90 | if __name__ == "__main__": 91 | opt = parse_opt() 92 | main(opt) 93 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/callbacks.py: -------------------------------------------------------------------------------- 1 | # YOLOv5 🚀 by Ultralytics, GPL-3.0 license 2 | """ 3 | Callback utils 4 | """ 5 | 6 | 7 | class Callbacks: 8 | """" 9 | Handles all registered callbacks for YOLOv5 Hooks 10 | """ 11 | 12 | def __init__(self): 13 | # Define the available callbacks 14 | self._callbacks = { 15 | 'on_pretrain_routine_start': [], 16 | 'on_pretrain_routine_end': [], 17 | 18 | 'on_train_start': [], 19 | 'on_train_epoch_start': [], 20 | 'on_train_batch_start': [], 21 | 'optimizer_step': [], 22 | 'on_before_zero_grad': [], 23 | 'on_train_batch_end': [], 24 | 'on_train_epoch_end': [], 25 | 26 | 'on_val_start': [], 27 | 'on_val_batch_start': [], 28 | 'on_val_image_end': [], 29 | 'on_val_batch_end': [], 30 | 'on_val_end': [], 31 | 32 | 'on_fit_epoch_end': [], # fit = train + val 33 | 'on_model_save': [], 34 | 'on_train_end': [], 35 | 'on_params_update': [], 36 | 'teardown': [], 37 | } 38 | self.stop_training = False # set True to interrupt training 39 | 40 | def register_action(self, hook, name='', callback=None): 41 | """ 42 | Register a new action to a callback hook 43 | 44 | Args: 45 | hook The callback hook name to register the action to 46 | name The name of the action for later reference 47 | callback The callback to fire 48 | """ 49 | assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" 50 | assert callable(callback), f"callback '{callback}' is not callable" 51 | self._callbacks[hook].append({'name': name, 'callback': callback}) 52 | 53 | def get_registered_actions(self, hook=None): 54 | """" 55 | Returns all the registered actions by callback hook 56 | 57 | Args: 58 | hook The name of the hook to check, defaults to all 59 | """ 60 | if hook: 61 | return self._callbacks[hook] 62 | else: 63 | return self._callbacks 64 | 65 | def run(self, hook, *args, **kwargs): 66 | """ 67 | Loop through the registered actions and fire all callbacks 68 | 69 | Args: 70 | hook The name of the hook to check, defaults to all 71 | args Arguments to receive from YOLOv5 72 | kwargs Keyword Arguments to receive from YOLOv5 73 | """ 74 | 75 | assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" 76 | 77 | for logger in self._callbacks[hook]: 78 | logger['callback'](*args, **kwargs) 79 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/flask_rest_api/README.md: -------------------------------------------------------------------------------- 1 | # Flask REST API 2 | 3 | [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are 4 | commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API 5 | created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). 6 | 7 | ## Requirements 8 | 9 | [Flask](https://palletsprojects.com/p/flask/) is required. Install with: 10 | 11 | ```shell 12 | $ pip install Flask 13 | ``` 14 | 15 | ## Run 16 | 17 | After Flask installation run: 18 | 19 | ```shell 20 | $ python3 restapi.py --port 5000 21 | ``` 22 | 23 | Then use [curl](https://curl.se/) to perform a request: 24 | 25 | ```shell 26 | $ curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s' 27 | ``` 28 | 29 | The model inference results are returned as a JSON response: 30 | 31 | ```json 32 | [ 33 | { 34 | "class": 0, 35 | "confidence": 0.8900438547, 36 | "height": 0.9318675399, 37 | "name": "person", 38 | "width": 0.3264600933, 39 | "xcenter": 0.7438579798, 40 | "ycenter": 0.5207948685 41 | }, 42 | { 43 | "class": 0, 44 | "confidence": 0.8440024257, 45 | "height": 0.7155083418, 46 | "name": "person", 47 | "width": 0.6546785235, 48 | "xcenter": 0.427829951, 49 | "ycenter": 0.6334488392 50 | }, 51 | { 52 | "class": 27, 53 | "confidence": 0.3771208823, 54 | "height": 0.3902671337, 55 | "name": "tie", 56 | "width": 0.0696444362, 57 | "xcenter": 0.3675483763, 58 | "ycenter": 0.7991207838 59 | }, 60 | { 61 | "class": 27, 62 | "confidence": 0.3527112305, 63 | "height": 0.1540903747, 64 | "name": "tie", 65 | "width": 0.0336618312, 66 | "xcenter": 0.7814827561, 67 | "ycenter": 0.5065554976 68 | } 69 | ] 70 | ``` 71 | 72 | An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given 73 | in `example_request.py` 74 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/flask_rest_api/example_request.py: -------------------------------------------------------------------------------- 1 | """Perform test request""" 2 | import pprint 3 | 4 | import requests 5 | 6 | DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s" 7 | TEST_IMAGE = "zidane.jpg" 8 | 9 | image_data = open(TEST_IMAGE, "rb").read() 10 | 11 | response = requests.post(DETECTION_URL, files={"image": image_data}).json() 12 | 13 | pprint.pprint(response) 14 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/flask_rest_api/restapi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Run a rest API exposing the yolov5s object detection model 3 | """ 4 | import argparse 5 | import io 6 | 7 | import torch 8 | from flask import Flask, request 9 | from PIL import Image 10 | 11 | app = Flask(__name__) 12 | 13 | DETECTION_URL = "/v1/object-detection/yolov5s" 14 | 15 | 16 | @app.route(DETECTION_URL, methods=["POST"]) 17 | def predict(): 18 | if not request.method == "POST": 19 | return 20 | 21 | if request.files.get("image"): 22 | image_file = request.files["image"] 23 | image_bytes = image_file.read() 24 | 25 | img = Image.open(io.BytesIO(image_bytes)) 26 | 27 | results = model(img, size=640) # reduce size=320 for faster inference 28 | return results.pandas().xyxy[0].to_json(orient="records") 29 | 30 | 31 | if __name__ == "__main__": 32 | parser = argparse.ArgumentParser(description="Flask API exposing YOLOv5 model") 33 | parser.add_argument("--port", default=5000, type=int, help="port number") 34 | args = parser.parse_args() 35 | 36 | model = torch.hub.load("ultralytics/yolov5", "yolov5s", force_reload=True) # force_reload to recache 37 | app.run(host="0.0.0.0", port=args.port) # debug=True causes Restarting with stat 38 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/google_app_engine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcr.io/google-appengine/python 2 | 3 | # Create a virtualenv for dependencies. This isolates these packages from 4 | # system-level packages. 5 | # Use -p python3 or -p python3.7 to select python version. Default is version 2. 6 | RUN virtualenv /env -p python3 7 | 8 | # Setting these environment variables are the same as running 9 | # source /env/bin/activate. 10 | ENV VIRTUAL_ENV /env 11 | ENV PATH /env/bin:$PATH 12 | 13 | RUN apt-get update && apt-get install -y python-opencv 14 | 15 | # Copy the application's requirements.txt and run pip to install all 16 | # dependencies into the virtualenv. 17 | ADD requirements.txt /app/requirements.txt 18 | RUN pip install -r /app/requirements.txt 19 | 20 | # Add the application source code. 21 | ADD . /app 22 | 23 | # Run a WSGI server to serve the application. gunicorn must be declared as 24 | # a dependency in requirements.txt. 25 | CMD gunicorn -b :$PORT main:app 26 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/google_app_engine/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: custom 2 | env: flex 3 | 4 | service: yolov5app 5 | 6 | liveness_check: 7 | initial_delay_sec: 600 8 | 9 | manual_scaling: 10 | instances: 1 11 | resources: 12 | cpu: 1 13 | memory_gb: 4 14 | disk_size_gb: 20 15 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/loggers/wandb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/detector/YOLOv5/utils/loggers/wandb/__init__.py -------------------------------------------------------------------------------- /detector/YOLOv5/utils/loggers/wandb/log_dataset.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from wandb_utils import WandbLogger 4 | 5 | from utils.general import LOGGER 6 | 7 | WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' 8 | 9 | 10 | def create_dataset_artifact(opt): 11 | logger = WandbLogger(opt, None, job_type='Dataset Creation') # TODO: return value unused 12 | if not logger.wandb: 13 | LOGGER.info("install wandb using `pip install wandb` to log the dataset") 14 | 15 | 16 | if __name__ == '__main__': 17 | parser = argparse.ArgumentParser() 18 | parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') 19 | parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') 20 | parser.add_argument('--project', type=str, default='YOLOv5', help='name of W&B Project') 21 | parser.add_argument('--entity', default=None, help='W&B entity') 22 | parser.add_argument('--name', type=str, default='log dataset', help='name of W&B run') 23 | 24 | opt = parser.parse_args() 25 | opt.resume = False # Explicitly disallow resume check for dataset upload job 26 | 27 | create_dataset_artifact(opt) 28 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/loggers/wandb/sweep.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | 4 | import wandb 5 | 6 | FILE = Path(__file__).resolve() 7 | ROOT = FILE.parents[3] # YOLOv5 root directory 8 | if str(ROOT) not in sys.path: 9 | sys.path.append(str(ROOT)) # add ROOT to PATH 10 | 11 | from train import parse_opt, train 12 | from utils.callbacks import Callbacks 13 | from utils.general import increment_path 14 | from utils.torch_utils import select_device 15 | 16 | 17 | def sweep(): 18 | wandb.init() 19 | # Get hyp dict from sweep agent 20 | hyp_dict = vars(wandb.config).get("_items") 21 | 22 | # Workaround: get necessary opt args 23 | opt = parse_opt(known=True) 24 | opt.batch_size = hyp_dict.get("batch_size") 25 | opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) 26 | opt.epochs = hyp_dict.get("epochs") 27 | opt.nosave = True 28 | opt.data = hyp_dict.get("data") 29 | opt.weights = str(opt.weights) 30 | opt.cfg = str(opt.cfg) 31 | opt.data = str(opt.data) 32 | opt.hyp = str(opt.hyp) 33 | opt.project = str(opt.project) 34 | device = select_device(opt.device, batch_size=opt.batch_size) 35 | 36 | # train 37 | train(hyp_dict, opt, device, callbacks=Callbacks()) 38 | 39 | 40 | if __name__ == "__main__": 41 | sweep() 42 | -------------------------------------------------------------------------------- /detector/YOLOv5/utils/loggers/wandb/sweep.yaml: -------------------------------------------------------------------------------- 1 | # Hyperparameters for training 2 | # To set range- 3 | # Provide min and max values as: 4 | # parameter: 5 | # 6 | # min: scalar 7 | # max: scalar 8 | # OR 9 | # 10 | # Set a specific list of search space- 11 | # parameter: 12 | # values: [scalar1, scalar2, scalar3...] 13 | # 14 | # You can use grid, bayesian and hyperopt search strategy 15 | # For more info on configuring sweeps visit - https://docs.wandb.ai/guides/sweeps/configuration 16 | 17 | program: utils/loggers/wandb/sweep.py 18 | method: random 19 | metric: 20 | name: metrics/mAP_0.5 21 | goal: maximize 22 | 23 | parameters: 24 | # hyperparameters: set either min, max range or values list 25 | data: 26 | value: "data/coco128.yaml" 27 | batch_size: 28 | values: [64] 29 | epochs: 30 | values: [10] 31 | 32 | lr0: 33 | distribution: uniform 34 | min: 1e-5 35 | max: 1e-1 36 | lrf: 37 | distribution: uniform 38 | min: 0.01 39 | max: 1.0 40 | momentum: 41 | distribution: uniform 42 | min: 0.6 43 | max: 0.98 44 | weight_decay: 45 | distribution: uniform 46 | min: 0.0 47 | max: 0.001 48 | warmup_epochs: 49 | distribution: uniform 50 | min: 0.0 51 | max: 5.0 52 | warmup_momentum: 53 | distribution: uniform 54 | min: 0.0 55 | max: 0.95 56 | warmup_bias_lr: 57 | distribution: uniform 58 | min: 0.0 59 | max: 0.2 60 | box: 61 | distribution: uniform 62 | min: 0.02 63 | max: 0.2 64 | cls: 65 | distribution: uniform 66 | min: 0.2 67 | max: 4.0 68 | cls_pw: 69 | distribution: uniform 70 | min: 0.5 71 | max: 2.0 72 | obj: 73 | distribution: uniform 74 | min: 0.2 75 | max: 4.0 76 | obj_pw: 77 | distribution: uniform 78 | min: 0.5 79 | max: 2.0 80 | iou_t: 81 | distribution: uniform 82 | min: 0.1 83 | max: 0.7 84 | anchor_t: 85 | distribution: uniform 86 | min: 2.0 87 | max: 8.0 88 | fl_gamma: 89 | distribution: uniform 90 | min: 0.0 91 | max: 0.1 92 | hsv_h: 93 | distribution: uniform 94 | min: 0.0 95 | max: 0.1 96 | hsv_s: 97 | distribution: uniform 98 | min: 0.0 99 | max: 0.9 100 | hsv_v: 101 | distribution: uniform 102 | min: 0.0 103 | max: 0.9 104 | degrees: 105 | distribution: uniform 106 | min: 0.0 107 | max: 45.0 108 | translate: 109 | distribution: uniform 110 | min: 0.0 111 | max: 0.9 112 | scale: 113 | distribution: uniform 114 | min: 0.0 115 | max: 0.9 116 | shear: 117 | distribution: uniform 118 | min: 0.0 119 | max: 10.0 120 | perspective: 121 | distribution: uniform 122 | min: 0.0 123 | max: 0.001 124 | flipud: 125 | distribution: uniform 126 | min: 0.0 127 | max: 1.0 128 | fliplr: 129 | distribution: uniform 130 | min: 0.0 131 | max: 1.0 132 | mosaic: 133 | distribution: uniform 134 | min: 0.0 135 | max: 1.0 136 | mixup: 137 | distribution: uniform 138 | min: 0.0 139 | max: 1.0 140 | copy_paste: 141 | distribution: uniform 142 | min: 0.0 143 | max: 1.0 144 | -------------------------------------------------------------------------------- /detector/__init__.py: -------------------------------------------------------------------------------- 1 | from .YOLOv3 import YOLOv3 2 | from .MMDet import MMDet 3 | from .YOLOv5 import YOLOv5 4 | from .Mask_RCNN import Mask_RCNN 5 | 6 | __all__ = ['build_detector'] 7 | 8 | 9 | def build_detector(cfg, use_cuda, segment=False): 10 | if cfg.USE_MMDET: 11 | return MMDet(cfg.MMDET.CFG, cfg.MMDET.CHECKPOINT, 12 | score_thresh=cfg.MMDET.SCORE_THRESH, 13 | is_xywh=True, use_cuda=use_cuda) 14 | elif cfg.USE_SEGMENT: 15 | return Mask_RCNN(segment, num_classes=cfg.MASKRCNN.NUM_CLASSES, box_thresh=cfg.MASKRCNN.BOX_THRESH, 16 | label_json_path=cfg.MASKRCNN.LABEL, weight_path=cfg.MASKRCNN.WEIGHT) 17 | else: 18 | if 'YOLOV5' in cfg: 19 | return YOLOv5(cfg.YOLOV5.WEIGHT, cfg.YOLOV5.DATA, cfg.YOLOV5.IMGSZ, 20 | cfg.YOLOV5.SCORE_THRESH, cfg.YOLOV5.NMS_THRESH, cfg.YOLOV5.MAX_DET) 21 | elif 'YOLOV3' in cfg: 22 | return YOLOv3(cfg.YOLOV3.CFG, cfg.YOLOV3.WEIGHT, cfg.YOLOV3.CLASS_NAMES, 23 | score_thresh=cfg.YOLOV3.SCORE_THRESH, nms_thresh=cfg.YOLOV3.NMS_THRESH, 24 | is_xywh=True, use_cuda=use_cuda) 25 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.3.0 2 | attrs==19.3.0 3 | colorama==0.4.3 4 | easydict~=1.13 5 | entrypoints==0.3 6 | et-xmlfile==1.0.1 7 | flake8==3.7.9 8 | flake8-import-order==0.18.1 9 | importlib-metadata==1.6.0 10 | jdcal==1.4.1 11 | joblib==0.14.1 12 | numpy~=1.23.5 13 | lap==0.4.0 14 | mccabe==0.6.1 15 | more-itertools==8.2.0 16 | motmetrics==1.2.0 17 | opencv-python~=4.8.1.78 18 | openpyxl==3.0.3 19 | packaging==20.3 20 | pandas~=1.5.2 21 | Pillow~=9.0.1 22 | pluggy==0.13.1 23 | py==1.10.0 24 | py-cpuinfo==5.0.0 25 | pycodestyle==2.5.0 26 | pyflakes==2.1.1 27 | pyparsing==2.4.7 28 | pytest==5.4.1 29 | pytest-benchmark==3.2.3 30 | python-dateutil==2.8.1 31 | pytz==2019.3 32 | PyYAML~=6.0 33 | scikit-learn==0.22.2.post1 34 | scipy~=1.10.1 35 | six==1.14.0 36 | sklearn==0.0 37 | torch~=1.12.1+cu113 38 | torchvision~=0.13.1+cu113 39 | Vizer==0.1.5 40 | wcwidth==0.1.9 41 | xmltodict==0.12.0 42 | zipp==3.1.0 43 | 44 | mmdet~=3.0.0 45 | setuptools~=56.0.0 46 | tqdm~=4.65.0 47 | matplotlib~=3.7.2 48 | seaborn~=0.11.2 49 | requests~=2.31.0 50 | thop~=0.1.1.post2209072238 51 | pycocotools~=2.0.6 52 | python-dotenv~=0.21.0 -------------------------------------------------------------------------------- /scripts/yolov3_deepsort.sh: -------------------------------------------------------------------------------- 1 | python yolov3_deepsort.py [VIDEO_PATH] --config_detection -------------------------------------------------------------------------------- /scripts/yolov3_tiny_deepsort.sh: -------------------------------------------------------------------------------- 1 | python yolov3_deepsort.py [VIDEO_PATH] --config_detection ./configs/yolov3_tiny.yaml -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | def datasets(): 2 | return None -------------------------------------------------------------------------------- /utils/asserts.py: -------------------------------------------------------------------------------- 1 | from os import environ 2 | 3 | 4 | def assert_in(file, files_to_check): 5 | if file not in files_to_check: 6 | raise AssertionError("{} does not exist in the list".format(str(file))) 7 | return True 8 | 9 | 10 | def assert_in_env(check_list: list): 11 | for item in check_list: 12 | assert_in(item, environ.keys()) 13 | return True 14 | -------------------------------------------------------------------------------- /utils/draw.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | palette = (2 ** 11 - 1, 2 ** 15 - 1, 2 ** 20 - 1) 5 | 6 | 7 | def compute_color_for_labels(label): 8 | """ 9 | Simple function that adds fixed color depending on the class 10 | """ 11 | color = [int((p * (label ** 2 - label + 1)) % 255) for p in palette] 12 | return tuple(color) 13 | 14 | 15 | def draw_masks(image, mask, color, thresh: float = 0.7, alpha: float = 0.5): 16 | np_image = np.asarray(image) 17 | mask = mask > thresh 18 | 19 | color = np.asarray(color) 20 | img_to_draw = np.copy(np_image) 21 | # TODO: There might be a way to vectorize this 22 | img_to_draw[mask] = color 23 | 24 | out = np_image * (1 - alpha) + img_to_draw * alpha 25 | return out.astype(np.uint8) 26 | 27 | 28 | def draw_boxes(img, bbox, names=None, identities=None, masks=None, offset=(0, 0)): 29 | for i, box in enumerate(bbox): 30 | x1, y1, x2, y2 = [int(i) for i in box] 31 | x1 += offset[0] 32 | x2 += offset[0] 33 | y1 += offset[1] 34 | y2 += offset[1] 35 | # box text and bar 36 | id = int(identities[i]) if identities is not None else 0 37 | color = compute_color_for_labels(id) 38 | label = '{:}{:d}'.format(names[i], id) 39 | t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_PLAIN, 2, 2)[0] 40 | if masks is not None: 41 | mask = masks[i] 42 | img = draw_masks(img, mask, color) 43 | cv2.rectangle(img, (x1, y1), (x2, y2), color, 3) 44 | cv2.rectangle(img, (x1, y1), (x1 + t_size[0] + 3, y1 + t_size[1] + 4), color, -1) 45 | cv2.putText(img, label, (x1, y1 + t_size[1] + 4), cv2.FONT_HERSHEY_PLAIN, 2, [255, 255, 255], 2) 46 | return img 47 | 48 | 49 | if __name__ == '__main__': 50 | for i in range(82): 51 | print(compute_color_for_labels(i)) 52 | -------------------------------------------------------------------------------- /utils/evaluation.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import copy 4 | import motmetrics as mm 5 | mm.lap.default_solver = 'lap' 6 | from utils.io import read_results, unzip_objs 7 | 8 | 9 | class Evaluator(object): 10 | 11 | def __init__(self, data_root, seq_name, data_type): 12 | self.data_root = data_root 13 | self.seq_name = seq_name 14 | self.data_type = data_type 15 | 16 | self.load_annotations() 17 | self.reset_accumulator() 18 | 19 | def load_annotations(self): 20 | assert self.data_type == 'mot' 21 | 22 | gt_filename = os.path.join(self.data_root, self.seq_name, 'gt', 'gt.txt') 23 | self.gt_frame_dict = read_results(gt_filename, self.data_type, is_gt=True) 24 | self.gt_ignore_frame_dict = read_results(gt_filename, self.data_type, is_ignore=True) 25 | 26 | def reset_accumulator(self): 27 | self.acc = mm.MOTAccumulator(auto_id=True) 28 | 29 | def eval_frame(self, frame_id, trk_tlwhs, trk_ids, rtn_events=False): 30 | # results 31 | trk_tlwhs = np.copy(trk_tlwhs) 32 | trk_ids = np.copy(trk_ids) 33 | 34 | # gts 35 | gt_objs = self.gt_frame_dict.get(frame_id, []) 36 | gt_tlwhs, gt_ids = unzip_objs(gt_objs)[:2] 37 | 38 | # ignore boxes 39 | ignore_objs = self.gt_ignore_frame_dict.get(frame_id, []) 40 | ignore_tlwhs = unzip_objs(ignore_objs)[0] 41 | 42 | 43 | # remove ignored results 44 | keep = np.ones(len(trk_tlwhs), dtype=bool) 45 | iou_distance = mm.distances.iou_matrix(ignore_tlwhs, trk_tlwhs, max_iou=0.5) 46 | if len(iou_distance) > 0: 47 | match_is, match_js = mm.lap.linear_sum_assignment(iou_distance) 48 | match_is, match_js = map(lambda a: np.asarray(a, dtype=int), [match_is, match_js]) 49 | match_ious = iou_distance[match_is, match_js] 50 | 51 | match_js = np.asarray(match_js, dtype=int) 52 | match_js = match_js[np.logical_not(np.isnan(match_ious))] 53 | keep[match_js] = False 54 | trk_tlwhs = trk_tlwhs[keep] 55 | trk_ids = trk_ids[keep] 56 | 57 | # get distance matrix 58 | iou_distance = mm.distances.iou_matrix(gt_tlwhs, trk_tlwhs, max_iou=0.5) 59 | 60 | # acc 61 | self.acc.update(gt_ids, trk_ids, iou_distance) 62 | 63 | if rtn_events and iou_distance.size > 0 and hasattr(self.acc, 'last_mot_events'): 64 | events = self.acc.last_mot_events # only supported by https://github.com/longcw/py-motmetrics 65 | else: 66 | events = None 67 | return events 68 | 69 | def eval_file(self, filename): 70 | self.reset_accumulator() 71 | 72 | result_frame_dict = read_results(filename, self.data_type, is_gt=False) 73 | frames = sorted(list(set(self.gt_frame_dict.keys()) | set(result_frame_dict.keys()))) 74 | for frame_id in frames: 75 | trk_objs = result_frame_dict.get(frame_id, []) 76 | trk_tlwhs, trk_ids = unzip_objs(trk_objs)[:2] 77 | self.eval_frame(frame_id, trk_tlwhs, trk_ids, rtn_events=False) 78 | 79 | return self.acc 80 | 81 | @staticmethod 82 | def get_summary(accs, names, metrics=('mota', 'num_switches', 'idp', 'idr', 'idf1', 'precision', 'recall')): 83 | names = copy.deepcopy(names) 84 | if metrics is None: 85 | metrics = mm.metrics.motchallenge_metrics 86 | metrics = copy.deepcopy(metrics) 87 | 88 | mh = mm.metrics.create() 89 | summary = mh.compute_many( 90 | accs, 91 | metrics=metrics, 92 | names=names, 93 | generate_overall=True 94 | ) 95 | 96 | return summary 97 | 98 | @staticmethod 99 | def save_summary(summary, filename): 100 | import pandas as pd 101 | writer = pd.ExcelWriter(filename) 102 | summary.to_excel(writer) 103 | writer.save() 104 | -------------------------------------------------------------------------------- /utils/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | def get_logger(name='root'): 5 | formatter = logging.Formatter( 6 | # fmt='%(asctime)s [%(levelname)s]: %(filename)s(%(funcName)s:%(lineno)s) >> %(message)s') 7 | fmt='%(asctime)s [%(levelname)s]: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') 8 | 9 | handler = logging.StreamHandler() 10 | handler.setFormatter(formatter) 11 | 12 | logger = logging.getLogger(name) 13 | logger.setLevel(logging.INFO) 14 | logger.addHandler(handler) 15 | return logger 16 | 17 | 18 | -------------------------------------------------------------------------------- /utils/parser.py: -------------------------------------------------------------------------------- 1 | import os 2 | import yaml 3 | from easydict import EasyDict as edict 4 | 5 | class YamlParser(edict): 6 | """ 7 | This is yaml parser based on EasyDict. 8 | """ 9 | def __init__(self, cfg_dict=None, config_file=None): 10 | if cfg_dict is None: 11 | cfg_dict = {} 12 | 13 | if config_file is not None: 14 | assert (os.path.isfile(config_file)) 15 | with open(config_file, 'r') as fo: 16 | cfg_dict.update(yaml.safe_load(fo.read())) 17 | 18 | super(YamlParser, self).__init__(cfg_dict) 19 | 20 | 21 | def merge_from_file(self, config_file): 22 | with open(config_file, 'r') as fo: 23 | self.update(yaml.safe_load(fo.read())) 24 | 25 | 26 | def merge_from_dict(self, config_dict): 27 | self.update(config_dict) 28 | 29 | 30 | def get_config(config_file=None): 31 | return YamlParser(config_file=config_file) 32 | 33 | 34 | if __name__ == "__main__": 35 | cfg = YamlParser(config_file="../configs/yolov3.yaml") 36 | cfg.merge_from_file("../configs/deep_sort.yaml") 37 | 38 | import ipdb; ipdb.set_trace() 39 | -------------------------------------------------------------------------------- /utils/tools.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | from time import time 3 | 4 | 5 | def is_video(ext: str): 6 | """ 7 | Returns true if ext exists in 8 | allowed_exts for video files. 9 | 10 | Args: 11 | ext: 12 | 13 | Returns: 14 | 15 | """ 16 | 17 | allowed_exts = ('.mp4', '.webm', '.ogg', '.avi', '.wmv', '.mkv', '.3gp') 18 | return any((ext.endswith(x) for x in allowed_exts)) 19 | 20 | 21 | def tik_tok(func): 22 | """ 23 | keep track of time for each process. 24 | Args: 25 | func: 26 | 27 | Returns: 28 | 29 | """ 30 | @wraps(func) 31 | def _time_it(*args, **kwargs): 32 | start = time() 33 | try: 34 | return func(*args, **kwargs) 35 | finally: 36 | end_ = time() 37 | print("time: {:.03f}s, fps: {:.03f}".format(end_ - start, 1 / (end_ - start))) 38 | 39 | return _time_it 40 | -------------------------------------------------------------------------------- /webserver/.env: -------------------------------------------------------------------------------- 1 | project_root="C:\Users\ZQ_deep_sort_pytorch" 2 | model_type="yolov3" 3 | output_dir="public/" 4 | json_output="json_output/" # ignored for the moment in ped_det_online_server.py 5 | reid_ckpt="deep_sort/deep/checkpoint/ckpt.t7" 6 | yolov3_cfg="detector/YOLOv3/cfg/yolo_v3.cfg" 7 | yolov3_weight="detector/YOLOv3/weight/yolov3.weights" 8 | yolov3_tiny_cfg="detector/YOLOv3/cfg/yolov3-tiny.cfg" 9 | yolov3_tiny_weight="detector/YOLOv3/weight/yolov3-tiny.weights" 10 | yolov3_class_names="detector/YOLOv3/cfg/coco.names" 11 | analysis_output="video_analysis/" 12 | app="flask_stream_server.py" 13 | camera_stream= "rtsp://user@111.222.333.444:somesecretcode" 14 | -------------------------------------------------------------------------------- /webserver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/webserver/__init__.py -------------------------------------------------------------------------------- /webserver/config/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | app_dir = os.path.abspath(os.path.dirname(__file__)) 4 | 5 | 6 | class BaseConfig: 7 | SECRET_KEY = os.environ.get('SECRET_KEY') or 'Sm9obiBTY2hyb20ga2lja3MgYXNz' 8 | SERVER_NAME = '127.0.0.1:8888' 9 | 10 | 11 | class DevelopmentConfig(BaseConfig): 12 | ENV = 'development' 13 | DEBUG = True 14 | 15 | 16 | class TestingConfig(BaseConfig): 17 | DEBUG = True 18 | 19 | 20 | class ProductionConfig(BaseConfig): 21 | DEBUG = False 22 | -------------------------------------------------------------------------------- /webserver/images/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/webserver/images/Thumbs.db -------------------------------------------------------------------------------- /webserver/images/arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/webserver/images/arc.png -------------------------------------------------------------------------------- /webserver/images/request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZQPei/deep_sort_pytorch/4f910afc16860ff05c6be408b120a49524bd4f68/webserver/images/request.png -------------------------------------------------------------------------------- /webserver/readme.md: -------------------------------------------------------------------------------- 1 | # Stream pedestrian detection web server 2 | 3 | ### Requirements 4 | 5 | - python = 3.7 6 | - redis 7 | - flask 8 | - opencv 9 | - pytorch 10 | - dotenv 11 | 12 | Please note that you need to install redis on your system. 13 | 14 | ### The architecture. 15 | 16 | ![web server architecture](images/arc.png) 17 | 18 | 1 - `RealTimeTracking` reads frames from rtsp link using threads 19 | (Using threads make the web server robust against network packet loss) 20 | 21 | 2 - In `RealTimeTracking.run` function in each iteration frame is stored in redis cache on server. 22 | 23 | 3 - Now we can serve the frames on redis to clients. 24 | 25 | 4 - To start the pedestrian detection, after running 26 | `rtsp_webserver.py`, send a GET request on `127.0.0.1:8888/run` 27 | with setting these GET method parameters 28 | 29 | | Param | Value | Description | 30 | | :-------------: | :-------------: | :-------------: | 31 | | run | 1/0 | to start the tracking set 1/ to stop tracking service set it as 0| 32 | | camera_stream | 'rtsp://ip:port/admin...' | provide it with valid rtsp link | 33 | 34 | for example: 35 | 36 | (to start the service) 127.0.0.1:8888/run?run=1 37 | (to stop the service) 127.0.0.1:8888/run?run=0 38 | (to change the camera) 39 | 1- 127.0.0.1:8888/run?run=0 (first stop the current service) 40 | 2- 127.0.0.1:8888/run?run=0&camera_stream=rtsp://ip:port/admin... (then start it with another rtsp link) 41 | 42 | ![web server architecture](images/request.png) 43 | 44 | 45 | 5 - get pedestrian detection stream in `127.0.0.1:8888` 46 | -------------------------------------------------------------------------------- /webserver/server_cfg.py: -------------------------------------------------------------------------------- 1 | """""" 2 | import sys 3 | from os.path import dirname, abspath, isfile 4 | 5 | sys.path.append(dirname(dirname(abspath(__file__)))) 6 | 7 | from dotenv import load_dotenv 8 | from utils.asserts import assert_in_env 9 | from os import getenv 10 | from os.path import join 11 | 12 | load_dotenv('.env') 13 | # Configure deep sort info 14 | deep_sort_info = dict(REID_CKPT=join(getenv('project_root'), getenv('reid_ckpt')), 15 | MAX_DIST=0.2, 16 | MIN_CONFIDENCE=.3, 17 | NMS_MAX_OVERLAP=0.5, 18 | MAX_IOU_DISTANCE=0.7, 19 | N_INIT=3, 20 | MAX_AGE=70, 21 | NN_BUDGET=100) 22 | deep_sort_dict = {'DEEPSORT': deep_sort_info} 23 | 24 | # Configure yolov3 info 25 | 26 | yolov3_info = dict(CFG=join(getenv('project_root'), getenv('yolov3_cfg')), 27 | WEIGHT=join(getenv('project_root'), getenv('yolov3_weight')), 28 | CLASS_NAMES=join(getenv('project_root'), getenv('yolov3_class_names')), 29 | SCORE_THRESH=0.5, 30 | NMS_THRESH=0.4 31 | ) 32 | yolov3_dict = {'YOLOV3': yolov3_info} 33 | 34 | # Configure yolov3-tiny info 35 | 36 | yolov3_tiny_info = dict(CFG=join(getenv('project_root'), getenv('yolov3_tiny_cfg')), 37 | WEIGHT=join(getenv('project_root'), getenv('yolov3_tiny_weight')), 38 | CLASS_NAMES=join(getenv('project_root'), getenv('yolov3_class_names')), 39 | SCORE_THRESH=0.5, 40 | NMS_THRESH=0.4 41 | ) 42 | yolov3_tiny_dict = {'YOLOV3': yolov3_tiny_info} 43 | 44 | 45 | check_list = ['project_root', 'reid_ckpt', 'yolov3_class_names', 'model_type', 'yolov3_cfg', 'yolov3_weight', 46 | 'yolov3_tiny_cfg', 'yolov3_tiny_weight', 'yolov3_class_names'] 47 | 48 | if assert_in_env(check_list): 49 | assert isfile(deep_sort_info['REID_CKPT']) 50 | if getenv('model_type') == 'yolov3': 51 | assert isfile(yolov3_info['WEIGHT']) 52 | assert isfile(yolov3_info['CFG']) 53 | assert isfile(yolov3_info['CLASS_NAMES']) 54 | model = yolov3_dict.copy() 55 | 56 | elif getenv('model_type') == 'yolov3_tiny': 57 | assert isfile(yolov3_tiny_info['WEIGHT']) 58 | assert isfile(yolov3_tiny_info['CFG']) 59 | assert isfile(yolov3_tiny_info['CLASS_NAMES']) 60 | model = yolov3_tiny_dict.copy() 61 | else: 62 | raise ValueError("Value '{}' for model_type is not valid".format(getenv('model_type'))) 63 | -------------------------------------------------------------------------------- /webserver/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | دوربین طبقه 2: راهرو 2 4 | 5 | 6 |

طبقه 2

7 | 8 | 9 | -------------------------------------------------------------------------------- /yolov3_deepsort_eval.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path as osp 3 | import logging 4 | import argparse 5 | from pathlib import Path 6 | 7 | from utils.log import get_logger 8 | from yolov3_deepsort import VideoTracker 9 | from utils.parser import get_config 10 | 11 | import motmetrics as mm 12 | mm.lap.default_solver = 'lap' 13 | from utils.evaluation import Evaluator 14 | 15 | def mkdir_if_missing(dir): 16 | os.makedirs(dir, exist_ok=True) 17 | 18 | def main(data_root='', seqs=('',), args=""): 19 | logger = get_logger() 20 | logger.setLevel(logging.INFO) 21 | data_type = 'mot' 22 | result_root = os.path.join(Path(data_root), "mot_results") 23 | mkdir_if_missing(result_root) 24 | 25 | cfg = get_config() 26 | cfg.merge_from_file(args.config_detection) 27 | cfg.merge_from_file(args.config_deepsort) 28 | 29 | # run tracking 30 | accs = [] 31 | for seq in seqs: 32 | logger.info('start seq: {}'.format(seq)) 33 | result_filename = os.path.join(result_root, '{}.txt'.format(seq)) 34 | video_path = data_root+"/"+seq+"/video/video.mp4" 35 | 36 | with VideoTracker(cfg, args, video_path, result_filename) as vdo_trk: 37 | vdo_trk.run() 38 | 39 | # eval 40 | logger.info('Evaluate seq: {}'.format(seq)) 41 | evaluator = Evaluator(data_root, seq, data_type) 42 | accs.append(evaluator.eval_file(result_filename)) 43 | 44 | # get summary 45 | metrics = mm.metrics.motchallenge_metrics 46 | mh = mm.metrics.create() 47 | summary = Evaluator.get_summary(accs, seqs, metrics) 48 | strsummary = mm.io.render_summary( 49 | summary, 50 | formatters=mh.formatters, 51 | namemap=mm.io.motchallenge_metric_names 52 | ) 53 | print(strsummary) 54 | Evaluator.save_summary(summary, os.path.join(result_root, 'summary_global.xlsx')) 55 | 56 | 57 | def parse_args(): 58 | parser = argparse.ArgumentParser() 59 | parser.add_argument("--config_detection", type=str, default="./configs/yolov3.yaml") 60 | parser.add_argument("--config_deepsort", type=str, default="./configs/deep_sort.yaml") 61 | parser.add_argument("--ignore_display", dest="display", action="store_false", default=False) 62 | parser.add_argument("--frame_interval", type=int, default=1) 63 | parser.add_argument("--display_width", type=int, default=800) 64 | parser.add_argument("--display_height", type=int, default=600) 65 | parser.add_argument("--save_path", type=str, default="./demo/demo.avi") 66 | parser.add_argument("--cpu", dest="use_cuda", action="store_false", default=True) 67 | parser.add_argument("--camera", action="store", dest="cam", type=int, default="-1") 68 | return parser.parse_args() 69 | 70 | if __name__ == '__main__': 71 | args = parse_args() 72 | 73 | seqs_str = '''MOT16-02 74 | MOT16-04 75 | MOT16-05 76 | MOT16-09 77 | MOT16-10 78 | MOT16-11 79 | MOT16-13 80 | ''' 81 | data_root = 'data/dataset/MOT16/train/' 82 | 83 | seqs = [seq.strip() for seq in seqs_str.split()] 84 | 85 | main(data_root=data_root, 86 | seqs=seqs, 87 | args=args) --------------------------------------------------------------------------------