This commit is contained in:
parent
f907094d1a
commit
559fef7bc4
67
Analyzer.py
67
Analyzer.py
|
|
@ -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()
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,9 +24,11 @@ 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:
|
||||
for bound in layer.bounds[0]:
|
||||
for bound2 in layer.bounds[-1]:
|
||||
if abs(bound[0] - bound2[0]) < 10:
|
||||
checks += 1
|
||||
if abs(self.layers[i].bounds[0][0][1] - self.layers[i].bounds[-1][0][1]) < 5:
|
||||
if abs(bound[1] - bound2[1]) < 10:
|
||||
checks += 1
|
||||
if checks <= 2:
|
||||
layers.append(layer)
|
||||
|
|
@ -43,7 +46,7 @@ class LayerFactory:
|
|||
|
||||
|
||||
def extractLayers(self, data = None):
|
||||
tol = self.tolerance
|
||||
|
||||
|
||||
if self.data is None:
|
||||
if data is None:
|
||||
|
|
@ -57,18 +60,32 @@ class LayerFactory:
|
|||
for contour in contours:
|
||||
self.layers.append(Layer(frameNumber, contour))
|
||||
|
||||
oldLayerIDs = []
|
||||
# inserts all the fucking contours as layers?
|
||||
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:
|
||||
tmp = [[frameNumber, contour] for contour in contours]
|
||||
#pool.map_async(self.getLayers, tmp)
|
||||
for x in tmp:
|
||||
self.getLayers(x)
|
||||
|
||||
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(oldLayerIDs)):
|
||||
for i in set(range(0, len(self.layers))).difference(set(self.oldLayerIDs)):
|
||||
if frameNumber - self.layers[i].lastFrame > self.ttolerance:
|
||||
oldLayerIDs.append(i)
|
||||
self.oldLayerIDs.append(i)
|
||||
continue
|
||||
|
||||
for bounds in self.layers[i].bounds[-1]:
|
||||
|
|
@ -82,9 +99,6 @@ class LayerFactory:
|
|||
|
||||
if not foundLayer:
|
||||
self.layers.append(Layer(frameNumber, (x,y,w,h)))
|
||||
self.freeData()
|
||||
self.sortLayers()
|
||||
return self.layers
|
||||
|
||||
def contoursOverlay(self, l1, r1, l2, r2):
|
||||
# If one rectangle is on left side of other
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ 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:
|
||||
|
|
@ -81,16 +80,35 @@ class VideoReader:
|
|||
# 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.1)
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
5
main.py
5
main.py
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Binary file not shown.
BIN
output/short.txt
BIN
output/short.txt
Binary file not shown.
Loading…
Reference in New Issue