{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# ⚽ DFL Bundesliga - detection 👁️ and tracking 👣\n---\n**last update: 13.08.2022**","metadata":{}},{"cell_type":"markdown","source":"**Note:** This kernel is still in progress and I'm working on it live on Twitch few days a week! Click on banner to join the stream next time.","metadata":{}},{"cell_type":"markdown","source":"<p align=\"center\">\n    <a href=\"https://www.twitch.tv/skalskip\" style=\"text-decoration:none;\">\n        <img src=\"https://blog.twitch.tv/assets/uploads/generic-email-header-1.jpg\" width=600 />\n    <a />\n</p>","metadata":{}},{"cell_type":"markdown","source":"## 00. Imports","metadata":{}},{"cell_type":"code","source":"!pip install frame_generator","metadata":{"execution":{"iopub.status.busy":"2022-08-13T22:48:35.002349Z","iopub.execute_input":"2022-08-13T22:48:35.002781Z","iopub.status.idle":"2022-08-13T22:48:46.111714Z","shell.execute_reply.started":"2022-08-13T22:48:35.002689Z","shell.execute_reply":"2022-08-13T22:48:46.110544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\ntorch.cuda.is_available()","metadata":{"execution":{"iopub.status.busy":"2022-08-13T22:49:18.129012Z","iopub.execute_input":"2022-08-13T22:49:18.130035Z","iopub.status.idle":"2022-08-13T22:49:20.066757Z","shell.execute_reply.started":"2022-08-13T22:49:18.129966Z","shell.execute_reply":"2022-08-13T22:49:20.065861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\n\nfrom typing import Optional, List, Tuple\n\nfrom frame_generator import FrameGenerator\nfrom IPython.display import Video\n\nfrom dataclasses import dataclass\nfrom matplotlib import pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:31:29.784516Z","iopub.execute_input":"2022-08-13T23:31:29.784897Z","iopub.status.idle":"2022-08-13T23:31:29.790354Z","shell.execute_reply.started":"2022-08-13T23:31:29.784862Z","shell.execute_reply":"2022-08-13T23:31:29.789363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 01. Settings","metadata":{}},{"cell_type":"code","source":"SOURCE_DIRECTORY_PATH = \"/kaggle/input/dfl-bundesliga-data-shootout\"\n\nCLIPS_DIRECTORY_PATH = os.path.join(SOURCE_DIRECTORY_PATH, \"clips\")\nTEST_DIRECTORY_PATH = os.path.join(SOURCE_DIRECTORY_PATH, \"test\")\nTRAIN_DIRECTORY_PATH = os.path.join(SOURCE_DIRECTORY_PATH, \"train\")\nTRAIN_CSV_PATH = os.path.join(SOURCE_DIRECTORY_PATH, \"train.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-08-13T22:50:09.391489Z","iopub.execute_input":"2022-08-13T22:50:09.391853Z","iopub.status.idle":"2022-08-13T22:50:09.398054Z","shell.execute_reply.started":"2022-08-13T22:50:09.391820Z","shell.execute_reply":"2022-08-13T22:50:09.396910Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 02. Computer Vision Utils","metadata":{}},{"cell_type":"code","source":"@dataclass(frozen=True)\nclass Point:\n    x: float\n    y: float\n    \n    @property\n    def int_xy_tuple(self) -> Tuple[int, int]:\n        return int(self.x), int(self.y)\n\n@dataclass(frozen=True)\nclass Rect:\n    x: float\n    y: float\n    width: float\n    height: float\n        \n    @property\n    def top_left(self) -> Point:\n        return Point(x=self.x, y=self.y)\n    \n    @property\n    def bottom_right(self) -> Point:\n        return Point(x=self.x + self.width, y=self.y + self.height)\n        \n@dataclass(frozen=True)\nclass Detection:\n    rect: Rect\n    class_id: int\n    confidence: float\n    tracker_id: Optional[int] = None\n        \n@dataclass(frozen=True)\nclass Color:\n    r: int\n    g: int\n    b: int\n        \n    @property\n    def bgr_tuple(self) -> Tuple[int, int, int]:\n        return self.b, self.g, self.r","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:30:28.729427Z","iopub.execute_input":"2022-08-13T23:30:28.729797Z","iopub.status.idle":"2022-08-13T23:30:28.742134Z","shell.execute_reply.started":"2022-08-13T23:30:28.729763Z","shell.execute_reply":"2022-08-13T23:30:28.740869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def draw_rect(image: np.ndarray, rect: Rect, color: Color, thickness: int = 2) -> np.ndarray:\n    cv2.rectangle(image, rect.top_left.int_xy_tuple, rect.bottom_right.int_xy_tuple, color.bgr_tuple, thickness)\n    return image\n\nclass BoxAnnotator:\n    \n    def __init__(self, color: Color, thickness: int):\n        self.color = color\n        self.thickness = thickness\n        \n    def annotate(self, image: np.ndarray, detections: List[Detection]) -> np.ndarray:\n        for detection in detections:\n            image = draw_rect(image=image, rect=detection.rect, color=self.color, thickness=self.thickness)\n        return image","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:33:29.908113Z","iopub.execute_input":"2022-08-13T23:33:29.908700Z","iopub.status.idle":"2022-08-13T23:33:29.918454Z","shell.execute_reply.started":"2022-08-13T23:33:29.908664Z","shell.execute_reply":"2022-08-13T23:33:29.917448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def postprocess_results(results: np.ndarray) -> List[Detection]:\n    return [\n        Detection(\n            rect=Rect(\n                x=float(x_min),\n                y=float(y_min),\n                width=float(x_max - x_min),\n                height=float(y_max - y_min)\n            ),\n            confidence=float(confidence),\n            class_id=int(class_id)\n        )\n        for x_min, y_min, x_max, y_max, confidence, class_id \n        in results\n    ]","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:33:30.994609Z","iopub.execute_input":"2022-08-13T23:33:30.994974Z","iopub.status.idle":"2022-08-13T23:33:31.001387Z","shell.execute_reply.started":"2022-08-13T23:33:30.994941Z","shell.execute_reply":"2022-08-13T23:33:31.000384Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 03. Test YOLOv5 player detection","metadata":{}},{"cell_type":"code","source":"video_path = os.path.join(CLIPS_DIRECTORY_PATH, \"08fd33_0.mp4\")","metadata":{"execution":{"iopub.status.busy":"2022-08-13T22:50:11.907496Z","iopub.execute_input":"2022-08-13T22:50:11.908466Z","iopub.status.idle":"2022-08-13T22:50:11.913381Z","shell.execute_reply.started":"2022-08-13T22:50:11.908420Z","shell.execute_reply":"2022-08-13T22:50:11.912204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Video(video_path, embed=True, width=600)","metadata":{"execution":{"iopub.status.busy":"2022-08-13T22:50:15.419148Z","iopub.execute_input":"2022-08-13T22:50:15.420099Z","iopub.status.idle":"2022-08-13T22:50:16.294333Z","shell.execute_reply.started":"2022-08-13T22:50:15.420059Z","shell.execute_reply":"2022-08-13T22:50:16.293096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = torch.hub.load('ultralytics/yolov5', 'yolov5l6', device=0)","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:27:29.236541Z","iopub.execute_input":"2022-08-13T23:27:29.236905Z","iopub.status.idle":"2022-08-13T23:27:30.475090Z","shell.execute_reply.started":"2022-08-13T23:27:29.236863Z","shell.execute_reply":"2022-08-13T23:27:30.474173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"frame_generator = FrameGenerator(video_source=video_path, show_video_info=True, every_nth_frame=1)\nframe_iterator = iter(frame_generator)","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:33:34.783851Z","iopub.execute_input":"2022-08-13T23:33:34.784849Z","iopub.status.idle":"2022-08-13T23:33:34.844759Z","shell.execute_reply.started":"2022-08-13T23:33:34.784800Z","shell.execute_reply":"2022-08-13T23:33:34.843704Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"frame = next(frame_iterator)\nresults = model(frame)","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:33:35.100474Z","iopub.execute_input":"2022-08-13T23:33:35.101071Z","iopub.status.idle":"2022-08-13T23:33:35.191405Z","shell.execute_reply.started":"2022-08-13T23:33:35.101033Z","shell.execute_reply":"2022-08-13T23:33:35.190359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"detections = postprocess_results(results=results.pred[0].detach().cpu().numpy())","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:33:35.560624Z","iopub.execute_input":"2022-08-13T23:33:35.560987Z","iopub.status.idle":"2022-08-13T23:33:35.566328Z","shell.execute_reply.started":"2022-08-13T23:33:35.560954Z","shell.execute_reply":"2022-08-13T23:33:35.565293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"color = Color(r=255, g=0, b=0)\nannotator = BoxAnnotator(color=color, thickness=2)","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:33:35.808975Z","iopub.execute_input":"2022-08-13T23:33:35.809650Z","iopub.status.idle":"2022-08-13T23:33:35.814635Z","shell.execute_reply.started":"2022-08-13T23:33:35.809614Z","shell.execute_reply":"2022-08-13T23:33:35.813690Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"annotated_image = annotator.annotate(image=frame, detections=detections)","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:33:36.706443Z","iopub.execute_input":"2022-08-13T23:33:36.707383Z","iopub.status.idle":"2022-08-13T23:33:36.712673Z","shell.execute_reply.started":"2022-08-13T23:33:36.707332Z","shell.execute_reply":"2022-08-13T23:33:36.711635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%matplotlib inline \n\nplt.figure(figsize=(12, 12))\nplt.imshow(annotated_image)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-13T23:35:09.529547Z","iopub.execute_input":"2022-08-13T23:35:09.529924Z","iopub.status.idle":"2022-08-13T23:35:10.077121Z","shell.execute_reply.started":"2022-08-13T23:35:09.529888Z","shell.execute_reply":"2022-08-13T23:35:10.076065Z"},"trusted":true},"execution_count":null,"outputs":[]}]}