Video-Summary/Application/LayerFactory.py

172 lines
5.9 KiB
Python
Raw Normal View History

2020-10-18 15:36:34 +00:00
from Application.Layer import Layer
from Application.Config import Config
2020-10-19 19:35:15 +00:00
from Application.VideoReader import VideoReader
from Application.Exporter import Exporter
2020-10-17 22:02:05 +00:00
from multiprocessing.pool import ThreadPool
2020-10-19 19:35:15 +00:00
import cv2
import numpy as np
2020-11-12 17:59:57 +00:00
import copy
2020-09-24 20:48:04 +00:00
2020-12-18 20:27:19 +00:00
2020-09-20 20:01:54 +00:00
class LayerFactory:
2020-10-11 15:09:49 +00:00
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"]
2020-10-18 15:36:34 +00:00
self.config = config
2020-09-24 20:48:04 +00:00
print("LayerFactory constructed")
self.data = data
if data is not None:
self.extractLayers(data)
2020-11-27 00:06:25 +00:00
def extractLayers(self, data, maskArr):
2020-10-31 19:36:43 +00:00
'''Bundle given contours together into Layer Objects'''
2020-09-24 20:48:04 +00:00
frameNumber = min(data)
contours = data[frameNumber]
2020-11-27 00:06:25 +00:00
masks = maskArr[frameNumber]
for contour, mask in zip(contours, masks):
mask = np.unpackbits(mask, axis=0)
self.layers.append(Layer(frameNumber, contour, mask, self.config))
2020-12-18 20:27:19 +00:00
2020-10-17 22:02:05 +00:00
self.oldLayerIDs = []
2020-12-18 20:27:19 +00:00
2020-10-17 22:02:05 +00:00
with ThreadPool(16) as pool:
for frameNumber in sorted(data.keys()):
contours = data[frameNumber]
2020-11-27 00:06:25 +00:00
masks = maskArr[frameNumber]
2020-12-18 20:27:19 +00:00
masks = [np.unpackbits(mask, axis=0)
for mask, contours in zip(masks, contours)]
if frameNumber % 100 == 0:
print(
f" {int(round(frameNumber/max(data.keys()), 2)*100)}% done with Layer extraction {len(self.layers)} Layers", end='\r')
tmp = [[frameNumber, contour, mask]
for contour, mask in zip(contours, masks)]
2020-11-08 15:28:47 +00:00
#pool.map(self.getLayers, tmp)
for x in tmp:
self.getLayers(x)
2020-10-18 17:24:55 +00:00
2020-12-18 20:27:19 +00:00
#self.joinLayers()
2020-10-13 22:16:39 +00:00
return self.layers
2020-09-24 20:48:04 +00:00
2020-10-17 22:02:05 +00:00
def getLayers(self, data):
frameNumber = data[0]
bounds = data[1]
2020-11-27 00:06:25 +00:00
mask = data[2]
2020-12-18 20:27:19 +00:00
(x, y, w, h) = bounds
2020-10-17 22:02:05 +00:00
tol = self.tolerance
2020-12-18 20:27:19 +00:00
foundLayerIDs = set()
for i, layer in enumerate(self.layers):
if frameNumber - layer.lastFrame > self.ttolerance:
2020-10-17 22:02:05 +00:00
continue
2020-12-18 20:27:19 +00:00
lastXframes = min(40, len(layer))
lastBounds = [bound for bounds in layer.bounds[-lastXframes:]
for bound in bounds]
for j, bounds in enumerate(sorted(lastBounds, reverse=True)):
2020-11-08 15:28:47 +00:00
if bounds is None:
2020-10-17 22:02:05 +00:00
break
2020-12-18 20:27:19 +00:00
(x2, y2, w2, h2) = bounds
if self.contoursOverlay((x-tol, y+h+tol), (x+w+tol, y-tol), (x2, y2+h2), (x2+w2, y2)):
layer.add(frameNumber, (x, y, w, h), mask)
foundLayerIDs.add(i)
2020-11-08 15:28:47 +00:00
break
2020-10-17 22:02:05 +00:00
2020-12-18 20:27:19 +00:00
foundLayerIDs = sorted(list(foundLayerIDs))
if len(foundLayerIDs) == 0:
self.layers.append(
Layer(frameNumber, (x, y, w, h), mask, self.config))
2020-11-12 17:59:57 +00:00
if len(foundLayerIDs) > 1:
self.mergeLayers(foundLayerIDs)
def mergeLayers(self, foundLayerIDs):
2020-12-18 20:27:19 +00:00
layers = self.getLayersByID(foundLayerIDs)
2020-11-12 17:59:57 +00:00
layer1 = layers[0]
2020-12-18 20:27:19 +00:00
for layer in layers[1:]:
for i, (contours, masks) in enumerate(zip(layer.bounds, layer.masks)):
for contour, mask in zip(contours, masks):
2020-12-20 12:49:14 +00:00
layer1.add(layer.startFrame + i, contour, mask)
2020-11-12 17:59:57 +00:00
2020-12-18 20:27:19 +00:00
for i, id in enumerate(foundLayerIDs):
del self.layers[id - i]
self.layers.append(layer1)
def joinLayers(self):
self.layers.sort(key=lambda c: c.startFrame)
minFrame = self.getMinStart(self.layers)
maxFrame = self.getMaxEnd(self.layers)
for i in range(minFrame, maxFrame):
pL, indexes = self.getPossibleLayers(i)
if len(pL) <= 1:
continue
merge = set()
innerMax = self.getMaxEnd(pL)
for x in range(self.getMinStart(pL), innerMax):
for lc, l in enumerate(pL):
if l.startFrame < x or l.lastFrame > x:
continue
for lc2, l2 in enumerate(pL):
if lc2 == lc:
continue
for cnt in l.bounds[x-l.startFrame]:
for cnt2 in l2.bounds[x-l2.startFrame]:
if self.contoursOverlay(cnt, cnt2):
merge.add(indexes[lc])
merge.add(indexes[lc2])
merge = list(merge)
if len(merge) > 1:
self.mergeLayers(megre)
i = innerMax
def getPossibleLayers(self, t):
ret = []
ii = []
2020-11-12 17:59:57 +00:00
for i, layer in enumerate(self.layers):
2020-12-18 20:27:19 +00:00
if layer.startFrame <= t and layer.lastFrame <= t:
ret.append(layer)
ii.append(i)
return (ret, ii)
def getMinStart(self, layers):
minFrame = layers[0].startFrame
for l in layers:
if l.startFrame < minFrame:
minFrame = l.startFrame
return minFrame
def getMaxEnd(self, layers):
maxFrame = layers[0].lastFrame
for l in layers:
if l.lastFrame < maxFrame:
maxFrame = l.lastFrame
return maxFrame
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]):
2020-09-24 20:48:04 +00:00
return False
2020-12-18 20:27:19 +00:00
# If one rectangle is above other
if(l1[1] <= r2[1] or l2[1] <= r1[1]):
2020-09-24 20:48:04 +00:00
return False
return True
2020-11-12 17:59:57 +00:00
2020-12-18 20:27:19 +00:00
def getLayersByID(self, foundLayerIDs):
2020-11-12 17:59:57 +00:00
layers = []
for layerID in foundLayerIDs:
layers.append(self.layers[layerID])
2020-12-18 20:27:19 +00:00
layers.sort(key=lambda c: c.startFrame)
return layers