diff --git a/Application/Config.py b/Application/Config.py index 7be1d09..2a6feec 100644 --- a/Application/Config.py +++ b/Application/Config.py @@ -3,25 +3,27 @@ class Config: c = { "min_area" : 100, "max_area" : 40000, - "threashold" : 5, + "threashold" : 8, "resizeWidth" : 512, "inputPath" : None, "outputPath": None, "maxLayerLength": 900, "minLayerLength": 20, - "tolerance": 20, + "tolerance": 10, "maxLength": None, "ttolerance": 60, "videoBufferLength": 500, - "noiseThreashold": 0.3, + "noiseThreashold": 0.25, "noiseSensitivity": 3/4, - "LayersPerContour": 5, - "averageFrames": 10 + "LayersPerContour": 2, + "avgNum":10 } def __init__(self): '''This is basically just a wrapper for a json / python dict''' - print("Current Config:", self.c) + print("Current Config:") + for key, value in self.c.items(): + print(f"{key}:\t\t{value}") def __getitem__(self, key): if key not in self.c: diff --git a/Application/ContourExctractor.py b/Application/ContourExctractor.py index c997e4d..a5f682d 100644 --- a/Application/ContourExctractor.py +++ b/Application/ContourExctractor.py @@ -109,7 +109,9 @@ class ContourExtractor: def computeMovingAverage(self, frames): avg = [] - averageFrames = self.config["averageFrames"] + averageFrames = self.config["avgNum"] + + nth = int(averageFrames/3) # only take /x x frames to average if frames[0][0] < averageFrames: frame = frames[0][1] frame = self.prepareFrame(frame) @@ -123,7 +125,7 @@ class ContourExtractor: if self.lastFrames is not None: frames = self.lastFrames + frames - tmp = [[j, frames, averageFrames]for j in range(averageFrames, len(frames))] + tmp = [[j, frames, averageFrames] for j in range(averageFrames, len(frames))] with ThreadPool(16) as pool: pool.map(self.averageDaFrames, tmp) @@ -136,6 +138,6 @@ class ContourExtractor: frame = self.prepareFrame(frame) avg = frame/averageFrames - for jj in reversed(range(averageFrames-1)): + for jj in range(0,averageFrames-1): avg += self.prepareFrame(frames[j-jj][1])/averageFrames self.averages[frameNumber] = np.array(np.round(avg), dtype=np.uint8) diff --git a/Application/Exporter.py b/Application/Exporter.py index e6fb691..e97b2da 100644 --- a/Application/Exporter.py +++ b/Application/Exporter.py @@ -16,17 +16,13 @@ class Exporter: self.config = config print("Exporter initiated") - def export(self, layers, raw = True, layered = False, overlayed = True): - + def export(self, layers, contours, raw = True, overlayed = True): if raw: - self.exportRawData(layers) - if layered and overlayed: - print("Layered and Individual are mutually exclusive, individual was choosen automatically") - overlayed = False - if layered and not overlayed: - self.exportLayers(layers) - if overlayed and not layered: + self.exportRawData(layers, contours) + if overlayed: self.exportOverlayed(layers) + else: + self.exportLayers(layers) def exportLayers(self, layers): @@ -37,7 +33,6 @@ class Exporter: maxLength = self.getMaxLengthOfLayers(layers) underlay = cv2.VideoCapture(self.footagePath).read()[1] underlay = cv2.cvtColor(underlay, cv2.COLOR_BGR2RGB) - frames = [underlay]*maxLength exportFrame = 0 self.fps = videoReader.getFPS() @@ -52,7 +47,7 @@ class Exporter: frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame2 = np.copy(underlay) - for layer in layers: + for xi, layer in enumerate(layers): if layer.startFrame <= frameCount and layer.startFrame + len(layer.bounds) > frameCount: for (x, y, w, h) in layer.bounds[frameCount - layer.startFrame]: if x is None: @@ -64,7 +59,7 @@ class Exporter: h = int(h * factor) 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) + cv2.putText(frame2, str(xi) + " " + 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) @@ -119,9 +114,10 @@ class Exporter: writer.close() - def exportRawData(self, layers): - with open(self.outputPath.split(".")[-2] + ".txt", "wb+") as file: - pickle.dump(layers, file) + def exportRawData(self, layers, contours): + with open(self.config["importPath"], "wb+") as file: + pickle.dump((layers, contours), file) + def getMaxLengthOfLayers(self, layers): diff --git a/Application/Importer.py b/Application/Importer.py index 332df6a..bc2fe11 100644 --- a/Application/Importer.py +++ b/Application/Importer.py @@ -5,6 +5,7 @@ class Importer: self.path = config["importPath"] def importRawData(self): + print("Loading previous results") with open(self.path, "rb") as file: - layers = pickle.load(file) - return layers \ No newline at end of file + layers, contours = pickle.load(file) + return (layers, contours) \ No newline at end of file diff --git a/Application/Layer.py b/Application/Layer.py index 9d909b0..26aeb62 100644 --- a/Application/Layer.py +++ b/Application/Layer.py @@ -37,40 +37,19 @@ class Layer: def add(self, frameNumber, bound): '''Adds a bound''' - if not self.startFrame + len(self.bounds) < frameNumber: - if len(self.bounds[self.startFrame - frameNumber]) >= 1: - self.bounds[self.startFrame - frameNumber].append(bound) + if self.startFrame + len(self.bounds) - 1 > frameNumber: + if len(self.bounds[frameNumber - self.startFrame]) >= 1: + self.bounds[frameNumber - self.startFrame].append(bound) else: self.lastFrame = frameNumber self.bounds.append([bound]) - self.getLength() - def getLength(self): return len(self) def __len__(self): self.length = len(self.bounds) return self.length - - def fill(self, inputPath, resizeWidth): - '''deprecated - - Fills the data[] array by iterateing over the bounds''' - - cap = cv2.VideoCapture(inputPath) - self.data = [None]*len(self.bounds) - i = 0 - cap.set(1, self.startFrame) - while i < len(self.bounds): - ret, frame = cap.read() - - if ret: - frame = imutils.resize(frame, width=resizeWidth) - (x, y, w, h) = self.bounds[i] - self.data[i] = frame[y:y+h, x:x+w] - i+=1 - cap.release() def clusterDelete(self): '''Uses a cluster analysis to remove contours which are not the result of movement''' @@ -146,13 +125,14 @@ class Layer: newContours = [[]] for i, dis in enumerate(dists): # copy contours which are spread out, delete rest by not copying them - if dis > noiseThreashold: - for j in classed[i]: - x, y = mapping[j] - while x >= len(newContours): - newContours.append([]) - while y > len(newContours[x]): - newContours[x].append((None, None, None, None)) + + for j in classed[i]: + x, y = mapping[j] + while x >= len(newContours): + newContours.append([]) + while y > len(newContours[x]): + newContours[x].append((None, None, None, None)) + if dis > noiseThreashold: newContours[x].append(org[x][y]) self.bounds = newContours diff --git a/Application/LayerFactory.py b/Application/LayerFactory.py index da584bb..90522fc 100644 --- a/Application/LayerFactory.py +++ b/Application/LayerFactory.py @@ -45,9 +45,9 @@ class LayerFactory: 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) + #pool.map(self.getLayers, tmp) + for x in tmp: + self.getLayers(x) return self.layers @@ -59,20 +59,28 @@ class LayerFactory: foundLayer = 0 for i in range(0, len(self.layers)): + if foundLayer >= self.config["LayersPerContour"]: + break + if i in self.oldLayerIDs: continue if frameNumber - self.layers[i].lastFrame > self.ttolerance: self.oldLayerIDs.append(i) continue + + lastXframes = 3 + if len(self.layers[i].bounds) < lastXframes: + lastXframes = len(self.layers[i].bounds) + lastBounds = [bound for bounds in self.layers[i].bounds[-lastXframes:] for bound in bounds] - for bounds in self.layers[i].bounds[-1]: - if bounds is None or foundLayer >= self.config["LayersPerContour"]: + for bounds in lastBounds: + 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 += 1 - #break + break if foundLayer == 0: self.layers.append(Layer(frameNumber, (x,y,w,h), self.config)) diff --git a/Application/LayerManager.py b/Application/LayerManager.py index ac9db09..b0a7f4f 100644 --- a/Application/LayerManager.py +++ b/Application/LayerManager.py @@ -28,7 +28,7 @@ class LayerManager: print("'Cleaning' Layers") self.freeMin() self.sortLayers() - self.cleanLayers2() + #self.cleanLayers2() self.freeMax() def removeStaticLayers(self): @@ -107,5 +107,8 @@ class LayerManager: self.layers.sort(key = lambda c:c.startFrame) def cleanLayers2(self): + #with ThreadPool(16) as pool: + # pool.map(self.getContours, tmpData) + for layer in self.layers: layer.clusterDelete() diff --git a/generate test footage/kap.py b/generate test footage/kap.py index 924ec0c..b7442f1 100644 --- a/generate test footage/kap.py +++ b/generate test footage/kap.py @@ -2,7 +2,7 @@ import cv2 import imageio import time -writer = imageio.get_writer("./x23.mp4", fps=20) +writer = imageio.get_writer("./x23.mp4", fps=15) url = "http://50.227.41.1/mjpg/video.mjpg" i = 0 @@ -20,15 +20,15 @@ while True : print("Error in cap.read()") # this is for preventing a breaking error # break; time.sleep(1) - continue + break frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) writer.append_data(frame) i+=1 - if i > 20*60*60: + if i > 20*60*60*2: break except Exception as e: - - cap.release() - cv2.destroyAllWindows() - writer.close() \ No newline at end of file + print("meh") +cap.release() +cv2.destroyAllWindows() +writer.close() \ No newline at end of file diff --git a/main.py b/main.py index ee90f76..f56d3e3 100644 --- a/main.py +++ b/main.py @@ -14,22 +14,26 @@ def main(): start = time.time() config = Config() - config["inputPath"] = os.path.join(os.path.dirname(__file__), "generate test footage/Merica-1.m4v") - #config["importPath"] = os.path.join(os.path.dirname(__file__), "output/short.txt") - config["outputPath"] = os.path.join(os.path.dirname(__file__), "output/shor.mp4") + fileName = "3.mp4" + outputPath = os.path.join(os.path.dirname(__file__), "output") + dirName = os.path.join(os.path.dirname(__file__), "generate test footage") - vr = VideoReader(config) - config["w"], config["h"] = vr.getWH() + config["inputPath"] = os.path.join(dirName, fileName) + config["outputPath"] = os.path.join(outputPath, fileName) - if config["importPath"] is None: + config["importPath"] = os.path.join(outputPath, fileName.split(".")[0] + ".txt") + + config["w"], config["h"] = VideoReader(config).getWH() + + if not os.path.exists(config["importPath"]): contours = ContourExtractor(config).extractContours() print("Time consumed extracting: ", time.time() - start) layerFactory = LayerFactory(config) - layers = layerFactory.extractLayers(contours) - else: - layers = Importer(config).importRawData() + layers, contours = Importer(config).importRawData() + #layerFactory = LayerFactory(config) + #layers = layerFactory.extractLayers(contours) layerManager = LayerManager(config, layers) layerManager.cleanLayers() @@ -37,7 +41,8 @@ def main(): #layerManager.tagLayers() layers = layerManager.layers exporter = Exporter(config) - exporter.export(layers, raw=False) + print(f"Exporting {len(contours)} Contours and {len(layers)} Layers") + exporter.export(layers, contours, raw=True, overlayed=False) print("Total time: ", time.time() - start) diff --git a/output/3.txt b/output/3.txt index 0606308..8e3a9b1 100644 Binary files a/output/3.txt and b/output/3.txt differ diff --git a/output/out.txt b/output/out.txt new file mode 100644 index 0000000..e7814e6 Binary files /dev/null and b/output/out.txt differ diff --git a/output/short.txt b/output/short.txt deleted file mode 100644 index 83597bd..0000000 Binary files a/output/short.txt and /dev/null differ diff --git a/output/x23.txt b/output/x23.txt new file mode 100644 index 0000000..86e1a40 Binary files /dev/null and b/output/x23.txt differ diff --git a/ueberblick.drawio.png b/ueberblick.drawio.png index 480ed33..14d15a0 100644 Binary files a/ueberblick.drawio.png and b/ueberblick.drawio.png differ