2020-10-18 15:36:34 +00:00
|
|
|
import numpy as np
|
|
|
|
|
import cv2
|
|
|
|
|
import imutils
|
|
|
|
|
|
|
|
|
|
class Layer:
|
|
|
|
|
#bounds = [[(x,y,w,h), ],]
|
|
|
|
|
|
|
|
|
|
startFrame = None
|
|
|
|
|
lastFrame = None
|
|
|
|
|
length = None
|
|
|
|
|
|
2020-11-27 00:06:25 +00:00
|
|
|
def __init__(self, startFrame, data, mask, config):
|
2020-10-31 19:36:43 +00:00
|
|
|
'''returns a Layer object
|
|
|
|
|
|
|
|
|
|
Layers are collections of contours with a StartFrame,
|
|
|
|
|
which is the number of the frame the first contour of
|
|
|
|
|
this layer was extraced from
|
|
|
|
|
|
|
|
|
|
A Contour is a CV2 Contour, which is a y*x*3 rgb numpy array,
|
|
|
|
|
but we only care about the corners of the contours.
|
|
|
|
|
So we save the bounds (x,y,w,h) in bounds[] and the actual content in data[]
|
|
|
|
|
'''
|
2020-10-18 15:36:34 +00:00
|
|
|
self.startFrame = startFrame
|
|
|
|
|
self.lastFrame = startFrame
|
|
|
|
|
self.config = config
|
|
|
|
|
self.data = []
|
|
|
|
|
self.bounds = []
|
2020-11-27 00:06:25 +00:00
|
|
|
self.masks = []
|
2020-11-11 21:32:12 +00:00
|
|
|
self.stats = dict()
|
2021-02-06 14:49:46 +00:00
|
|
|
self.exportOffset = 0
|
2020-11-11 21:32:12 +00:00
|
|
|
|
2020-10-18 15:36:34 +00:00
|
|
|
self.bounds.append([data])
|
2020-11-27 00:06:25 +00:00
|
|
|
self.masks.append([mask])
|
2020-10-18 15:36:34 +00:00
|
|
|
#print("Layer constructed")
|
|
|
|
|
|
2020-11-27 00:06:25 +00:00
|
|
|
def add(self, frameNumber, bound, mask):
|
2020-11-21 18:13:17 +00:00
|
|
|
'''Adds a bound to the Layer at the layer index which corresponds to the given framenumber'''
|
2020-12-18 20:27:19 +00:00
|
|
|
index = frameNumber - self.startFrame
|
2020-12-19 13:00:58 +00:00
|
|
|
if index < 0:
|
|
|
|
|
return
|
2020-12-18 20:27:19 +00:00
|
|
|
if frameNumber > self.lastFrame:
|
|
|
|
|
for i in range(frameNumber - self.lastFrame):
|
2020-12-26 13:58:58 +00:00
|
|
|
self.bounds.append([])
|
|
|
|
|
self.masks.append([])
|
2020-10-18 15:36:34 +00:00
|
|
|
self.lastFrame = frameNumber
|
|
|
|
|
|
2020-12-18 20:27:19 +00:00
|
|
|
if bound not in self.bounds[index]:
|
|
|
|
|
self.bounds[index].append(bound)
|
|
|
|
|
self.masks[index].append(mask)
|
|
|
|
|
|
|
|
|
|
|
2020-11-11 21:32:12 +00:00
|
|
|
def calcStats(self):
|
2020-11-27 00:06:25 +00:00
|
|
|
'''calculates average distance, variation and deviation of layer movement'''
|
2020-11-11 21:32:12 +00:00
|
|
|
middles = []
|
|
|
|
|
for i, bounds in enumerate(self.bounds):
|
|
|
|
|
for j, bound in enumerate(bounds):
|
|
|
|
|
if None in bound:
|
|
|
|
|
continue
|
|
|
|
|
x = (bound[0] + bound[2]/2)
|
|
|
|
|
y = (bound[1] + bound[3]/2)
|
|
|
|
|
middles.append([x,y])
|
|
|
|
|
|
2020-11-21 18:13:17 +00:00
|
|
|
avg = 0
|
2020-11-11 21:32:12 +00:00
|
|
|
for i in range(1, len(middles), 2):
|
2020-11-21 18:13:17 +00:00
|
|
|
avg += (((float(middles[i][0]-middles[i-1][0])/len(middles))**2 + float(middles[i][1]-middles[i-1][1])/len(middles))**2)**(1/2)
|
2020-11-11 21:32:12 +00:00
|
|
|
self.stats = dict()
|
2020-11-21 18:13:17 +00:00
|
|
|
self.stats["avg"] = round(avg,2)
|
2020-11-11 21:32:12 +00:00
|
|
|
|
|
|
|
|
x=0
|
2020-11-21 18:13:17 +00:00
|
|
|
for i in range(1, len(middles), 2):
|
|
|
|
|
x += (((((float(middles[i][0]-middles[i-1][0])/len(middles))**2 + float(middles[i][1]-middles[i-1][1])/len(middles))**2)**(1/2)) - avg)**2
|
2020-11-11 21:32:12 +00:00
|
|
|
|
|
|
|
|
x /= (len(middles)-1)
|
|
|
|
|
|
2020-11-21 18:13:17 +00:00
|
|
|
self.stats["var"] = round(x,2)
|
|
|
|
|
self.stats["dev"] = round((x)**(1/2), 2)
|
2020-11-11 21:32:12 +00:00
|
|
|
|
|
|
|
|
|
2020-10-18 15:36:34 +00:00
|
|
|
def getLength(self):
|
2020-10-31 19:36:43 +00:00
|
|
|
return len(self)
|
|
|
|
|
|
|
|
|
|
def __len__(self):
|
2020-10-18 15:36:34 +00:00
|
|
|
self.length = len(self.bounds)
|
|
|
|
|
return self.length
|
2021-02-05 19:04:10 +00:00
|
|
|
|
|
|
|
|
def spaceOverlaps(self, layer2):
|
|
|
|
|
'''Checks if there is an overlap in the bounds of current layer with given layer'''
|
|
|
|
|
overlap = False
|
|
|
|
|
maxLen = min(len(layer2.bounds), len(self.bounds))
|
|
|
|
|
bounds = self.bounds[:maxLen]
|
2022-01-02 22:40:05 +00:00
|
|
|
for b1s, b2s in zip(bounds[::10], layer2.bounds[:maxLen:10]):
|
2021-02-05 19:04:10 +00:00
|
|
|
for b1 in b1s:
|
|
|
|
|
for b2 in b2s:
|
|
|
|
|
if self.contoursOverlay((b1[0], b1[1]+b1[3]), (b1[0]+b1[2], b1[1]), (b2[0], b2[1]+b2[3]), (b2[0]+b2[2], b2[1])):
|
|
|
|
|
overlap = True
|
|
|
|
|
break
|
|
|
|
|
return overlap
|
|
|
|
|
|
|
|
|
|
def timeOverlaps(self, layer2):
|
|
|
|
|
'''Checks for overlap in time between current and given layer'''
|
2022-01-02 22:40:05 +00:00
|
|
|
s1 = self.exportOffset
|
|
|
|
|
e1 = self.lastFrame - self.startFrame + self.exportOffset
|
2022-01-05 12:25:49 +00:00
|
|
|
s2 = layer2.exportOffset
|
2022-01-02 22:40:05 +00:00
|
|
|
e2 = layer2.lastFrame - layer2.startFrame + self.exportOffset
|
2021-02-05 19:04:10 +00:00
|
|
|
|
|
|
|
|
if s2 >= s1 and s2 <= e1:
|
|
|
|
|
return True
|
|
|
|
|
elif s1 >= s2 and s1 <= e2:
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def contoursOverlay(self, l1, r1, l2, r2):
|
|
|
|
|
if(l1[0] >= r2[0] or l2[0] >= r1[0]):
|
|
|
|
|
return False
|
|
|
|
|
if(l1[1] <= r2[1] or l2[1] <= r1[1]):
|
|
|
|
|
return False
|
|
|
|
|
return True
|
2020-10-18 15:36:34 +00:00
|
|
|
|