├── .idea
├── .gitignore
├── Yolov5_DeepSort_Pytorch.iml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── other.xml
├── vcs.xml
└── workspace.xml
├── LICENSE
├── README.md
├── Town.gif
├── __pycache__
└── track.cpython-38.pyc
├── app.py
├── camera1.py
├── deep_sort
├── .gitignore
├── LICENSE
├── README.md
├── configs
│ ├── deep_sort.yaml
│ ├── yolov3.yaml
│ └── yolov3_tiny.yaml
├── deep_sort
│ ├── README.md
│ ├── __init__.py
│ ├── deep
│ │ ├── __init__.py
│ │ ├── checkpoint
│ │ │ └── .gitkeep
│ │ ├── evaluate.py
│ │ ├── feature_extractor.py
│ │ ├── model.py
│ │ ├── original_model.py
│ │ ├── test.py
│ │ ├── train.jpg
│ │ └── train.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
├── demo
│ ├── 1.jpg
│ ├── 2.jpg
│ └── demo.gif
├── detector
│ ├── 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
│ └── __init__.py
├── ped_det_server.py
├── 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.py
└── yolov3_deepsort_eval.py
├── requirements.txt
├── templates
└── index.html
├── track.py
├── track_demo.py
└── yolov5
├── .dockerignore
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── --bug-report.md
│ ├── --feature-request.md
│ └── -question.md
└── workflows
│ ├── ci-testing.yml
│ ├── greetings.yml
│ ├── rebase.yml
│ └── stale.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── detect.py
├── hubconf.py
├── models
├── __init__.py
├── common.py
├── experimental.py
├── export.py
├── hub
│ ├── yolov3-spp.yaml
│ ├── yolov5-fpn.yaml
│ └── yolov5-panet.yaml
├── yolo.py
├── yolov5l.yaml
├── yolov5m.yaml
├── yolov5s.yaml
└── yolov5x.yaml
├── requirements.txt
├── test.py
├── train.py
├── tutorial.ipynb
├── utils
├── __init__.py
├── activations.py
├── datasets.py
├── evolve.sh
├── general.py
├── google_utils.py
└── torch_utils.py
└── weights
└── download_weights.sh
/.idea/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/.idea/.gitignore
--------------------------------------------------------------------------------
/.idea/Yolov5_DeepSort_Pytorch.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/other.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PyQt5_YoLoV5_DeepSort
2 |
3 |
4 | This is a PyQt5 GUI program, which is based on YoloV5 and DeepSort to track person, and give a warning when someone comes to the "dangerous area".
5 | =======
6 | This is a PyQt5 GUI program, which is based on YoloV5 and DeepSort to track person, and give a warning when someone comes to the "dangerous area".
7 |
--------------------------------------------------------------------------------
/Town.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/Town.gif
--------------------------------------------------------------------------------
/__pycache__/track.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/__pycache__/track.cpython-38.pyc
--------------------------------------------------------------------------------
/camera1.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: UTF-8 -*-
3 | import sys
4 | import cv2
5 | import torch
6 | from PyQt5 import QtCore, QtGui, QtWidgets
7 | from PyQt5.QtWidgets import *
8 | from track import detect
9 |
10 |
11 | class Ui_MainWindow(QtWidgets.QWidget):
12 | def __init__(self, parent=None):
13 | super(Ui_MainWindow, self).__init__(parent)
14 | self.CAM_NUM = 1
15 | self.timer_camera = QtCore.QTimer()
16 | self.s_rtsp = "rtsp://iscas:opqwer12@192.168.100.176:554/Streaming/Channels/101"
17 | self.cap = cv2.VideoCapture()
18 |
19 | self.set_ui()
20 | self.slot_init()
21 | self.__flag_work = 0
22 | self.x = 0
23 | self.count = 0
24 |
25 | def set_ui(self):
26 |
27 | self.__layout_main = QtWidgets.QHBoxLayout()
28 | self.__layout_fun_button = QtWidgets.QVBoxLayout()
29 | self.__layout_data_show = QtWidgets.QVBoxLayout()
30 |
31 | self.button_open_camera = QtWidgets.QPushButton(u'打开相机')
32 |
33 | self.button_detect = QtWidgets.QPushButton(u'开始检测')
34 |
35 | self.button_close = QtWidgets.QPushButton(u'退出')
36 |
37 | # Button 的颜色修改
38 | button_color = [self.button_open_camera, self.button_detect, self.button_close]
39 | for i in range(len(button_color)):
40 | button_color[i].setStyleSheet("QPushButton{color:black}"
41 | "QPushButton:hover{color:red}"
42 | "QPushButton{background-color:rgb(78,255,255)}"
43 | "QPushButton{border:2px}"
44 | "QPushButton{border-radius:10px}"
45 | "QPushButton{padding:2px 4px}")
46 |
47 | self.button_open_camera.setMinimumHeight(50)
48 | self.button_detect.setMinimumHeight(50)
49 | self.button_close.setMinimumHeight(50)
50 |
51 | # move()方法移动窗口在屏幕上的位置到x = 300,y = 300坐标。
52 | self.move(500, 500)
53 |
54 | # 信息显示
55 | self.label_show_camera = QtWidgets.QLabel()
56 | self.label_move = QtWidgets.QLabel()
57 | self.label_move.setFixedSize(100, 100)
58 |
59 | self.label_show_camera.setFixedSize(700, 600)
60 | self.label_show_camera.setAutoFillBackground(False)
61 |
62 | self.__layout_fun_button.addWidget(self.button_open_camera)
63 | self.__layout_fun_button.addWidget(self.button_detect)
64 | self.__layout_fun_button.addWidget(self.button_close)
65 | self.__layout_fun_button.addWidget(self.label_move)
66 |
67 | self.__layout_main.addLayout(self.__layout_fun_button)
68 | self.__layout_main.addWidget(self.label_show_camera)
69 |
70 | self.setLayout(self.__layout_main)
71 | self.label_move.raise_()
72 | self.setWindowTitle(u'摄像头')
73 |
74 | # 设置背景图片
75 | # palette1 = QPalette()
76 | # palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('1.png')))
77 | # self.setPalette(palette1)
78 |
79 | def slot_init(self):
80 | self.button_open_camera.clicked.connect(self.button_open_camera_click)
81 | self.timer_camera.timeout.connect(self.show_camera)
82 | self.button_close.clicked.connect(self.close)
83 | # self.button_detect.clicked.connect(self.button_detect_click)
84 |
85 | def button_detect_click(self):
86 | pass
87 |
88 | def button_open_camera_click(self):
89 | if not self.timer_camera.isActive():
90 | flag = self.cap.open(self.s_rtsp)
91 | # flag = self.cap.isOpened()
92 | if not flag:
93 | msg = QtWidgets.QMessageBox.warning(self, u"Warning", u"请检测相机与电脑是否连接正确",
94 | buttons=QtWidgets.QMessageBox.Ok,
95 | defaultButton=QtWidgets.QMessageBox.Ok)
96 | # if msg==QtGui.QMessageBox.Cancel:
97 | # pass
98 | else:
99 | self.timer_camera.start(30)
100 |
101 | self.button_open_camera.setText(u'关闭相机')
102 | else:
103 | self.timer_camera.stop()
104 | self.cap.release()
105 | self.label_show_camera.clear()
106 | self.button_open_camera.setText(u'打开相机')
107 |
108 | def show_camera(self):
109 | flag, image = self.cap.read()
110 |
111 | show = cv2.resize(image, (640, 480))
112 | show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
113 |
114 | showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
115 | self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage))
116 |
117 | def closeEvent(self, event):
118 | ok = QtWidgets.QPushButton()
119 | cacel = QtWidgets.QPushButton()
120 |
121 | msg = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning, u"关闭", u"确定退出?")
122 |
123 | msg.addButton(ok, QtWidgets.QMessageBox.ActionRole)
124 | msg.addButton(cacel, QtWidgets.QMessageBox.RejectRole)
125 | ok.setText(u'确定')
126 | cacel.setText(u'取消')
127 | # msg.setDetailedText('sdfsdff')
128 | if msg.exec_() == QtWidgets.QMessageBox.RejectRole:
129 | event.ignore()
130 | else:
131 | # self.socket_client.send_command(self.socket_client.current_user_command)
132 | if self.cap.isOpened():
133 | self.cap.release()
134 | if self.timer_camera.isActive():
135 | self.timer_camera.stop()
136 | event.accept()
137 |
138 |
139 | if __name__ == "__main__":
140 | App = QApplication(sys.argv)
141 | ex = Ui_MainWindow()
142 | ex.show()
143 | sys.exit(App.exec_())
144 |
--------------------------------------------------------------------------------
/deep_sort/.gitignore:
--------------------------------------------------------------------------------
1 | # Folders
2 | __pycache__/
3 | build/
4 | *.egg-info
5 |
6 |
7 | # Files
8 | *.weights
9 | *.t7
10 | *.mp4
11 | *.avi
12 | *.so
13 | *.txt
14 |
--------------------------------------------------------------------------------
/deep_sort/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.
--------------------------------------------------------------------------------
/deep_sort/README.md:
--------------------------------------------------------------------------------
1 | # Deep Sort with PyTorch
2 |
3 | 
4 |
5 | ## Update(1-1-2020)
6 | Changes
7 | - fix bugs
8 | - refactor code
9 | - accerate detection by adding nms on gpu
10 |
11 | ## Latest Update(07-22)
12 | Changes
13 | - bug fix (Thanks @JieChen91 and @yingsen1 for bug reporting).
14 | - using batch for feature extracting for each frame, which lead to a small speed up.
15 | - code improvement.
16 |
17 | Futher improvement direction
18 | - Train detector on specific dataset rather than the official one.
19 | - Retrain REID model on pedestrain dataset for better performance.
20 | - Replace YOLOv3 detector with advanced ones.
21 |
22 | **Any contributions to this repository is welcome!**
23 |
24 |
25 | ## Introduction
26 | This is an implement of MOT tracking algorithm deep sort. Deep sort is basicly the same with sort but added a CNN model to extract features in image of human part bounded by a detector. This CNN model is indeed a RE-ID model and the detector used in [PAPER](https://arxiv.org/abs/1703.07402) is FasterRCNN , and the original source code is [HERE](https://github.com/nwojke/deep_sort).
27 | However in original code, the CNN model is implemented with tensorflow, which I'm not familier with. SO I re-implemented the CNN feature extraction model with PyTorch, and changed the CNN model a little bit. Also, I use **YOLOv3** to generate bboxes instead of FasterRCNN.
28 |
29 | ## Dependencies
30 | - python 3 (python2 not sure)
31 | - numpy
32 | - scipy
33 | - opencv-python
34 | - sklearn
35 | - torch >= 0.4
36 | - torchvision >= 0.1
37 | - pillow
38 | - vizer
39 | - edict
40 |
41 | ## Quick Start
42 | 0. Check all dependencies installed
43 | ```bash
44 | pip install -r requirements.txt
45 | ```
46 | for user in china, you can specify pypi source to accelerate install like:
47 | ```bash
48 | pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
49 | ```
50 |
51 | 1. Clone this repository
52 | ```
53 | git clone git@github.com:ZQPei/deep_sort_pytorch.git
54 | ```
55 |
56 | 2. Download YOLOv3 parameters
57 | ```
58 | cd detector/YOLOv3/weight/
59 | wget https://pjreddie.com/media/files/yolov3.weights
60 | wget https://pjreddie.com/media/files/yolov3-tiny.weights
61 | cd ../../../
62 | ```
63 |
64 | 3. Download deepsort parameters ckpt.t7
65 | ```
66 | cd deep_sort/deep/checkpoint
67 | # download ckpt.t7 from
68 | https://drive.google.com/drive/folders/1xhG0kRH1EX5B9_Iz8gQJb7UNnn_riXi6 to this folder
69 | cd ../../../
70 | ```
71 |
72 | 4. Compile nms module
73 | ```bash
74 | cd detector/YOLOv3/nms
75 | sh build.sh
76 | cd ../../..
77 | ```
78 |
79 | Notice:
80 | If compiling failed, the simplist way is to **Upgrade your pytorch >= 1.1 and torchvision >= 0.3" and you can avoid the troublesome compiling problems which are most likely caused by either `gcc version too low` or `libraries missing`.
81 |
82 | 5. Run demo
83 | ```
84 | usage: python yolov3_deepsort.py VIDEO_PATH
85 | [--help]
86 | [--frame_interval FRAME_INTERVAL]
87 | [--config_detection CONFIG_DETECTION]
88 | [--config_deepsort CONFIG_DEEPSORT]
89 | [--display]
90 | [--display_width DISPLAY_WIDTH]
91 | [--display_height DISPLAY_HEIGHT]
92 | [--save_path SAVE_PATH]
93 | [--cpu]
94 |
95 | # yolov3 + deepsort
96 | python yolov3_deepsort.py [VIDEO_PATH]
97 |
98 | # yolov3_tiny + deepsort
99 | python yolov3_deepsort.py [VIDEO_PATH] --config_detection ./configs/yolov3_tiny.yaml
100 |
101 | # yolov3 + deepsort on webcam
102 | python3 yolov3_deepsort.py /dev/video0 --camera 0
103 |
104 | # yolov3_tiny + deepsort on webcam
105 | python3 yolov3_deepsort.py /dev/video0 --config_detection ./configs/yolov3_tiny.yaml --camera 0
106 | ```
107 | Use `--display` to enable display.
108 | Results will be saved to `./output/results.avi` and `./output/results.txt`.
109 |
110 | All files above can also be accessed from BaiduDisk!
111 | linker:[BaiduDisk](https://pan.baidu.com/s/1YJ1iPpdFTlUyLFoonYvozg)
112 | passwd:fbuw
113 |
114 | ## Training the RE-ID model
115 | The original model used in paper is in original_model.py, and its parameter here [original_ckpt.t7](https://drive.google.com/drive/folders/1xhG0kRH1EX5B9_Iz8gQJb7UNnn_riXi6).
116 |
117 | 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.
118 |
119 | Then you can try [train.py](deep_sort/deep/train.py) to train your own parameter and evaluate it using [test.py](deep_sort/deep/test.py) and [evaluate.py](deep_sort/deep/evalute.py).
120 | 
121 |
122 | ## Demo videos and images
123 | [demo.avi](https://drive.google.com/drive/folders/1xhG0kRH1EX5B9_Iz8gQJb7UNnn_riXi6)
124 | [demo2.avi](https://drive.google.com/drive/folders/1xhG0kRH1EX5B9_Iz8gQJb7UNnn_riXi6)
125 |
126 | 
127 | 
128 |
129 |
130 | ## References
131 | - paper: [Simple Online and Realtime Tracking with a Deep Association Metric](https://arxiv.org/abs/1703.07402)
132 |
133 | - code: [nwojke/deep_sort](https://github.com/nwojke/deep_sort)
134 |
135 | - paper: [YOLOv3](https://pjreddie.com/media/files/papers/YOLOv3.pdf)
136 |
137 | - code: [Joseph Redmon/yolov3](https://pjreddie.com/darknet/yolo/)
138 |
--------------------------------------------------------------------------------
/deep_sort/configs/deep_sort.yaml:
--------------------------------------------------------------------------------
1 | DEEPSORT:
2 | REID_CKPT: "deep_sort/deep_sort/deep/checkpoint/ckpt.t7"
3 | MAX_DIST: 0.2
4 | MIN_CONFIDENCE: 0.3
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 |
11 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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
--------------------------------------------------------------------------------
/deep_sort/deep_sort/README.md:
--------------------------------------------------------------------------------
1 | # Deep Sort
2 |
3 | This is the implemention of deep sort with pytorch.
--------------------------------------------------------------------------------
/deep_sort/deep_sort/__init__.py:
--------------------------------------------------------------------------------
1 | from .deep_sort import DeepSort
2 |
3 |
4 | __all__ = ['DeepSort', 'build_tracker']
5 |
6 |
7 | def build_tracker(cfg, use_cuda):
8 | return DeepSort(cfg.DEEPSORT.REID_CKPT,
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, use_cuda=use_cuda)
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/deep_sort/deep_sort/deep/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/deep_sort/deep/__init__.py
--------------------------------------------------------------------------------
/deep_sort/deep_sort/deep/checkpoint/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/deep_sort/deep/checkpoint/.gitkeep
--------------------------------------------------------------------------------
/deep_sort/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_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 |
9 | class Extractor(object):
10 | def __init__(self, model_path, use_cuda=True):
11 | self.net = Net(reid=True)
12 | self.device = "cuda" if torch.cuda.is_available() and use_cuda else "cpu"
13 | state_dict = torch.load(model_path, map_location=lambda storage, loc: storage)['net_dict']
14 | self.net.load_state_dict(state_dict)
15 | logger = logging.getLogger("root.tracker")
16 | logger.info("Loading weights from {}... Done!".format(model_path))
17 | self.net.to(self.device)
18 | self.size = (64, 128)
19 | self.norm = transforms.Compose([
20 | transforms.ToTensor(),
21 | transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
22 | ])
23 |
24 |
25 |
26 | def _preprocess(self, im_crops):
27 | """
28 | TODO:
29 | 1. to float with scale from 0 to 1
30 | 2. resize to (64, 128) as Market1501 dataset did
31 | 3. concatenate to a numpy array
32 | 3. to torch Tensor
33 | 4. normalize
34 | """
35 | def _resize(im, size):
36 | return cv2.resize(im.astype(np.float32)/255., size)
37 |
38 | im_batch = torch.cat([self.norm(_resize(im, self.size)).unsqueeze(0) for im in im_crops], dim=0).float()
39 | return im_batch
40 |
41 |
42 | def __call__(self, im_crops):
43 | im_batch = self._preprocess(im_crops)
44 | with torch.no_grad():
45 | im_batch = im_batch.to(self.device)
46 | features = self.net(im_batch)
47 | return features.cpu().numpy()
48 |
49 |
50 | if __name__ == '__main__':
51 | img = cv2.imread("demo.jpg")[:,:,(2,1,0)]
52 | extr = Extractor("checkpoint/ckpt.t7")
53 | feature = extr(img)
54 | print(feature.shape)
55 |
56 |
--------------------------------------------------------------------------------
/deep_sort/deep_sort/deep/model.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn as nn
3 | import torch.nn.functional as F
4 |
5 | class BasicBlock(nn.Module):
6 | def __init__(self, c_in, c_out,is_downsample=False):
7 | super(BasicBlock,self).__init__()
8 | self.is_downsample = is_downsample
9 | if is_downsample:
10 | self.conv1 = nn.Conv2d(c_in, c_out, 3, stride=2, padding=1, bias=False)
11 | else:
12 | self.conv1 = nn.Conv2d(c_in, c_out, 3, stride=1, padding=1, bias=False)
13 | self.bn1 = nn.BatchNorm2d(c_out)
14 | self.relu = nn.ReLU(True)
15 | self.conv2 = nn.Conv2d(c_out,c_out,3,stride=1,padding=1, bias=False)
16 | self.bn2 = nn.BatchNorm2d(c_out)
17 | if is_downsample:
18 | self.downsample = nn.Sequential(
19 | nn.Conv2d(c_in, c_out, 1, stride=2, bias=False),
20 | nn.BatchNorm2d(c_out)
21 | )
22 | elif c_in != c_out:
23 | self.downsample = nn.Sequential(
24 | nn.Conv2d(c_in, c_out, 1, stride=1, bias=False),
25 | nn.BatchNorm2d(c_out)
26 | )
27 | self.is_downsample = True
28 |
29 | def forward(self,x):
30 | y = self.conv1(x)
31 | y = self.bn1(y)
32 | y = self.relu(y)
33 | y = self.conv2(y)
34 | y = self.bn2(y)
35 | if self.is_downsample:
36 | x = self.downsample(x)
37 | return F.relu(x.add(y),True)
38 |
39 | def make_layers(c_in,c_out,repeat_times, is_downsample=False):
40 | blocks = []
41 | for i in range(repeat_times):
42 | if i ==0:
43 | blocks += [BasicBlock(c_in,c_out, is_downsample=is_downsample),]
44 | else:
45 | blocks += [BasicBlock(c_out,c_out),]
46 | return nn.Sequential(*blocks)
47 |
48 | class Net(nn.Module):
49 | def __init__(self, num_classes=751 ,reid=False):
50 | super(Net,self).__init__()
51 | # 3 128 64
52 | self.conv = nn.Sequential(
53 | nn.Conv2d(3,64,3,stride=1,padding=1),
54 | nn.BatchNorm2d(64),
55 | nn.ReLU(inplace=True),
56 | # nn.Conv2d(32,32,3,stride=1,padding=1),
57 | # nn.BatchNorm2d(32),
58 | # nn.ReLU(inplace=True),
59 | nn.MaxPool2d(3,2,padding=1),
60 | )
61 | # 32 64 32
62 | self.layer1 = make_layers(64,64,2,False)
63 | # 32 64 32
64 | self.layer2 = make_layers(64,128,2,True)
65 | # 64 32 16
66 | self.layer3 = make_layers(128,256,2,True)
67 | # 128 16 8
68 | self.layer4 = make_layers(256,512,2,True)
69 | # 256 8 4
70 | self.avgpool = nn.AvgPool2d((8,4),1)
71 | # 256 1 1
72 | self.reid = reid
73 | self.classifier = nn.Sequential(
74 | nn.Linear(512, 256),
75 | nn.BatchNorm1d(256),
76 | nn.ReLU(inplace=True),
77 | nn.Dropout(),
78 | nn.Linear(256, num_classes),
79 | )
80 |
81 | def forward(self, x):
82 | x = self.conv(x)
83 | x = self.layer1(x)
84 | x = self.layer2(x)
85 | x = self.layer3(x)
86 | x = self.layer4(x)
87 | x = self.avgpool(x)
88 | x = x.view(x.size(0),-1)
89 | # B x 128
90 | if self.reid:
91 | x = x.div(x.norm(p=2,dim=1,keepdim=True))
92 | return x
93 | # classifier
94 | x = self.classifier(x)
95 | return x
96 |
97 |
98 | if __name__ == '__main__':
99 | net = Net()
100 | x = torch.randn(4,3,128,64)
101 | y = net(x)
102 | import ipdb; ipdb.set_trace()
103 |
104 |
105 |
--------------------------------------------------------------------------------
/deep_sort/deep_sort/deep/original_model.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn as nn
3 | import torch.nn.functional as F
4 |
5 | class BasicBlock(nn.Module):
6 | def __init__(self, c_in, c_out,is_downsample=False):
7 | super(BasicBlock,self).__init__()
8 | self.is_downsample = is_downsample
9 | if is_downsample:
10 | self.conv1 = nn.Conv2d(c_in, c_out, 3, stride=2, padding=1, bias=False)
11 | else:
12 | self.conv1 = nn.Conv2d(c_in, c_out, 3, stride=1, padding=1, bias=False)
13 | self.bn1 = nn.BatchNorm2d(c_out)
14 | self.relu = nn.ReLU(True)
15 | self.conv2 = nn.Conv2d(c_out,c_out,3,stride=1,padding=1, bias=False)
16 | self.bn2 = nn.BatchNorm2d(c_out)
17 | if is_downsample:
18 | self.downsample = nn.Sequential(
19 | nn.Conv2d(c_in, c_out, 1, stride=2, bias=False),
20 | nn.BatchNorm2d(c_out)
21 | )
22 | elif c_in != c_out:
23 | self.downsample = nn.Sequential(
24 | nn.Conv2d(c_in, c_out, 1, stride=1, bias=False),
25 | nn.BatchNorm2d(c_out)
26 | )
27 | self.is_downsample = True
28 |
29 | def forward(self,x):
30 | y = self.conv1(x)
31 | y = self.bn1(y)
32 | y = self.relu(y)
33 | y = self.conv2(y)
34 | y = self.bn2(y)
35 | if self.is_downsample:
36 | x = self.downsample(x)
37 | return F.relu(x.add(y),True)
38 |
39 | def make_layers(c_in,c_out,repeat_times, is_downsample=False):
40 | blocks = []
41 | for i in range(repeat_times):
42 | if i ==0:
43 | blocks += [BasicBlock(c_in,c_out, is_downsample=is_downsample),]
44 | else:
45 | blocks += [BasicBlock(c_out,c_out),]
46 | return nn.Sequential(*blocks)
47 |
48 | class Net(nn.Module):
49 | def __init__(self, num_classes=625 ,reid=False):
50 | super(Net,self).__init__()
51 | # 3 128 64
52 | self.conv = nn.Sequential(
53 | nn.Conv2d(3,32,3,stride=1,padding=1),
54 | nn.BatchNorm2d(32),
55 | nn.ELU(inplace=True),
56 | nn.Conv2d(32,32,3,stride=1,padding=1),
57 | nn.BatchNorm2d(32),
58 | nn.ELU(inplace=True),
59 | nn.MaxPool2d(3,2,padding=1),
60 | )
61 | # 32 64 32
62 | self.layer1 = make_layers(32,32,2,False)
63 | # 32 64 32
64 | self.layer2 = make_layers(32,64,2,True)
65 | # 64 32 16
66 | self.layer3 = make_layers(64,128,2,True)
67 | # 128 16 8
68 | self.dense = nn.Sequential(
69 | nn.Dropout(p=0.6),
70 | nn.Linear(128*16*8, 128),
71 | nn.BatchNorm1d(128),
72 | nn.ELU(inplace=True)
73 | )
74 | # 256 1 1
75 | self.reid = reid
76 | self.batch_norm = nn.BatchNorm1d(128)
77 | self.classifier = nn.Sequential(
78 | nn.Linear(128, num_classes),
79 | )
80 |
81 | def forward(self, x):
82 | x = self.conv(x)
83 | x = self.layer1(x)
84 | x = self.layer2(x)
85 | x = self.layer3(x)
86 |
87 | x = x.view(x.size(0),-1)
88 | if self.reid:
89 | x = self.dense[0](x)
90 | x = self.dense[1](x)
91 | x = x.div(x.norm(p=2,dim=1,keepdim=True))
92 | return x
93 | x = self.dense(x)
94 | # B x 128
95 | # classifier
96 | x = self.classifier(x)
97 | return x
98 |
99 |
100 | if __name__ == '__main__':
101 | net = Net(reid=True)
102 | x = torch.randn(4,3,128,64)
103 | y = net(x)
104 | import ipdb; ipdb.set_trace()
105 |
106 |
107 |
--------------------------------------------------------------------------------
/deep_sort/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.datasets.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")
--------------------------------------------------------------------------------
/deep_sort/deep_sort/deep/train.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/deep_sort/deep/train.jpg
--------------------------------------------------------------------------------
/deep_sort/deep_sort/deep_sort.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import torch
3 |
4 | from .deep.feature_extractor import Extractor
5 | from .sort.nn_matching import NearestNeighborDistanceMetric
6 | from .sort.preprocessing import non_max_suppression
7 | from .sort.detection import Detection
8 | from .sort.tracker import Tracker
9 |
10 |
11 | __all__ = ['DeepSort']
12 |
13 |
14 | class DeepSort(object):
15 | def __init__(self, model_path, max_dist=0.2, min_confidence=0.3, nms_max_overlap=1.0, max_iou_distance=0.7, max_age=70, n_init=3, nn_budget=100, use_cuda=True):
16 | self.min_confidence = min_confidence
17 | self.nms_max_overlap = nms_max_overlap
18 |
19 | self.extractor = Extractor(model_path, use_cuda=use_cuda)
20 |
21 | max_cosine_distance = max_dist
22 | nn_budget = 100
23 | metric = NearestNeighborDistanceMetric("cosine", max_cosine_distance, nn_budget)
24 | self.tracker = Tracker(metric, max_iou_distance=max_iou_distance, max_age=max_age, n_init=n_init)
25 |
26 | def update(self, bbox_xywh, confidences, ori_img):
27 | self.height, self.width = ori_img.shape[:2]
28 | # generate detections
29 | features = self._get_features(bbox_xywh, ori_img)
30 | bbox_tlwh = self._xywh_to_tlwh(bbox_xywh)
31 | detections = [Detection(bbox_tlwh[i], conf, features[i]) for i,conf in enumerate(confidences) if conf>self.min_confidence]
32 |
33 | # run on non-maximum supression
34 | boxes = np.array([d.tlwh for d in detections])
35 | scores = np.array([d.confidence for d in detections])
36 | indices = non_max_suppression(boxes, self.nms_max_overlap, scores)
37 | detections = [detections[i] for i in indices]
38 |
39 | # update tracker
40 | self.tracker.predict()
41 | self.tracker.update(detections)
42 |
43 | # output bbox identities
44 | outputs = []
45 | for track in self.tracker.tracks:
46 | if not track.is_confirmed() or track.time_since_update > 1:
47 | continue
48 | box = track.to_tlwh()
49 | x1,y1,x2,y2 = self._tlwh_to_xyxy(box)
50 | track_id = track.track_id
51 | outputs.append(np.array([x1,y1,x2,y2,track_id], dtype=np.int))
52 | if len(outputs) > 0:
53 | outputs = np.stack(outputs,axis=0)
54 | return outputs
55 |
56 |
57 | """
58 | TODO:
59 | Convert bbox from xc_yc_w_h to xtl_ytl_w_h
60 | Thanks JieChen91@github.com for reporting this bug!
61 | """
62 | @staticmethod
63 | def _xywh_to_tlwh(bbox_xywh):
64 | if isinstance(bbox_xywh, np.ndarray):
65 | bbox_tlwh = bbox_xywh.copy()
66 | elif isinstance(bbox_xywh, torch.Tensor):
67 | bbox_tlwh = bbox_xywh.clone()
68 | bbox_tlwh[:,0] = bbox_xywh[:,0] - bbox_xywh[:,2]/2.
69 | bbox_tlwh[:,1] = bbox_xywh[:,1] - bbox_xywh[:,3]/2.
70 | return bbox_tlwh
71 |
72 |
73 | def _xywh_to_xyxy(self, bbox_xywh):
74 | x,y,w,h = bbox_xywh
75 | x1 = max(int(x-w/2),0)
76 | x2 = min(int(x+w/2),self.width-1)
77 | y1 = max(int(y-h/2),0)
78 | y2 = min(int(y+h/2),self.height-1)
79 | return x1,y1,x2,y2
80 |
81 | def _tlwh_to_xyxy(self, bbox_tlwh):
82 | """
83 | TODO:
84 | Convert bbox from xtl_ytl_w_h to xc_yc_w_h
85 | Thanks JieChen91@github.com for reporting this bug!
86 | """
87 | x,y,w,h = bbox_tlwh
88 | x1 = max(int(x),0)
89 | x2 = min(int(x+w),self.width-1)
90 | y1 = max(int(y),0)
91 | y2 = min(int(y+h),self.height-1)
92 | return x1,y1,x2,y2
93 |
94 | def _xyxy_to_tlwh(self, bbox_xyxy):
95 | x1,y1,x2,y2 = bbox_xyxy
96 |
97 | t = x1
98 | l = y1
99 | w = int(x2-x1)
100 | h = int(y2-y1)
101 | return t,l,w,h
102 |
103 | def _get_features(self, bbox_xywh, ori_img):
104 | im_crops = []
105 | for box in bbox_xywh:
106 | x1,y1,x2,y2 = self._xywh_to_xyxy(box)
107 | im = ori_img[y1:y2,x1:x2]
108 | im_crops.append(im)
109 | if im_crops:
110 | features = self.extractor(im_crops)
111 | else:
112 | features = np.array([])
113 | return features
114 |
115 |
116 |
--------------------------------------------------------------------------------
/deep_sort/deep_sort/sort/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/deep_sort/sort/__init__.py
--------------------------------------------------------------------------------
/deep_sort/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, feature):
30 | self.tlwh = np.asarray(tlwh, dtype=np.float)
31 | self.confidence = float(confidence)
32 | self.feature = np.asarray(feature, dtype=np.float32)
33 |
34 | def to_tlbr(self):
35 | """Convert bounding box to format `(min x, min y, max x, max y)`, i.e.,
36 | `(top left, bottom right)`.
37 | """
38 | ret = self.tlwh.copy()
39 | ret[2:] += ret[:2]
40 | return ret
41 |
42 | def to_xyah(self):
43 | """Convert bounding box to format `(center x, center y, aspect ratio,
44 | height)`, where the aspect ratio is `width / height`.
45 | """
46 | ret = self.tlwh.copy()
47 | ret[:2] += ret[2:] / 2
48 | ret[2] /= ret[3]
49 | return ret
50 |
--------------------------------------------------------------------------------
/deep_sort/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/deep_sort/sort/nn_matching.py:
--------------------------------------------------------------------------------
1 | # vim: expandtab:ts=4:sw=4
2 | import numpy as np
3 |
4 |
5 | def _pdist(a, b):
6 | """Compute pair-wise squared distance between points in `a` and `b`.
7 |
8 | Parameters
9 | ----------
10 | a : array_like
11 | An NxM matrix of N samples of dimensionality M.
12 | b : array_like
13 | An LxM matrix of L samples of dimensionality M.
14 |
15 | Returns
16 | -------
17 | ndarray
18 | Returns a matrix of size len(a), len(b) such that eleement (i, j)
19 | contains the squared distance between `a[i]` and `b[j]`.
20 |
21 | """
22 | a, b = np.asarray(a), np.asarray(b)
23 | if len(a) == 0 or len(b) == 0:
24 | return np.zeros((len(a), len(b)))
25 | a2, b2 = np.square(a).sum(axis=1), np.square(b).sum(axis=1)
26 | r2 = -2. * np.dot(a, b.T) + a2[:, None] + b2[None, :]
27 | r2 = np.clip(r2, 0., float(np.inf))
28 | return r2
29 |
30 |
31 | def _cosine_distance(a, b, data_is_normalized=False):
32 | """Compute pair-wise cosine distance between points in `a` and `b`.
33 |
34 | Parameters
35 | ----------
36 | a : array_like
37 | An NxM matrix of N samples of dimensionality M.
38 | b : array_like
39 | An LxM matrix of L samples of dimensionality M.
40 | data_is_normalized : Optional[bool]
41 | If True, assumes rows in a and b are unit length vectors.
42 | Otherwise, a and b are explicitly normalized to lenght 1.
43 |
44 | Returns
45 | -------
46 | ndarray
47 | Returns a matrix of size len(a), len(b) such that eleement (i, j)
48 | contains the squared distance between `a[i]` and `b[j]`.
49 |
50 | """
51 | if not data_is_normalized:
52 | a = np.asarray(a) / np.linalg.norm(a, axis=1, keepdims=True)
53 | b = np.asarray(b) / np.linalg.norm(b, axis=1, keepdims=True)
54 | return 1. - np.dot(a, b.T)
55 |
56 |
57 | def _nn_euclidean_distance(x, y):
58 | """ Helper function for nearest neighbor distance metric (Euclidean).
59 |
60 | Parameters
61 | ----------
62 | x : ndarray
63 | A matrix of N row-vectors (sample points).
64 | y : ndarray
65 | A matrix of M row-vectors (query points).
66 |
67 | Returns
68 | -------
69 | ndarray
70 | A vector of length M that contains for each entry in `y` the
71 | smallest Euclidean distance to a sample in `x`.
72 |
73 | """
74 | distances = _pdist(x, y)
75 | return np.maximum(0.0, distances.min(axis=0))
76 |
77 |
78 | def _nn_cosine_distance(x, y):
79 | """ Helper function for nearest neighbor distance metric (cosine).
80 |
81 | Parameters
82 | ----------
83 | x : ndarray
84 | A matrix of N row-vectors (sample points).
85 | y : ndarray
86 | A matrix of M row-vectors (query points).
87 |
88 | Returns
89 | -------
90 | ndarray
91 | A vector of length M that contains for each entry in `y` the
92 | smallest cosine distance to a sample in `x`.
93 |
94 | """
95 | distances = _cosine_distance(x, y)
96 | return distances.min(axis=0)
97 |
98 |
99 | class NearestNeighborDistanceMetric(object):
100 | """
101 | A nearest neighbor distance metric that, for each target, returns
102 | the closest distance to any sample that has been observed so far.
103 |
104 | Parameters
105 | ----------
106 | metric : str
107 | Either "euclidean" or "cosine".
108 | matching_threshold: float
109 | The matching threshold. Samples with larger distance are considered an
110 | invalid match.
111 | budget : Optional[int]
112 | If not None, fix samples per class to at most this number. Removes
113 | the oldest samples when the budget is reached.
114 |
115 | Attributes
116 | ----------
117 | samples : Dict[int -> List[ndarray]]
118 | A dictionary that maps from target identities to the list of samples
119 | that have been observed so far.
120 |
121 | """
122 |
123 | def __init__(self, metric, matching_threshold, budget=None):
124 |
125 |
126 | if metric == "euclidean":
127 | self._metric = _nn_euclidean_distance
128 | elif metric == "cosine":
129 | self._metric = _nn_cosine_distance
130 | else:
131 | raise ValueError(
132 | "Invalid metric; must be either 'euclidean' or 'cosine'")
133 | self.matching_threshold = matching_threshold
134 | self.budget = budget
135 | self.samples = {}
136 |
137 | def partial_fit(self, features, targets, active_targets):
138 | """Update the distance metric with new data.
139 |
140 | Parameters
141 | ----------
142 | features : ndarray
143 | An NxM matrix of N features of dimensionality M.
144 | targets : ndarray
145 | An integer array of associated target identities.
146 | active_targets : List[int]
147 | A list of targets that are currently present in the scene.
148 |
149 | """
150 | for feature, target in zip(features, targets):
151 | self.samples.setdefault(target, []).append(feature)
152 | if self.budget is not None:
153 | self.samples[target] = self.samples[target][-self.budget:]
154 | self.samples = {k: self.samples[k] for k in active_targets}
155 |
156 | def distance(self, features, targets):
157 | """Compute distance between features and targets.
158 |
159 | Parameters
160 | ----------
161 | features : ndarray
162 | An NxM matrix of N features of dimensionality M.
163 | targets : List[int]
164 | A list of targets to match the given `features` against.
165 |
166 | Returns
167 | -------
168 | ndarray
169 | Returns a cost matrix of shape len(targets), len(features), where
170 | element (i, j) contains the closest squared distance between
171 | `targets[i]` and `features[j]`.
172 |
173 | """
174 | cost_matrix = np.zeros((len(targets), len(features)))
175 | for i, target in enumerate(targets):
176 | cost_matrix[i, :] = self._metric(self.samples[target], features)
177 | return cost_matrix
178 |
--------------------------------------------------------------------------------
/deep_sort/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.float)
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]]
68 |
69 | idxs = np.delete(
70 | idxs, np.concatenate(
71 | ([last], np.where(overlap > max_bbox_overlap)[0])))
72 |
73 | return pick
74 |
--------------------------------------------------------------------------------
/deep_sort/deep_sort/sort/track.py:
--------------------------------------------------------------------------------
1 | # vim: expandtab:ts=4:sw=4
2 |
3 |
4 | class TrackState:
5 | """
6 | Enumeration type for the single target track state. Newly created tracks are
7 | classified as `tentative` until enough evidence has been collected. Then,
8 | the track state is changed to `confirmed`. Tracks that are no longer alive
9 | are classified as `deleted` to mark them for removal from the set of active
10 | tracks.
11 |
12 | """
13 |
14 | Tentative = 1
15 | Confirmed = 2
16 | Deleted = 3
17 |
18 |
19 | class Track:
20 | """
21 | A single target track with state space `(x, y, a, h)` and associated
22 | velocities, where `(x, y)` is the center of the bounding box, `a` is the
23 | aspect ratio and `h` is the height.
24 |
25 | Parameters
26 | ----------
27 | mean : ndarray
28 | Mean vector of the initial state distribution.
29 | covariance : ndarray
30 | Covariance matrix of the initial state distribution.
31 | track_id : int
32 | A unique track identifier.
33 | n_init : int
34 | Number of consecutive detections before the track is confirmed. The
35 | track state is set to `Deleted` if a miss occurs within the first
36 | `n_init` frames.
37 | max_age : int
38 | The maximum number of consecutive misses before the track state is
39 | set to `Deleted`.
40 | feature : Optional[ndarray]
41 | Feature vector of the detection this track originates from. If not None,
42 | this feature is added to the `features` cache.
43 |
44 | Attributes
45 | ----------
46 | mean : ndarray
47 | Mean vector of the initial state distribution.
48 | covariance : ndarray
49 | Covariance matrix of the initial state distribution.
50 | track_id : int
51 | A unique track identifier.
52 | hits : int
53 | Total number of measurement updates.
54 | age : int
55 | Total number of frames since first occurance.
56 | time_since_update : int
57 | Total number of frames since last measurement update.
58 | state : TrackState
59 | The current track state.
60 | features : List[ndarray]
61 | A cache of features. On each measurement update, the associated feature
62 | vector is added to this list.
63 |
64 | """
65 |
66 | def __init__(self, mean, covariance, track_id, n_init, max_age,
67 | feature=None):
68 | self.mean = mean
69 | self.covariance = covariance
70 | self.track_id = track_id
71 | self.hits = 1
72 | self.age = 1
73 | self.time_since_update = 0
74 |
75 | self.state = TrackState.Tentative
76 | self.features = []
77 | if feature is not None:
78 | self.features.append(feature)
79 |
80 | self._n_init = n_init
81 | self._max_age = max_age
82 |
83 | def to_tlwh(self):
84 | """Get current position in bounding box format `(top left x, top left y,
85 | width, height)`.
86 |
87 | Returns
88 | -------
89 | ndarray
90 | The bounding box.
91 |
92 | """
93 | ret = self.mean[:4].copy()
94 | ret[2] *= ret[3]
95 | ret[:2] -= ret[2:] / 2
96 | return ret
97 |
98 | def to_tlbr(self):
99 | """Get current position in bounding box format `(min x, miny, max x,
100 | max y)`.
101 |
102 | Returns
103 | -------
104 | ndarray
105 | The bounding box.
106 |
107 | """
108 | ret = self.to_tlwh()
109 | ret[2:] = ret[:2] + ret[2:]
110 | return ret
111 |
112 | def predict(self, kf):
113 | """Propagate the state distribution to the current time step using a
114 | Kalman filter prediction step.
115 |
116 | Parameters
117 | ----------
118 | kf : kalman_filter.KalmanFilter
119 | The Kalman filter.
120 |
121 | """
122 | self.mean, self.covariance = kf.predict(self.mean, self.covariance)
123 | self.age += 1
124 | self.time_since_update += 1
125 |
126 | def update(self, kf, detection):
127 | """Perform Kalman filter measurement update step and update the feature
128 | cache.
129 |
130 | Parameters
131 | ----------
132 | kf : kalman_filter.KalmanFilter
133 | The Kalman filter.
134 | detection : Detection
135 | The associated detection.
136 |
137 | """
138 | self.mean, self.covariance = kf.update(
139 | self.mean, self.covariance, detection.to_xyah())
140 | self.features.append(detection.feature)
141 |
142 | self.hits += 1
143 | self.time_since_update = 0
144 | if self.state == TrackState.Tentative and self.hits >= self._n_init:
145 | self.state = TrackState.Confirmed
146 |
147 | def mark_missed(self):
148 | """Mark this track as missed (no association at the current time step).
149 | """
150 | if self.state == TrackState.Tentative:
151 | self.state = TrackState.Deleted
152 | elif self.time_since_update > self._max_age:
153 | self.state = TrackState.Deleted
154 |
155 | def is_tentative(self):
156 | """Returns True if this track is tentative (unconfirmed).
157 | """
158 | return self.state == TrackState.Tentative
159 |
160 | def is_confirmed(self):
161 | """Returns True if this track is confirmed."""
162 | return self.state == TrackState.Confirmed
163 |
164 | def is_deleted(self):
165 | """Returns True if this track is dead and should be deleted."""
166 | return self.state == TrackState.Deleted
167 |
--------------------------------------------------------------------------------
/deep_sort/deep_sort/sort/tracker.py:
--------------------------------------------------------------------------------
1 | # vim: expandtab:ts=4:sw=4
2 | from __future__ import absolute_import
3 | import numpy as np
4 | from . import kalman_filter
5 | from . import linear_assignment
6 | from . import iou_matching
7 | from .track import Track
8 |
9 |
10 | class Tracker:
11 | """
12 | This is the multi-target tracker.
13 |
14 | Parameters
15 | ----------
16 | metric : nn_matching.NearestNeighborDistanceMetric
17 | A distance metric for measurement-to-track association.
18 | max_age : int
19 | Maximum number of missed misses before a track is deleted.
20 | n_init : int
21 | Number of consecutive detections before the track is confirmed. The
22 | track state is set to `Deleted` if a miss occurs within the first
23 | `n_init` frames.
24 |
25 | Attributes
26 | ----------
27 | metric : nn_matching.NearestNeighborDistanceMetric
28 | The distance metric used for measurement to track association.
29 | max_age : int
30 | Maximum number of missed misses before a track is deleted.
31 | n_init : int
32 | Number of frames that a track remains in initialization phase.
33 | kf : kalman_filter.KalmanFilter
34 | A Kalman filter to filter target trajectories in image space.
35 | tracks : List[Track]
36 | The list of active tracks at the current time step.
37 |
38 | """
39 |
40 | def __init__(self, metric, max_iou_distance=0.7, max_age=70, n_init=3):
41 | self.metric = metric
42 | self.max_iou_distance = max_iou_distance
43 | self.max_age = max_age
44 | self.n_init = n_init
45 |
46 | self.kf = kalman_filter.KalmanFilter()
47 | self.tracks = []
48 | self._next_id = 1
49 |
50 | def predict(self):
51 | """Propagate track state distributions one time step forward.
52 |
53 | This function should be called once every time step, before `update`.
54 | """
55 | for track in self.tracks:
56 | track.predict(self.kf)
57 |
58 | def update(self, detections):
59 | """Perform measurement update and track management.
60 |
61 | Parameters
62 | ----------
63 | detections : List[deep_sort.detection.Detection]
64 | A list of detections at the current time step.
65 |
66 | """
67 | # Run matching cascade.
68 | matches, unmatched_tracks, unmatched_detections = \
69 | self._match(detections)
70 |
71 | # Update track set.
72 | for track_idx, detection_idx in matches:
73 | self.tracks[track_idx].update(
74 | self.kf, detections[detection_idx])
75 | for track_idx in unmatched_tracks:
76 | self.tracks[track_idx].mark_missed()
77 | for detection_idx in unmatched_detections:
78 | self._initiate_track(detections[detection_idx])
79 | self.tracks = [t for t in self.tracks if not t.is_deleted()]
80 |
81 | # Update distance metric.
82 | active_targets = [t.track_id for t in self.tracks if t.is_confirmed()]
83 | features, targets = [], []
84 | for track in self.tracks:
85 | if not track.is_confirmed():
86 | continue
87 | features += track.features
88 | targets += [track.track_id for _ in track.features]
89 | track.features = []
90 | self.metric.partial_fit(
91 | np.asarray(features), np.asarray(targets), active_targets)
92 |
93 | def _match(self, detections):
94 |
95 | def gated_metric(tracks, dets, track_indices, detection_indices):
96 | features = np.array([dets[i].feature for i in detection_indices])
97 | targets = np.array([tracks[i].track_id for i in track_indices])
98 | cost_matrix = self.metric.distance(features, targets)
99 | cost_matrix = linear_assignment.gate_cost_matrix(
100 | self.kf, cost_matrix, tracks, dets, track_indices,
101 | detection_indices)
102 |
103 | return cost_matrix
104 |
105 | # Split track set into confirmed and unconfirmed tracks.
106 | confirmed_tracks = [
107 | i for i, t in enumerate(self.tracks) if t.is_confirmed()]
108 | unconfirmed_tracks = [
109 | i for i, t in enumerate(self.tracks) if not t.is_confirmed()]
110 |
111 | # Associate confirmed tracks using appearance features.
112 | matches_a, unmatched_tracks_a, unmatched_detections = \
113 | linear_assignment.matching_cascade(
114 | gated_metric, self.metric.matching_threshold, self.max_age,
115 | self.tracks, detections, confirmed_tracks)
116 |
117 | # Associate remaining tracks together with unconfirmed tracks using IOU.
118 | iou_track_candidates = unconfirmed_tracks + [
119 | k for k in unmatched_tracks_a if
120 | self.tracks[k].time_since_update == 1]
121 | unmatched_tracks_a = [
122 | k for k in unmatched_tracks_a if
123 | self.tracks[k].time_since_update != 1]
124 | matches_b, unmatched_tracks_b, unmatched_detections = \
125 | linear_assignment.min_cost_matching(
126 | iou_matching.iou_cost, self.max_iou_distance, self.tracks,
127 | detections, iou_track_candidates, unmatched_detections)
128 |
129 | matches = matches_a + matches_b
130 | unmatched_tracks = list(set(unmatched_tracks_a + unmatched_tracks_b))
131 | return matches, unmatched_tracks, unmatched_detections
132 |
133 | def _initiate_track(self, detection):
134 | mean, covariance = self.kf.initiate(detection.to_xyah())
135 | self.tracks.append(Track(
136 | mean, covariance, self._next_id, self.n_init, self.max_age,
137 | detection.feature))
138 | self._next_id += 1
139 |
--------------------------------------------------------------------------------
/deep_sort/demo/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/demo/1.jpg
--------------------------------------------------------------------------------
/deep_sort/demo/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/demo/2.jpg
--------------------------------------------------------------------------------
/deep_sort/demo/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/demo/demo.gif
--------------------------------------------------------------------------------
/deep_sort/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 | ```
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/__init__.py:
--------------------------------------------------------------------------------
1 | import sys
2 | sys.path.append("detector/YOLOv3")
3 |
4 |
5 | from .detector import YOLOv3
6 | __all__ = ['YOLOv3']
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/demo/004545.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/detector/YOLOv3/demo/004545.jpg
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/demo/results/004545.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/detector/YOLOv3/demo/results/004545.jpg
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/detect.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import time
3 | from PIL import Image, ImageDraw
4 | #from models.tiny_yolo import TinyYoloNet
5 | from yolo_utils import *
6 | from darknet import Darknet
7 |
8 | import cv2
9 |
10 | namesfile=None
11 | def detect(cfgfile, weightfile, imgfolder):
12 | m = Darknet(cfgfile)
13 |
14 | #m.print_network()
15 | m.load_weights(weightfile)
16 | print('Loading weights from %s... Done!' % (weightfile))
17 |
18 | # if m.num_classes == 20:
19 | # namesfile = 'data/voc.names'
20 | # elif m.num_classes == 80:
21 | # namesfile = 'data/coco.names'
22 | # else:
23 | # namesfile = 'data/names'
24 |
25 | use_cuda = True
26 | if use_cuda:
27 | m.cuda()
28 |
29 | imgfiles = [x for x in os.listdir(imgfolder) if x[-4:] == '.jpg']
30 | imgfiles.sort()
31 | for imgname in imgfiles:
32 | imgfile = os.path.join(imgfolder,imgname)
33 |
34 | img = Image.open(imgfile).convert('RGB')
35 | sized = img.resize((m.width, m.height))
36 |
37 | #for i in range(2):
38 | start = time.time()
39 | boxes = do_detect(m, sized, 0.5, 0.4, use_cuda)
40 | finish = time.time()
41 | #if i == 1:
42 | print('%s: Predicted in %f seconds.' % (imgfile, (finish-start)))
43 |
44 | class_names = load_class_names(namesfile)
45 | img = plot_boxes(img, boxes, 'result/{}'.format(os.path.basename(imgfile)), class_names)
46 | img = np.array(img)
47 | cv2.imshow('{}'.format(os.path.basename(imgfolder)), img)
48 | cv2.resizeWindow('{}'.format(os.path.basename(imgfolder)), 1000,800)
49 | cv2.waitKey(1000)
50 |
51 | def detect_cv2(cfgfile, weightfile, imgfile):
52 | import cv2
53 | m = Darknet(cfgfile)
54 |
55 | m.print_network()
56 | m.load_weights(weightfile)
57 | print('Loading weights from %s... Done!' % (weightfile))
58 |
59 | if m.num_classes == 20:
60 | namesfile = 'data/voc.names'
61 | elif m.num_classes == 80:
62 | namesfile = 'data/coco.names'
63 | else:
64 | namesfile = 'data/names'
65 |
66 | use_cuda = True
67 | if use_cuda:
68 | m.cuda()
69 |
70 | img = cv2.imread(imgfile)
71 | sized = cv2.resize(img, (m.width, m.height))
72 | sized = cv2.cvtColor(sized, cv2.COLOR_BGR2RGB)
73 |
74 | for i in range(2):
75 | start = time.time()
76 | boxes = do_detect(m, sized, 0.5, 0.4, use_cuda)
77 | finish = time.time()
78 | if i == 1:
79 | print('%s: Predicted in %f seconds.' % (imgfile, (finish-start)))
80 |
81 | class_names = load_class_names(namesfile)
82 | plot_boxes_cv2(img, boxes, savename='predictions.jpg', class_names=class_names)
83 |
84 | def detect_skimage(cfgfile, weightfile, imgfile):
85 | from skimage import io
86 | from skimage.transform import resize
87 | m = Darknet(cfgfile)
88 |
89 | m.print_network()
90 | m.load_weights(weightfile)
91 | print('Loading weights from %s... Done!' % (weightfile))
92 |
93 | if m.num_classes == 20:
94 | namesfile = 'data/voc.names'
95 | elif m.num_classes == 80:
96 | namesfile = 'data/coco.names'
97 | else:
98 | namesfile = 'data/names'
99 |
100 | use_cuda = True
101 | if use_cuda:
102 | m.cuda()
103 |
104 | img = io.imread(imgfile)
105 | sized = resize(img, (m.width, m.height)) * 255
106 |
107 | for i in range(2):
108 | start = time.time()
109 | boxes = do_detect(m, sized, 0.5, 0.4, use_cuda)
110 | finish = time.time()
111 | if i == 1:
112 | print('%s: Predicted in %f seconds.' % (imgfile, (finish-start)))
113 |
114 | class_names = load_class_names(namesfile)
115 | plot_boxes_cv2(img, boxes, savename='predictions.jpg', class_names=class_names)
116 |
117 | if __name__ == '__main__':
118 | if len(sys.argv) == 5:
119 | cfgfile = sys.argv[1]
120 | weightfile = sys.argv[2]
121 | imgfolder = sys.argv[3]
122 | cv2.namedWindow('{}'.format(os.path.basename(imgfolder)), cv2.WINDOW_NORMAL )
123 | cv2.resizeWindow('{}'.format(os.path.basename(imgfolder)), 1000,800)
124 | globals()["namesfile"] = sys.argv[4]
125 | detect(cfgfile, weightfile, imgfolder)
126 | #detect_cv2(cfgfile, weightfile, imgfile)
127 | #detect_skimage(cfgfile, weightfile, imgfile)
128 | else:
129 | print('Usage: ')
130 | print(' python detect.py cfgfile weightfile imgfolder names')
131 | #detect('cfg/tiny-yolo-voc.cfg', 'tiny-yolo-voc.weights', 'data/person.jpg', version=1)
132 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/nms/__init__.py:
--------------------------------------------------------------------------------
1 | from .nms import boxes_nms
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/nms/build.sh:
--------------------------------------------------------------------------------
1 | cd ext
2 |
3 | python build.py build_ext develop
4 |
5 | cd ..
6 |
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/nms/ext/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/detector/YOLOv3/nms/ext/__init__.py
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 | }
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/nms/ext/cuda/nms.cu:
--------------------------------------------------------------------------------
1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2 | #include
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include
9 | #include
10 |
11 | int const threadsPerBlock = sizeof(unsigned long long) * 8;
12 |
13 | __device__ inline float devIoU(float const * const a, float const * const b) {
14 | float left = max(a[0], b[0]), right = min(a[2], b[2]);
15 | float top = max(a[1], b[1]), bottom = min(a[3], b[3]);
16 | float width = max(right - left, 0.f), height = max(bottom - top, 0.f);
17 | float interS = width * height;
18 | float Sa = (a[2] - a[0]) * (a[3] - a[1]);
19 | float Sb = (b[2] - b[0]) * (b[3] - b[1]);
20 | return interS / (Sa + Sb - interS);
21 | }
22 |
23 | __global__ void nms_kernel(const int n_boxes, const float nms_overlap_thresh,
24 | const float *dev_boxes, unsigned long long *dev_mask) {
25 | const int row_start = blockIdx.y;
26 | const int col_start = blockIdx.x;
27 |
28 | // if (row_start > col_start) return;
29 |
30 | const int row_size =
31 | min(n_boxes - row_start * threadsPerBlock, threadsPerBlock);
32 | const int col_size =
33 | min(n_boxes - col_start * threadsPerBlock, threadsPerBlock);
34 |
35 | __shared__ float block_boxes[threadsPerBlock * 5];
36 | if (threadIdx.x < col_size) {
37 | block_boxes[threadIdx.x * 5 + 0] =
38 | dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 0];
39 | block_boxes[threadIdx.x * 5 + 1] =
40 | dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 1];
41 | block_boxes[threadIdx.x * 5 + 2] =
42 | dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 2];
43 | block_boxes[threadIdx.x * 5 + 3] =
44 | dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 3];
45 | block_boxes[threadIdx.x * 5 + 4] =
46 | dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 4];
47 | }
48 | __syncthreads();
49 |
50 | if (threadIdx.x < row_size) {
51 | const int cur_box_idx = threadsPerBlock * row_start + threadIdx.x;
52 | const float *cur_box = dev_boxes + cur_box_idx * 5;
53 | int i = 0;
54 | unsigned long long t = 0;
55 | int start = 0;
56 | if (row_start == col_start) {
57 | start = threadIdx.x + 1;
58 | }
59 | for (i = start; i < col_size; i++) {
60 | if (devIoU(cur_box, block_boxes + i * 5) > nms_overlap_thresh) {
61 | t |= 1ULL << i;
62 | }
63 | }
64 | const int col_blocks = THCCeilDiv(n_boxes, threadsPerBlock);
65 | dev_mask[cur_box_idx * col_blocks + col_start] = t;
66 | }
67 | }
68 |
69 | // boxes is a N x 5 tensor
70 | at::Tensor nms_cuda(const at::Tensor boxes, float nms_overlap_thresh) {
71 | using scalar_t = float;
72 | AT_ASSERTM(boxes.type().is_cuda(), "boxes must be a CUDA tensor");
73 | auto scores = boxes.select(1, 4);
74 | auto order_t = std::get<1>(scores.sort(0, /* descending=*/true));
75 | auto boxes_sorted = boxes.index_select(0, order_t);
76 |
77 | int boxes_num = boxes.size(0);
78 |
79 | const int col_blocks = THCCeilDiv(boxes_num, threadsPerBlock);
80 |
81 | scalar_t* boxes_dev = boxes_sorted.data();
82 |
83 | THCState *state = at::globalContext().lazyInitCUDA(); // TODO replace with getTHCState
84 |
85 | unsigned long long* mask_dev = NULL;
86 | //THCudaCheck(THCudaMalloc(state, (void**) &mask_dev,
87 | // boxes_num * col_blocks * sizeof(unsigned long long)));
88 |
89 | mask_dev = (unsigned long long*) THCudaMalloc(state, boxes_num * col_blocks * sizeof(unsigned long long));
90 |
91 | dim3 blocks(THCCeilDiv(boxes_num, threadsPerBlock),
92 | THCCeilDiv(boxes_num, threadsPerBlock));
93 | dim3 threads(threadsPerBlock);
94 | nms_kernel<<>>(boxes_num,
95 | nms_overlap_thresh,
96 | boxes_dev,
97 | mask_dev);
98 |
99 | std::vector mask_host(boxes_num * col_blocks);
100 | THCudaCheck(cudaMemcpy(&mask_host[0],
101 | mask_dev,
102 | sizeof(unsigned long long) * boxes_num * col_blocks,
103 | cudaMemcpyDeviceToHost));
104 |
105 | std::vector remv(col_blocks);
106 | memset(&remv[0], 0, sizeof(unsigned long long) * col_blocks);
107 |
108 | at::Tensor keep = at::empty({boxes_num}, boxes.options().dtype(at::kLong).device(at::kCPU));
109 | int64_t* keep_out = keep.data();
110 |
111 | int num_to_keep = 0;
112 | for (int i = 0; i < boxes_num; i++) {
113 | int nblock = i / threadsPerBlock;
114 | int inblock = i % threadsPerBlock;
115 |
116 | if (!(remv[nblock] & (1ULL << inblock))) {
117 | keep_out[num_to_keep++] = i;
118 | unsigned long long *p = &mask_host[0] + i * col_blocks;
119 | for (int j = nblock; j < col_blocks; j++) {
120 | remv[j] |= p[j];
121 | }
122 | }
123 | }
124 |
125 | THCudaFree(state, mask_dev);
126 | // TODO improve this part
127 | return std::get<0>(order_t.index({
128 | keep.narrow(/*dim=*/0, /*start=*/0, /*length=*/num_to_keep).to(
129 | order_t.device(), keep.scalar_type())
130 | }).sort(0, false));
131 | }
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
19 |
20 | def boxes_nms(boxes, scores, nms_thresh, max_count=-1):
21 | """ Performs non-maximum suppression, run on GPU or CPU according to
22 | boxes's device.
23 | Args:
24 | boxes(Tensor): `xyxy` mode boxes, use absolute coordinates(or relative coordinates), shape is (n, 4)
25 | scores(Tensor): scores, shape is (n, )
26 | nms_thresh(float): thresh
27 | max_count (int): if > 0, then only the top max_proposals are kept after non-maximum suppression
28 | Returns:
29 | indices kept.
30 | """
31 | keep = _nms(boxes, scores, nms_thresh)
32 | if max_count > 0:
33 | keep = keep[:max_count]
34 | return keep
35 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/detector/YOLOv3/weight/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/detector/YOLOv3/weight/.gitkeep
--------------------------------------------------------------------------------
/deep_sort/detector/__init__.py:
--------------------------------------------------------------------------------
1 | from .YOLOv3 import YOLOv3
2 |
3 |
4 | __all__ = ['build_detector']
5 |
6 | def build_detector(cfg, use_cuda):
7 | return YOLOv3(cfg.YOLOV3.CFG, cfg.YOLOV3.WEIGHT, cfg.YOLOV3.CLASS_NAMES,
8 | score_thresh=cfg.YOLOV3.SCORE_THRESH, nms_thresh=cfg.YOLOV3.NMS_THRESH,
9 | is_xywh=True, use_cuda=use_cuda)
10 |
--------------------------------------------------------------------------------
/deep_sort/ped_det_server.py:
--------------------------------------------------------------------------------
1 | """
2 | This module gets video in input and outputs the
3 | json file with coordination of bboxes in the video.
4 |
5 | """
6 | from os.path import basename, splitext, join, isfile, isdir, dirname
7 | from os import makedirs
8 |
9 | from tqdm import tqdm
10 | import cv2
11 | import argparse
12 | import torch
13 |
14 | from detector import build_detector
15 | from deep_sort import build_tracker
16 | from utils.tools import tik_tok, is_video
17 | from utils.draw import compute_color_for_labels
18 | from utils.parser import get_config
19 | from utils.json_logger import BboxToJsonLogger
20 | import warnings
21 |
22 |
23 | def parse_args():
24 | parser = argparse.ArgumentParser()
25 | parser.add_argument("--VIDEO_PATH", type=str, default="./demo/ped.avi")
26 | parser.add_argument("--config_detection", type=str, default="./configs/yolov3.yaml")
27 | parser.add_argument("--config_deepsort", type=str, default="./configs/deep_sort.yaml")
28 | parser.add_argument("--write-fps", type=int, default=20)
29 | parser.add_argument("--frame_interval", type=int, default=1)
30 | parser.add_argument("--save_path", type=str, default="./output")
31 | parser.add_argument("--cpu", dest="use_cuda", action="store_false", default=True)
32 | args = parser.parse_args()
33 |
34 | assert isfile(args.VIDEO_PATH), "Error: Video not found"
35 | assert is_video(args.VIDEO_PATH), "Error: Not Supported format"
36 | if args.frame_interval < 1: args.frame_interval = 1
37 |
38 | return args
39 |
40 |
41 | class VideoTracker(object):
42 | def __init__(self, cfg, args):
43 | self.cfg = cfg
44 | self.args = args
45 | use_cuda = args.use_cuda and torch.cuda.is_available()
46 | if not use_cuda:
47 | warnings.warn("Running in cpu mode!")
48 |
49 | self.vdo = cv2.VideoCapture()
50 | self.detector = build_detector(cfg, use_cuda=use_cuda)
51 | self.deepsort = build_tracker(cfg, use_cuda=use_cuda)
52 | self.class_names = self.detector.class_names
53 |
54 | # Configure output video and json
55 | self.logger = BboxToJsonLogger()
56 | filename, extension = splitext(basename(self.args.VIDEO_PATH))
57 | self.output_file = join(self.args.save_path, f'{filename}.avi')
58 | self.json_output = join(self.args.save_path, f'{filename}.json')
59 | if not isdir(dirname(self.json_output)):
60 | makedirs(dirname(self.json_output))
61 |
62 | def __enter__(self):
63 | self.vdo.open(self.args.VIDEO_PATH)
64 | self.total_frames = int(cv2.VideoCapture.get(self.vdo, cv2.CAP_PROP_FRAME_COUNT))
65 | self.im_width = int(self.vdo.get(cv2.CAP_PROP_FRAME_WIDTH))
66 | self.im_height = int(self.vdo.get(cv2.CAP_PROP_FRAME_HEIGHT))
67 |
68 | video_details = {'frame_width': self.im_width,
69 | 'frame_height': self.im_height,
70 | 'frame_rate': self.args.write_fps,
71 | 'video_name': self.args.VIDEO_PATH}
72 | codec = cv2.VideoWriter_fourcc(*'XVID')
73 | self.writer = cv2.VideoWriter(self.output_file, codec, self.args.write_fps,
74 | (self.im_width, self.im_height))
75 | self.logger.add_video_details(**video_details)
76 |
77 | assert self.vdo.isOpened()
78 | return self
79 |
80 | def __exit__(self, exc_type, exc_value, exc_traceback):
81 | if exc_type:
82 | print(exc_type, exc_value, exc_traceback)
83 |
84 | def run(self):
85 | idx_frame = 0
86 | pbar = tqdm(total=self.total_frames + 1)
87 | while self.vdo.grab():
88 | if idx_frame % args.frame_interval == 0:
89 | _, ori_im = self.vdo.retrieve()
90 | timestamp = self.vdo.get(cv2.CAP_PROP_POS_MSEC)
91 | frame_id = int(self.vdo.get(cv2.CAP_PROP_POS_FRAMES))
92 | self.logger.add_frame(frame_id=frame_id, timestamp=timestamp)
93 | self.detection(frame=ori_im, frame_id=frame_id)
94 | self.save_frame(ori_im)
95 | idx_frame += 1
96 | pbar.update()
97 | self.logger.json_output(self.json_output)
98 |
99 | @tik_tok
100 | def detection(self, frame, frame_id):
101 | im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
102 | # do detection
103 | bbox_xywh, cls_conf, cls_ids = self.detector(im)
104 | if bbox_xywh is not None:
105 | # select person class
106 | mask = cls_ids == 0
107 |
108 | bbox_xywh = bbox_xywh[mask]
109 | bbox_xywh[:, 3:] *= 1.2 # bbox dilation just in case bbox too small
110 | cls_conf = cls_conf[mask]
111 |
112 | # do tracking
113 | outputs = self.deepsort.update(bbox_xywh, cls_conf, im)
114 |
115 | # draw boxes for visualization
116 | if len(outputs) > 0:
117 | frame = self.draw_boxes(img=frame, frame_id=frame_id, output=outputs)
118 |
119 | def draw_boxes(self, img, frame_id, output, offset=(0, 0)):
120 | for i, box in enumerate(output):
121 | x1, y1, x2, y2, identity = [int(ii) for ii in box]
122 | self.logger.add_bbox_to_frame(frame_id=frame_id,
123 | bbox_id=identity,
124 | top=y1,
125 | left=x1,
126 | width=x2 - x1,
127 | height=y2 - y1)
128 | x1 += offset[0]
129 | x2 += offset[0]
130 | y1 += offset[1]
131 | y2 += offset[1]
132 |
133 | # box text and bar
134 | self.logger.add_label_to_bbox(frame_id=frame_id, bbox_id=identity, category='pedestrian', confidence=0.9)
135 | color = compute_color_for_labels(identity)
136 | label = '{}{:d}'.format("", identity)
137 | t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_PLAIN, 2, 2)[0]
138 | cv2.rectangle(img, (x1, y1), (x2, y2), color, 3)
139 | cv2.rectangle(img, (x1, y1), (x1 + t_size[0] + 3, y1 + t_size[1] + 4), color, -1)
140 | cv2.putText(img, label, (x1, y1 + t_size[1] + 4), cv2.FONT_HERSHEY_PLAIN, 2, [255, 255, 255], 2)
141 | return img
142 |
143 | def save_frame(self, frame) -> None:
144 | if frame is not None: self.writer.write(frame)
145 |
146 |
147 | if __name__ == "__main__":
148 | args = parse_args()
149 | cfg = get_config()
150 | cfg.merge_from_file(args.config_detection)
151 | cfg.merge_from_file(args.config_deepsort)
152 |
153 | with VideoTracker(cfg, args) as vdo_trk:
154 | vdo_trk.run()
155 |
156 |
--------------------------------------------------------------------------------
/deep_sort/scripts/yolov3_deepsort.sh:
--------------------------------------------------------------------------------
1 | python yolov3_deepsort.py [VIDEO_PATH] --config_detection
--------------------------------------------------------------------------------
/deep_sort/scripts/yolov3_tiny_deepsort.sh:
--------------------------------------------------------------------------------
1 | python yolov3_deepsort.py [VIDEO_PATH] --config_detection ./configs/yolov3_tiny.yaml
--------------------------------------------------------------------------------
/deep_sort/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/utils/__init__.py
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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_boxes(img, bbox, identities=None, offset=(0,0)):
16 | for i,box in enumerate(bbox):
17 | x1,y1,x2,y2 = [int(i) for i in box]
18 | x1 += offset[0]
19 | x2 += offset[0]
20 | y1 += offset[1]
21 | y2 += offset[1]
22 | # box text and bar
23 | id = int(identities[i]) if identities is not None else 0
24 | color = compute_color_for_labels(id)
25 | label = '{}{:d}'.format("", id)
26 | t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_PLAIN, 2 , 2)[0]
27 | cv2.rectangle(img,(x1, y1),(x2,y2),color,3)
28 | cv2.rectangle(img,(x1, y1),(x1+t_size[0]+3,y1+t_size[1]+4), color,-1)
29 | cv2.putText(img,label,(x1,y1+t_size[1]+4), cv2.FONT_HERSHEY_PLAIN, 2, [255,255,255], 2)
30 | return img
31 |
32 |
33 |
34 | if __name__ == '__main__':
35 | for i in range(82):
36 | print(compute_color_for_labels(i))
37 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/utils/io.py:
--------------------------------------------------------------------------------
1 | import os
2 | from typing import Dict
3 | import numpy as np
4 |
5 | # from utils.log import get_logger
6 |
7 |
8 | def write_results(filename, results, data_type):
9 | if data_type == 'mot':
10 | save_format = '{frame},{id},{x1},{y1},{w},{h},-1,-1,-1,-1\n'
11 | elif data_type == 'kitti':
12 | save_format = '{frame} {id} pedestrian 0 0 -10 {x1} {y1} {x2} {y2} -10 -10 -10 -1000 -1000 -1000 -10\n'
13 | else:
14 | raise ValueError(data_type)
15 |
16 | with open(filename, 'w') as f:
17 | for frame_id, tlwhs, track_ids in results:
18 | if data_type == 'kitti':
19 | frame_id -= 1
20 | for tlwh, track_id in zip(tlwhs, track_ids):
21 | if track_id < 0:
22 | continue
23 | x1, y1, w, h = tlwh
24 | x2, y2 = x1 + w, y1 + h
25 | line = save_format.format(frame=frame_id, id=track_id, x1=x1, y1=y1, x2=x2, y2=y2, w=w, h=h)
26 | f.write(line)
27 |
28 |
29 | # def write_results(filename, results_dict: Dict, data_type: str):
30 | # if not filename:
31 | # return
32 | # path = os.path.dirname(filename)
33 | # if not os.path.exists(path):
34 | # os.makedirs(path)
35 |
36 | # if data_type in ('mot', 'mcmot', 'lab'):
37 | # save_format = '{frame},{id},{x1},{y1},{w},{h},1,-1,-1,-1\n'
38 | # elif data_type == 'kitti':
39 | # save_format = '{frame} {id} pedestrian -1 -1 -10 {x1} {y1} {x2} {y2} -1 -1 -1 -1000 -1000 -1000 -10 {score}\n'
40 | # else:
41 | # raise ValueError(data_type)
42 |
43 | # with open(filename, 'w') as f:
44 | # for frame_id, frame_data in results_dict.items():
45 | # if data_type == 'kitti':
46 | # frame_id -= 1
47 | # for tlwh, track_id in frame_data:
48 | # if track_id < 0:
49 | # continue
50 | # x1, y1, w, h = tlwh
51 | # x2, y2 = x1 + w, y1 + h
52 | # line = save_format.format(frame=frame_id, id=track_id, x1=x1, y1=y1, x2=x2, y2=y2, w=w, h=h, score=1.0)
53 | # f.write(line)
54 | # logger.info('Save results to {}'.format(filename))
55 |
56 |
57 | def read_results(filename, data_type: str, is_gt=False, is_ignore=False):
58 | if data_type in ('mot', 'lab'):
59 | read_fun = read_mot_results
60 | else:
61 | raise ValueError('Unknown data type: {}'.format(data_type))
62 |
63 | return read_fun(filename, is_gt, is_ignore)
64 |
65 |
66 | """
67 | labels={'ped', ... % 1
68 | 'person_on_vhcl', ... % 2
69 | 'car', ... % 3
70 | 'bicycle', ... % 4
71 | 'mbike', ... % 5
72 | 'non_mot_vhcl', ... % 6
73 | 'static_person', ... % 7
74 | 'distractor', ... % 8
75 | 'occluder', ... % 9
76 | 'occluder_on_grnd', ... %10
77 | 'occluder_full', ... % 11
78 | 'reflection', ... % 12
79 | 'crowd' ... % 13
80 | };
81 | """
82 |
83 |
84 | def read_mot_results(filename, is_gt, is_ignore):
85 | valid_labels = {1}
86 | ignore_labels = {2, 7, 8, 12}
87 | results_dict = dict()
88 | if os.path.isfile(filename):
89 | with open(filename, 'r') as f:
90 | for line in f.readlines():
91 | linelist = line.split(',')
92 | if len(linelist) < 7:
93 | continue
94 | fid = int(linelist[0])
95 | if fid < 1:
96 | continue
97 | results_dict.setdefault(fid, list())
98 |
99 | if is_gt:
100 | if 'MOT16-' in filename or 'MOT17-' in filename:
101 | label = int(float(linelist[7]))
102 | mark = int(float(linelist[6]))
103 | if mark == 0 or label not in valid_labels:
104 | continue
105 | score = 1
106 | elif is_ignore:
107 | if 'MOT16-' in filename or 'MOT17-' in filename:
108 | label = int(float(linelist[7]))
109 | vis_ratio = float(linelist[8])
110 | if label not in ignore_labels and vis_ratio >= 0:
111 | continue
112 | else:
113 | continue
114 | score = 1
115 | else:
116 | score = float(linelist[6])
117 |
118 | tlwh = tuple(map(float, linelist[2:6]))
119 | target_id = int(linelist[1])
120 |
121 | results_dict[fid].append((tlwh, target_id, score))
122 |
123 | return results_dict
124 |
125 |
126 | def unzip_objs(objs):
127 | if len(objs) > 0:
128 | tlwhs, ids, scores = zip(*objs)
129 | else:
130 | tlwhs, ids, scores = [], [], []
131 | tlwhs = np.asarray(tlwhs, dtype=float).reshape(-1, 4)
132 |
133 | return tlwhs, ids, scores
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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.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.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()
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/webserver/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/webserver/__init__.py
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/webserver/images/Thumbs.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/webserver/images/Thumbs.db
--------------------------------------------------------------------------------
/deep_sort/webserver/images/arc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/webserver/images/arc.png
--------------------------------------------------------------------------------
/deep_sort/webserver/images/request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/deep_sort/webserver/images/request.png
--------------------------------------------------------------------------------
/deep_sort/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 | 
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 | 
43 |
44 |
45 | 5 - get pedestrian detection stream in `127.0.0.1:8888`
46 |
--------------------------------------------------------------------------------
/deep_sort/webserver/rtsp_threaded_tracker.py:
--------------------------------------------------------------------------------
1 | import warnings
2 | from os import getenv
3 | import sys
4 | from os.path import dirname, abspath
5 |
6 | sys.path.append(dirname(dirname(abspath(__file__))))
7 |
8 | import torch
9 | from deep_sort import build_tracker
10 | from detector import build_detector
11 | import cv2
12 | from utils.draw import compute_color_for_labels
13 | from concurrent.futures import ThreadPoolExecutor
14 | from redis import Redis
15 |
16 | redis_cache = Redis('127.0.0.1')
17 |
18 |
19 | class RealTimeTracking(object):
20 | """
21 | This class is built to get frame from rtsp link and continuously
22 | assign each frame to an attribute namely as frame in order to
23 | compensate the network packet loss. then we use flask to give it
24 | as service to client.
25 | Args:
26 | args: parse_args inputs
27 | cfg: deepsort dict and yolo-model cfg from server_cfg file
28 |
29 | """
30 |
31 | def __init__(self, cfg, args):
32 | # Create a VideoCapture object
33 | self.cfg = cfg
34 | self.args = args
35 | use_cuda = self.args.use_cuda and torch.cuda.is_available()
36 |
37 | if not use_cuda:
38 | warnings.warn(UserWarning("Running in cpu mode!"))
39 |
40 | self.detector = build_detector(cfg, use_cuda=use_cuda)
41 | self.deepsort = build_tracker(cfg, use_cuda=use_cuda)
42 | self.class_names = self.detector.class_names
43 |
44 | self.vdo = cv2.VideoCapture(self.args.input)
45 | self.status, self.frame = None, None
46 | self.total_frames = int(cv2.VideoCapture.get(self.vdo, cv2.CAP_PROP_FRAME_COUNT))
47 | self.im_width = int(self.vdo.get(cv2.CAP_PROP_FRAME_WIDTH))
48 | self.im_height = int(self.vdo.get(cv2.CAP_PROP_FRAME_HEIGHT))
49 |
50 | self.output_frame = None
51 |
52 | self.thread = ThreadPoolExecutor(max_workers=1)
53 | self.thread.submit(self.update)
54 |
55 | def update(self):
56 | while True:
57 | if self.vdo.isOpened():
58 | (self.status, self.frame) = self.vdo.read()
59 |
60 | def run(self):
61 | print('streaming started ...')
62 | while getenv('in_progress') != 'off':
63 | try:
64 | frame = self.frame.copy()
65 | self.detection(frame=frame)
66 | frame_to_bytes = cv2.imencode('.jpg', frame)[1].tobytes()
67 | redis_cache.set('frame', frame_to_bytes)
68 | except AttributeError:
69 | pass
70 | print('streaming stopped ...')
71 |
72 |
73 | def detection(self, frame):
74 | im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
75 | # do detection
76 | bbox_xywh, cls_conf, cls_ids = self.detector(im)
77 | if bbox_xywh is not None:
78 | # select person class
79 | mask = cls_ids == 0
80 |
81 | bbox_xywh = bbox_xywh[mask]
82 | bbox_xywh[:, 3:] *= 1.2 # bbox dilation just in case bbox too small
83 | cls_conf = cls_conf[mask]
84 |
85 | # do tracking
86 | outputs = self.deepsort.update(bbox_xywh, cls_conf, im)
87 |
88 | # draw boxes for visualization
89 | if len(outputs) > 0:
90 | self.draw_boxes(img=frame, output=outputs)
91 |
92 | @staticmethod
93 | def draw_boxes(img, output, offset=(0, 0)):
94 | for i, box in enumerate(output):
95 | x1, y1, x2, y2, identity = [int(ii) for ii in box]
96 | x1 += offset[0]
97 | x2 += offset[0]
98 | y1 += offset[1]
99 | y2 += offset[1]
100 |
101 | # box text and bar
102 | color = compute_color_for_labels(identity)
103 | label = '{}{:d}'.format("", identity)
104 | t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_PLAIN, 2, 2)[0]
105 | cv2.rectangle(img, (x1, y1), (x2, y2), color, 3)
106 | cv2.rectangle(img, (x1, y1), (x1 + t_size[0] + 3, y1 + t_size[1] + 4), color, -1)
107 | cv2.putText(img, label, (x1, y1 + t_size[1] + 4), cv2.FONT_HERSHEY_PLAIN, 2, [255, 255, 255], 2)
108 | return img
109 |
--------------------------------------------------------------------------------
/deep_sort/webserver/rtsp_webserver.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | # TODO: Load ML model with redis and keep it for sometime.
4 | 1- detector/yolov3/detector.py |=> yolov3 weightfile -> redis cache
5 | 2- deepsort/deep/feature_extractor |=> model_path -> redis cache
6 | 3- Use tmpfs (Insert RAM as a virtual disk and store model state): https://pypi.org/project/memory-tempfile/
7 |
8 | """
9 | from os.path import join
10 | from os import getenv, environ
11 | from dotenv import load_dotenv
12 | import argparse
13 | from threading import Thread
14 |
15 | from redis import Redis
16 | from flask import Response, Flask, jsonify, request, abort
17 |
18 | from rtsp_threaded_tracker import RealTimeTracking
19 | from server_cfg import model, deep_sort_dict
20 | from config.config import DevelopmentConfig
21 | from utils.parser import get_config
22 |
23 | redis_cache = Redis('127.0.0.1')
24 | app = Flask(__name__)
25 | environ['in_progress'] = 'off'
26 |
27 |
28 | def parse_args():
29 | """
30 | Parses the arguments
31 | Returns:
32 | argparse Namespace
33 | """
34 | assert 'project_root' in environ.keys()
35 | project_root = getenv('project_root')
36 | parser = argparse.ArgumentParser()
37 |
38 | parser.add_argument("--input",
39 | type=str,
40 | default=getenv('camera_stream'))
41 |
42 | parser.add_argument("--model",
43 | type=str,
44 | default=join(project_root,
45 | getenv('model_type')))
46 |
47 | parser.add_argument("--cpu",
48 | dest="use_cuda",
49 | action="store_false", default=True)
50 | args = parser.parse_args()
51 |
52 | return args
53 |
54 |
55 | def gen():
56 | """
57 |
58 | Returns: video frames from redis cache
59 |
60 | """
61 | while True:
62 | frame = redis_cache.get('frame')
63 | if frame is not None:
64 | yield b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n'
65 |
66 |
67 | def pedestrian_tracking(cfg, args):
68 | """
69 | starts the pedestrian detection on rtsp link
70 | Args:
71 | cfg:
72 | args:
73 |
74 | Returns:
75 |
76 | """
77 | tracker = RealTimeTracking(cfg, args)
78 | tracker.run()
79 |
80 |
81 | def trigger_process(cfg, args):
82 | """
83 | triggers pedestrian_tracking process on rtsp link using a thread
84 | Args:
85 | cfg:
86 | args:
87 |
88 | Returns:
89 | """
90 | try:
91 | t = Thread(target=pedestrian_tracking, args=(cfg, args))
92 | t.start()
93 | return jsonify({"message": "Pedestrian detection started successfully"})
94 | except Exception:
95 | return jsonify({'message': "Unexpected exception occured in process"})
96 |
97 |
98 | @app.errorhandler(400)
99 | def bad_argument(error):
100 | return jsonify({'message': error.description['message']})
101 |
102 |
103 | # Routes
104 | @app.route('/stream', methods=['GET'])
105 | def stream():
106 | """
107 | Provides video frames on http link
108 | Returns:
109 |
110 | """
111 | return Response(gen(),
112 | mimetype='multipart/x-mixed-replace; boundary=frame')
113 |
114 |
115 | @app.route("/run", methods=['GET'])
116 | def process_manager():
117 | """
118 | request parameters:
119 | run (bool): 1 -> start the pedestrian tracking
120 | 0 -> stop it
121 | camera_stream: str -> rtsp link to security camera
122 |
123 | :return:
124 | """
125 | # data = request.args
126 | data = request.args
127 | status = data['run']
128 | status = int(status) if status.isnumeric() else abort(400, {'message': f"bad argument for run {data['run']}"})
129 | if status == 1:
130 | # if pedestrian tracking is not running, start it off!
131 | try:
132 | if environ.get('in_progress', 'off') == 'off':
133 | global cfg, args
134 | vdo = data.get('camera_stream')
135 | if vdo is not None:
136 | args.input = int(vdo)
137 | environ['in_progress'] = 'on'
138 | return trigger_process(cfg, args)
139 | elif environ.get('in_progress') == 'on':
140 | # if pedestrian tracking is running, don't start another one (we are short of gpu resources)
141 | return jsonify({"message": " Pedestrian detection is already in progress."})
142 | except Exception:
143 | environ['in_progress'] = 'off'
144 | return abort(503)
145 | elif status == 0:
146 | if environ.get('in_progress', 'off') == 'off':
147 | return jsonify({"message": "pedestrian detection is already terminated!"})
148 | else:
149 | environ['in_progress'] = 'off'
150 | return jsonify({"message": "Pedestrian detection terminated!"})
151 |
152 |
153 | if __name__ == '__main__':
154 | load_dotenv()
155 | app.config.from_object(DevelopmentConfig)
156 |
157 | # BackProcess Initialization
158 | args = parse_args()
159 | cfg = get_config()
160 | cfg.merge_from_dict(model)
161 | cfg.merge_from_dict(deep_sort_dict)
162 | # Start the flask app
163 | app.run()
164 |
--------------------------------------------------------------------------------
/deep_sort/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 |
--------------------------------------------------------------------------------
/deep_sort/webserver/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | دوربین طبقه 2: راهرو 2
4 |
5 |
6 | طبقه 2
7 |
8 |
9 |
--------------------------------------------------------------------------------
/deep_sort/yolov3_deepsort.py:
--------------------------------------------------------------------------------
1 | import os
2 | import cv2
3 | import time
4 | import argparse
5 | import torch
6 | import warnings
7 | import numpy as np
8 |
9 | from detector import build_detector
10 | from deep_sort import build_tracker
11 | from utils.draw import draw_boxes
12 | from utils.parser import get_config
13 | from utils.log import get_logger
14 | from utils.io import write_results
15 |
16 |
17 | class VideoTracker(object):
18 | def __init__(self, cfg, args, video_path):
19 | self.cfg = cfg
20 | self.args = args
21 | self.video_path = video_path
22 | self.logger = get_logger("root")
23 |
24 | use_cuda = args.use_cuda and torch.cuda.is_available()
25 | if not use_cuda:
26 | warnings.warn("Running in cpu mode which maybe very slow!", UserWarning)
27 |
28 | if args.display:
29 | cv2.namedWindow("test", cv2.WINDOW_NORMAL)
30 | cv2.resizeWindow("test", args.display_width, args.display_height)
31 |
32 | if args.cam != -1:
33 | print("Using webcam " + str(args.cam))
34 | self.vdo = cv2.VideoCapture(args.cam)
35 | else:
36 | self.vdo = cv2.VideoCapture()
37 | self.detector = build_detector(cfg, use_cuda=use_cuda)
38 | self.deepsort = build_tracker(cfg, use_cuda=use_cuda)
39 | self.class_names = self.detector.class_names
40 |
41 | def __enter__(self):
42 | if self.args.cam != -1:
43 | ret, frame = self.vdo.read()
44 | assert ret, "Error: Camera error"
45 | self.im_width = frame.shape[0]
46 | self.im_height = frame.shape[1]
47 |
48 | else:
49 | assert os.path.isfile(self.video_path), "Path error"
50 | self.vdo.open(self.video_path)
51 | self.im_width = int(self.vdo.get(cv2.CAP_PROP_FRAME_WIDTH))
52 | self.im_height = int(self.vdo.get(cv2.CAP_PROP_FRAME_HEIGHT))
53 | assert self.vdo.isOpened()
54 |
55 | if self.args.save_path:
56 | os.makedirs(self.args.save_path, exist_ok=True)
57 |
58 | # path of saved video and results
59 | self.save_video_path = os.path.join(self.args.save_path, "results.avi")
60 | self.save_results_path = os.path.join(self.args.save_path, "results.txt")
61 |
62 | # create video writer
63 | fourcc = cv2.VideoWriter_fourcc(*'MJPG')
64 | self.writer = cv2.VideoWriter(self.save_video_path, fourcc, 20, (self.im_width, self.im_height))
65 |
66 | # logging
67 | self.logger.info("Save results to {}".format(self.args.save_path))
68 |
69 | return self
70 |
71 | def __exit__(self, exc_type, exc_value, exc_traceback):
72 | if exc_type:
73 | print(exc_type, exc_value, exc_traceback)
74 |
75 | def run(self):
76 | results = []
77 | idx_frame = 0
78 | while self.vdo.grab():
79 | idx_frame += 1
80 | if idx_frame % self.args.frame_interval:
81 | continue
82 |
83 | start = time.time()
84 | _, ori_im = self.vdo.retrieve()
85 | im = cv2.cvtColor(ori_im, cv2.COLOR_BGR2RGB)
86 |
87 | # do detection
88 | bbox_xywh, cls_conf, cls_ids = self.detector(im)
89 |
90 | # select person class
91 | mask = cls_ids == 0
92 |
93 | bbox_xywh = bbox_xywh[mask]
94 | # bbox dilation just in case bbox too small, delete this line if using a better pedestrian detector
95 | bbox_xywh[:, 3:] *= 1.2
96 | cls_conf = cls_conf[mask]
97 |
98 | # do tracking
99 | outputs = self.deepsort.update(bbox_xywh, cls_conf, im)
100 |
101 | # draw boxes for visualization
102 | if len(outputs) > 0:
103 | bbox_tlwh = []
104 | bbox_xyxy = outputs[:, :4]
105 | identities = outputs[:, -1]
106 | ori_im = draw_boxes(ori_im, bbox_xyxy, identities)
107 |
108 | for bb_xyxy in bbox_xyxy:
109 | bbox_tlwh.append(self.deepsort._xyxy_to_tlwh(bb_xyxy))
110 |
111 | results.append((idx_frame - 1, bbox_tlwh, identities))
112 |
113 | end = time.time()
114 |
115 | if self.args.display:
116 | cv2.imshow("test", ori_im)
117 | cv2.waitKey(1)
118 |
119 | if self.args.save_path:
120 | self.writer.write(ori_im)
121 |
122 | # save results
123 | write_results(self.save_results_path, results, 'mot')
124 |
125 | # logging
126 | self.logger.info("time: {:.03f}s, fps: {:.03f}, detection numbers: {}, tracking numbers: {}" \
127 | .format(end - start, 1 / (end - start), bbox_xywh.shape[0], len(outputs)))
128 |
129 |
130 | def parse_args():
131 | parser = argparse.ArgumentParser()
132 | parser.add_argument("VIDEO_PATH", type=str)
133 | parser.add_argument("--config_detection", type=str, default="./configs/yolov3.yaml")
134 | parser.add_argument("--config_deepsort", type=str, default="./configs/deep_sort.yaml")
135 | # parser.add_argument("--ignore_display", dest="display", action="store_false", default=True)
136 | parser.add_argument("--display", action="store_true")
137 | parser.add_argument("--frame_interval", type=int, default=1)
138 | parser.add_argument("--display_width", type=int, default=800)
139 | parser.add_argument("--display_height", type=int, default=600)
140 | parser.add_argument("--save_path", type=str, default="./output/")
141 | parser.add_argument("--cpu", dest="use_cuda", action="store_false", default=True)
142 | parser.add_argument("--camera", action="store", dest="cam", type=int, default="-1")
143 | return parser.parse_args()
144 |
145 |
146 | if __name__ == "__main__":
147 | args = parse_args()
148 | cfg = get_config()
149 | cfg.merge_from_file(args.config_detection)
150 | cfg.merge_from_file(args.config_deepsort)
151 |
152 | with VideoTracker(cfg, args, video_path=args.VIDEO_PATH) as vdo_trk:
153 | vdo_trk.run()
154 |
--------------------------------------------------------------------------------
/deep_sort/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)
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # pip install -U -r requirements.txt
2 | Cython
3 | matplotlib>=3.2.2
4 | numpy>=1.18.5
5 | opencv-python>=4.1.2
6 | pillow
7 | easydict
8 | pycocotools>=2.0
9 | PyYAML>=5.3
10 | scipy>=1.4.1
11 | tensorboard>=2.2
12 | tqdm>=4.41.0
13 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | 多目标跟踪
7 |
8 |
9 | 多目标跟踪
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/yolov5/.dockerignore:
--------------------------------------------------------------------------------
1 | # Repo-specific DockerIgnore -------------------------------------------------------------------------------------------
2 | # .git
3 | .cache
4 | .idea
5 | runs
6 | output
7 | coco
8 | storage.googleapis.com
9 |
10 | data/samples/*
11 | **/results*.txt
12 | *.jpg
13 |
14 | # Neural Network weights -----------------------------------------------------------------------------------------------
15 | **/*.weights
16 | **/*.pt
17 | **/*.pth
18 | **/*.onnx
19 | **/*.mlmodel
20 | **/*.torchscript
21 |
22 |
23 | # Below Copied From .gitignore -----------------------------------------------------------------------------------------
24 | # Below Copied From .gitignore -----------------------------------------------------------------------------------------
25 |
26 |
27 | # GitHub Python GitIgnore ----------------------------------------------------------------------------------------------
28 | # Byte-compiled / optimized / DLL files
29 | __pycache__/
30 | *.py[cod]
31 | *$py.class
32 |
33 | # C extensions
34 | *.so
35 |
36 | # Distribution / packaging
37 | .Python
38 | env/
39 | build/
40 | develop-eggs/
41 | dist/
42 | downloads/
43 | eggs/
44 | .eggs/
45 | lib/
46 | lib64/
47 | parts/
48 | sdist/
49 | var/
50 | wheels/
51 | *.egg-info/
52 | .installed.cfg
53 | *.egg
54 |
55 | # PyInstaller
56 | # Usually these files are written by a python script from a template
57 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
58 | *.manifest
59 | *.spec
60 |
61 | # Installer logs
62 | pip-log.txt
63 | pip-delete-this-directory.txt
64 |
65 | # Unit test / coverage reports
66 | htmlcov/
67 | .tox/
68 | .coverage
69 | .coverage.*
70 | .cache
71 | nosetests.xml
72 | coverage.xml
73 | *.cover
74 | .hypothesis/
75 |
76 | # Translations
77 | *.mo
78 | *.pot
79 |
80 | # Django stuff:
81 | *.log
82 | local_settings.py
83 |
84 | # Flask stuff:
85 | instance/
86 | .webassets-cache
87 |
88 | # Scrapy stuff:
89 | .scrapy
90 |
91 | # Sphinx documentation
92 | docs/_build/
93 |
94 | # PyBuilder
95 | target/
96 |
97 | # Jupyter Notebook
98 | .ipynb_checkpoints
99 |
100 | # pyenv
101 | .python-version
102 |
103 | # celery beat schedule file
104 | celerybeat-schedule
105 |
106 | # SageMath parsed files
107 | *.sage.py
108 |
109 | # dotenv
110 | .env
111 |
112 | # virtualenv
113 | .venv
114 | venv*/
115 | ENV/
116 |
117 | # Spyder project settings
118 | .spyderproject
119 | .spyproject
120 |
121 | # Rope project settings
122 | .ropeproject
123 |
124 | # mkdocs documentation
125 | /site
126 |
127 | # mypy
128 | .mypy_cache/
129 |
130 |
131 | # https://github.com/github/gitignore/blob/master/Global/macOS.gitignore -----------------------------------------------
132 |
133 | # General
134 | .DS_Store
135 | .AppleDouble
136 | .LSOverride
137 |
138 | # Icon must end with two \r
139 | Icon
140 | Icon?
141 |
142 | # Thumbnails
143 | ._*
144 |
145 | # Files that might appear in the root of a volume
146 | .DocumentRevisions-V100
147 | .fseventsd
148 | .Spotlight-V100
149 | .TemporaryItems
150 | .Trashes
151 | .VolumeIcon.icns
152 | .com.apple.timemachine.donotpresent
153 |
154 | # Directories potentially created on remote AFP share
155 | .AppleDB
156 | .AppleDesktop
157 | Network Trash Folder
158 | Temporary Items
159 | .apdisk
160 |
161 |
162 | # https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore
163 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
164 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
165 |
166 | # User-specific stuff:
167 | .idea/*
168 | .idea/**/workspace.xml
169 | .idea/**/tasks.xml
170 | .idea/dictionaries
171 | .html # Bokeh Plots
172 | .pg # TensorFlow Frozen Graphs
173 | .avi # videos
174 |
175 | # Sensitive or high-churn files:
176 | .idea/**/dataSources/
177 | .idea/**/dataSources.ids
178 | .idea/**/dataSources.local.xml
179 | .idea/**/sqlDataSources.xml
180 | .idea/**/dynamic.xml
181 | .idea/**/uiDesigner.xml
182 |
183 | # Gradle:
184 | .idea/**/gradle.xml
185 | .idea/**/libraries
186 |
187 | # CMake
188 | cmake-build-debug/
189 | cmake-build-release/
190 |
191 | # Mongo Explorer plugin:
192 | .idea/**/mongoSettings.xml
193 |
194 | ## File-based project format:
195 | *.iws
196 |
197 | ## Plugin-specific files:
198 |
199 | # IntelliJ
200 | out/
201 |
202 | # mpeltonen/sbt-idea plugin
203 | .idea_modules/
204 |
205 | # JIRA plugin
206 | atlassian-ide-plugin.xml
207 |
208 | # Cursive Clojure plugin
209 | .idea/replstate.xml
210 |
211 | # Crashlytics plugin (for Android Studio and IntelliJ)
212 | com_crashlytics_export_strings.xml
213 | crashlytics.properties
214 | crashlytics-build.properties
215 | fabric.properties
216 |
--------------------------------------------------------------------------------
/yolov5/.gitattributes:
--------------------------------------------------------------------------------
1 | # this drop notebooks from GitHub language stats
2 | *.ipynb linguist-vendored
3 |
--------------------------------------------------------------------------------
/yolov5/.github/ISSUE_TEMPLATE/--bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41BBug report"
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | Before submitting a bug report, please be aware that your issue **must be reproducible** with all of the following, otherwise it is non-actionable, and we can not help you:
11 | - **Current repo**: run `git fetch && git status -uno` to check and `git pull` to update repo
12 | - **Common dataset**: coco.yaml or coco128.yaml
13 | - **Common environment**: Colab, Google Cloud, or Docker image. See https://github.com/ultralytics/yolov5#environments
14 |
15 | If this is a custom dataset/training question you **must include** your `train*.jpg`, `test*.jpg` and `results.png` figures, or we can not help you. You can generate these with `utils.plot_results()`.
16 |
17 |
18 | ## 🐛 Bug
19 | A clear and concise description of what the bug is.
20 |
21 |
22 | ## To Reproduce (REQUIRED)
23 |
24 | Input:
25 | ```
26 | import torch
27 |
28 | a = torch.tensor([5])
29 | c = a / 0
30 | ```
31 |
32 | Output:
33 | ```
34 | Traceback (most recent call last):
35 | File "/Users/glennjocher/opt/anaconda3/envs/env1/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code
36 | exec(code_obj, self.user_global_ns, self.user_ns)
37 | File "", line 5, in
38 | c = a / 0
39 | RuntimeError: ZeroDivisionError
40 | ```
41 |
42 |
43 | ## Expected behavior
44 | A clear and concise description of what you expected to happen.
45 |
46 |
47 | ## Environment
48 | If applicable, add screenshots to help explain your problem.
49 |
50 | - OS: [e.g. Ubuntu]
51 | - GPU [e.g. 2080 Ti]
52 |
53 |
54 | ## Additional context
55 | Add any other context about the problem here.
56 |
--------------------------------------------------------------------------------
/yolov5/.github/ISSUE_TEMPLATE/--feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F680Feature request"
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## 🚀 Feature
11 |
12 |
13 | ## Motivation
14 |
15 |
16 |
17 | ## Pitch
18 |
19 |
20 |
21 | ## Alternatives
22 |
23 |
24 |
25 | ## Additional context
26 |
27 |
28 |
--------------------------------------------------------------------------------
/yolov5/.github/ISSUE_TEMPLATE/-question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "❓Question"
3 | about: Ask a general question
4 | title: ''
5 | labels: question
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## ❔Question
11 |
12 |
13 | ## Additional context
14 |
--------------------------------------------------------------------------------
/yolov5/.github/workflows/ci-testing.yml:
--------------------------------------------------------------------------------
1 | name: CI CPU testing
2 |
3 | on: # https://help.github.com/en/actions/reference/events-that-trigger-workflows
4 | push:
5 | pull_request:
6 | schedule:
7 | - cron: "0 0 * * *"
8 |
9 | jobs:
10 | cpu-tests:
11 |
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | os: [ubuntu-latest, macos-latest, windows-latest]
17 | python-version: [3.8]
18 | model: ['yolov5s'] # models to test
19 |
20 | # Timeout: https://stackoverflow.com/a/59076067/4521646
21 | timeout-minutes: 50
22 | steps:
23 | - uses: actions/checkout@v2
24 | - name: Set up Python ${{ matrix.python-version }}
25 | uses: actions/setup-python@v2
26 | with:
27 | python-version: ${{ matrix.python-version }}
28 |
29 | # Note: This uses an internal pip API and may not always work
30 | # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow
31 | - name: Get pip cache
32 | id: pip-cache
33 | run: |
34 | python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)"
35 |
36 | - name: Cache pip
37 | uses: actions/cache@v1
38 | with:
39 | path: ${{ steps.pip-cache.outputs.dir }}
40 | key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements.txt') }}
41 | restore-keys: |
42 | ${{ runner.os }}-${{ matrix.python-version }}-pip-
43 |
44 | - name: Install dependencies
45 | run: |
46 | python -m pip install --upgrade pip
47 | pip install -qr requirements.txt -f https://download.pytorch.org/whl/cpu/torch_stable.html
48 | pip install -q onnx
49 | python --version
50 | pip --version
51 | pip list
52 | shell: bash
53 |
54 | - name: Download data
55 | run: |
56 | curl -L -o temp.zip https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip
57 | unzip -q temp.zip -d ../
58 | rm temp.zip
59 |
60 | - name: Tests workflow
61 | run: |
62 | export PYTHONPATH="$PWD" # to run *.py. files in subdirectories
63 | di=cpu # inference devices # define device
64 |
65 | # train
66 | python train.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --cfg models/${{ matrix.model }}.yaml --epochs 1 --device $di
67 | # detect
68 | python detect.py --weights weights/${{ matrix.model }}.pt --device $di
69 | python detect.py --weights runs/exp0/weights/last.pt --device $di
70 | # test
71 | python test.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --device $di
72 | python test.py --img 256 --batch 8 --weights runs/exp0/weights/last.pt --device $di
73 |
74 | python models/yolo.py --cfg models/${{ matrix.model }}.yaml # inspect
75 | python models/export.py --img 256 --batch 1 --weights weights/${{ matrix.model }}.pt # export
76 | shell: bash
77 |
--------------------------------------------------------------------------------
/yolov5/.github/workflows/greetings.yml:
--------------------------------------------------------------------------------
1 | name: Greetings
2 |
3 | on: [pull_request_target, issues]
4 |
5 | jobs:
6 | greeting:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/first-interaction@v1
10 | with:
11 | repo-token: ${{ secrets.GITHUB_TOKEN }}
12 | pr-message: |
13 | Hello @${{ github.actor }}, thank you for submitting a PR! To allow your work to be integrated as seamlessly as possible, we advise you to:
14 | - Verify your PR is **up-to-date with origin/master.** If your PR is behind origin/master update by running the following, replacing 'feature' with the name of your local branch:
15 | ```bash
16 | git remote add upstream https://github.com/ultralytics/yolov5.git
17 | git fetch upstream
18 | git checkout feature # <----- replace 'feature' with local branch name
19 | git rebase upstream/master
20 | git push -u origin -f
21 | ```
22 | - Verify all Continuous Integration (CI) **checks are passing**.
23 | - Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee
24 |
25 | issue-message: |
26 | Hello @${{ github.actor }}, thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data) to get started, and see our [Jupyter Notebook](https://github.com/ultralytics/yolov5/blob/master/tutorial.ipynb)
, [Docker Image](https://hub.docker.com/r/ultralytics/yolov5), and [Google Cloud Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart) for example environments.
27 |
28 | If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you.
29 |
30 | If this is a custom model or data training question, please note Ultralytics does **not** provide free personal support. As a leader in vision ML and AI, we do offer professional consulting, from simple expert advice up to delivery of fully customized, end-to-end production solutions for our clients, such as:
31 | - **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.**
32 | - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.**
33 | - **Custom data training**, hyperparameter evolution, and model exportation to any destination.
34 |
35 | For more information please visit https://www.ultralytics.com.
36 |
--------------------------------------------------------------------------------
/yolov5/.github/workflows/rebase.yml:
--------------------------------------------------------------------------------
1 | name: Automatic Rebase
2 | # https://github.com/marketplace/actions/automatic-rebase
3 |
4 | on:
5 | issue_comment:
6 | types: [created]
7 |
8 | jobs:
9 | rebase:
10 | name: Rebase
11 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout the latest code
15 | uses: actions/checkout@v2
16 | with:
17 | fetch-depth: 0
18 | - name: Automatic Rebase
19 | uses: cirrus-actions/rebase@1.3.1
20 | env:
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 |
--------------------------------------------------------------------------------
/yolov5/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: Close stale issues
2 | on:
3 | schedule:
4 | - cron: "0 0 * * *"
5 |
6 | jobs:
7 | stale:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/stale@v1
11 | with:
12 | repo-token: ${{ secrets.GITHUB_TOKEN }}
13 | stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
14 | stale-pr-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
15 | days-before-stale: 30
16 | days-before-close: 5
17 | exempt-issue-label: 'documentation,tutorial'
18 | operations-per-run: 100 # The maximum number of operations per run, used to control rate limiting.
19 |
--------------------------------------------------------------------------------
/yolov5/.gitignore:
--------------------------------------------------------------------------------
1 | # Repo-specific GitIgnore ----------------------------------------------------------------------------------------------
2 | *.jpg
3 | *.jpeg
4 | *.png
5 | *.bmp
6 | *.tif
7 | *.tiff
8 | *.heic
9 | *.JPG
10 | *.JPEG
11 | *.PNG
12 | *.BMP
13 | *.TIF
14 | *.TIFF
15 | *.HEIC
16 | *.mp4
17 | *.mov
18 | *.MOV
19 | *.avi
20 | *.data
21 | *.json
22 |
23 | *.cfg
24 | !cfg/yolov3*.cfg
25 |
26 | storage.googleapis.com
27 | runs/*
28 | data/*
29 | !data/samples/zidane.jpg
30 | !data/samples/bus.jpg
31 | !data/coco.names
32 | !data/coco_paper.names
33 | !data/coco.data
34 | !data/coco_*.data
35 | !data/coco_*.txt
36 | !data/trainvalno5k.shapes
37 | !data/*.sh
38 |
39 | pycocotools/*
40 | results*.txt
41 | gcp_test*.sh
42 |
43 | # MATLAB GitIgnore -----------------------------------------------------------------------------------------------------
44 | *.m~
45 | *.mat
46 | !targets*.mat
47 |
48 | # Neural Network weights -----------------------------------------------------------------------------------------------
49 | *.weights
50 | *.pt
51 | *.onnx
52 | *.mlmodel
53 | *.torchscript
54 | darknet53.conv.74
55 | yolov3-tiny.conv.15
56 |
57 | # GitHub Python GitIgnore ----------------------------------------------------------------------------------------------
58 | # Byte-compiled / optimized / DLL files
59 | __pycache__/
60 | *.py[cod]
61 | *$py.class
62 |
63 | # C extensions
64 | *.so
65 |
66 | # Distribution / packaging
67 | .Python
68 | env/
69 | build/
70 | develop-eggs/
71 | dist/
72 | downloads/
73 | eggs/
74 | .eggs/
75 | lib/
76 | lib64/
77 | parts/
78 | sdist/
79 | var/
80 | wheels/
81 | *.egg-info/
82 | .installed.cfg
83 | *.egg
84 |
85 | # PyInstaller
86 | # Usually these files are written by a python script from a template
87 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
88 | *.manifest
89 | *.spec
90 |
91 | # Installer logs
92 | pip-log.txt
93 | pip-delete-this-directory.txt
94 |
95 | # Unit test / coverage reports
96 | htmlcov/
97 | .tox/
98 | .coverage
99 | .coverage.*
100 | .cache
101 | nosetests.xml
102 | coverage.xml
103 | *.cover
104 | .hypothesis/
105 |
106 | # Translations
107 | *.mo
108 | *.pot
109 |
110 | # Django stuff:
111 | *.log
112 | local_settings.py
113 |
114 | # Flask stuff:
115 | instance/
116 | .webassets-cache
117 |
118 | # Scrapy stuff:
119 | .scrapy
120 |
121 | # Sphinx documentation
122 | docs/_build/
123 |
124 | # PyBuilder
125 | target/
126 |
127 | # Jupyter Notebook
128 | .ipynb_checkpoints
129 |
130 | # pyenv
131 | .python-version
132 |
133 | # celery beat schedule file
134 | celerybeat-schedule
135 |
136 | # SageMath parsed files
137 | *.sage.py
138 |
139 | # dotenv
140 | .env
141 |
142 | # virtualenv
143 | .venv
144 | venv/
145 | ENV/
146 |
147 | # Spyder project settings
148 | .spyderproject
149 | .spyproject
150 |
151 | # Rope project settings
152 | .ropeproject
153 |
154 | # mkdocs documentation
155 | /site
156 |
157 | # mypy
158 | .mypy_cache/
159 |
160 |
161 | # https://github.com/github/gitignore/blob/master/Global/macOS.gitignore -----------------------------------------------
162 |
163 | # General
164 | .DS_Store
165 | .AppleDouble
166 | .LSOverride
167 |
168 | # Icon must end with two \r
169 | Icon
170 | Icon?
171 |
172 | # Thumbnails
173 | ._*
174 |
175 | # Files that might appear in the root of a volume
176 | .DocumentRevisions-V100
177 | .fseventsd
178 | .Spotlight-V100
179 | .TemporaryItems
180 | .Trashes
181 | .VolumeIcon.icns
182 | .com.apple.timemachine.donotpresent
183 |
184 | # Directories potentially created on remote AFP share
185 | .AppleDB
186 | .AppleDesktop
187 | Network Trash Folder
188 | Temporary Items
189 | .apdisk
190 |
191 |
192 | # https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore
193 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
194 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
195 |
196 | # User-specific stuff:
197 | .idea/*
198 | .idea/**/workspace.xml
199 | .idea/**/tasks.xml
200 | .idea/dictionaries
201 | .html # Bokeh Plots
202 | .pg # TensorFlow Frozen Graphs
203 | .avi # videos
204 |
205 | # Sensitive or high-churn files:
206 | .idea/**/dataSources/
207 | .idea/**/dataSources.ids
208 | .idea/**/dataSources.local.xml
209 | .idea/**/sqlDataSources.xml
210 | .idea/**/dynamic.xml
211 | .idea/**/uiDesigner.xml
212 |
213 | # Gradle:
214 | .idea/**/gradle.xml
215 | .idea/**/libraries
216 |
217 | # CMake
218 | cmake-build-debug/
219 | cmake-build-release/
220 |
221 | # Mongo Explorer plugin:
222 | .idea/**/mongoSettings.xml
223 |
224 | ## File-based project format:
225 | *.iws
226 |
227 | ## Plugin-specific files:
228 |
229 | # IntelliJ
230 | out/
231 |
232 | # mpeltonen/sbt-idea plugin
233 | .idea_modules/
234 |
235 | # JIRA plugin
236 | atlassian-ide-plugin.xml
237 |
238 | # Cursive Clojure plugin
239 | .idea/replstate.xml
240 |
241 | # Crashlytics plugin (for Android Studio and IntelliJ)
242 | com_crashlytics_export_strings.xml
243 | crashlytics.properties
244 | crashlytics-build.properties
245 | fabric.properties
246 |
--------------------------------------------------------------------------------
/yolov5/Dockerfile:
--------------------------------------------------------------------------------
1 | # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch
2 | FROM nvcr.io/nvidia/pytorch:20.08-py3
3 |
4 | # Install dependencies
5 | # COPY requirements.txt .
6 | # RUN pip install -r requirements.txt
7 | RUN pip install gsutil
8 |
9 | # Create working directory
10 | RUN mkdir -p /usr/src/app
11 | WORKDIR /usr/src/app
12 |
13 | # Copy contents
14 | COPY . /usr/src/app
15 |
16 | # Copy weights
17 | #RUN python3 -c "from models import *; \
18 | #attempt_download('weights/yolov5s.pt'); \
19 | #attempt_download('weights/yolov5m.pt'); \
20 | #attempt_download('weights/yolov5l.pt')"
21 |
22 |
23 | # --------------------------------------------------- Extras Below ---------------------------------------------------
24 |
25 | # Build and Push
26 | # t=ultralytics/yolov5:latest && sudo docker build -t $t . && sudo docker push $t
27 | # for v in {300..303}; do t=ultralytics/coco:v$v && sudo docker build -t $t . && sudo docker push $t; done
28 |
29 | # Pull and Run
30 | # t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host $t
31 |
32 | # Pull and Run with local directory access
33 | # t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/coco:/usr/src/coco $t
34 |
35 | # Kill all
36 | # sudo docker kill "$(sudo docker ps -q)"
37 |
38 | # Kill all image-based
39 | # sudo docker kill $(sudo docker ps -a -q --filter ancestor=ultralytics/yolov5:latest)
40 |
41 | # Bash into running container
42 | # sudo docker container exec -it ba65811811ab bash
43 |
44 | # Bash into stopped container
45 | # sudo docker commit 092b16b25c5b usr/resume && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco --entrypoint=sh usr/resume
46 |
47 | # Send weights to GCP
48 | # python -c "from utils.general import *; strip_optimizer('runs/exp0_*/weights/best.pt', 'tmp.pt')" && gsutil cp tmp.pt gs://*.pt
49 |
50 | # Clean up
51 | # docker system prune -a --volumes
52 |
--------------------------------------------------------------------------------
/yolov5/hubconf.py:
--------------------------------------------------------------------------------
1 | """File for accessing YOLOv5 via PyTorch Hub https://pytorch.org/hub/
2 |
3 | Usage:
4 | import torch
5 | model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True, channels=3, classes=80)
6 | """
7 |
8 | dependencies = ['torch', 'yaml']
9 | import os
10 |
11 | import torch
12 |
13 | from models.yolo import Model
14 | from utils.google_utils import attempt_download
15 |
16 |
17 | def create(name, pretrained, channels, classes):
18 | """Creates a specified YOLOv5 model
19 |
20 | Arguments:
21 | name (str): name of model, i.e. 'yolov5s'
22 | pretrained (bool): load pretrained weights into the model
23 | channels (int): number of input channels
24 | classes (int): number of model classes
25 |
26 | Returns:
27 | pytorch model
28 | """
29 | config = os.path.join(os.path.dirname(__file__), 'models', '%s.yaml' % name) # model.yaml path
30 | try:
31 | model = Model(config, channels, classes)
32 | if pretrained:
33 | ckpt = '%s.pt' % name # checkpoint filename
34 | attempt_download(ckpt) # download if not found locally
35 | state_dict = torch.load(ckpt, map_location=torch.device('cpu'))['model'].float().state_dict() # to FP32
36 | state_dict = {k: v for k, v in state_dict.items() if model.state_dict()[k].shape == v.shape} # filter
37 | model.load_state_dict(state_dict, strict=False) # load
38 | return model
39 |
40 | except Exception as e:
41 | help_url = 'https://github.com/ultralytics/yolov5/issues/36'
42 | s = 'Cache maybe be out of date, deleting cache and retrying may solve this. See %s for help.' % help_url
43 | raise Exception(s) from e
44 |
45 |
46 | def yolov5s(pretrained=False, channels=3, classes=80):
47 | """YOLOv5-small model from https://github.com/ultralytics/yolov5
48 |
49 | Arguments:
50 | pretrained (bool): load pretrained weights into the model, default=False
51 | channels (int): number of input channels, default=3
52 | classes (int): number of model classes, default=80
53 |
54 | Returns:
55 | pytorch model
56 | """
57 | return create('yolov5s', pretrained, channels, classes)
58 |
59 |
60 | def yolov5m(pretrained=False, channels=3, classes=80):
61 | """YOLOv5-medium model from https://github.com/ultralytics/yolov5
62 |
63 | Arguments:
64 | pretrained (bool): load pretrained weights into the model, default=False
65 | channels (int): number of input channels, default=3
66 | classes (int): number of model classes, default=80
67 |
68 | Returns:
69 | pytorch model
70 | """
71 | return create('yolov5m', pretrained, channels, classes)
72 |
73 |
74 | def yolov5l(pretrained=False, channels=3, classes=80):
75 | """YOLOv5-large model from https://github.com/ultralytics/yolov5
76 |
77 | Arguments:
78 | pretrained (bool): load pretrained weights into the model, default=False
79 | channels (int): number of input channels, default=3
80 | classes (int): number of model classes, default=80
81 |
82 | Returns:
83 | pytorch model
84 | """
85 | return create('yolov5l', pretrained, channels, classes)
86 |
87 |
88 | def yolov5x(pretrained=False, channels=3, classes=80):
89 | """YOLOv5-xlarge model from https://github.com/ultralytics/yolov5
90 |
91 | Arguments:
92 | pretrained (bool): load pretrained weights into the model, default=False
93 | channels (int): number of input channels, default=3
94 | classes (int): number of model classes, default=80
95 |
96 | Returns:
97 | pytorch model
98 | """
99 | return create('yolov5x', pretrained, channels, classes)
100 |
--------------------------------------------------------------------------------
/yolov5/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/yolov5/models/__init__.py
--------------------------------------------------------------------------------
/yolov5/models/common.py:
--------------------------------------------------------------------------------
1 | # This file contains modules common to various models
2 | import math
3 |
4 | import torch
5 | import torch.nn as nn
6 |
7 |
8 | def autopad(k, p=None): # kernel, padding
9 | # Pad to 'same'
10 | if p is None:
11 | p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad
12 | return p
13 |
14 |
15 | def DWConv(c1, c2, k=1, s=1, act=True):
16 | # Depthwise convolution
17 | return Conv(c1, c2, k, s, g=math.gcd(c1, c2), act=act)
18 |
19 |
20 | class Conv(nn.Module):
21 | # Standard convolution
22 | def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
23 | super(Conv, self).__init__()
24 | self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
25 | self.bn = nn.BatchNorm2d(c2)
26 | self.act = nn.Hardswish() if act else nn.Identity()
27 |
28 | def forward(self, x):
29 | return self.act(self.bn(self.conv(x)))
30 |
31 | def fuseforward(self, x):
32 | return self.act(self.conv(x))
33 |
34 |
35 | class Bottleneck(nn.Module):
36 | # Standard bottleneck
37 | def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion
38 | super(Bottleneck, self).__init__()
39 | c_ = int(c2 * e) # hidden channels
40 | self.cv1 = Conv(c1, c_, 1, 1)
41 | self.cv2 = Conv(c_, c2, 3, 1, g=g)
42 | self.add = shortcut and c1 == c2
43 |
44 | def forward(self, x):
45 | return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
46 |
47 |
48 | class BottleneckCSP(nn.Module):
49 | # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
50 | def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
51 | super(BottleneckCSP, self).__init__()
52 | c_ = int(c2 * e) # hidden channels
53 | self.cv1 = Conv(c1, c_, 1, 1)
54 | self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)
55 | self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False)
56 | self.cv4 = Conv(2 * c_, c2, 1, 1)
57 | self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3)
58 | self.act = nn.LeakyReLU(0.1, inplace=True)
59 | self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)])
60 |
61 | def forward(self, x):
62 | y1 = self.cv3(self.m(self.cv1(x)))
63 | y2 = self.cv2(x)
64 | return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1))))
65 |
66 |
67 | class SPP(nn.Module):
68 | # Spatial pyramid pooling layer used in YOLOv3-SPP
69 | def __init__(self, c1, c2, k=(5, 9, 13)):
70 | super(SPP, self).__init__()
71 | c_ = c1 // 2 # hidden channels
72 | self.cv1 = Conv(c1, c_, 1, 1)
73 | self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
74 | self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k])
75 |
76 | def forward(self, x):
77 | x = self.cv1(x)
78 | return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1))
79 |
80 |
81 | class Focus(nn.Module):
82 | # Focus wh information into c-space
83 | def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
84 | super(Focus, self).__init__()
85 | self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
86 |
87 | def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
88 | return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
89 |
90 |
91 | class Concat(nn.Module):
92 | # Concatenate a list of tensors along dimension
93 | def __init__(self, dimension=1):
94 | super(Concat, self).__init__()
95 | self.d = dimension
96 |
97 | def forward(self, x):
98 | return torch.cat(x, self.d)
99 |
100 |
101 | class Flatten(nn.Module):
102 | # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions
103 | @staticmethod
104 | def forward(x):
105 | return x.view(x.size(0), -1)
106 |
107 |
108 | class Classify(nn.Module):
109 | # Classification head, i.e. x(b,c1,20,20) to x(b,c2)
110 | def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups
111 | super(Classify, self).__init__()
112 | self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1)
113 | self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) # to x(b,c2,1,1)
114 | self.flat = Flatten()
115 |
116 | def forward(self, x):
117 | z = torch.cat([self.aap(y) for y in (x if isinstance(x, list) else [x])], 1) # cat if list
118 | return self.flat(self.conv(z)) # flatten to x(b,c2)
119 |
--------------------------------------------------------------------------------
/yolov5/models/experimental.py:
--------------------------------------------------------------------------------
1 | # This file contains experimental modules
2 |
3 | import numpy as np
4 | import torch
5 | import torch.nn as nn
6 |
7 | from models.common import Conv, DWConv
8 | from utils.google_utils import attempt_download
9 |
10 |
11 | class CrossConv(nn.Module):
12 | # Cross Convolution Downsample
13 | def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False):
14 | # ch_in, ch_out, kernel, stride, groups, expansion, shortcut
15 | super(CrossConv, self).__init__()
16 | c_ = int(c2 * e) # hidden channels
17 | self.cv1 = Conv(c1, c_, (1, k), (1, s))
18 | self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g)
19 | self.add = shortcut and c1 == c2
20 |
21 | def forward(self, x):
22 | return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
23 |
24 |
25 | class C3(nn.Module):
26 | # Cross Convolution CSP
27 | def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
28 | super(C3, self).__init__()
29 | c_ = int(c2 * e) # hidden channels
30 | self.cv1 = Conv(c1, c_, 1, 1)
31 | self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)
32 | self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False)
33 | self.cv4 = Conv(2 * c_, c2, 1, 1)
34 | self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3)
35 | self.act = nn.LeakyReLU(0.1, inplace=True)
36 | self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])
37 |
38 | def forward(self, x):
39 | y1 = self.cv3(self.m(self.cv1(x)))
40 | y2 = self.cv2(x)
41 | return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1))))
42 |
43 |
44 | class Sum(nn.Module):
45 | # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070
46 | def __init__(self, n, weight=False): # n: number of inputs
47 | super(Sum, self).__init__()
48 | self.weight = weight # apply weights boolean
49 | self.iter = range(n - 1) # iter object
50 | if weight:
51 | self.w = nn.Parameter(-torch.arange(1., n) / 2, requires_grad=True) # layer weights
52 |
53 | def forward(self, x):
54 | y = x[0] # no weight
55 | if self.weight:
56 | w = torch.sigmoid(self.w) * 2
57 | for i in self.iter:
58 | y = y + x[i + 1] * w[i]
59 | else:
60 | for i in self.iter:
61 | y = y + x[i + 1]
62 | return y
63 |
64 |
65 | class GhostConv(nn.Module):
66 | # Ghost Convolution https://github.com/huawei-noah/ghostnet
67 | def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
68 | super(GhostConv, self).__init__()
69 | c_ = c2 // 2 # hidden channels
70 | self.cv1 = Conv(c1, c_, k, s, g, act)
71 | self.cv2 = Conv(c_, c_, 5, 1, c_, act)
72 |
73 | def forward(self, x):
74 | y = self.cv1(x)
75 | return torch.cat([y, self.cv2(y)], 1)
76 |
77 |
78 | class GhostBottleneck(nn.Module):
79 | # Ghost Bottleneck https://github.com/huawei-noah/ghostnet
80 | def __init__(self, c1, c2, k, s):
81 | super(GhostBottleneck, self).__init__()
82 | c_ = c2 // 2
83 | self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw
84 | DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
85 | GhostConv(c_, c2, 1, 1, act=False)) # pw-linear
86 | self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False),
87 | Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity()
88 |
89 | def forward(self, x):
90 | return self.conv(x) + self.shortcut(x)
91 |
92 |
93 | class MixConv2d(nn.Module):
94 | # Mixed Depthwise Conv https://arxiv.org/abs/1907.09595
95 | def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True):
96 | super(MixConv2d, self).__init__()
97 | groups = len(k)
98 | if equal_ch: # equal c_ per group
99 | i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices
100 | c_ = [(i == g).sum() for g in range(groups)] # intermediate channels
101 | else: # equal weight.numel() per group
102 | b = [c2] + [0] * groups
103 | a = np.eye(groups + 1, groups, k=-1)
104 | a -= np.roll(a, 1, axis=1)
105 | a *= np.array(k) ** 2
106 | a[0] = 1
107 | c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b
108 |
109 | self.m = nn.ModuleList([nn.Conv2d(c1, int(c_[g]), k[g], s, k[g] // 2, bias=False) for g in range(groups)])
110 | self.bn = nn.BatchNorm2d(c2)
111 | self.act = nn.LeakyReLU(0.1, inplace=True)
112 |
113 | def forward(self, x):
114 | return x + self.act(self.bn(torch.cat([m(x) for m in self.m], 1)))
115 |
116 |
117 | class Ensemble(nn.ModuleList):
118 | # Ensemble of models
119 | def __init__(self):
120 | super(Ensemble, self).__init__()
121 |
122 | def forward(self, x, augment=False):
123 | y = []
124 | for module in self:
125 | y.append(module(x, augment)[0])
126 | # y = torch.stack(y).max(0)[0] # max ensemble
127 | # y = torch.cat(y, 1) # nms ensemble
128 | y = torch.stack(y).mean(0) # mean ensemble
129 | return y, None # inference, train output
130 |
131 |
132 | def attempt_load(weights, map_location=None):
133 | # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
134 | model = Ensemble()
135 | for w in weights if isinstance(weights, list) else [weights]:
136 | attempt_download(w)
137 | model.append(torch.load(w, map_location=map_location)['model'].float().fuse().eval()) # load FP32 model
138 |
139 | if len(model) == 1:
140 | return model[-1] # return model
141 | else:
142 | print('Ensemble created with %s\n' % weights)
143 | for k in ['names', 'stride']:
144 | setattr(model, k, getattr(model[-1], k))
145 | return model # return ensemble
146 |
--------------------------------------------------------------------------------
/yolov5/models/export.py:
--------------------------------------------------------------------------------
1 | """Exports a YOLOv5 *.pt model to ONNX and TorchScript formats
2 |
3 | Usage:
4 | $ export PYTHONPATH="$PWD" && python models/export.py --weights ./weights/yolov5s.pt --img 640 --batch 1
5 | """
6 |
7 | import argparse
8 |
9 | import torch
10 | import torch.nn as nn
11 |
12 | from models.common import Conv
13 | from models.experimental import attempt_load
14 | from utils.activations import Hardswish
15 | from utils.general import set_logging
16 |
17 | if __name__ == '__main__':
18 | parser = argparse.ArgumentParser()
19 | parser.add_argument('--weights', type=str, default='./yolov5s.pt', help='weights path') # from yolov5/models/
20 | parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') # height, width
21 | parser.add_argument('--batch-size', type=int, default=1, help='batch size')
22 | opt = parser.parse_args()
23 | opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand
24 | print(opt)
25 | set_logging()
26 |
27 | # Input
28 | img = torch.zeros((opt.batch_size, 3, *opt.img_size)) # image size(1,3,320,192) iDetection
29 |
30 | # Load PyTorch model
31 | model = attempt_load(opt.weights, map_location=torch.device('cpu')) # load FP32 model
32 |
33 | # Update model
34 | for k, m in model.named_modules():
35 | m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatability
36 | if isinstance(m, Conv) and isinstance(m.act, nn.Hardswish):
37 | m.act = Hardswish() # assign activation
38 | # if isinstance(m, Detect):
39 | # m.forward = m.forward_export # assign forward (optional)
40 | model.model[-1].export = True # set Detect() layer export=True
41 | y = model(img) # dry run
42 |
43 | # TorchScript export
44 | try:
45 | print('\nStarting TorchScript export with torch %s...' % torch.__version__)
46 | f = opt.weights.replace('.pt', '.torchscript.pt') # filename
47 | ts = torch.jit.trace(model, img)
48 | ts.save(f)
49 | print('TorchScript export success, saved as %s' % f)
50 | except Exception as e:
51 | print('TorchScript export failure: %s' % e)
52 |
53 | # ONNX export
54 | try:
55 | import onnx
56 |
57 | print('\nStarting ONNX export with onnx %s...' % onnx.__version__)
58 | f = opt.weights.replace('.pt', '.onnx') # filename
59 | torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'],
60 | output_names=['classes', 'boxes'] if y is None else ['output'])
61 |
62 | # Checks
63 | onnx_model = onnx.load(f) # load onnx model
64 | onnx.checker.check_model(onnx_model) # check onnx model
65 | # print(onnx.helper.printable_graph(onnx_model.graph)) # print a human readable model
66 | print('ONNX export success, saved as %s' % f)
67 | except Exception as e:
68 | print('ONNX export failure: %s' % e)
69 |
70 | # CoreML export
71 | try:
72 | import coremltools as ct
73 |
74 | print('\nStarting CoreML export with coremltools %s...' % ct.__version__)
75 | # convert model from torchscript and apply pixel scaling as per detect.py
76 | model = ct.convert(ts, inputs=[ct.ImageType(name='images', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])])
77 | f = opt.weights.replace('.pt', '.mlmodel') # filename
78 | model.save(f)
79 | print('CoreML export success, saved as %s' % f)
80 | except Exception as e:
81 | print('CoreML export failure: %s' % e)
82 |
83 | # Finish
84 | print('\nExport complete. Visualize with https://github.com/lutzroeder/netron.')
85 |
--------------------------------------------------------------------------------
/yolov5/models/hub/yolov3-spp.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 80 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [10,13, 16,30, 33,23] # P3/8
9 | - [30,61, 62,45, 59,119] # P4/16
10 | - [116,90, 156,198, 373,326] # P5/32
11 |
12 | # darknet53 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Conv, [32, 3, 1]], # 0
16 | [-1, 1, Conv, [64, 3, 2]], # 1-P1/2
17 | [-1, 1, Bottleneck, [64]],
18 | [-1, 1, Conv, [128, 3, 2]], # 3-P2/4
19 | [-1, 2, Bottleneck, [128]],
20 | [-1, 1, Conv, [256, 3, 2]], # 5-P3/8
21 | [-1, 8, Bottleneck, [256]],
22 | [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
23 | [-1, 8, Bottleneck, [512]],
24 | [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32
25 | [-1, 4, Bottleneck, [1024]], # 10
26 | ]
27 |
28 | # YOLOv3-SPP head
29 | head:
30 | [[-1, 1, Bottleneck, [1024, False]],
31 | [-1, 1, SPP, [512, [5, 9, 13]]],
32 | [-1, 1, Conv, [1024, 3, 1]],
33 | [-1, 1, Conv, [512, 1, 1]],
34 | [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large)
35 |
36 | [-2, 1, Conv, [256, 1, 1]],
37 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
38 | [[-1, 8], 1, Concat, [1]], # cat backbone P4
39 | [-1, 1, Bottleneck, [512, False]],
40 | [-1, 1, Bottleneck, [512, False]],
41 | [-1, 1, Conv, [256, 1, 1]],
42 | [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium)
43 |
44 | [-2, 1, Conv, [128, 1, 1]],
45 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
46 | [[-1, 6], 1, Concat, [1]], # cat backbone P3
47 | [-1, 1, Bottleneck, [256, False]],
48 | [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small)
49 |
50 | [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
51 | ]
52 |
--------------------------------------------------------------------------------
/yolov5/models/hub/yolov5-fpn.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 80 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [10,13, 16,30, 33,23] # P3/8
9 | - [30,61, 62,45, 59,119] # P4/16
10 | - [116,90, 156,198, 373,326] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Focus, [64, 3]], # 0-P1/2
16 | [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17 | [-1, 3, Bottleneck, [128]],
18 | [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19 | [-1, 9, BottleneckCSP, [256]],
20 | [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21 | [-1, 9, BottleneckCSP, [512]],
22 | [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23 | [-1, 1, SPP, [1024, [5, 9, 13]]],
24 | [-1, 6, BottleneckCSP, [1024]], # 9
25 | ]
26 |
27 | # YOLOv5 FPN head
28 | head:
29 | [[-1, 3, BottleneckCSP, [1024, False]], # 10 (P5/32-large)
30 |
31 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
32 | [[-1, 6], 1, Concat, [1]], # cat backbone P4
33 | [-1, 1, Conv, [512, 1, 1]],
34 | [-1, 3, BottleneckCSP, [512, False]], # 14 (P4/16-medium)
35 |
36 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
37 | [[-1, 4], 1, Concat, [1]], # cat backbone P3
38 | [-1, 1, Conv, [256, 1, 1]],
39 | [-1, 3, BottleneckCSP, [256, False]], # 18 (P3/8-small)
40 |
41 | [[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
42 | ]
43 |
--------------------------------------------------------------------------------
/yolov5/models/hub/yolov5-panet.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 80 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [116,90, 156,198, 373,326] # P5/32
9 | - [30,61, 62,45, 59,119] # P4/16
10 | - [10,13, 16,30, 33,23] # P3/8
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Focus, [64, 3]], # 0-P1/2
16 | [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17 | [-1, 3, BottleneckCSP, [128]],
18 | [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19 | [-1, 9, BottleneckCSP, [256]],
20 | [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21 | [-1, 9, BottleneckCSP, [512]],
22 | [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23 | [-1, 1, SPP, [1024, [5, 9, 13]]],
24 | [-1, 3, BottleneckCSP, [1024, False]], # 9
25 | ]
26 |
27 | # YOLOv5 PANet head
28 | head:
29 | [[-1, 1, Conv, [512, 1, 1]],
30 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31 | [[-1, 6], 1, Concat, [1]], # cat backbone P4
32 | [-1, 3, BottleneckCSP, [512, False]], # 13
33 |
34 | [-1, 1, Conv, [256, 1, 1]],
35 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36 | [[-1, 4], 1, Concat, [1]], # cat backbone P3
37 | [-1, 3, BottleneckCSP, [256, False]], # 17 (P3/8-small)
38 |
39 | [-1, 1, Conv, [256, 3, 2]],
40 | [[-1, 14], 1, Concat, [1]], # cat head P4
41 | [-1, 3, BottleneckCSP, [512, False]], # 20 (P4/16-medium)
42 |
43 | [-1, 1, Conv, [512, 3, 2]],
44 | [[-1, 10], 1, Concat, [1]], # cat head P5
45 | [-1, 3, BottleneckCSP, [1024, False]], # 23 (P5/32-large)
46 |
47 | [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P5, P4, P3)
48 | ]
49 |
--------------------------------------------------------------------------------
/yolov5/models/yolov5l.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 80 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [10,13, 16,30, 33,23] # P3/8
9 | - [30,61, 62,45, 59,119] # P4/16
10 | - [116,90, 156,198, 373,326] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Focus, [64, 3]], # 0-P1/2
16 | [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17 | [-1, 3, BottleneckCSP, [128]],
18 | [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19 | [-1, 9, BottleneckCSP, [256]],
20 | [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21 | [-1, 9, BottleneckCSP, [512]],
22 | [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23 | [-1, 1, SPP, [1024, [5, 9, 13]]],
24 | [-1, 3, BottleneckCSP, [1024, False]], # 9
25 | ]
26 |
27 | # YOLOv5 head
28 | head:
29 | [[-1, 1, Conv, [512, 1, 1]],
30 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31 | [[-1, 6], 1, Concat, [1]], # cat backbone P4
32 | [-1, 3, BottleneckCSP, [512, False]], # 13
33 |
34 | [-1, 1, Conv, [256, 1, 1]],
35 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36 | [[-1, 4], 1, Concat, [1]], # cat backbone P3
37 | [-1, 3, BottleneckCSP, [256, False]], # 17 (P3/8-small)
38 |
39 | [-1, 1, Conv, [256, 3, 2]],
40 | [[-1, 14], 1, Concat, [1]], # cat head P4
41 | [-1, 3, BottleneckCSP, [512, False]], # 20 (P4/16-medium)
42 |
43 | [-1, 1, Conv, [512, 3, 2]],
44 | [[-1, 10], 1, Concat, [1]], # cat head P5
45 | [-1, 3, BottleneckCSP, [1024, False]], # 23 (P5/32-large)
46 |
47 | [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48 | ]
49 |
--------------------------------------------------------------------------------
/yolov5/models/yolov5m.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 80 # number of classes
3 | depth_multiple: 0.67 # model depth multiple
4 | width_multiple: 0.75 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [10,13, 16,30, 33,23] # P3/8
9 | - [30,61, 62,45, 59,119] # P4/16
10 | - [116,90, 156,198, 373,326] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Focus, [64, 3]], # 0-P1/2
16 | [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17 | [-1, 3, BottleneckCSP, [128]],
18 | [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19 | [-1, 9, BottleneckCSP, [256]],
20 | [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21 | [-1, 9, BottleneckCSP, [512]],
22 | [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23 | [-1, 1, SPP, [1024, [5, 9, 13]]],
24 | [-1, 3, BottleneckCSP, [1024, False]], # 9
25 | ]
26 |
27 | # YOLOv5 head
28 | head:
29 | [[-1, 1, Conv, [512, 1, 1]],
30 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31 | [[-1, 6], 1, Concat, [1]], # cat backbone P4
32 | [-1, 3, BottleneckCSP, [512, False]], # 13
33 |
34 | [-1, 1, Conv, [256, 1, 1]],
35 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36 | [[-1, 4], 1, Concat, [1]], # cat backbone P3
37 | [-1, 3, BottleneckCSP, [256, False]], # 17 (P3/8-small)
38 |
39 | [-1, 1, Conv, [256, 3, 2]],
40 | [[-1, 14], 1, Concat, [1]], # cat head P4
41 | [-1, 3, BottleneckCSP, [512, False]], # 20 (P4/16-medium)
42 |
43 | [-1, 1, Conv, [512, 3, 2]],
44 | [[-1, 10], 1, Concat, [1]], # cat head P5
45 | [-1, 3, BottleneckCSP, [1024, False]], # 23 (P5/32-large)
46 |
47 | [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48 | ]
49 |
--------------------------------------------------------------------------------
/yolov5/models/yolov5s.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 80 # number of classes
3 | depth_multiple: 0.33 # model depth multiple
4 | width_multiple: 0.50 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [10,13, 16,30, 33,23] # P3/8
9 | - [30,61, 62,45, 59,119] # P4/16
10 | - [116,90, 156,198, 373,326] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Focus, [64, 3]], # 0-P1/2
16 | [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17 | [-1, 3, BottleneckCSP, [128]],
18 | [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19 | [-1, 9, BottleneckCSP, [256]],
20 | [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21 | [-1, 9, BottleneckCSP, [512]],
22 | [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23 | [-1, 1, SPP, [1024, [5, 9, 13]]],
24 | [-1, 3, BottleneckCSP, [1024, False]], # 9
25 | ]
26 |
27 | # YOLOv5 head
28 | head:
29 | [[-1, 1, Conv, [512, 1, 1]],
30 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31 | [[-1, 6], 1, Concat, [1]], # cat backbone P4
32 | [-1, 3, BottleneckCSP, [512, False]], # 13
33 |
34 | [-1, 1, Conv, [256, 1, 1]],
35 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36 | [[-1, 4], 1, Concat, [1]], # cat backbone P3
37 | [-1, 3, BottleneckCSP, [256, False]], # 17 (P3/8-small)
38 |
39 | [-1, 1, Conv, [256, 3, 2]],
40 | [[-1, 14], 1, Concat, [1]], # cat head P4
41 | [-1, 3, BottleneckCSP, [512, False]], # 20 (P4/16-medium)
42 |
43 | [-1, 1, Conv, [512, 3, 2]],
44 | [[-1, 10], 1, Concat, [1]], # cat head P5
45 | [-1, 3, BottleneckCSP, [1024, False]], # 23 (P5/32-large)
46 |
47 | [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48 | ]
49 |
--------------------------------------------------------------------------------
/yolov5/models/yolov5x.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 80 # number of classes
3 | depth_multiple: 1.33 # model depth multiple
4 | width_multiple: 1.25 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [10,13, 16,30, 33,23] # P3/8
9 | - [30,61, 62,45, 59,119] # P4/16
10 | - [116,90, 156,198, 373,326] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, Focus, [64, 3]], # 0-P1/2
16 | [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
17 | [-1, 3, BottleneckCSP, [128]],
18 | [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
19 | [-1, 9, BottleneckCSP, [256]],
20 | [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
21 | [-1, 9, BottleneckCSP, [512]],
22 | [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
23 | [-1, 1, SPP, [1024, [5, 9, 13]]],
24 | [-1, 3, BottleneckCSP, [1024, False]], # 9
25 | ]
26 |
27 | # YOLOv5 head
28 | head:
29 | [[-1, 1, Conv, [512, 1, 1]],
30 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31 | [[-1, 6], 1, Concat, [1]], # cat backbone P4
32 | [-1, 3, BottleneckCSP, [512, False]], # 13
33 |
34 | [-1, 1, Conv, [256, 1, 1]],
35 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36 | [[-1, 4], 1, Concat, [1]], # cat backbone P3
37 | [-1, 3, BottleneckCSP, [256, False]], # 17 (P3/8-small)
38 |
39 | [-1, 1, Conv, [256, 3, 2]],
40 | [[-1, 14], 1, Concat, [1]], # cat head P4
41 | [-1, 3, BottleneckCSP, [512, False]], # 20 (P4/16-medium)
42 |
43 | [-1, 1, Conv, [512, 3, 2]],
44 | [[-1, 10], 1, Concat, [1]], # cat head P5
45 | [-1, 3, BottleneckCSP, [1024, False]], # 23 (P5/32-large)
46 |
47 | [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
48 | ]
49 |
--------------------------------------------------------------------------------
/yolov5/requirements.txt:
--------------------------------------------------------------------------------
1 | # pip install -r requirements.txt
2 |
3 | # base ----------------------------------------
4 | Cython
5 | matplotlib>=3.2.2
6 | numpy>=1.18.5
7 | opencv-python>=4.1.2
8 | pillow
9 | PyYAML>=5.3
10 | scipy>=1.4.1
11 | tensorboard>=2.2
12 | torch>=1.6.0
13 | torchvision>=0.7.0
14 | tqdm>=4.41.0
15 |
16 | # coco ----------------------------------------
17 | # pycocotools>=2.0
18 |
19 | # export --------------------------------------
20 | # packaging # for coremltools
21 | # coremltools==4.0b3
22 | # onnx>=1.7.0
23 | # scikit-learn==0.19.2 # for coreml quantization
24 |
25 | # extras --------------------------------------
26 | # thop
27 |
--------------------------------------------------------------------------------
/yolov5/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BioMeasure/PyQt5_YoLoV5_DeepSort/4510632b9ed8dcb22c19f4ef87588f1b42d2575c/yolov5/utils/__init__.py
--------------------------------------------------------------------------------
/yolov5/utils/activations.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn as nn
3 | import torch.nn.functional as F
4 |
5 |
6 | # Swish https://arxiv.org/pdf/1905.02244.pdf ---------------------------------------------------------------------------
7 | class Swish(nn.Module): #
8 | @staticmethod
9 | def forward(x):
10 | return x * torch.sigmoid(x)
11 |
12 |
13 | class Hardswish(nn.Module): # export-friendly version of nn.Hardswish()
14 | @staticmethod
15 | def forward(x):
16 | # return x * F.hardsigmoid(x) # for torchscript and CoreML
17 | return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX
18 |
19 |
20 | class MemoryEfficientSwish(nn.Module):
21 | class F(torch.autograd.Function):
22 | @staticmethod
23 | def forward(ctx, x):
24 | ctx.save_for_backward(x)
25 | return x * torch.sigmoid(x)
26 |
27 | @staticmethod
28 | def backward(ctx, grad_output):
29 | x = ctx.saved_tensors[0]
30 | sx = torch.sigmoid(x)
31 | return grad_output * (sx * (1 + x * (1 - sx)))
32 |
33 | def forward(self, x):
34 | return self.F.apply(x)
35 |
36 |
37 | # Mish https://github.com/digantamisra98/Mish --------------------------------------------------------------------------
38 | class Mish(nn.Module):
39 | @staticmethod
40 | def forward(x):
41 | return x * F.softplus(x).tanh()
42 |
43 |
44 | class MemoryEfficientMish(nn.Module):
45 | class F(torch.autograd.Function):
46 | @staticmethod
47 | def forward(ctx, x):
48 | ctx.save_for_backward(x)
49 | return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x)))
50 |
51 | @staticmethod
52 | def backward(ctx, grad_output):
53 | x = ctx.saved_tensors[0]
54 | sx = torch.sigmoid(x)
55 | fx = F.softplus(x).tanh()
56 | return grad_output * (fx + x * sx * (1 - fx * fx))
57 |
58 | def forward(self, x):
59 | return self.F.apply(x)
60 |
61 |
62 | # FReLU https://arxiv.org/abs/2007.11824 -------------------------------------------------------------------------------
63 | class FReLU(nn.Module):
64 | def __init__(self, c1, k=3): # ch_in, kernel
65 | super().__init__()
66 | self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1)
67 | self.bn = nn.BatchNorm2d(c1)
68 |
69 | def forward(self, x):
70 | return torch.max(x, self.bn(self.conv(x)))
71 |
--------------------------------------------------------------------------------
/yolov5/utils/evolve.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Hyperparameter evolution commands (avoids CUDA memory leakage issues)
3 | # Replaces train.py python generations 'for' loop with a bash 'for' loop
4 |
5 | # Start on 4-GPU machine
6 | #for i in 0 1 2 3; do
7 | # t=ultralytics/yolov5:test && sudo docker pull $t && sudo docker run -d --ipc=host --gpus all -v "$(pwd)"/VOC:/usr/src/VOC $t bash utils/evolve.sh $i
8 | # sleep 60 # avoid simultaneous evolve.txt read/write
9 | #done
10 |
11 | # Hyperparameter evolution commands
12 | while true; do
13 | python train.py --batch 64 --weights yolov5m.pt --data voc.yaml --img 512 --epochs 50 --evolve --bucket ult/voc --device $1
14 | done
15 |
--------------------------------------------------------------------------------
/yolov5/utils/google_utils.py:
--------------------------------------------------------------------------------
1 | # This file contains google utils: https://cloud.google.com/storage/docs/reference/libraries
2 | # pip install --upgrade google-cloud-storage
3 | # from google.cloud import storage
4 |
5 | import os
6 | import platform
7 | import time
8 | from pathlib import Path
9 |
10 | import torch
11 |
12 |
13 | def attempt_download(weights):
14 | # Attempt to download pretrained weights if not found locally
15 | weights = weights.strip().replace("'", '')
16 | file = Path(weights).name
17 |
18 | msg = weights + ' missing, try downloading from https://github.com/ultralytics/yolov5/releases/'
19 | models = ['yolov5s.pt', 'yolov5m.pt', 'yolov5l.pt', 'yolov5x.pt'] # available models
20 |
21 | if file in models and not os.path.isfile(weights):
22 | # Google Drive
23 | # d = {'yolov5s.pt': '1R5T6rIyy3lLwgFXNms8whc-387H0tMQO',
24 | # 'yolov5m.pt': '1vobuEExpWQVpXExsJ2w-Mbf3HJjWkQJr',
25 | # 'yolov5l.pt': '1hrlqD1Wdei7UT4OgT785BEk1JwnSvNEV',
26 | # 'yolov5x.pt': '1mM8aZJlWTxOg7BZJvNUMrTnA2AbeCVzS'}
27 | # r = gdrive_download(id=d[file], name=weights) if file in d else 1
28 | # if r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6: # check
29 | # return
30 |
31 | try: # GitHub
32 | url = 'https://github.com/ultralytics/yolov5/releases/download/v3.0/' + file
33 | print('Downloading %s to %s...' % (url, weights))
34 | if platform.system() == 'Darwin': # avoid MacOS python requests certificate error
35 | r = os.system('curl -L %s -o %s' % (url, weights))
36 | else:
37 | torch.hub.download_url_to_file(url, weights)
38 | assert os.path.exists(weights) and os.path.getsize(weights) > 1E6 # check
39 | except Exception as e: # GCP
40 | print('Download error: %s' % e)
41 | url = 'https://storage.googleapis.com/ultralytics/yolov5/ckpt/' + file
42 | print('Downloading %s to %s...' % (url, weights))
43 | r = os.system('curl -L %s -o %s' % (url, weights)) # torch.hub.download_url_to_file(url, weights)
44 | finally:
45 | if not (os.path.exists(weights) and os.path.getsize(weights) > 1E6): # check
46 | os.remove(weights) if os.path.exists(weights) else None # remove partial downloads
47 | print('ERROR: Download failure: %s' % msg)
48 | print('')
49 | return
50 |
51 |
52 | def gdrive_download(id='1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', name='coco128.zip'):
53 | # Downloads a file from Google Drive. from utils.google_utils import *; gdrive_download()
54 | t = time.time()
55 |
56 | print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='')
57 | os.remove(name) if os.path.exists(name) else None # remove existing
58 | os.remove('cookie') if os.path.exists('cookie') else None
59 |
60 | # Attempt file download
61 | out = "NUL" if platform.system() == "Windows" else "/dev/null"
62 | os.system('curl -c ./cookie -s -L "drive.google.com/uc?export=download&id=%s" > %s ' % (id, out))
63 | if os.path.exists('cookie'): # large file
64 | s = 'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm=%s&id=%s" -o %s' % (get_token(), id, name)
65 | else: # small file
66 | s = 'curl -s -L -o %s "drive.google.com/uc?export=download&id=%s"' % (name, id)
67 | r = os.system(s) # execute, capture return
68 | os.remove('cookie') if os.path.exists('cookie') else None
69 |
70 | # Error check
71 | if r != 0:
72 | os.remove(name) if os.path.exists(name) else None # remove partial
73 | print('Download error ') # raise Exception('Download error')
74 | return r
75 |
76 | # Unzip if archive
77 | if name.endswith('.zip'):
78 | print('unzipping... ', end='')
79 | os.system('unzip -q %s' % name) # unzip
80 | os.remove(name) # remove zip to free space
81 |
82 | print('Done (%.1fs)' % (time.time() - t))
83 | return r
84 |
85 |
86 | def get_token(cookie="./cookie"):
87 | with open(cookie) as f:
88 | for line in f:
89 | if "download" in line:
90 | return line.split()[-1]
91 | return ""
92 |
93 | # def upload_blob(bucket_name, source_file_name, destination_blob_name):
94 | # # Uploads a file to a bucket
95 | # # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python
96 | #
97 | # storage_client = storage.Client()
98 | # bucket = storage_client.get_bucket(bucket_name)
99 | # blob = bucket.blob(destination_blob_name)
100 | #
101 | # blob.upload_from_filename(source_file_name)
102 | #
103 | # print('File {} uploaded to {}.'.format(
104 | # source_file_name,
105 | # destination_blob_name))
106 | #
107 | #
108 | # def download_blob(bucket_name, source_blob_name, destination_file_name):
109 | # # Uploads a blob from a bucket
110 | # storage_client = storage.Client()
111 | # bucket = storage_client.get_bucket(bucket_name)
112 | # blob = bucket.blob(source_blob_name)
113 | #
114 | # blob.download_to_filename(destination_file_name)
115 | #
116 | # print('Blob {} downloaded to {}.'.format(
117 | # source_blob_name,
118 | # destination_file_name))
119 |
--------------------------------------------------------------------------------
/yolov5/weights/download_weights.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Download common models
3 |
4 | python -c "
5 | from utils.google_utils import *;
6 | attempt_download('weights/yolov5s.pt');
7 | attempt_download('weights/yolov5m.pt');
8 | attempt_download('weights/yolov5l.pt');
9 | attempt_download('weights/yolov5x.pt')
10 | "
11 |
--------------------------------------------------------------------------------