diff --git a/dataset/tf_records/.gitignore b/dataset/tf_records/.gitignore deleted file mode 100644 index b9045fd730d938c05f2a0a14dcc3b4a035e0a633..0000000000000000000000000000000000000000 --- a/dataset/tf_records/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.record \ No newline at end of file diff --git a/dataset/twitch/robots-views/.gitignore b/dataset/twitch/robots-views/.gitignore deleted file mode 100644 index c96a04f008ee21e260b28f7701595ed59e2839e3..0000000000000000000000000000000000000000 --- a/dataset/twitch/robots-views/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/dataset/twitch/runes/.gitignore b/dataset/twitch/runes/.gitignore deleted file mode 100644 index c96a04f008ee21e260b28f7701595ed59e2839e3..0000000000000000000000000000000000000000 --- a/dataset/twitch/runes/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/dataset/twitch/aerial-views/.gitignore b/dataset/twitch/v1/runes/.gitignore similarity index 100% rename from dataset/twitch/aerial-views/.gitignore rename to dataset/twitch/v1/runes/.gitignore diff --git a/src/research/dataset/scripts/move_aerial_views.py b/src/research/dataset/scripts/move_aerial_views.py deleted file mode 100644 index 5b71f39bf6459e6b48d6ccadf361930ddcfe04b5..0000000000000000000000000000000000000000 --- a/src/research/dataset/scripts/move_aerial_views.py +++ /dev/null @@ -1,20 +0,0 @@ -from shutil import move - -from skimage import io -from tqdm import tqdm - -from research.common.constants import TWITCH_DSET_DIR, TWITCH_ROBOTS_VIEWS_DIR -from research.dataset.twitch.aerial_view_detector import aerial_view_detector - -AERIAL_VIEWS_DIR = TWITCH_DSET_DIR / "aerial-views" - -AERIAL_VIEWS_DIR.mkdir(parents=True, exist_ok=True) - -if __name__ == "__main__": - n = 0 - for file_path in tqdm(list(TWITCH_ROBOTS_VIEWS_DIR.glob("*.jpg")), unit="image", desc="Moving aerial views"): - if aerial_view_detector.is_matching(io.imread(str(file_path))): - move(str(file_path), str(AERIAL_VIEWS_DIR / file_path.name)) - n += 1 - - print(f"Moved {n} images") diff --git a/src/research/dataset/twitch/README.md b/src/research/dataset/twitch/README.md index 00976f6f0216dc4c077f4a35a3dbe904253f6343..d1a360b28438a6ba2c3c31efe12a30120d587399 100644 --- a/src/research/dataset/twitch/README.md +++ b/src/research/dataset/twitch/README.md @@ -43,8 +43,8 @@ You have 2 options to download the videos: 3. Rename it using the video id on twitch, and place it in [dataset/twitch/videos](../../../../dataset/twitch/videos) 5. Launch the python script [../scripts/extract_robots_views_from_video.py](../scripts/extract_robots_views_from_video.py), with the video id as parameter (In Pycharm, `Run` > `Edit Configurations...`, then in parameters enter the id). You can put multiple video ids by separating them with spaces. -The frames will appear in the [dataset/twitch/robots-views](../../../../dataset/twitch/robots-views) folder. +The frames will appear in the [dataset/twitch/robots-views](../../../../dataset/twitch/robots-views-hd-decalees) folder. ## Aerial dataset -Once you have the robots views in the [dataset/twitch/robots-views](../../../../dataset/twitch/robots-views) folder, run the python script [../scripts/move_aerial_views.py](../scripts/move_aerial_views.py). It will put the aerial views in the [dataset/twitch/aerial-views](../../../../dataset/twitch/aerial-views) directory. +Once you have the robots views in the [dataset/twitch/robots-views](../../../../dataset/twitch/robots-views-hd-decalees) folder, run the python script [../scripts/move_aerial_views.py](../scripts/move_aerial_and_runes_views.py). It will put the aerial views in the [dataset/twitch/aerial-views](../../../../dataset/twitch/aerial-views) directory. diff --git a/src/research/dataset/twitch/aerial_view_detector.py b/src/research/dataset/twitch/aerial_view_detector.py deleted file mode 100644 index f1f0332f34b623eac8566e1c36a133c4843677dd..0000000000000000000000000000000000000000 --- a/src/research/dataset/twitch/aerial_view_detector.py +++ /dev/null @@ -1,23 +0,0 @@ -from pathlib import Path - -from skimage import io - -from research.common.constants import TWITCH_DSET_DIR -from research.dataset.twitch.mask_detector import MaskDetector - -aerial_view_detector = MaskDetector( - Path(__file__).parent / "mask_aerial.jpg", - [ - (527, 528, 292, 297, 20), - (527, 531, 303, 303, 20), - (532, 537, 286, 287, 20), - (536, 541, 302, 303, 20), - (543, 544, 292, 297, 20), - (535, 535, 292, 297, 20), - ], -) - -if __name__ == "__main__": - for file_path in sorted((TWITCH_DSET_DIR / "robots-views").glob("*.jpg")): - if aerial_view_detector.is_matching(io.imread(str(file_path))): - print(file_path.name) diff --git a/src/research/dataset/twitch/mask_aerial_blue_2_hd.jpg b/src/research/dataset/twitch/mask_aerial_blue_2_hd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..27e14148e00f8bb34ade761c4314ee14813ffc62 Binary files /dev/null and b/src/research/dataset/twitch/mask_aerial_blue_2_hd.jpg differ diff --git a/src/research/dataset/twitch/mask_aerial_blue_hd.jpg b/src/research/dataset/twitch/mask_aerial_blue_hd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b208e82ae4a622880a4af3146bb4bc65cbbfd118 Binary files /dev/null and b/src/research/dataset/twitch/mask_aerial_blue_hd.jpg differ diff --git a/src/research/dataset/twitch/mask_aerial_red_2_hd.jpg b/src/research/dataset/twitch/mask_aerial_red_2_hd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0fedc05eb627cbbf82a084c3815930f0740f6b88 Binary files /dev/null and b/src/research/dataset/twitch/mask_aerial_red_2_hd.jpg differ diff --git a/src/research/dataset/twitch/mask_aerial_red_hd.jpg b/src/research/dataset/twitch/mask_aerial_red_hd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fd8e3e99827af2527f68b19837673ed306e031ce Binary files /dev/null and b/src/research/dataset/twitch/mask_aerial_red_hd.jpg differ diff --git a/src/research/dataset/twitch/mask_bonus.jpg b/src/research/dataset/twitch/mask_bonus.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5f5182c80aa14f0a836d88e7c464eb8e95504397 Binary files /dev/null and b/src/research/dataset/twitch/mask_bonus.jpg differ diff --git a/src/research/dataset/twitch/mask_bonus_2.jpg b/src/research/dataset/twitch/mask_bonus_2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9b90558a8f1026913bb4480f4fe562a24ff7a9e Binary files /dev/null and b/src/research/dataset/twitch/mask_bonus_2.jpg differ diff --git a/src/research/dataset/twitch/mask_bonus_3.jpg b/src/research/dataset/twitch/mask_bonus_3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9c5d13959b5e6c3d7ca12463f4df1209c1c9365b Binary files /dev/null and b/src/research/dataset/twitch/mask_bonus_3.jpg differ diff --git a/src/research/dataset/twitch/mask_detector.py b/src/research/dataset/twitch/mask_detector.py index 8ffd748dc0fe4468087b6053acb8777385a3ed5d..4d63b526c8dda29406ba90f826450a5440f6b773 100644 --- a/src/research/dataset/twitch/mask_detector.py +++ b/src/research/dataset/twitch/mask_detector.py @@ -1,67 +1,51 @@ -import math from pathlib import Path -from typing import List, Tuple -import cv2 import numpy as np +from polystar.models.image import Image, load_image -class Zone: - def __init__(self, x_min, x_max, y_min, y_max, threshold, active_pixels, image_mask): +DIR_PATH = Path(__file__).parent - self.pixels = [(x, y) for x, y in active_pixels if (y_min <= y <= y_max) and (x_min <= x <= x_max)] - self.mean_r = self.get_mean(0, image_mask) - self.mean_g = self.get_mean(1, image_mask) - self.mean_b = self.get_mean(2, image_mask) - self.threshold = threshold +class Mask: + def __init__(self, mask_file: Path, threshold: float): + self._threshold = threshold + mask_image = load_image(mask_file) + self._mask_coordinates = np.where(mask_image.max(axis=-1) > 40) + self._mask_values = mask_image[self._mask_coordinates].astype(np.int16) - def get_mean(self, color, img): - return sum([img[pix[0], pix[1]][color] for pix in self.pixels]) / len(self.pixels) + def match(self, image: Image) -> bool: + value = np.abs(self._mask_values - image[self._mask_coordinates]).mean() + # print(value) + return value <= self._threshold - def get_means(self, img): - mr, mg, mb = 0, 0, 0 - for pix in self.pixels: - p = img[pix[0], pix[1]] - mr += p[0] - mg += p[1] - mb += p[2] - n_pixels = len(self.pixels) - return mr / n_pixels, mg / n_pixels, mb / n_pixels +robot_view_mask_hd = Mask(DIR_PATH / "mask_robot_view_hd.jpg", 20) +aerial_view_mask_red_hd = Mask(DIR_PATH / "mask_aerial_red_hd.jpg", 15) +aerial_view_mask_red_2_hd = Mask(DIR_PATH / "mask_aerial_red_2_hd.jpg", 15) +aerial_view_mask_blue_hd = Mask(DIR_PATH / "mask_aerial_blue_hd.jpg", 15) +aerial_view_mask_blue_2_hd = Mask(DIR_PATH / "mask_aerial_blue_2_hd.jpg", 15) +bonus_view_mask_hd = Mask(DIR_PATH / "mask_bonus.jpg", 20) +bonus_2_view_mask_hd = Mask(DIR_PATH / "mask_bonus_2.jpg", 20) +bonus_3_view_mask_hd = Mask(DIR_PATH / "mask_bonus_3.jpg", 20) - def is_matching(self, frame: np.ndarray): - mean_r, mean_g, mean_b = self.get_means(frame) - return ( - math.sqrt(pow(mean_r - self.mean_r, 2) + pow(mean_g - self.mean_g, 2) + pow(mean_b - self.mean_b, 2)) - < self.threshold - ) - - -class MaskDetector: - def __init__(self, image_path: Path, zones_params: List[Tuple[int, int, int, int, int]]): - image_mask = cv2.imread(str(image_path)) - active_px = [ - (a, b) - for a in range(0, 720) - for b in range(0, 1280) - if ( - image_mask[a, b].any() - and int(image_mask[a, b][0]) + int(image_mask[a, b][1]) + int(image_mask[a, b][2]) > 50 - ) - ] - self.zones = [Zone(*zone_params, active_px, image_mask) for zone_params in zones_params] +def is_aerial_view(image: Image) -> bool: + return ( + aerial_view_mask_red_hd.match(image) + or aerial_view_mask_red_2_hd.match(image) + or aerial_view_mask_blue_hd.match(image) + or aerial_view_mask_blue_2_hd.match(image) + ) - def is_matching(self, frame: np.ndarray): - return all(zone.is_matching(frame) for zone in self.zones) +def has_bonus_icon(image: Image) -> bool: + return bonus_view_mask_hd.match(image) or bonus_2_view_mask_hd.match(image) or bonus_3_view_mask_hd.match(image) -robot_view_detector = MaskDetector( - Path(__file__).parent / "mask_robot_view.jpg", - [(0, 2000, 20, 70, 20), (0, 2000, 270, 370, 20), (0, 2000, 510, 770, 20),], -) - -def is_image_from_robot_view(frame): - return robot_view_detector.is_matching(frame) +if __name__ == "__main__": + has_bonus_icon( + load_image( + Path("/Users/cytadel/polystar/cv-code/dataset/twitch/robots-views/470152932/470152932-frame-007460.jpg") + ) + ) diff --git a/src/research/dataset/twitch/mask_robot_view_hd.jpg b/src/research/dataset/twitch/mask_robot_view_hd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c788ec54004dcb1ffe416f3c25a0cf972e295e2c Binary files /dev/null and b/src/research/dataset/twitch/mask_robot_view_hd.jpg differ diff --git a/src/research/dataset/twitch/resize_mask.py b/src/research/dataset/twitch/resize_mask.py new file mode 100644 index 0000000000000000000000000000000000000000..238629956b3c4f23043b34287016a14f9b7c5c57 --- /dev/null +++ b/src/research/dataset/twitch/resize_mask.py @@ -0,0 +1,7 @@ +from pathlib import Path + +from imutils import resize + +from polystar.models.image import load_image, save_image + +save_image(resize(load_image(Path("mask_aerial.jpg")), 1920, 1080), Path("mask_aerial_red_hd.jpg")) diff --git a/src/research/dataset/twitch/robots_views_extractor.py b/src/research/dataset/twitch/robots_views_extractor.py index aa2b306a3da58c6ff5c01ad2a50a29e7b608f280..aa58f27bb3b6b1b29dbf234bfa63ac623c92c40b 100644 --- a/src/research/dataset/twitch/robots_views_extractor.py +++ b/src/research/dataset/twitch/robots_views_extractor.py @@ -5,23 +5,27 @@ from tqdm import tqdm from polystar.frame_generators.fps_video_frame_generator import FPSVideoFrameGenerator from research.common.constants import TWITCH_DSET_DIR, TWITCH_ROBOTS_VIEWS_DIR -from research.dataset.twitch.mask_detector import is_image_from_robot_view +from research.dataset.twitch.mask_detector import has_bonus_icon, robot_view_mask_hd class RobotsViewExtractor: FPS = 2 + OFFSET_SECONDS = 3140 // 2 def __init__(self, video_name: str): self.video_name: str = video_name self.video_path = TWITCH_DSET_DIR / "videos" / f"{video_name}.mp4" - self.frame_generator: FPSVideoFrameGenerator = FPSVideoFrameGenerator(self.video_path, self.FPS) + self.frame_generator: FPSVideoFrameGenerator = FPSVideoFrameGenerator( + self.video_path, self.OFFSET_SECONDS, self.FPS + ) self.count = 0 (TWITCH_ROBOTS_VIEWS_DIR / self.video_name).mkdir(exist_ok=True) + self._progress_bar = None def run(self): self._progress_bar = tqdm( - enumerate(self.frame_generator.generate()), + enumerate(self.frame_generator.generate(), 1 + self.OFFSET_SECONDS * self.FPS), total=self._get_number_of_frames(), desc=f"Extracting robots views from video {self.video_name}.mp4", unit="frames", @@ -32,7 +36,7 @@ class RobotsViewExtractor: print(f"Detected {self.count} robots views") def _process_frame(self, frame: np.ndarray, frame_number: int): - if is_image_from_robot_view(frame): + if robot_view_mask_hd.match(frame) and not has_bonus_icon(frame): self._save_frame(frame, frame_number) self.count += 1 self._progress_bar.set_description( @@ -40,9 +44,7 @@ class RobotsViewExtractor: ) def _save_frame(self, frame: np.ndarray, frame_number: int): - cv2.imwrite( - f"{TWITCH_ROBOTS_VIEWS_DIR}/{self.video_name}/{self.video_name}-frame-{frame_number + 1:06}.jpg", frame - ) + cv2.imwrite(f"{TWITCH_ROBOTS_VIEWS_DIR}/{self.video_name}/{self.video_name}-frame-{frame_number:06}.jpg", frame) def _get_number_of_frames(self): return int(ffmpeg.probe(str(self.video_path))["format"]["duration"].split(".")[0]) * self.FPS diff --git a/src/research/tmp.py b/src/research/tmp.py deleted file mode 100644 index b30695e9cbcc3862e45409624640cf572662785f..0000000000000000000000000000000000000000 --- a/src/research/tmp.py +++ /dev/null @@ -1,3 +0,0 @@ -from research.common.constants import DSET_DIR - -print(DSET_DIR)