├── .gitignore ├── README.md ├── assets ├── Flask_logo.svg ├── screen.gif ├── zidane_bbox.png └── zidane_pose.png ├── client.py ├── data ├── coco.yaml ├── coco128-seg.yaml ├── coco128.yaml └── images │ ├── bus.jpg │ ├── ppe.png │ └── zidane.jpg ├── predict_api.py ├── requirements.txt ├── templates └── index.html └── utils └── general.py /.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 | *.cfg 23 | !setup.cfg 24 | !cfg/yolov3*.cfg 25 | 26 | storage.googleapis.com 27 | runs/* 28 | data/* 29 | data/images/* 30 | !data/*.yaml 31 | !data/hyps 32 | !data/scripts 33 | !data/images 34 | !data/images/zidane.jpg 35 | !data/images/bus.jpg 36 | !data/*.sh 37 | 38 | results*.csv 39 | 40 | # Datasets ------------------------------------------------------------------------------------------------------------- 41 | coco/ 42 | coco128/ 43 | VOC/ 44 | 45 | # MATLAB GitIgnore ----------------------------------------------------------------------------------------------------- 46 | *.m~ 47 | *.mat 48 | !targets*.mat 49 | 50 | # Neural Network weights ----------------------------------------------------------------------------------------------- 51 | *.weights 52 | *.pt 53 | *.pb 54 | *.onnx 55 | *.engine 56 | *.mlmodel 57 | *.torchscript 58 | *.tflite 59 | *.h5 60 | *_saved_model/ 61 | *_web_model/ 62 | *_openvino_model/ 63 | *_paddle_model/ 64 | darknet53.conv.74 65 | yolov3-tiny.conv.15 66 | 67 | # GitHub Python GitIgnore ---------------------------------------------------------------------------------------------- 68 | # Byte-compiled / optimized / DLL files 69 | __pycache__/ 70 | *.py[cod] 71 | *$py.class 72 | 73 | # C extensions 74 | *.so 75 | 76 | # Distribution / packaging 77 | .Python 78 | env/ 79 | build/ 80 | develop-eggs/ 81 | dist/ 82 | downloads/ 83 | eggs/ 84 | .eggs/ 85 | lib/ 86 | lib64/ 87 | parts/ 88 | sdist/ 89 | var/ 90 | wheels/ 91 | *.egg-info/ 92 | /wandb/ 93 | .installed.cfg 94 | *.egg 95 | 96 | 97 | # PyInstaller 98 | # Usually these files are written by a python script from a template 99 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 100 | *.manifest 101 | *.spec 102 | 103 | # Installer logs 104 | pip-log.txt 105 | pip-delete-this-directory.txt 106 | 107 | # Unit test / coverage reports 108 | htmlcov/ 109 | .tox/ 110 | .coverage 111 | .coverage.* 112 | .cache 113 | nosetests.xml 114 | coverage.xml 115 | *.cover 116 | .hypothesis/ 117 | 118 | # Translations 119 | *.mo 120 | *.pot 121 | 122 | # Django stuff: 123 | *.log 124 | local_settings.py 125 | 126 | # Flask stuff: 127 | instance/ 128 | .webassets-cache 129 | 130 | # Scrapy stuff: 131 | .scrapy 132 | 133 | # Sphinx documentation 134 | docs/_build/ 135 | 136 | # PyBuilder 137 | target/ 138 | 139 | # Jupyter Notebook 140 | .ipynb_checkpoints 141 | 142 | # pyenv 143 | .python-version 144 | 145 | # celery beat schedule file 146 | celerybeat-schedule 147 | 148 | # SageMath parsed files 149 | *.sage.py 150 | 151 | # dotenv 152 | .env 153 | 154 | # virtualenv 155 | .venv* 156 | venv*/ 157 | ENV*/ 158 | 159 | # Spyder project settings 160 | .spyderproject 161 | .spyproject 162 | 163 | # Rope project settings 164 | .ropeproject 165 | 166 | # mkdocs documentation 167 | /site 168 | 169 | # mypy 170 | .mypy_cache/ 171 | 172 | 173 | # https://github.com/github/gitignore/blob/master/Global/macOS.gitignore ----------------------------------------------- 174 | 175 | # General 176 | .DS_Store 177 | .AppleDouble 178 | .LSOverride 179 | 180 | # Icon must end with two \r 181 | Icon 182 | Icon? 183 | 184 | # Thumbnails 185 | ._* 186 | 187 | # Files that might appear in the root of a volume 188 | .DocumentRevisions-V100 189 | .fseventsd 190 | .Spotlight-V100 191 | .TemporaryItems 192 | .Trashes 193 | .VolumeIcon.icns 194 | .com.apple.timemachine.donotpresent 195 | 196 | # Directories potentially created on remote AFP share 197 | .AppleDB 198 | .AppleDesktop 199 | Network Trash Folder 200 | Temporary Items 201 | .apdisk 202 | 203 | 204 | # https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore 205 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 206 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 207 | 208 | # User-specific stuff: 209 | .idea/* 210 | .idea/**/workspace.xml 211 | .idea/**/tasks.xml 212 | .idea/dictionaries 213 | .html # Bokeh Plots 214 | .pg # TensorFlow Frozen Graphs 215 | .avi # videos 216 | 217 | # Sensitive or high-churn files: 218 | .idea/**/dataSources/ 219 | .idea/**/dataSources.ids 220 | .idea/**/dataSources.local.xml 221 | .idea/**/sqlDataSources.xml 222 | .idea/**/dynamic.xml 223 | .idea/**/uiDesigner.xml 224 | 225 | # Gradle: 226 | .idea/**/gradle.xml 227 | .idea/**/libraries 228 | 229 | # CMake 230 | cmake-build-debug/ 231 | cmake-build-release/ 232 | 233 | # Mongo Explorer plugin: 234 | .idea/**/mongoSettings.xml 235 | 236 | ## File-based project format: 237 | *.iws 238 | 239 | ## Plugin-specific files: 240 | 241 | # IntelliJ 242 | out/ 243 | 244 | # mpeltonen/sbt-idea plugin 245 | .idea_modules/ 246 | 247 | # JIRA plugin 248 | atlassian-ide-plugin.xml 249 | 250 | # Cursive Clojure plugin 251 | .idea/replstate.xml 252 | 253 | # Crashlytics plugin (for Android Studio and IntelliJ) 254 | com_crashlytics_export_strings.xml 255 | crashlytics.properties 256 | crashlytics-build.properties 257 | fabric.properties 258 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # Ultralytics Flask API for detection and segmentation 6 | 7 |
8 | 9 | Buy Me A Coffee 10 | 11 |
12 | 13 | ![Screen GIF](assets/screen.gif) 14 | 15 | This code is based on the Ultralytics repo and it has all the functionalities that the original code has: 16 | - Different source: images, videos, webcam, RTSP cameras. 17 | - All the weights are supported: TensorRT, Onnx, DNN, openvino. 18 | 19 | The API can be called in an interactive way, and also as a single API called from terminal and it supports all the tasks provided by Ultralytics (detection, segmentation, classification and pose estimation) in the same API!!!! 20 | 21 | All [models](https://github.com/ultralytics/ultralytics/tree/main/ultralytics/cfg/models) download automatically from the latest Ultralytics [release](https://github.com/ultralytics/assets/releases) on first use. 22 | 23 | 24 | 25 | ## Requirements 26 | 27 | Python 3.8 or later with all [requirements.txt](requirements.txt) dependencies installed, including `torch>=1.7`. To install run: 28 | 29 | ```bash 30 | $ pip3 install -r requirements.txt 31 | ``` 32 | 33 | ## [Detection](https://docs.ultralytics.com/tasks/detect), [Segmentation](https://docs.ultralytics.com/tasks/segment), [Classification](https://docs.ultralytics.com/tasks/classify) and [Pose Estimation](https://docs.ultralytics.com/tasks/pose) models pretrained on the [COCO](https://docs.ultralytics.com/datasets/detect/coco) in the same API 34 | 35 | `predict_api.py` can deal with several sources and can run into the cpu, but it is highly recommendable to run in gpu. 36 | 37 | ```bash 38 | Usage - formats: 39 | $ python predict_api.py --weights yolov8s.pt # PyTorch 40 | yolov8s.torchscript # TorchScript 41 | yolov8s.onnx # ONNX Runtime or OpenCV DNN with --dnn 42 | yolov8s_openvino_model # OpenVINO 43 | yolov8s.engine # TensorRT 44 | yolov8s.mlmodel # CoreML (macOS-only) 45 | yolov8s_saved_model # TensorFlow SavedModel 46 | yolov8s.pb # TensorFlow GraphDef 47 | yolov8s.tflite # TensorFlow Lite 48 | yolov8s_edgetpu.tflite # TensorFlow Edge TPU 49 | yolov8s_paddle_model # PaddlePaddle 50 | 51 | Usage - tasks: 52 | $ python predict_api.py --weights yolov8s.pt # Detection 53 | yolov8s-seg.pt # Segmentation 54 | yolov8s-cls.pt # Classification 55 | yolov8s-pose.pt # Pose Estimation 56 | ``` 57 | 58 | ## Interactive implementation implemntation 59 | 60 | You can deploy the API able to label an interactive way. 61 | 62 | Run: 63 | 64 | ```bash 65 | $ python predict_api.py --device cpu # to run into cpu (by default is gpu) 66 | ``` 67 | Open the application in any browser 0.0.0.0:5000 and upload your image or video as is shown in video above. 68 | 69 | 70 | ## How to use the API 71 | 72 | ### Interactive way 73 | Just open your favorite browser and go to 0.0.0.0:5000 and intuitevely load the image you want to label and press the buttom "Upload image". 74 | 75 | The API will return the image or video labeled. 76 | 77 | ![Alt text](assets/zidane_bbox.png) 78 | 79 | All tasks are supported, for pose estimation, resutls should be as follow: 80 | ![Zidane pose](assets/zidane_pose.png) 81 | 82 | 83 | ### Call from terminal or python script 84 | The `client.py` code provides several example about how the API can be called. A very common way to do it is to call a public image from url and to get the coordinates of the bounding boxes: 85 | 86 | ```python 87 | import requests 88 | 89 | resp = requests.get("http://0.0.0.0:5000/predict?source=https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/assets/zidane.jpg&save_txt=T", 90 | verify=False) 91 | print(resp.content) 92 | 93 | ``` 94 | And you will get a json with the following data: 95 | 96 | ``` 97 | b'{"results": [{"name": "person", "class": 0, "confidence": 0.8892598748207092, "box": {"x1": 747.315673828125, "y1": 41.47210693359375, "x2": 1140.3927001953125, "y2": 712.91650390625}}, {"name": "person", "class": 0, "confidence": 0.8844665288925171, "box": {"x1": 144.88815307617188, "y1": 200.0352783203125, "x2": 1107.232177734375, "y2": 712.7000732421875}}, {"name": "tie", "class": 27, "confidence": 0.7176544070243835, "box": {"x1": 437.38336181640625, "y1": 434.477294921875, "x2": 529.9751586914062, "y2": 717.05126953125}}]}' 98 | ``` 99 | 100 | In the case of pose estimation results are like this: 101 | ``` 102 | b'{"results": [{"name": "person", "class": 0, "confidence": 0.9490957260131836, "box": {"x1": 239.0, "y1": 15.0, "x2": 1018.0, "y2": 1053.0}, "keypoints": {"x": [604.9951782226562, 653.2091064453125, 552.5707397460938, 697.6889038085938, 457.49749755859375, 786.6876831054688, 358.194091796875, 954.072998046875, 488.3907775878906, 684.831298828125, 802.8469848632812, 687.2332153320312, 412.4287414550781, 924.52685546875, 632.3346557617188, 811.2559814453125, 768.5433349609375], "y": [316.5501403808594, 260.7156066894531, 257.27691650390625, 291.1667175292969, 285.6615905761719, 566.11962890625, 596.4549560546875, 909.6119384765625, 965.7925415039062, 997.584716796875, 841.6057739257812, 1066.0, 1066.0, 850.1934204101562, 812.7511596679688, 954.5965576171875, 951.3284912109375], "visible": [0.9959749579429626, 0.9608340859413147, 0.9934138655662537, 0.4281827211380005, 0.9349473118782043, 0.9848191738128662, 0.9723504185676575, 0.8565006852149963, 0.8561225533485413, 0.9004713296890259, 0.9377612471580505, 0.10934382677078247, 0.08168646693229675, 0.008380762301385403, 0.008864155039191246, 0.0017155600944533944, 0.001865472993813455]}}]}' 103 | ``` 104 | 105 | 106 | ## TODO 107 | - [ ] Return txt values for videos 108 | - [ ] save folder according to task: detect, pose, segment, ... 109 | - [ ] Support any other model: SAM, RTDETR, NAS. 110 | - [ ] Docker files 111 | - [ ] Improve index template 112 | 113 | 114 | ## About me and contact 115 | 116 | This code is based on the Ultralytics code and it has been modified by Henry Navarro 117 | 118 | If you want to know more about me, please visit my blog: [henrynavarro.org](https://henrynavarro.org). 119 | -------------------------------------------------------------------------------- /assets/Flask_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 27 | 34 | 41 | 48 | 55 | 62 | 69 | 76 | 83 | 90 | 97 | 104 | 105 | 123 | 125 | 126 | 128 | image/svg+xml 129 | 131 | 132 | 133 | 134 | 135 | 140 | 144 | 147 | 151 | 155 | 159 | 163 | 167 | 168 | 172 | 176 | 180 | 184 | 188 | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | 256 | 260 | 264 | 268 | 272 | 276 | 280 | 284 | 288 | 289 | 290 | 291 | -------------------------------------------------------------------------------- /assets/screen.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdnh2006/ultralyticsAPI/f9cd75046c86d16f7fd11513f2ef83d559999357/assets/screen.gif -------------------------------------------------------------------------------- /assets/zidane_bbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdnh2006/ultralyticsAPI/f9cd75046c86d16f7fd11513f2ef83d559999357/assets/zidane_bbox.png -------------------------------------------------------------------------------- /assets/zidane_pose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdnh2006/ultralyticsAPI/f9cd75046c86d16f7fd11513f2ef83d559999357/assets/zidane_pose.png -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | ____ _ _ _ 4 | / ___| | | (_) ___ _ __ | |_ _ __ _ _ 5 | | | | | | | / _ \ | '_ \ | __| | '_ \ | | | | 6 | | |___ | | | | | __/ | | | | | |_ _ | |_) | | |_| | 7 | \____| |_| |_| \___| |_| |_| \__| (_) | .__/ \__, | 8 | |_| |___/ 9 | 10 | The following lines of code show how to make requests to the API 11 | ''' 12 | 13 | import requests 14 | 15 | # ====================== Public image ====================== # 16 | 17 | # Saving txt file 18 | resp = requests.get('http://0.0.0.0:5000/predict?source=https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/assets/zidane.jpg&save_txt=T', 19 | verify=False) 20 | print(resp.content) 21 | 22 | # Without save txt file, just labeling the image 23 | resp = requests.get('http://0.0.0.0:5000/predict?source=https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/assets/zidane.jpg', 24 | verify=False) 25 | print(resp.content) 26 | 27 | # You can also copy and paste the following url in your browser 28 | 'http://0.0.0.0:5000/predict?source=https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/assets/zidane.jpg' 29 | 30 | 31 | # ====================== Public video ====================== # 32 | # (Youtube or any public server). It is not ready (yet) to return all frames labeled while using save_txt=T. So, don't try it! 33 | 34 | resp = requests.get('http://0.0.0.0:5000/predict?source=https://www.youtube.com/watch?v=MNn9qKG2UFI', 35 | verify=False) 36 | 37 | # You can also copy and paste the following url in your browser 38 | 'http://0.0.0.0:5000/predict?source=https://www.youtube.com/watch?v=MNn9qKG2UFI' 39 | 40 | # ====================== Send local file ==================== # 41 | 42 | 43 | url = 'http://0.0.0.0:5000/predict' 44 | file_path = 'data/images/bus.jpg' 45 | 46 | params = { 47 | 'save_txt': 'T' 48 | } 49 | 50 | with open(file_path, "rb") as f: 51 | response = requests.post(url, files={"myfile": f}, data=params, verify=False) 52 | 53 | print(response.content) -------------------------------------------------------------------------------- /data/coco.yaml: -------------------------------------------------------------------------------- 1 | # VISION ANALYTICS 👁️ OBJECT DETECTOR by Vision Analytics 2 | # COCO 2017 dataset http://cocodataset.org by Microsoft 3 | # Example usage: python train.py --data coco.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── coco ← downloads here (20.1 GB) 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/coco # dataset root dir 12 | train: train2017.txt # train images (relative to 'path') 118287 images 13 | val: val2017.txt # val images (relative to 'path') 5000 images 14 | test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 15 | 16 | # Classes 17 | names: 18 | 0: person 19 | 1: bicycle 20 | 2: car 21 | 3: motorcycle 22 | 4: airplane 23 | 5: bus 24 | 6: train 25 | 7: truck 26 | 8: boat 27 | 9: traffic light 28 | 10: fire hydrant 29 | 11: stop sign 30 | 12: parking meter 31 | 13: bench 32 | 14: bird 33 | 15: cat 34 | 16: dog 35 | 17: horse 36 | 18: sheep 37 | 19: cow 38 | 20: elephant 39 | 21: bear 40 | 22: zebra 41 | 23: giraffe 42 | 24: backpack 43 | 25: umbrella 44 | 26: handbag 45 | 27: tie 46 | 28: suitcase 47 | 29: frisbee 48 | 30: skis 49 | 31: snowboard 50 | 32: sports ball 51 | 33: kite 52 | 34: baseball bat 53 | 35: baseball glove 54 | 36: skateboard 55 | 37: surfboard 56 | 38: tennis racket 57 | 39: bottle 58 | 40: wine glass 59 | 41: cup 60 | 42: fork 61 | 43: knife 62 | 44: spoon 63 | 45: bowl 64 | 46: banana 65 | 47: apple 66 | 48: sandwich 67 | 49: orange 68 | 50: broccoli 69 | 51: carrot 70 | 52: hot dog 71 | 53: pizza 72 | 54: donut 73 | 55: cake 74 | 56: chair 75 | 57: couch 76 | 58: potted plant 77 | 59: bed 78 | 60: dining table 79 | 61: toilet 80 | 62: tv 81 | 63: laptop 82 | 64: mouse 83 | 65: remote 84 | 66: keyboard 85 | 67: cell phone 86 | 68: microwave 87 | 69: oven 88 | 70: toaster 89 | 71: sink 90 | 72: refrigerator 91 | 73: book 92 | 74: clock 93 | 75: vase 94 | 76: scissors 95 | 77: teddy bear 96 | 78: hair drier 97 | 79: toothbrush 98 | 99 | 100 | # Download script/URL (optional) 101 | download: | 102 | from utils.general import download, Path 103 | 104 | 105 | # Download labels 106 | segments = False # segment or box labels 107 | dir = Path(yaml['path']) # dataset root dir 108 | url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/' 109 | urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')] # labels 110 | download(urls, dir=dir.parent) 111 | 112 | # Download data 113 | urls = ['http://images.cocodataset.org/zips/train2017.zip', # 19G, 118k images 114 | 'http://images.cocodataset.org/zips/val2017.zip', # 1G, 5k images 115 | 'http://images.cocodataset.org/zips/test2017.zip'] # 7G, 41k images (optional) 116 | download(urls, dir=dir / 'images', threads=3) 117 | -------------------------------------------------------------------------------- /data/coco128-seg.yaml: -------------------------------------------------------------------------------- 1 | # VISION ANALYTICS 👁️ OBJECT DETECTOR by Vision Analytics 2 | # COCO128-seg dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Vision Analytics 3 | # Example usage: python train.py --data coco128.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── coco128-seg ← downloads here (7 MB) 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/coco128-seg # dataset root dir 12 | train: images/train2017 # train images (relative to 'path') 128 images 13 | val: images/train2017 # val images (relative to 'path') 128 images 14 | test: # test images (optional) 15 | 16 | # Classes 17 | names: 18 | 0: person 19 | 1: bicycle 20 | 2: car 21 | 3: motorcycle 22 | 4: airplane 23 | 5: bus 24 | 6: train 25 | 7: truck 26 | 8: boat 27 | 9: traffic light 28 | 10: fire hydrant 29 | 11: stop sign 30 | 12: parking meter 31 | 13: bench 32 | 14: bird 33 | 15: cat 34 | 16: dog 35 | 17: horse 36 | 18: sheep 37 | 19: cow 38 | 20: elephant 39 | 21: bear 40 | 22: zebra 41 | 23: giraffe 42 | 24: backpack 43 | 25: umbrella 44 | 26: handbag 45 | 27: tie 46 | 28: suitcase 47 | 29: frisbee 48 | 30: skis 49 | 31: snowboard 50 | 32: sports ball 51 | 33: kite 52 | 34: baseball bat 53 | 35: baseball glove 54 | 36: skateboard 55 | 37: surfboard 56 | 38: tennis racket 57 | 39: bottle 58 | 40: wine glass 59 | 41: cup 60 | 42: fork 61 | 43: knife 62 | 44: spoon 63 | 45: bowl 64 | 46: banana 65 | 47: apple 66 | 48: sandwich 67 | 49: orange 68 | 50: broccoli 69 | 51: carrot 70 | 52: hot dog 71 | 53: pizza 72 | 54: donut 73 | 55: cake 74 | 56: chair 75 | 57: couch 76 | 58: potted plant 77 | 59: bed 78 | 60: dining table 79 | 61: toilet 80 | 62: tv 81 | 63: laptop 82 | 64: mouse 83 | 65: remote 84 | 66: keyboard 85 | 67: cell phone 86 | 68: microwave 87 | 69: oven 88 | 70: toaster 89 | 71: sink 90 | 72: refrigerator 91 | 73: book 92 | 74: clock 93 | 75: vase 94 | 76: scissors 95 | 77: teddy bear 96 | 78: hair drier 97 | 79: toothbrush 98 | 99 | 100 | # Download script/URL (optional) 101 | download: https://ultralytics.com/assets/coco128-seg.zip 102 | -------------------------------------------------------------------------------- /data/coco128.yaml: -------------------------------------------------------------------------------- 1 | # VISION ANALYTICS 👁️ OBJECT DETECTOR by Vision Analytics 2 | # COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Vision Analytics 3 | # Example usage: python train.py --data coco128.yaml 4 | # parent 5 | # ├── yolov5 6 | # └── datasets 7 | # └── coco128 ← downloads here (7 MB) 8 | 9 | 10 | # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] 11 | path: ../datasets/coco128 # dataset root dir 12 | train: images/train2017 # train images (relative to 'path') 128 images 13 | val: images/train2017 # val images (relative to 'path') 128 images 14 | test: # test images (optional) 15 | 16 | # Classes 17 | names: 18 | 0: person 19 | 1: bicycle 20 | 2: car 21 | 3: motorcycle 22 | 4: airplane 23 | 5: bus 24 | 6: train 25 | 7: truck 26 | 8: boat 27 | 9: traffic light 28 | 10: fire hydrant 29 | 11: stop sign 30 | 12: parking meter 31 | 13: bench 32 | 14: bird 33 | 15: cat 34 | 16: dog 35 | 17: horse 36 | 18: sheep 37 | 19: cow 38 | 20: elephant 39 | 21: bear 40 | 22: zebra 41 | 23: giraffe 42 | 24: backpack 43 | 25: umbrella 44 | 26: handbag 45 | 27: tie 46 | 28: suitcase 47 | 29: frisbee 48 | 30: skis 49 | 31: snowboard 50 | 32: sports ball 51 | 33: kite 52 | 34: baseball bat 53 | 35: baseball glove 54 | 36: skateboard 55 | 37: surfboard 56 | 38: tennis racket 57 | 39: bottle 58 | 40: wine glass 59 | 41: cup 60 | 42: fork 61 | 43: knife 62 | 44: spoon 63 | 45: bowl 64 | 46: banana 65 | 47: apple 66 | 48: sandwich 67 | 49: orange 68 | 50: broccoli 69 | 51: carrot 70 | 52: hot dog 71 | 53: pizza 72 | 54: donut 73 | 55: cake 74 | 56: chair 75 | 57: couch 76 | 58: potted plant 77 | 59: bed 78 | 60: dining table 79 | 61: toilet 80 | 62: tv 81 | 63: laptop 82 | 64: mouse 83 | 65: remote 84 | 66: keyboard 85 | 67: cell phone 86 | 68: microwave 87 | 69: oven 88 | 70: toaster 89 | 71: sink 90 | 72: refrigerator 91 | 73: book 92 | 74: clock 93 | 75: vase 94 | 76: scissors 95 | 77: teddy bear 96 | 78: hair drier 97 | 79: toothbrush 98 | 99 | 100 | # Download script/URL (optional) 101 | download: https://ultralytics.com/assets/coco128.zip 102 | -------------------------------------------------------------------------------- /data/images/bus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdnh2006/ultralyticsAPI/f9cd75046c86d16f7fd11513f2ef83d559999357/data/images/bus.jpg -------------------------------------------------------------------------------- /data/images/ppe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdnh2006/ultralyticsAPI/f9cd75046c86d16f7fd11513f2ef83d559999357/data/images/ppe.png -------------------------------------------------------------------------------- /data/images/zidane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdnh2006/ultralyticsAPI/f9cd75046c86d16f7fd11513f2ef83d559999357/data/images/zidane.jpg -------------------------------------------------------------------------------- /predict_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Tue Sep 19 13:58:02 2023 5 | 6 | @author: henry 7 | """ 8 | 9 | 10 | 11 | from flask import Flask, render_template, Response, request 12 | import json 13 | import argparse 14 | import os 15 | import sys 16 | from pathlib import Path 17 | 18 | from ultralytics import YOLO 19 | from ultralytics.utils.checks import cv2, print_args 20 | from utils.general import update_options 21 | 22 | # Initialize paths 23 | FILE = Path(__file__).resolve() 24 | ROOT = FILE.parents[0] 25 | if str(ROOT) not in sys.path: 26 | sys.path.append(str(ROOT)) 27 | ROOT = Path(os.path.relpath(ROOT, Path.cwd())) 28 | 29 | # Initialize Flask API 30 | app = Flask(__name__) 31 | 32 | 33 | def predict(opt): 34 | """ 35 | Perform object detection using the YOLO model and yield results. 36 | 37 | Parameters: 38 | - opt (Namespace): A namespace object that contains all the options for YOLO object detection, 39 | including source, model path, confidence thresholds, etc. 40 | 41 | Yields: 42 | - JSON: If opt.save_txt is True, yields a JSON string containing the detection results. 43 | - bytes: If opt.save_txt is False, yields JPEG-encoded image bytes with object detection results plotted. 44 | """ 45 | 46 | results = model(**vars(opt), stream=True) 47 | 48 | for result in results: 49 | if opt.save_txt: 50 | result_json = json.loads(result.tojson()) 51 | yield json.dumps({'results': result_json}) 52 | else: 53 | im0 = cv2.imencode('.jpg', result.plot())[1].tobytes() 54 | yield (b'--frame\r\n' 55 | b'Content-Type: image/jpeg\r\n\r\n' + im0 + b'\r\n') 56 | 57 | 58 | @app.route('/') 59 | def index(): 60 | """ 61 | Video streaming home page. 62 | """ 63 | 64 | return render_template('index.html') 65 | 66 | 67 | @app.route('/predict', methods=['GET', 'POST']) 68 | def video_feed(): 69 | if request.method == 'POST': 70 | uploaded_file = request.files.get('myfile') 71 | save_txt = request.form.get('save_txt', 'F') # Default to 'F' if save_txt is not provided 72 | 73 | if uploaded_file: 74 | source = Path(__file__).parent / raw_data / uploaded_file.filename 75 | uploaded_file.save(source) 76 | opt.source = source 77 | else: 78 | opt.source, _ = update_options(request) 79 | 80 | opt.save_txt = True if save_txt == 'T' else False 81 | 82 | elif request.method == 'GET': 83 | opt.source, opt.save_txt = update_options(request) 84 | 85 | return Response(predict(opt), mimetype='multipart/x-mixed-replace; boundary=frame') 86 | 87 | 88 | 89 | if __name__ == '__main__': 90 | # Input arguments 91 | parser = argparse.ArgumentParser() 92 | parser.add_argument('--model','--weights', type=str, default=ROOT / 'yolov8s.pt', help='model path or triton URL') 93 | parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='source directory for images or videos') 94 | parser.add_argument('--conf','--conf-thres', type=float, default=0.25, help='object confidence threshold for detection') 95 | parser.add_argument('--iou', '--iou-thres', type=float, default=0.7, help='intersection over union (IoU) threshold for NMS') 96 | parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='image size as scalar or (h, w) list, i.e. (640, 480)') 97 | parser.add_argument('--half', action='store_true', help='use half precision (FP16)') 98 | parser.add_argument('--device', default='', help='device to run on, i.e. cuda device=0/1/2/3 or device=cpu') 99 | parser.add_argument('--show','--view-img', default=False, action='store_true', help='show results if possible') 100 | parser.add_argument('--save', action='store_true', help='save images with results') 101 | parser.add_argument('--save_txt','--save-txt', action='store_true', help='save results as .txt file') 102 | parser.add_argument('--save_conf', '--save-conf', action='store_true', help='save results with confidence scores') 103 | parser.add_argument('--save_crop', '--save-crop', action='store_true', help='save cropped images with results') 104 | parser.add_argument('--show_labels','--show-labels', default=True, action='store_true', help='show labels') 105 | parser.add_argument('--show_conf', '--show-conf', default=True, action='store_true', help='show confidence scores') 106 | parser.add_argument('--max_det','--max-det', type=int, default=300, help='maximum number of detections per image') 107 | parser.add_argument('--vid_stride', '--vid-stride', type=int, default=1, help='video frame-rate stride') 108 | parser.add_argument('--stream_buffer', '--stream-buffer', default=False, action='store_true', help='buffer all streaming frames (True) or return the most recent frame (False)') 109 | parser.add_argument('--line_width', '--line-thickness', default=None, type=int, help='The line width of the bounding boxes. If None, it is scaled to the image size.') 110 | parser.add_argument('--visualize', default=False, action='store_true', help='visualize model features') 111 | parser.add_argument('--augment', default=False, action='store_true', help='apply image augmentation to prediction sources') 112 | parser.add_argument('--agnostic_nms', '--agnostic-nms', default=False, action='store_true', help='class-agnostic NMS') 113 | parser.add_argument('--retina_masks', '--retina-masks', default=False, action='store_true', help='whether to plot masks in native resolution') 114 | parser.add_argument('--classes', type=list, help='filter results by class, i.e. classes=0, or classes=[0,2,3]') # 'filter by class: --classes 0, or --classes 0 2 3') 115 | parser.add_argument('--show-boxes', default=True, action='store_false', help='Show boxes in segmentation predictions') 116 | parser.add_argument('--exist_ok', '--exist-ok', action='store_true', help='existing project/name ok, do not increment') 117 | parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name') 118 | parser.add_argument('--name', default='exp', help='save results to project/name') 119 | parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') 120 | parser.add_argument('--raw_data', '--raw-data', default=ROOT / 'data/raw', help='save raw images to data/raw') 121 | parser.add_argument('--port', default=5000, type=int, help='port deployment') 122 | opt, unknown = parser.parse_known_args() 123 | 124 | # print used arguments 125 | print_args(vars(opt)) 126 | 127 | # Get por to deploy 128 | port = opt.port 129 | delattr(opt, 'port') 130 | 131 | # Create path for raw data 132 | raw_data = Path(opt.raw_data) 133 | raw_data.mkdir(parents=True, exist_ok=True) 134 | delattr(opt, 'raw_data') 135 | 136 | # Load model (Ensemble is not supported) 137 | model = YOLO(str(opt.model)) 138 | 139 | # Run app 140 | app.run(host='0.0.0.0', port=port, debug=False) # Don't use debug=True, model will be loaded twice (https://stackoverflow.com/questions/26958952/python-program-seems-to-be-running-twice) 141 | 142 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Usage: pip install -r requirements.txt 2 | 3 | # Base ---------------------------------------- 4 | ultralytics>=8.0.181 5 | 6 | # Plotting ------------------------------------ 7 | pandas>=1.1.4 8 | seaborn>=0.11.0 9 | 10 | # Export -------------------------------------- 11 | # coremltools>=6.0 # CoreML export 12 | # onnx>=1.12.0 # ONNX export 13 | # onnxsim>=0.4.1 # ONNX simplifier 14 | # nvidia-pyindex # TensorRT export 15 | # nvidia-tensorrt # TensorRT export 16 | # scikit-learn==0.19.2 # CoreML quantization 17 | # tensorflow>=2.4.1 # TF exports (-cpu, -aarch64, -macos) 18 | # tflite-support 19 | # tensorflowjs>=3.9.0 # TF.js export 20 | # openvino-dev>=2022.3 # OpenVINO export 21 | 22 | # Extras -------------------------------------- 23 | psutil # system utilization 24 | thop>=0.1.1 # FLOPs computation 25 | # ipython # interactive notebook 26 | # albumentations>=1.0.3 27 | # pycocotools>=2.0.6 # COCO mAP 28 | # roboflow 29 | 30 | # API ----------------------------------------- 31 | Flask>=2.0 32 | 33 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Image Analysis Flask API 8 | 9 | 11 | 12 | 147 | 148 | 149 | 150 |
151 |
152 |
153 |
154 |
155 | 156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |

Flask API for detection, segmentation, classsification and pose estimation

171 |

172 | This API has been adapted by Henry Navaro. 173 |

Files supported are the common formats of images and videos: ('bmp', 'jpeg', 'jpg', 'webp',... and 'avi', 'gif', 'mp4', ...)

174 |

The algorithm will return to you a labeled image with all the objects detected/segmented by your model.

175 |

Instructions:

176 |

1) Drag your file or use the button "Select file"

