This commit is contained in:
Askill 2020-10-18 00:02:05 +02:00
parent f907094d1a
commit 559fef7bc4
9 changed files with 145 additions and 88 deletions

View File

@ -10,35 +10,48 @@ import _thread
import imageio
import numpy as np
import matplotlib.pyplot as plt
from VideoReader import VideoReader
from multiprocessing.pool import ThreadPool
import imutils
class Analyzer:
def __init__(self, videoPath):
def __init__(self, config):
print("Analyzer constructed")
data = self.readIntoMem(videoPath)
vs = cv2.VideoCapture(videoPath)
threashold = 13
res, image = vs.read()
firstFrame = None
i = 0
diff = []
while res:
res, frame = vs.read()
if not res:
break
frame = imutils.resize(frame, width=500)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)
if firstFrame is None:
firstFrame = gray
videoReader = VideoReader(config)
videoReader.fillBuffer()
self.config = config
self.avg = imutils.resize(np.zeros((videoReader.h,videoReader.w,3),np.float), width=config["resizeWidth"])
self.end = videoReader.endFrame
self.c = 0
start = time.time()
fak = 10
while not videoReader.videoEnded():
self.c, frame = videoReader.pop()
if not self.c%fak == 0:
continue
frameDelta = cv2.absdiff(gray, firstFrame)
thresh = cv2.threshold(frameDelta, threashold, 255, cv2.THRESH_BINARY)[1]
diff.append(np.count_nonzero(thresh))
i+=1
if i % (60*30) == 0:
print("Minutes processed: ", i/(60*30))
#print(diff)
if videoReader.endFrame - self.c <= fak:
break
frame = imutils.resize(frame, width=self.config["resizeWidth"])
self.avg += frame.astype(np.float)/(self.end/fak)
if self.c%(1800*6) == 0:
print(f"{self.c/(60*30)} Minutes processed in {round((time.time() - start), 2)} each")
start = time.time()
#print("done")
videoReader.thread.join()
self.avg = np.array(np.round(self.avg), dtype=np.uint8)
#return self.avg
cv2.imshow("changes overlayed", self.avg)
cv2.waitKey(10) & 0XFF
def average(self, frame):
frame = imutils.resize(frame[1], width=self.config["resizeWidth"])
self.avg += frame.astype(np.float)/(self.end/5)
plt.plot(diff)
plt.ylabel('some numbers')
plt.show()

View File

@ -2,17 +2,17 @@
class Config:
c = {
"min_area" : 500,
"max_area" : 9000,
"threashold" : 10,
"max_area" : 20000,
"threashold" : 13,
"resizeWidth" : 512,
"inputPath" : None,
"outputPath": None,
"maxLayerLength": 900,
"minLayerLength": 30,
"minLayerLength": 20,
"tolerance": 10,
"maxLength": None,
"ttolerance": 10,
"videoBufferLength": 16
"videoBufferLength": 1000
}
def __init__(self):

View File

