From 15bfcc8e92f112363f29754fd0cb171cceecd672 Mon Sep 17 00:00:00 2001 From: Askill Date: Fri, 9 Oct 2020 23:59:04 +0200 Subject: [PATCH] rewrote exporter layers are now only filled on export --- ContourExctractor.py | 4 +- Exporter.py | 87 +++++++++++++------ VideoReader.py | 50 ++++++++--- __pycache__/Analyzer.cpython-37.pyc | Bin 1322 -> 0 bytes __pycache__/ContourExctractor.cpython-37.pyc | Bin 3606 -> 0 bytes __pycache__/LayerFactory.cpython-37.pyc | Bin 3015 -> 0 bytes main.py | 12 +-- motion_detector.py | 72 --------------- 8 files changed, 110 insertions(+), 115 deletions(-) delete mode 100644 __pycache__/Analyzer.cpython-37.pyc delete mode 100644 __pycache__/ContourExctractor.cpython-37.pyc delete mode 100644 __pycache__/LayerFactory.cpython-37.pyc delete mode 100644 motion_detector.py diff --git a/ContourExctractor.py b/ContourExctractor.py index f075177..6393c1f 100644 --- a/ContourExctractor.py +++ b/ContourExctractor.py @@ -20,8 +20,8 @@ class ContourExtractor: #X = {frame_number: [(contour, (x,y,w,h)), ...], } extractedContours = dict() - min_area = 500 - max_area = 28000 + min_area = 100 + max_area = 1000 threashold = 13 xDim = 0 yDim = 0 diff --git a/Exporter.py b/Exporter.py index bcdca3c..96199f8 100644 --- a/Exporter.py +++ b/Exporter.py @@ -1,8 +1,11 @@ import imageio import imutils import numpy as np -from Layer import Layer +from Layer import Layer import cv2 +from VideoReader import VideoReader + + class Exporter: fps = 30 @@ -16,10 +19,11 @@ class Exporter: writer.append_data(np.array(frame)) writer.close() - def exportLayers(self,underlay, layers, outputPath, resizeWidth): + def exportLayers(self, layers, outputPath, resizeWidth): + underlay = cv2.VideoCapture(footagePath).read()[1] fps = self.fps writer = imageio.get_writer(outputPath, fps=fps) - i=0 + i = 0 for layer in layers: data = layer.data contours = layer.bounds @@ -32,35 +36,60 @@ class Exporter: frame1 = imutils.resize(frame1, width=resizeWidth) frame1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2RGB) frame1[y:y+frame.shape[0], x:x+frame.shape[1]] = frame - cv2.putText(frame1, str(i), (30,30), cv2.FONT_HERSHEY_SIMPLEX, 1,(255,255,255), 2) + cv2.putText(frame1, str(i), (30, 30), + cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) writer.append_data(np.array(frame1)) #cv2.imshow("changes overlayed", frame) #cv2.waitKey(10) & 0XFF i += 1 - - writer.close() - #cv2.destroyAllWindows() - - def exportOverlayed(self, underlay, layers, outputPath, resizeWidth): + + writer.close() + # cv2.destroyAllWindows() + + def exportOverlayed(self, layers, footagePath, outputPath, resizeWidth): + + + listOfFrames = self.makeListOfFrames(layers) + videoReader = VideoReader(footagePath, listOfFrames) + videoReader.fillBuffer() + maxLength = self.getMaxLengthOfLayers(layers) + underlay = cv2.VideoCapture(footagePath).read()[1] + underlay = cv2.cvtColor(underlay, cv2.COLOR_BGR2RGB) + frames = [underlay]*maxLength + exportFrame = 0 + + + while not videoReader.videoEnded(): + frameCount, frame = videoReader.pop() + if frameCount % (60*self.fps) == 0: + print("Minutes processed: ", frameCount/(60*self.fps)) + if frame is None: + print("ContourExtractor: frame was None") + continue + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + for layer in layers: + if layer.startFrame <= frameCount and layer.startFrame + len(layer.bounds) > frameCount: + (x, y, w, h) = layer.bounds[frameCount - layer.startFrame] + factor = videoReader.w / resizeWidth + x = int(x * factor) + y = int(y * factor) + w = int(w * factor) + h = int(h * factor) + # 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) + + + videoReader.thread.join() + + fps = self.fps writer = imageio.get_writer(outputPath, fps=fps) - - maxLength = self.getMaxLengthOfLayers(layers) + for frame in frames: + writer.append_data(frame) - for i in range(maxLength): - frame1 = underlay - frame1 = imutils.resize(frame1, width=resizeWidth) - frame1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2RGB) - for layer in layers: - data = layer.data - if len(layer.data) > i: - (x, y, w, h) = layer.bounds[i] - frame = layer.data[i] - if frame is not None: - frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - frame1[y:y+h, x:x+w] = frame - writer.append_data(np.array(frame1)) - writer.close() + writer.close() def getMaxLengthOfLayers(self, layers): maxLength = 0 @@ -69,3 +98,11 @@ class Exporter: maxLength = layer.getLength() return maxLength + def makeListOfFrames(self, layers): + '''Returns set of all Frames which are relavant to the Layers''' + frameNumbers = set() + for layer in layers: + frameNumbers.update( + list(range(layer.startFrame, layer.startFrame + len(layer.bounds)))) + + return list(frameNumbers) diff --git a/VideoReader.py b/VideoReader.py index 8020441..4c42cde 100644 --- a/VideoReader.py +++ b/VideoReader.py @@ -4,11 +4,14 @@ import cv2 from time import sleep from queue import Queue import threading + + class VideoReader: #buffer = [(frameNumber, frame)] + listOfFrames = None - def __init__(self, videoPath): + def __init__(self, videoPath, setOfFrames = None): if videoPath is None: print("Video reader needs a videoPath!") return None @@ -21,9 +24,8 @@ class VideoReader: res, image = self.vc.read() self.w = image.shape[1] self.h = image.shape[0] - - print(f"Video reader startet with buffer length of 16") - + if setOfFrames is not None: + self.listOfFrames = sorted(setOfFrames) def pop(self): return self.buffer.get(block=True) @@ -35,8 +37,12 @@ class VideoReader: if self.buffer.full(): print("VideoReader::fillBuffer was called when buffer was full.") self.endFrame = int(self.vc.get(cv2.CAP_PROP_FRAME_COUNT)) - self.endFrame = 10*60*30 - self.thread = threading.Thread(target=self.readFrames, args=()) + + #self.endFrame = 10*60*30 + if self.listOfFrames is not None: + self.thread = threading.Thread(target=self.readFramesByList, args=()) + else: + self.thread = threading.Thread(target=self.readFrames, args=()) self.thread.start() def stop(self): @@ -46,10 +52,34 @@ class VideoReader: def readFrames(self): while self.lastFrame < self.endFrame: if not self.buffer.full(): - res, frame = self.vc.read() - if res: - self.buffer.put((self.lastFrame, frame)) - self.lastFrame += 1 + res, frame = self.vc.read() + if res: + self.buffer.put((self.lastFrame, frame)) + self.lastFrame += 1 + else: + sleep(0.5) + self.stopped = True + + + def readFramesByList(self): + self.vc.set(1, self.listOfFrames[0]) + self.lastFrame = self.listOfFrames[0] + 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] else: sleep(0.5) self.stopped = True diff --git a/__pycache__/Analyzer.cpython-37.pyc b/__pycache__/Analyzer.cpython-37.pyc deleted file mode 100644 index 31b382ebec61ad7d2812925034ef7b8782d7eaf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1322 zcmZWpJ8v8}5GJ|L+uPN{HiQIe)Wz4hFbo7Z1c4&#kmm~ogaqfC;c$n;Z^+$Gk_bWDd+}5Dhl|kf##lE8 zl;<$y90WrQm#D%i#zrS4Nr^=#bu7B6Ytc(Ri+<``4AQ`2n1&Vy>A+%?Miz%@Y%!@e z(oKwBBIYpn17hwiNw*j|K_l-D_D3VEhu;;9Hz!JPS{>$Qa@`0h&tb?%AUH}fLy#V3 zq^nk&xk65vB% z5XE00fqn0N!PLdwKQMJ?=feP@`NOwGJyl%pwxY?ol$?!s=do-mzFSYL2^VtoP_k*qj7(*tz@YcHCT>Ezp2$6uek%JyF$?j8T2ecHCXW}4KkPV#12 ztE_HnxCD)M+EQt^EgO~kvyx7Dsa=TiezXC|ONe@7uG2Ngh>7>;a`#X9O(S}aXvl;{w{g0 zlpKe!FnL?Ju1V~zybcJFE{5F?+`5MlJNm_?ru8#SYxzO?x5HZm7 I{~nWn0akHkasU7T diff --git a/__pycache__/ContourExctractor.cpython-37.pyc b/__pycache__/ContourExctractor.cpython-37.pyc deleted file mode 100644 index e56e16b1f3925a2b39f0bb12acc485bd067407d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3606 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 diff --git a/main.py b/main.py index 05d607b..c5cea65 100644 --- a/main.py +++ b/main.py @@ -11,8 +11,8 @@ import cv2 def demo(): print("startup") - resizeWidth = 512 - maxLayerLength = 1*60*30 + resizeWidth = 256 + maxLayerLength = 20*30 minLayerLength = 30 start = time.time() @@ -27,10 +27,10 @@ def demo(): layerFactory.freeData(maxLayerLength, minLayerLength) print("sort Layers") layerFactory.sortLayers() - print("fill Layers") - layerFactory.fillLayers(footagePath, resizeWidth) - underlay = cv2.VideoCapture(footagePath).read()[1] - Exporter().exportOverlayed(underlay, layerFactory.layers, os.path.join(os.path.dirname(__file__), "./short.mp4"), resizeWidth) + #print("fill Layers") + #layerFactory.fillLayers(footagePath, resizeWidth) + + Exporter().exportOverlayed(layerFactory.layers,footagePath, os.path.join(os.path.dirname(__file__), "./short.mp4"), resizeWidth) print("Total time: ", time.time() - start) def init(): diff --git a/motion_detector.py b/motion_detector.py deleted file mode 100644 index ec6ea66..0000000 --- a/motion_detector.py +++ /dev/null @@ -1,72 +0,0 @@ -from imutils.video import VideoStream -import argparse -import datetime -import imutils -import time -import cv2 -import os - -import traceback -import _thread - - - -def compare(): - try: - url = os.path.join(os.path.dirname(__file__), "./generate test footage/out.mp4") - - min_area = 100 - max_area = 30000 - - threashold = 10 - - # initialize the first frame in the video stream - vs = cv2.VideoCapture(url) - - res = vs.read()[0] - firstFrame = None - # loop over the frames of the video - while res: - - res, frame = vs.read() - - # resize the frame, convert it to grayscale, and blur it - frame = imutils.resize(frame, width=500) - cv2.imshow( "frame", frame ) - gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - gray = cv2.GaussianBlur(gray, (31, 31), 0) - - # if the first frame is None, initialize it - if firstFrame is None: - firstFrame = gray - continue - - frameDelta = cv2.absdiff(gray, firstFrame) - - thresh = cv2.threshold(frameDelta, threashold, 255, cv2.THRESH_BINARY)[1] - - - # dilate the thresholded image to fill in holes, then find contours - thresh = cv2.dilate(thresh, None, iterations=3) - cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - cnts = imutils.grab_contours(cnts) - - # loop over the contours - for c in cnts: - if cv2.contourArea(c) < min_area or cv2.contourArea(c) > max_area: - continue - - (x, y, w, h) = cv2.boundingRect(c) - cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) - text = "Occupied" - - - cv2.imshow( "annotated", frame ) - print("1") - - cv2.waitKey(10) & 0XFF - - except Exception as e: - traceback.print_exc() - -compare()