Skip to content

Commit fa662d0

Browse files
first commit
1 parent 2bbfed7 commit fa662d0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+7963
-1
lines changed

.DS_Store

6 KB
Binary file not shown.

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
1-
# SoccerNet
1+
[![Python](https://img.shields.io/pypi/pyversions/SoccerNet)](https://img.shields.io/pypi/pyversions/SoccerNet)
2+
[![Pypi](https://img.shields.io/pypi/v/SoccerNet)](https://pypi.org/project/SoccerNet/)
3+
[![Downloads](https://static.pepy.tech/personalized-badge/SoccerNet?period=month&units=international_system&left_color=grey&right_color=brightgreen&left_text=PyPI%20downloads/month)](https://pepy.tech/project/SoccerNet)
4+
[![Downloads](https://static.pepy.tech/personalized-badge/SoccerNet?period=total&units=international_system&left_color=grey&right_color=brightgreen&left_text=Downloads)](https://pepy.tech/project/SoccerNet)
5+
[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/SoccerNet/SoccerNet/blob/master/LICENSE)
6+
<!-- [![LOC](https://sloc.xyz/github/SoccerNet/SoccerNet/?category=code)](https://github.com/SoccerNet/SoccerNet/) -->
7+
<!-- [![Forks](https://img.shields.io/github/forks/SoccerNet/SoccerNet.svg)](https://github.com/SoccerNet/SoccerNet/network) -->
8+
<!-- [![Issues](https://img.shields.io/github/issues/SoccerNet/SoccerNet.svg)](https://github.com/SoccerNet/SoccerNet/issues) -->
9+
<!-- [![Project Status](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active) -->
10+
11+
# SoccerNet library

SoccerNet/.DS_Store

6 KB
Binary file not shown.

SoccerNet/DataLoader.py

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
2+
# from .utils import getListGames
3+
import os
4+
5+
import numpy as np
6+
import cv2 # pip install opencv-python (==3.4.11.41)
7+
import imutils # pip install imutils
8+
import skvideo.io
9+
from tqdm import tqdm
10+
import logging
11+
import moviepy.editor
12+
13+
def getDuration(video_path):
14+
"""Get the duration (in seconds) for a video.
15+
16+
Keyword arguments:
17+
video_path -- the path of the video
18+
"""
19+
return moviepy.editor.VideoFileClip(video_path).duration
20+
21+
import cv2
22+
class FrameCV():
23+
def __init__(self, video_path, FPS=2, transform=None, start=None, duration=None):
24+
"""Create a list of frame from a video using OpenCV.
25+
26+
Keyword arguments:
27+
video_path -- the path of the video
28+
FPS -- the desired FPS for the frames (default:2)
29+
transform -- the desired transformation for the frames (default:2)
30+
start -- the desired starting time for the list of frames (default:None)
31+
duration -- the desired duration time for the list of frames (default:None)
32+
"""
33+
34+
self.FPS = FPS
35+
self.transform = transform
36+
self.start = start
37+
self.duration = duration
38+
39+
# read video
40+
vidcap = cv2.VideoCapture(video_path)
41+
# read FPS
42+
self.fps_video = vidcap.get(cv2.CAP_PROP_FPS)
43+
# read duration
44+
self.time_second = getDuration(video_path)
45+
46+
# loop until the number of frame is consistent with the expected number of frame,
47+
# given the duratio nand the FPS
48+
good_number_of_frames = False
49+
while not good_number_of_frames:
50+
51+
# read video
52+
vidcap = cv2.VideoCapture(video_path)
53+
54+
# get number of frames
55+
self.numframe = int(self.time_second*self.fps_video)
56+
57+
# frame drop ratio
58+
drop_extra_frames = self.fps_video/self.FPS
59+
60+
# init list of frames
61+
self.frames = []
62+
63+
# TQDM progress bar
64+
pbar = tqdm(range(self.numframe), desc='Grabbing Video Frames', unit='frame')
65+
i_frame = 0
66+
ret, frame = vidcap.read()
67+
68+
# loop until no frame anymore
69+
while ret:
70+
# update TQDM
71+
pbar.update(1)
72+
i_frame += 1
73+
74+
# skip until starting time
75+
if self.start is not None:
76+
if i_frame < self.fps_video * self.start:
77+
ret, frame = vidcap.read()
78+
continue
79+
80+
# skip after duration time
81+
if self.duration is not None:
82+
if i_frame > self.fps_video * (self.start + self.duration):
83+
ret, frame = vidcap.read()
84+
continue
85+
86+
87+
if (i_frame % drop_extra_frames < 1):
88+
89+
# crop keep the central square of the frame
90+
if self.transform == "resize256crop224":
91+
frame = imutils.resize(frame, height=256) # keep aspect ratio
92+
# number of pixel to remove per side
93+
off_h = int((frame.shape[0] - 224)/2)
94+
off_w = int((frame.shape[1] - 224)/2)
95+
frame = frame[off_h:-off_h,
96+
off_w:-off_w, :] # remove pixel at each side
97+
98+
# crop remove the side of the frame
99+
elif self.transform == "crop":
100+
frame = imutils.resize(frame, height=224) # keep aspect ratio
101+
# number of pixel to remove per side
102+
off_side = int((frame.shape[1] - 224)/2)
103+
frame = frame[:, off_side:-
104+
off_side, :] # remove them
105+
106+
# resize change the aspect ratio
107+
elif self.transform == "resize":
108+
# lose aspect ratio
109+
frame = cv2.resize(frame, (224, 224),
110+
interpolation=cv2.INTER_CUBIC)
111+
112+
# append the frame to the list
113+
self.frames.append(frame)
114+
115+
# read next frame
116+
ret, frame = vidcap.read()
117+
118+
# check if the expected number of frames were read
119+
if self.numframe - (i_frame+1) <=1:
120+
logging.debug("Video read properly")
121+
good_number_of_frames = True
122+
else:
123+
logging.debug("Video NOT read properly, adjusting fps and read again")
124+
self.fps_video = (i_frame+1) / self.time_second
125+
126+
# convert frame from list to numpy array
127+
self.frames = np.array(self.frames)
128+
129+
def __len__(self):
130+
"""Return number of frames."""
131+
return len(self.frames)
132+
133+
def __iter__(self, index):
134+
"""Return frame at given index."""
135+
return self.frames[index]
136+
137+
138+
139+
class Frame():
140+
def __init__(self, video_path, FPS=2, transform=None, start=None, duration=None):
141+
142+
self.FPS = FPS
143+
self.transform = transform
144+
145+
# Knowing number of frames from FFMPEG metadata w/o without iterating over all frames
146+
videodata = skvideo.io.FFmpegReader(video_path)
147+
# numFrame x H x W x channels
148+
(numframe, _, _, _) = videodata.getShape()
149+
# if self.verbose:
150+
# print("shape video", videodata.getShape())
151+
self.time_second = getDuration(video_path)
152+
# fps_video = numframe / time_second
153+
154+
# time_second = getDuration(video_path)
155+
# if self.verbose:
156+
# print("duration video", time_second)
157+
158+
good_number_of_frames = False
159+
while not good_number_of_frames:
160+
fps_video = numframe / self.time_second
161+
# time_second = numframe / fps_video
162+
163+
self.frames = []
164+
videodata = skvideo.io.vreader(video_path)
165+
# fps_desired = 2
166+
drop_extra_frames = fps_video/self.FPS
167+
168+
# print(int(fps_video * start), int(fps_video * (start+45*60)))
169+
for i_frame, frame in tqdm(enumerate(videodata), total=numframe):
170+
# print(i_frame)
171+
172+
for t in [0,5,10,15,20,25,30,35,40,45]:
173+
174+
if start is not None:
175+
if i_frame == int(fps_video * (start + t*60)):
176+
# print("saving image")
177+
skvideo.io.vwrite(video_path.replace(".mkv", f"snap_{t}.png"), frame)
178+
# os.path.join(os.path.dirname(video_path), f"snap_{t}.png"), frame)
179+
# if i_frame == int(fps_video * (start+45*60)):
180+
# print("saving image")
181+
# skvideo.io.vwrite(os.path.join(os.path.dirname(video_path), "45.png"), frame)
182+
183+
if start is not None:
184+
if i_frame < fps_video * start:
185+
continue
186+
187+
if duration is not None:
188+
if i_frame > fps_video * (start + duration):
189+
# print("end of duration :)")
190+
continue
191+
192+
if (i_frame % drop_extra_frames < 1):
193+
194+
if self.transform == "resize256crop224": # crop keep the central square of the frame
195+
frame = imutils.resize(
196+
frame, height=256) # keep aspect ratio
197+
# number of pixel to remove per side
198+
off_side_h = int((frame.shape[0] - 224)/2)
199+
off_side_w = int((frame.shape[1] - 224)/2)
200+
frame = frame[off_side_h:-off_side_h,
201+
off_side_w:-off_side_w, :] # remove them
202+
203+
elif self.transform == "crop": # crop keep the central square of the frame
204+
frame = imutils.resize(
205+
frame, height=224) # keep aspect ratio
206+
# number of pixel to remove per side
207+
off_side = int((frame.shape[1] - 224)/2)
208+
frame = frame[:, off_side:-
209+
off_side, :] # remove them
210+
211+
elif self.transform == "resize": # resize change the aspect ratio
212+
# lose aspect ratio
213+
frame = cv2.resize(frame, (224, 224),
214+
interpolation=cv2.INTER_CUBIC)
215+
216+
# else:
217+
# raise NotImplmentedError()
218+
# if self.array:
219+
# frame = img_to_array(frame)
220+
self.frames.append(frame)
221+
222+
print("expected number of frames", numframe,
223+
"real number of available frames", i_frame+1)
224+
225+
if numframe == i_frame+1:
226+
print("===>>> proper read! Proceeding! :)")
227+
good_number_of_frames = True
228+
else:
229+
print("===>>> not read properly... Read frames again! :(")
230+
numframe = i_frame+1
231+
232+
self.frames = np.array(self.frames)
233+
234+
def __len__(self):
235+
"""Return number of frames."""
236+
return len(self.frames)
237+
238+
def __iter__(self, index):
239+
"""Return frame at given index."""
240+
return self.frames[index]
241+
242+
# def frames(self):
243+
244+
# class VideoLoader():
245+
# def __init__(self, SoccerNetDir, split="v1"):
246+
# self.SoccerNetDir = SoccerNetDir
247+
# self.split = split
248+
# # if split == "v1":
249+
# # self.listGame = getListGames("v1")
250+
# # # elif split == "challenge":
251+
# # # self.listGame = getListGames()
252+
# # else:
253+
# self.listGame = getListGames(split)
254+
255+
# def __len__(self):
256+
# return len(self.listGame)
257+
258+
# def __iter__(self, index):
259+
# video_path = self.listGame[index]
260+
261+
# # Read RELIABLE lenght for the video, in second
262+
# if args.verbose:
263+
# print("video path", video_path)
264+
# v = cv2.VideoCapture(video_path)
265+
# v.set(cv2.CAP_PROP_POS_AVI_RATIO, 1)
266+
# time_second = v.get(cv2.CAP_PROP_POS_MSEC)/1000
267+
# if args.verbose:
268+
# print("duration video", time_second)
269+
# import json
270+
# metadata = skvideo.io.ffprobe(video_path)
271+
# # print(metadata.keys())
272+
# # print(json.dumps(metadata["video"], indent=4))
273+
# # getduration
274+
# # print(metadata["video"]["@avg_frame_rate"])
275+
# # # print(metadata["video"]["@duration"])
276+
277+
# # Knowing number of frames from FFMPEG metadata w/o without iterating over all frames
278+
# videodata = skvideo.io.FFmpegReader(video_path)
279+
# (numframe, _, _, _) = videodata.getShape() # numFrame x H x W x channels
280+
# if args.verbose:
281+
# print("shape video", videodata.getShape())
282+
283+
# # # extract REAL FPS
284+
# fps_video = metadata["video"]["@avg_frame_rate"]
285+
# fps_video = float(fps_video.split("/")[0])/float(fps_video.split("/")[1])
286+
# # fps_video = numframe/time_second
287+
# if args.verbose:
288+
# print("fps=", fps_video)
289+
# time_second = numframe / fps_video
290+
# if args.verbose:
291+
# print("duration video", time_second)
292+
# frames = []
293+
# videodata = skvideo.io.vreader(video_path)
294+
# fps_desired = 2
295+
# drop_extra_frames = fps_video/fps_desired
296+
# for i_frame, frame in tqdm(enumerate(videodata), total=numframe):
297+
# # print(i_frame % drop_extra_frames)
298+
# if (i_frame % drop_extra_frames < 1):
299+
300+
# if args.preprocess == "resize256crop224": # crop keep the central square of the frame
301+
# frame = imutils.resize(frame, height=256) # keep aspect ratio
302+
# # number of pixel to remove per side
303+
# off_side_h = int((frame.shape[0] - 224)/2)
304+
# off_side_w = int((frame.shape[1] - 224)/2)
305+
# frame = frame[off_side_h:-off_side_h,
306+
# off_side_w:-off_side_w, :] # remove them
307+
308+
# elif args.preprocess == "crop": # crop keep the central square of the frame
309+
# frame = imutils.resize(frame, height=224) # keep aspect ratio
310+
# # number of pixel to remove per side
311+
# off_side = int((frame.shape[1] - 224)/2)
312+
# frame = frame[:, off_side:-off_side, :] # remove them
313+
314+
# elif args.preprocess == "resize": # resize change the aspect ratio
315+
# # lose aspect ratio
316+
# frame = cv2.resize(frame, (224, 224),
317+
# interpolation=cv2.INTER_CUBIC)
318+
319+
# else:
320+
# raise NotImplmentedError()
321+
# frames.append(frame)
322+
323+
# # create numpy aray (nb_frames x 224 x 224 x 3)
324+
# frames = np.array(frames)
325+
# return frames
326+
327+
328+
if __name__ == "__main__":
329+
from SoccerNet.utils import getListGames
330+
import argparse
331+
332+
333+
parser = argparse.ArgumentParser(description='Test dataloader.')
334+
335+
parser.add_argument('--soccernet_dirpath', type=str, default="/media/giancos/Football/SoccerNet_HQ/",
336+
help="Path for SoccerNet directory [default:/media/giancos/Football/SoccerNet_HQ/]")
337+
parser.add_argument('--idx_game', type=int, default=0,
338+
help="index of the game ot test [default:0]")
339+
args = parser.parse_args()
340+
print(args)
341+
342+
# read ini
343+
import configparser
344+
config = configparser.ConfigParser()
345+
config.read(os.path.join(args.soccernet_dirpath, getListGames("all")[args.idx_game], "video.ini"))
346+
347+
# loop over videos in game
348+
for vid in config.sections():
349+
video_path = os.path.join(args.soccernet_dirpath, getListGames("all")[args.idx_game], vid)
350+
351+
print(video_path)
352+
loader = FrameCV(video_path,
353+
start=float(config[vid]["start_time_second"]),
354+
duration=float(config[vid]["duration_second"]))
355+
print(loader)

0 commit comments

Comments
 (0)