@ -16,7 +16,7 @@ import concurrent.futures
from VideoReader import VideoReader
from queue import Queue
import threading
from multiprocessing.pool import ThreadPool
from Config import Config
class ContourExtractor:
@ -38,6 +38,7 @@ class ContourExtractor:
self.xDim = 0
self.yDim = 0
self.config = config
self.diff = []
print("ContourExtractor initiated")
@ -50,6 +51,7 @@ class ContourExtractor:
videoReader.fillBuffer()
frameCount, frame = videoReader.pop()
#init compare image
frame = imutils.resize(frame, width=self.resizeWidth)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
@ -57,36 +59,42 @@ class ContourExtractor:
gray = cv2.GaussianBlur(gray, (5, 5), 0)
self.firstFrame = gray
threads = 16
start = time.time()
threads = self.config["videoBufferLength"]
self.start = time.time()
with ThreadPool(threads) as pool:
while not videoReader.videoEnded():
#FrameCount, frame = videoReader.pop()
if frameCount % (60*30) == 0:
print(f"{frameCount/(60*30)} Minutes processed in {round((time.time() - start), 2)} each")
start = time.time()
if videoReader.buffer.qsize() == 0:
time.sleep(.5)
tmpData = [videoReader.pop() for i in range(0, videoReader.buffer.qsize())]
frameCount = tmpData[-1][0]
pool.map(self.getContours, tmpData)
#for data in tmpData:
#self.getContours(data)
frameCount = tmpData[-1][0]
videoReader.thread.join()
return self.extractedContours
def getContours(self, data):
frameCount, frame = data
firstFrame = self.firstFrame
if frameCount % (60*30) == 0:
print(f"{frameCount/(60*30)} Minutes processed in {round((time.time() - self.start), 2)} each")
self.start = time.time()
frame = imutils.resize(frame, width=self.resizeWidth)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
frameDelta = cv2.absdiff(gray, firstFrame)
thresh = cv2.threshold(frameDelta, self.threashold, 255, cv2.THRESH_BINARY)[1]
# dilate the thresholded image to fill in holes, then find contours
thresh = cv2.dilate(thresh, None, iterations=4)
thresh = cv2.dilate(thresh, None, iterations=10)
#cv2.imshow("changes x", thresh)
#cv2.waitKey(10) & 0XFF
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
self.diff.append(np.count_nonzero(thresh))
cnts = imutils.grab_contours(cnts)
contours = []
@ -111,8 +119,7 @@ class ContourExtractor:
frame = np.zeros(shape=[self.yDim, self.xDim, 3], dtype=np.uint8)
frame = imutils.resize(frame, width=512)
frame[y:y+v.shape[0], x:x+v.shape[1]] = v
cv2.imshow("changes overlayed", frame)
cv2.waitKey(10) & 0XFF
cv2.destroyAllWindows()
def exportContours(self):

View File

@ -45,7 +45,7 @@ class Exporter:
continue
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame2 = underlay
frame2 = np.copy(underlay)
for layer in layers:
if layer.startFrame <= frameCount and layer.startFrame + len(layer.bounds) > frameCount:
for (x, y, w, h) in layer.bounds[frameCount - layer.startFrame]:
@ -55,7 +55,8 @@ class Exporter:
w = int(w * factor)
h = int(h * factor)
frame2[y:y+h, x:x+w] = frame[y:y+h, x:x+w]
frame2[y:y+h, x:x+w] = np.copy(frame[y:y+h, x:x+w])
cv2.putText(frame2, str(int(frameCount/self.fps)), (int(x+w/2), int(y+h/2)), cv2.FONT_HERSHEY_SIMPLEX, 1,(255,255,255), 2)
writer.append_data(frame2)
@ -94,7 +95,10 @@ class Exporter:
# if exportFrame as index instead of frameCount - layer.startFrame then we have layer after layer
frame2 = frames[frameCount - layer.startFrame]
frame2[y:y+h, x:x+w] = frame[y:y+h, x:x+w]
frames[frameCount - layer.startFrame] = np.copy(frame2)
cv2.putText(frames[frameCount - layer.startFrame], str(int(frameCount/self.fps)), (int(x+w/2), int(y+h/2)), cv2.FONT_HERSHEY_SIMPLEX, 1,(255,255,255), 2)
videoReader.thread.join()
self.fps = videoReader.getFPS()

View File

