Video-Summary/Application/LayerFactory.py

166 lines
5.6 KiB
Python

from Application.Layer import Layer
from Application.Config import Config
from Application.VideoReader import VideoReader
from Application.Exporter import Exporter
from multiprocessing.pool import ThreadPool
import cv2
import numpy as np
class LayerFactory:
def __init__(self, config, data=None):
self.data = {}
self.layers = []
self.tolerance = config["tolerance"]
self.ttolerance = config["ttolerance"]
self.minLayerLength = config["minLayerLength"]
self.maxLayerLength = config["maxLayerLength"]
self.resizeWidth = config["resizeWidth"]
self.footagePath = config["inputPath"]
self.config = config
print("LayerFactory constructed")
self.data = data
if data is not None:
self.extractLayers(data)
def removeStaticLayers(self):
'''Removes Layers with little to no movement'''
layers = []
for i, layer in enumerate(self.layers):
checks = 0
for bound in layer.bounds[0]:
if bound[0] is None:
continue
for bound2 in layer.bounds[-1]:
if bound2[0] is None:
continue
if abs(bound[0] - bound2[0]) < 10:
checks += 1
if abs(bound[1] - bound2[1]) < 10:
checks += 1
if checks <= 2:
layers.append(layer)
self.layers = layers
def freeMin(self):
self.data.clear()
layers = []
for l in self.layers:
if l.getLength() > self.minLayerLength:
layers.append(l)
self.layers = layers
self.removeStaticLayers()
def freeMax(self):
layers = []
for l in self.layers:
if l.getLength() < self.maxLayerLength:
layers.append(l)
self.layers = layers
self.removeStaticLayers()
def extractLayers(self, data = None):
if self.data is None:
if data is None:
print("LayerFactory data was none")
return None
else:
self.data = data
frameNumber = min(data)
contours = data[frameNumber]
for contour in contours:
self.layers.append(Layer(frameNumber, contour, self.config))
self.oldLayerIDs = []
with ThreadPool(16) as pool:
for frameNumber in sorted(data.keys()):
contours = data[frameNumber]
if frameNumber%5000 == 0:
print(f"{int(round(frameNumber/max(data.keys()), 2)*100)}% done with Layer extraction")
tmp = [[frameNumber, contour] for contour in contours]
pool.map(self.getLayers, tmp)
#for x in tmp:
#self.getLayers(x)
self.freeMin()
self.sortLayers()
self.cleanLayers()
self.freeMax()
return self.layers
def getLayers(self, data):
frameNumber = data[0]
bounds = data[1]
(x,y,w,h) = bounds
tol = self.tolerance
foundLayer = 0
for i in range(0, len(self.layers)):
if i in self.oldLayerIDs:
continue
if frameNumber - self.layers[i].lastFrame > self.ttolerance:
self.oldLayerIDs.append(i)
continue
for bounds in self.layers[i].bounds[-1]:
if bounds is None or foundLayer >= self.config["LayersPerContour"]:
break
(x2,y2,w2,h2) = bounds
if self.contoursOverlay((x-tol,y+h+tol), (x+w+tol,y-tol), (x2,y2+h2), (x2+w2,y2)):
self.layers[i].add(frameNumber, (x,y,w,h))
foundLayer += 1
#break
if foundLayer == 0:
self.layers.append(Layer(frameNumber, (x,y,w,h), self.config))
def contoursOverlay(self, l1, r1, l2, r2):
# If one rectangle is on left side of other
if(l1[0] >= r2[0] or l2[0] >= r1[0]):
return False
# If one rectangle is above other
if(l1[1] <= r2[1] or l2[1] <= r1[1]):
return False
return True
def fillLayers(self):
listOfFrames = Exporter(self.config).makeListOfFrames(self.layers)
videoReader = VideoReader(self.config, listOfFrames)
videoReader.fillBuffer()
while not videoReader.videoEnded():
frameCount, frame = videoReader.pop()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
for i, layer in enumerate(self.layers):
if i % 20 == 0:
print(f"filled {int(round(i/len(self.layers),2)*100)}% of all Layers")
if layer.startFrame <= frameCount and layer.startFrame + len(layer.bounds) > frameCount:
data = []
for (x, y, w, h) in layer.bounds[frameCount - layer.startFrame]:
if x is None:
break
factor = videoReader.w / self.resizeWidth
x = int(x * factor)
y = int(y * factor)
w = int(w * factor)
h = int(h * factor)
data.append(np.copy(frame[y:y+h, x:x+w]))
layer.data.append(data)
videoReader.thread.join()
def sortLayers(self):
self.layers.sort(key = lambda c:c.startFrame)
def cleanLayers(self):
for layer in self.layers:
layer.clusterDelete()