2022-08-16 20:50:00 +00:00
|
|
|
import pickle
|
|
|
|
|
import time
|
2020-12-26 13:58:58 +00:00
|
|
|
from datetime import datetime
|
2022-08-16 20:50:00 +00:00
|
|
|
|
|
|
|
|
import cv2
|
2020-09-23 20:02:46 +00:00
|
|
|
import imageio
|
2020-09-25 17:52:41 +00:00
|
|
|
import imutils
|
2020-09-23 20:02:46 +00:00
|
|
|
import numpy as np
|
2022-08-16 20:50:00 +00:00
|
|
|
|
|
|
|
|
from Application.VideoReader import VideoReader
|
2020-12-26 13:58:58 +00:00
|
|
|
|
2020-10-09 21:59:04 +00:00
|
|
|
|
2020-09-20 20:01:54 +00:00
|
|
|
class Exporter:
|
2020-10-11 15:09:49 +00:00
|
|
|
def __init__(self, config):
|
2022-09-11 09:25:36 +00:00
|
|
|
self.footage_path = config["inputPath"]
|
|
|
|
|
self.output_path = config["outputPath"]
|
|
|
|
|
self.resize_width = config["resizeWidth"]
|
2020-10-11 15:09:49 +00:00
|
|
|
self.config = config
|
2020-09-23 20:02:46 +00:00
|
|
|
print("Exporter initiated")
|
2020-09-24 13:47:49 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def export(self, layers, contours, masks, raw=True, overlayed=True, black_background=False, show_progress=False):
|
2020-10-23 22:14:43 +00:00
|
|
|
if raw:
|
2022-09-11 09:25:36 +00:00
|
|
|
self.export_raw_data(layers, contours, masks)
|
2020-11-08 15:28:47 +00:00
|
|
|
if overlayed:
|
2022-09-11 09:25:36 +00:00
|
|
|
self.export_overlayed(layers, black_background, show_progress)
|
2020-11-08 15:28:47 +00:00
|
|
|
else:
|
2022-09-11 09:25:36 +00:00
|
|
|
self.export_layers(layers)
|
2020-09-25 17:52:41 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def export_layers(self, layers):
|
|
|
|
|
list_of_frames = self.make_list_of_frames(layers)
|
|
|
|
|
with VideoReader(self.config, list_of_frames) as video_reader:
|
2022-08-16 20:50:00 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
underlay = cv2.VideoCapture(self.footage_path).read()[1]
|
2022-08-16 20:50:00 +00:00
|
|
|
underlay = cv2.cvtColor(underlay, cv2.COLOR_BGR2RGB)
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
fps = video_reader.get_fps()
|
|
|
|
|
writer = imageio.get_writer(self.output_path, fps=fps)
|
2022-08-16 20:50:00 +00:00
|
|
|
|
|
|
|
|
start = time.time()
|
|
|
|
|
for i, layer in enumerate(layers):
|
|
|
|
|
print(f"\r {i}/{len(layers)} {round(i/len(layers)*100,2)}% {round((time.time() - start), 2)}s", end="\r")
|
|
|
|
|
if len(layer.bounds[0]) == 0:
|
|
|
|
|
continue
|
2022-09-11 09:25:36 +00:00
|
|
|
video_reader = VideoReader(self.config)
|
|
|
|
|
list_of_frames = self.make_list_of_frames([layer])
|
|
|
|
|
video_reader.fill_buffer(list_of_frames)
|
|
|
|
|
while not video_reader.video_ended():
|
|
|
|
|
frame_count, frame = video_reader.pop()
|
2022-08-16 20:50:00 +00:00
|
|
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
|
|
|
frame2 = np.copy(underlay)
|
2022-09-11 09:25:36 +00:00
|
|
|
for (x, y, w, h) in layer.bounds[frame_count - layer.startFrame]:
|
2022-08-16 20:50:00 +00:00
|
|
|
if x is None:
|
|
|
|
|
continue
|
2022-09-11 09:25:36 +00:00
|
|
|
factor = video_reader.w / self.resize_width
|
2022-08-16 20:50:00 +00:00
|
|
|
x, y, w, h = (int(x * factor), int(y * factor), int(w * factor), int(h * factor))
|
|
|
|
|
|
|
|
|
|
frame2[y : y + h, x : x + w] = np.copy(frame[y : y + h, x : x + w])
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
self.add_timestamp(frame2, video_reader, frame_count, x, y, w, h)
|
2022-08-16 20:50:00 +00:00
|
|
|
writer.append_data(frame2)
|
2020-10-09 21:59:04 +00:00
|
|
|
|
2022-08-16 20:50:00 +00:00
|
|
|
writer.close()
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def export_overlayed(self, layers, black_background=False, show_progress=False):
|
|
|
|
|
|
|
|
|
|
list_of_frames = self.make_list_of_frames(layers)
|
|
|
|
|
max_length = self.get_max_length_of_layers(layers)
|
|
|
|
|
|
|
|
|
|
with VideoReader(self.config, list_of_frames) as videoReader:
|
|
|
|
|
if black_background:
|
|
|
|
|
underlay = np.zeros(shape=[videoReader.h, videoReader.w, 3], dtype=np.uint8)
|
|
|
|
|
else:
|
|
|
|
|
underlay = cv2.VideoCapture(self.footage_path).read()[1]
|
|
|
|
|
underlay = cv2.cvtColor(underlay, cv2.COLOR_BGR2RGB)
|
|
|
|
|
|
|
|
|
|
frames = []
|
|
|
|
|
for i in range(max_length):
|
|
|
|
|
frames.append(np.copy(underlay))
|
|
|
|
|
fps = videoReader.fps
|
|
|
|
|
while not videoReader.video_ended():
|
|
|
|
|
frame_count, frame = videoReader.pop()
|
|
|
|
|
if frame_count % (60 * fps) == 0:
|
|
|
|
|
print("Minutes processed: ", frame_count / (60 * fps), end="\r")
|
2022-08-16 20:50:00 +00:00
|
|
|
if frame is None:
|
|
|
|
|
print("ContourExtractor: frame was None")
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
|
|
|
for layer in layers:
|
2022-09-11 09:25:36 +00:00
|
|
|
if layer.startFrame <= frame_count and layer.startFrame + len(layer.bounds) > frame_count:
|
|
|
|
|
for i in range(0, len(layer.bounds[frame_count - layer.startFrame])):
|
2022-08-16 20:50:00 +00:00
|
|
|
try:
|
2022-09-11 09:25:36 +00:00
|
|
|
x, y, w, h = layer.bounds[frame_count - layer.startFrame][i]
|
2022-08-16 20:50:00 +00:00
|
|
|
if None in (x, y, w, h):
|
|
|
|
|
break
|
2022-09-11 09:25:36 +00:00
|
|
|
factor = videoReader.w / self.resize_width
|
2022-08-16 20:50:00 +00:00
|
|
|
x, y, w, h = (int(x * factor), int(y * factor), int(w * factor), int(h * factor))
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
mask = self.get_mask(i, frame_count, layer, w, h)
|
|
|
|
|
background = frames[frame_count - layer.startFrame + layer.exportOffset]
|
|
|
|
|
self.add_masked_content(frame, x, y, w, h, mask, background)
|
|
|
|
|
frames[frame_count - layer.startFrame + layer.exportOffset] = np.copy(background)
|
2022-08-16 20:50:00 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
if show_progress:
|
2022-08-16 20:50:00 +00:00
|
|
|
cv2.imshow("changes x", background)
|
|
|
|
|
cv2.waitKey(10) & 0xFF
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
self.add_timestamp(frames[frame_count - layer.startFrame + layer.exportOffset], videoReader, frame_count, x, y, w, h)
|
2022-08-16 20:50:00 +00:00
|
|
|
except:
|
|
|
|
|
continue
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
writer = imageio.get_writer(self.output_path, fps=videoReader.get_fps())
|
2020-10-09 21:59:04 +00:00
|
|
|
for frame in frames:
|
|
|
|
|
writer.append_data(frame)
|
|
|
|
|
|
|
|
|
|
writer.close()
|
2020-09-30 17:22:10 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def add_masked_content(self, frame, x, y, w, h, mask, background):
|
|
|
|
|
masked_frame = np.copy(
|
2022-08-16 20:50:00 +00:00
|
|
|
cv2.bitwise_and(
|
|
|
|
|
background[y : y + h, x : x + w],
|
|
|
|
|
background[y : y + h, x : x + w],
|
|
|
|
|
mask=cv2.bitwise_not(mask),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
background[y : y + h, x : x + w] = cv2.addWeighted(
|
2022-09-11 09:25:36 +00:00
|
|
|
masked_frame,
|
2022-08-16 20:50:00 +00:00
|
|
|
1,
|
|
|
|
|
np.copy(cv2.bitwise_and(frame[y : y + h, x : x + w], frame[y : y + h, x : x + w], mask=mask)),
|
|
|
|
|
1,
|
|
|
|
|
0,
|
|
|
|
|
)
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def add_timestamp(self, frame, video_reader, frame_count, x, y, w, h):
|
|
|
|
|
time = datetime.fromtimestamp(int(frame_count / video_reader.fps) + video_reader.get_start_time())
|
2022-08-16 20:50:00 +00:00
|
|
|
cv2.putText(
|
|
|
|
|
frame,
|
|
|
|
|
f"{time.hour}:{time.minute}:{time.second}",
|
|
|
|
|
(int(x + w / 2), int(y + h / 2)),
|
|
|
|
|
cv2.FONT_HERSHEY_SIMPLEX,
|
|
|
|
|
1,
|
|
|
|
|
(255, 255, 255),
|
|
|
|
|
2,
|
|
|
|
|
)
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def get_mask(self, i, frame_count, layer, w, h):
|
|
|
|
|
mask = layer.masks[frame_count - layer.startFrame][i]
|
2022-08-16 20:50:00 +00:00
|
|
|
mask = imutils.resize(mask, width=w, height=h + 1)
|
|
|
|
|
mask = np.resize(mask, (h, w))
|
|
|
|
|
mask = cv2.erode(mask, None, iterations=10)
|
|
|
|
|
mask *= 255
|
|
|
|
|
return mask
|
|
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def export_raw_data(self, layers, contours, masks):
|
|
|
|
|
with open(self.config["importPath"] + "_layers", "wb+") as file:
|
|
|
|
|
pickle.dump(layers, file)
|
|
|
|
|
with open(self.config["importPath"] + "_contours", "wb+") as file:
|
|
|
|
|
pickle.dump(contours, file)
|
|
|
|
|
with open(self.config["importPath"] + "_masks", "wb+") as file:
|
|
|
|
|
pickle.dump(masks, file)
|
2020-12-26 13:58:58 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def get_max_length_of_layers(self, layers):
|
|
|
|
|
max_length = 0
|
2020-09-30 17:22:10 +00:00
|
|
|
for layer in layers:
|
2022-09-11 09:25:36 +00:00
|
|
|
if layer.getLength() > max_length:
|
|
|
|
|
max_length = layer.getLength()
|
|
|
|
|
return max_length
|
2020-09-30 17:22:10 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
def make_list_of_frames(self, layers):
|
|
|
|
|
"""Returns set of all Frames which are relevant to the Layers"""
|
|
|
|
|
frame_numbers = set()
|
2020-10-09 21:59:04 +00:00
|
|
|
for layer in layers:
|
2022-09-11 09:25:36 +00:00
|
|
|
frame_numbers.update(list(range(layer.startFrame, layer.startFrame + len(layer))))
|
2020-10-09 21:59:04 +00:00
|
|
|
|
2022-09-11 09:25:36 +00:00
|
|
|
return sorted(list(frame_numbers))
|