@ -1,5 +1,6 @@
from Layer import Layer
from Config import Config
from multiprocessing.pool import ThreadPool
class LayerFactory:
def __init__(self, config, data=None):
@ -23,10 +24,12 @@ class LayerFactory:
layers = []
for i, layer in enumerate(self.layers):
checks = 0
if abs(self.layers[i].bounds[0][0][0] - self.layers[i].bounds[-1][0][0]) < 5:
checks += 1
if abs(self.layers[i].bounds[0][0][1] - self.layers[i].bounds[-1][0][1]) < 5:
checks += 1
for bound in layer.bounds[0]:
for bound2 in layer.bounds[-1]:
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
@ -43,7 +46,7 @@ class LayerFactory:
def extractLayers(self, data = None):
tol = self.tolerance
if self.data is None:
if data is None:
@ -57,35 +60,46 @@ class LayerFactory:
for contour in contours:
self.layers.append(Layer(frameNumber, contour))
oldLayerIDs = []
# inserts all the fucking contours as layers?
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")
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")
for (x,y,w,h) in contours:
foundLayer = False
for i in set(range(0, len(self.layers))).difference(set(oldLayerIDs)):
if frameNumber - self.layers[i].lastFrame > self.ttolerance:
oldLayerIDs.append(i)
continue
tmp = [[frameNumber, contour] for contour in contours]
#pool.map_async(self.getLayers, tmp)
for x in tmp:
self.getLayers(x)
for bounds in self.layers[i].bounds[-1]:
if bounds is None:
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 = True
break
if not foundLayer:
self.layers.append(Layer(frameNumber, (x,y,w,h)))
self.freeData()
self.sortLayers()
return self.layers
def getLayers(self, data):
frameNumber = data[0]
bounds = data[1]
(x,y,w,h) = bounds
tol = self.tolerance
foundLayer = False
for i in set(range(0, len(self.layers))).difference(set(self.oldLayerIDs)):
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:
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 = True
break
if not foundLayer:
self.layers.append(Layer(frameNumber, (x,y,w,h)))
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]):

View File

@ -68,28 +68,46 @@ class VideoReader:
self.endFrame = self.listOfFrames[-1]
while self.lastFrame < self.endFrame:
if not self.buffer.full():
if self.lastFrame in self.listOfFrames:
res, frame = self.vc.read()
if res:
self.buffer.put((self.lastFrame, frame))
# since the list is sorted the first element is always the lowest relevant framenumber
# [0,1,2,3,32,33,34,35,67,68,69]
self.listOfFrames.pop(0)
self.lastFrame += 1
else:
# if current Frame number is not in list of Frames, we can skip a few frames
self.vc.set(1, self.listOfFrames[0])
self.lastFrame = self.listOfFrames[0]
if self.lastFrame in self.listOfFrames:
res, frame = self.vc.read()
if res:
self.buffer.put((self.lastFrame, frame))
# since the list is sorted the first element is always the lowest relevant framenumber
# [0,1,2,3,32,33,34,35,67,68,69]
self.listOfFrames.pop(0)
self.lastFrame += 1
else:
sleep(0.1)
# if current Frame number is not in list of Frames, we can skip a few frames
self.vc.set(1, self.listOfFrames[0])
self.lastFrame = self.listOfFrames[0]
self.stopped = True
def videoEnded(self):
return self.stopped
if self.stopped and self.buffer.empty():
return True
else:
return False
def getFPS(self):
return self.vc.get(cv2.CAP_PROP_FPS)
def get_file_metadata(self, path, filename, metadata):
# Path shouldn't end with backslash, i.e. "E:\Images\Paris"
# filename must include extension, i.e. "PID manual.pdf"
# Returns dictionary containing all file metadata.
sh = win32com.client.gencache.EnsureDispatch('Shell.Application', 0)
ns = sh.NameSpace(path)
# Enumeration is necessary because ns.GetDetailsOf only accepts an integer as 2nd argument
file_metadata = dict()
item = ns.ParseName(str(filename))
for ind, attribute in enumerate(metadata):
attr_value = ns.GetDetailsOf(item, ind)
if attr_value:
file_metadata[attribute] = attr_value
return file_metadata

View File

@ -4,7 +4,6 @@ from ContourExctractor import ContourExtractor
from Exporter import Exporter
from LayerFactory import LayerFactory
from Analyzer import Analyzer
from VideoReader import VideoReader
from Config import Config
from Importer import Importer
import cv2
@ -21,6 +20,8 @@ def demo():
config["outputPath"] = os.path.join(os.path.dirname(__file__), "output/short.mp4")
if config["importPath"] is None:
#ana = Analyzer(config)
#ref = ana.avg
contours = ContourExtractor(config).extractContours()
print("Time consumed extracting: ", time.time() - start)
layerFactory = LayerFactory(config)
@ -30,7 +31,7 @@ def demo():
exporter = Exporter(config)
exporter.exportRawData(layers)
exporter.exportOverlayed(layers)
exporter.exportLayers(layers)
print("Total time: ", time.time() - start)

BIN
output/3.txt Normal file

Binary file not shown.

Binary file not shown.