177 |

2) Press "Upload file"

178 |

179 |
180 |
181 |
182 | 183 | Drag and drop file here 184 | 186 | 187 | 188 |
189 | OR 190 | 191 |
192 |
193 | 194 |
195 |
196 |
198 |
199 |
200 | 201 |
202 |

203 | 204 |
205 | 206 | 207 |
208 |
209 | 221 | 222 | 226 | 253 | 254 | 255 | 256 | -------------------------------------------------------------------------------- /utils/general.py: -------------------------------------------------------------------------------- 1 | # Utils by Henry Navarro 2 | 3 | """ 4 | This module contains utility functions and constants for various purposes. 5 | 6 | """ 7 | 8 | 9 | import os 10 | from pathlib import Path 11 | 12 | import json # Henry 13 | 14 | 15 | FILE = Path(__file__).resolve() 16 | ROOT = FILE.parents[1] # YOLOv8API root directory 17 | RANK = int(os.getenv('RANK', -1)) 18 | 19 | def update_options(request): 20 | """ 21 | Args: 22 | - request: Flask request object 23 | 24 | Returns: 25 | - source: URL string 26 | - save_txt: Boolean indicating whether to save text or not 27 | """ 28 | 29 | # GET parameters 30 | if request.method == 'GET': 31 | #all_args = request.args # TODO: get all parameters in one line 32 | source = request.args.get('source') 33 | save_txt = request.args.get('save_txt') 34 | 35 | 36 | # POST parameters 37 | if request.method == 'POST': 38 | json_data = request.get_json() #Get the POSTed json 39 | json_data = json.dumps(json_data) # API receive a dictionary, so I have to do this to convert to string 40 | dict_data = json.loads(json_data) # Convert json to dictionary 41 | source = dict_data['source'] 42 | save_txt = dict_data.get('save_txt', None) 43 | 44 | return source, bool(save_txt) 45 | --------------------------------------------------------------------------------