From 68c730ff6ec15d81f4232adb42369e1d0e02afe8 Mon Sep 17 00:00:00 2001 From: Askill Date: Thu, 8 Oct 2020 22:26:29 +0200 Subject: [PATCH] video reader object --- ContourExctractor.py | 84 ++++++++----------- LayerFactory.py | 13 +-- VideoReader.py | 70 ++++++++++++++++ __pycache__/Analyzer.cpython-37.pyc | Bin 430 -> 1322 bytes __pycache__/ContourExctractor.cpython-37.pyc | Bin 3956 -> 3606 bytes __pycache__/LayerFactory.cpython-37.pyc | Bin 2372 -> 3015 bytes main.py | 6 +- 7 files changed, 110 insertions(+), 63 deletions(-) create mode 100644 VideoReader.py diff --git a/ContourExctractor.py b/ContourExctractor.py index aa4ffab..f075177 100644 --- a/ContourExctractor.py +++ b/ContourExctractor.py @@ -14,6 +14,7 @@ from threading import Thread from multiprocessing import Queue, Process, Pool from multiprocessing.pool import ThreadPool import concurrent.futures +from VideoReader import VideoReader class ContourExtractor: @@ -32,61 +33,43 @@ class ContourExtractor: print("ContourExtractor initiated") def extractContours(self, videoPath, resizeWidth): - - - # initialize the first frame in the video stream - vs = cv2.VideoCapture(videoPath) - - res, image = vs.read() - self.xDim = image.shape[1] - self.yDim = image.shape[0] firstFrame = None - # loop over the frames of the video - frameCount = -1 - extractedContours = dict() - - results = [] - extractedContours = dict() + extractedContours = dict() + videoReader = VideoReader(videoPath) + self.xDim = videoReader.w + self.yDim = videoReader.h + videoReader.fillBuffer() - imageBuffer = [] - - with concurrent.futures.ProcessPoolExecutor() as executor: - while res: - frameCount += 1 - if frameCount % (60*30) == 0: - print("Minutes processed: ", frameCount/(60*30)) - + while not videoReader.videoEnded(): + frameCount, frame = videoReader.pop() + if frameCount % (60*30) == 0: + print("Minutes processed: ", frameCount/(60*30)) + + if frame is None: + print("ContourExtractor: frame was None") + continue - res, frame = vs.read() - # resize the frame, convert it to grayscale, and blur it - if frame is None: - print("ContourExtractor: frame was None") - break + # resize the frame, convert it to grayscale, and blur it + frame = imutils.resize(frame, width=resizeWidth) + gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - frame = imutils.resize(frame, width=resizeWidth) - gray = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB) + # if the first frame is None, initialize it + if firstFrame is None: + #gray = np.asarray(gray[:,:,1]/2 + gray[:,:,2]/2).astype(np.uint8) + gray = cv2.GaussianBlur(gray, (5, 5), 0) + firstFrame = gray + continue + x = self.getContours(gray, firstFrame) + if x is not None: + extractedContours[frameCount] = x - # if the first frame is None, initialize it - if firstFrame is None: - gray = np.asarray(gray[:,:,1]/2 + gray[:,:,2]/2).astype(np.uint8) - gray = cv2.GaussianBlur(gray, (5, 5), 0) - firstFrame = gray - continue - - results.append(executor.submit(self.getContours, frameCount, gray, firstFrame)) - - #contours = self.getContours(frameCount, gray, firstFrame) - - for f in concurrent.futures.as_completed(results): - x=f.result() - if x is not None: - extractedContours = {**extractedContours, **x} - + print("done") + videoReader.thread.join() self.extractedContours = extractedContours return extractedContours - def getContours(self, frameCount, gray, firstFrame): - gray = np.asarray(gray[:,:,1]/2 + gray[:,:,2]/2).astype(np.uint8) + def getContours(self, gray, firstFrame): + gray = cv2.GaussianBlur(gray, (5, 5), 0) frameDelta = cv2.absdiff(gray, firstFrame) thresh = cv2.threshold(frameDelta, self.threashold, 255, cv2.THRESH_BINARY)[1] @@ -104,10 +87,9 @@ class ContourExtractor: #print((x, y, w, h)) contours.append((x, y, w, h)) - if len(contours) != 0: - return {frameCount: contours} - else: - return None + if len(contours) != 0 and contours is not None: + return contours + def displayContours(self): values = self.extractedContours.values() diff --git a/LayerFactory.py b/LayerFactory.py index d95d5fe..d19ee38 100644 --- a/LayerFactory.py +++ b/LayerFactory.py @@ -53,10 +53,8 @@ class LayerFactory: # inserts all the fucking contours as layers? for frameNumber, contours in data.items(): if frameNumber%5000 == 0: - print(f"{round(frameNumber/max(data.keys()), 2)}% done with Layer extraction") + print(f"{int(round(frameNumber/max(data.keys()), 2)*100)}% done with Layer extraction") - for frameNumber in sorted(data): - contours = data[frameNumber] for (x,y,w,h) in contours: foundLayer = False for i in set(range(0, len(self.layers))).difference(set(oldLayerIDs)): @@ -85,15 +83,10 @@ class LayerFactory: def fillLayers(self, footagePath, resizeWidth): for i in range(len(self.layers)): + if i % 20 == 0: + print(f"filled {int(round(i/len(self.layers),2)*100)}% of all Layers") self.layers[i].fill(footagePath, resizeWidth) def sortLayers(self): # straight bubble self.layers.sort(key = lambda c:c.lastFrame) - - - - - - - diff --git a/VideoReader.py b/VideoReader.py new file mode 100644 index 0000000..8020441 --- /dev/null +++ b/VideoReader.py @@ -0,0 +1,70 @@ + +import multiprocessing +import cv2 +from time import sleep +from queue import Queue +import threading +class VideoReader: + + #buffer = [(frameNumber, frame)] + + def __init__(self, videoPath): + if videoPath is None: + print("Video reader needs a videoPath!") + return None + + self.videoPath = videoPath + self.lastFrame = 0 + self.buffer = Queue(16) + self.vc = cv2.VideoCapture(videoPath) + self.stopped = False + 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") + + + def pop(self): + return self.buffer.get(block=True) + + def get(self): + return self.buffer[-1] + + def fillBuffer(self): + 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.thread.start() + + def stop(self): + self.thread.join() + self.vc.release() + + 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 + else: + sleep(0.5) + self.stopped = True + + def videoEnded(self): + if self.stopped: + return True + else: + return False + + + + + + + + + diff --git a/__pycache__/Analyzer.cpython-37.pyc b/__pycache__/Analyzer.cpython-37.pyc index 405b5718706641c5ffe7b672daabc6d742e3472a..31b382ebec61ad7d2812925034ef7b8782d7eaf5 100644 GIT binary patch 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 delta 247 zcmZ3*wT_w3iIns#OyrZ05CZbt8B!Qh7+Zk2nJJ1Pg(;XplX>E9=MW~K z90)rDaWM~&C;=&9WCSV)Dq-@g5^>B+%&DwOEmBC%&nqq|Dorj)P0?h$#ad95nOCC8 zbc>}pH76~KJuN@KBr!d8B|{O*T4rb$RrB@LyYxRh2@r7EQqnzRjvDlMr5!W5QO?4;iH+S{>r zyQ#)niEsg_h{zJ+xGN#`KR}!~ApQUjh{K$E;8MX62?_D_o)=QJsxANK&3n%?@4flG z`EBuw1$(JlH3>Yua8UoFwqwuHuXm1KdCu^N$HKB(E=JQei_vl`#i+U3&S$6hgRF~WJmX{H8QaXA^VkjIly`o*Tyv27THUFJn zrTg+r?4!jBgutu2V1p!$dOe7Ov|itz|IAJdFiZ`;W%!Z@03OMdlx&ksO{t*UG}DCE zWP;Qc7*!ZyKGa8qlKz(zz8l-xd^nuDe#N`iUXJ(iWy%CIT`oA!uhhENLkuRvQ9hNpXMq=44Ql-tJz8BPfB z0Kc+;YPQP!xF`!%=;vYCcL;1z!Yv@=J;O;17Hp(GB~+-Ou^Jd9C=7*c^KaBQ1`d0O zCE!y4QuX4Cevir$fG|5DJF^p;e&Kyb~CAPkqf8yh}%%^n`a<;e3rsdVBF zpTK`gLA#pb14{(#qPYGb?Ks-<6e>MmI@< zMzj=mxwJNYaE#Kp%VCN17Kd||YBLTZZo%@7$t(Gv+WbI5Bs@v4@J8D&EUs0AGv)=v ziH7C48>Lb!WT|fQ#+Ic0CwWox`zdd%@9ugKwn|C zS6~44z~Xj`Bw-=dS}Onib_n(fwBJ;-a%N^$RuTGe5AewpmZ)r~BP44GteO=1HiX?$ z_zys9WF3q*pk;tnrB#O&3>pJvM={o-9r!Vj9458oR-@xf%}cjBen1$; z&L{I<%!N0eM-RK;n$&xZu?o zS}VU(-5flF-q_syMT8RwFCbtw#}U?0+JkTu0S}wMj&Kp-QJD$}Z+l(_z-ui*vKWdE zjr!lq34 jz00{DjjzdKm8S(Ejq~l;>xTXX?1bb%{#NaP0yo9KABUUg delta 2100 zcmah~&2QX96rUM?uGhOslQbXAHcbnqT0ki+rR|}#bkinORBcElQmn#iSv#qd{mR%5 zn`+z@4P1~4jV$%Nd*#qSf-?uiaSj}~MdAPgi4&CfyiJ;-O4yp;ym{}RD>XFo3d zIh8Nvau$JS;jhiIH?*A}r{8U#m^+$riOXu1W2Jr8$)>&S*lBM%neA`RjLZ{Pca1NJ zYiu!R%w@Mo(cJ#!YI2r-&2CR7-_x7aPKMZZT1d+5!BiHO;r1TnK$2#;>^JY&}E>_LJRIwLPFA|g7#>v2&Kz<pjSsp$7O4bKL{;XL&YT7VwCJ# z*cPz=HIsM2L*Js5ERZm}3R=Nj;~|S}NH-?{SMxm<=Y)>luuLHw=nje;oE`a!Jwv*z zOc2+cB>VIoG@HAIG18;m1L45x5bQq(p@+dWwgm?ublxL}a@M1z8;xhJXco zY7f#{ca})|t#rp@BGaQ+$S2crUgW#uJrWOy0Z1zYY0U{!3_NBrq_{q}M3%@2mwZST z$!!7#Ql1bd+^BV92kwDzgq^4G_@`H)nq8>glHk?(rV*-9&n zxF=QaRa~hBcPlLzw6FMescxp|`qfZc)n=m_aqcxj$5@VVO5hAH@MhHuf`w+YcD3zQ zqp->O04yO5zaE8tEs%N#9Q}KqV^%l9*=DWDo!sor>o*t6rTN9v*DseOYqX?M2`Zdd zHlRgJJmp$&7-m{HLEuA3M6-=BiOWNMgn&b;@T0H^BBf)LEdf-< zZ_7gk$K9;Zx^|C%B?m1Jq4bndIxL|B&5ibg(4olRk4^ACAWYC_L`yI9W}P%Y-|ISZW+KJOJsq@x#d28o-C0N7_~)Rbxi@L3<@d?pWcEq=(nPI zgCBsS;v)b>mezkC`aDVg*2fBCd>UPjBH)ejR}e-KUQG%{K&O&N#^uBOIB29&^BToG zPd}1xqRUByHWX1gLc$y_9 z#m@jhsuR#j%|$x+gn^3k;pBd%aOrKd=leCPZ&YfL7o;1I+C7gq13rmC4k4ubm_q3Y z0!HMciOjryBTXL*Q?hnjvW-(5bLa0OTtv8pHoC!QaPXg>!GP-rty*PsmwT;b(fX(J z(hczUVE$hEAQ!V~;vCoRA3Ij@|KyAZ4-=m!t*6ur_!XRc72(tc#254DbEtdS4)R{R z)#Q60k2uNND^3Buk@@@_!g+*u5Yn?uPZgQR@#n`+BjAFodj diff --git a/__pycache__/LayerFactory.cpython-37.pyc b/__pycache__/LayerFactory.cpython-37.pyc index 84f01634ea423aff1b80452774d50c54f8d9ee83..def7d127ed3e829fad1646e6dd5abb695350ef5d 100644 GIT binary patch literal 3015 zcmZuz&2JmW6`z^?;BrYyvf|28;wD5Or(jSRi4QFh7>1Dw?gtDuhz$r~6%cFAP@=db zrP)zT5xeL?KJ?HQ26}8$NI+4bLH~&U9dqr;w*tKcxwOAGOVW}Y67zOG-kW*z-ut~b zpEepX!>@Dv+wPz0jQyJii=T(iL$vH&5XmG@*@$%*XFq3BNbd!c-kIod=|5qu;1zgS zi`(FFa;kKXMvLEapQo5n3=*s(2CU=lvyLx$Cy+O!C;b<^6Usn_FIcA{D>A}2lIyZ6 zW2{tVP1Z3J%Z6ORw!f(3f=h8CtdtVsMu; z&RNcL*5x_$8CG>OXXhg47nqj}dy4jK^YW(6-ejB^ebO^Zwmcgg>A~1oUnVB84K+0y zXFL9^C9I#Rw68;)^$(`2_$RMp z`?*J^K3?0MyFrF9dS%x7T#Y7QsjOMrviW>q4w~t}m{c{*q&c26X?di^M$?sF{SQCw zQ_l^_*X>qdt7?2QQaUlphABm4X1(NDX2WNbld;4%IXY5f*$OlnSFeFsKCpq~?S#Dp z)f;Bcb0r~^*mdo6dtwqZ=#~04FrVE7VZ!G(xz9g>kElg_h0oq|O!KI``=)e{!jgXE zF}j5F+UMxNFYKIO0BrD|H~k1>0pER4__=@XUBG7W$Hu%bhCccpZ0b9kZosAe;(7fFWT}axXm#RdUm#*$B^H`1d&4GRk=jsiRxmE1SD4Dt&lnfXT#+Sx(tEJb? z6!o=IJHW*|*ehEBVLXOu>UwZkNPp-M8|iH$ zN*vSmN-P^MN01kwxwnNtoxYp>`e#B0H`$+=48InXOQzqtlm4^k7nLF^ zszod-MQ!>oQ!{nxnFgJI#?QcezG7;5c!o>^&Hh@{$yJAbUIz$QH<^rv{!6Y|9-aqz z-RWtU>ua*Q#c)ESSSePEHMsXiUdhEK%cDHL#d2|r^#x|CWgoLx!%QPz$=BRkBVWbZ zN?%;~db#iUI&`RjyPC&+|3V;O;-dB$JGKaD0i~Wc`8L#eDsQ{gu*ba*F&RW$Q+nFDSEH4+_~@pG4Xxqi0InXdz=O z^IoSmNu|5kFLyG_r)jQV#V~H6{q();yK#Ey=$n_R0-~&Wj_I7 zJQT6ZGQJ1}Wt*692w!XfWZPmLVB6*!m=j`?Kjd#?93nqmb*^ZJA&xxsnB!33mF} zFoXJk2t>NF_(|az+{^&^i+SK&0Oy{=x&O82-VBhS+yZo>a1vIigt-J8v}cw6AWfBQ zx)9et#DU-OJ4m}9pr?OCger{-UHv|K)+d3M@1hE^G?|!WUwxLC16#w}U@%j=1Buj3 z0dg%MY)qo=@)

GKxut8nn%4x31XaHQ(};K(%t|WJ>uk1YQD?OF_@NKP(Hp&XuEllF^$9vb6jP9q&=$T9&{01EVMPswp73H#toxl(2u=ePH;sjd+ro9Wv`D5^9Cr@l|*QzEaGb3M{fleww6*FpqD l(mxKPl_-wyL~#^2jy5h!y1T*m?PH_+rJ4`O8Sb8S@qg05x=R26 delta 1194 zcmY*YOK%)S5bo~jc|Uf&8QHOk&>8~L27+?n0wjn8V}#^{L`Jd{5yIe}UB|nbiF-P* z4&5@+<`xbK{Regh7led_xFdv+$REgM{(%p0;K&84XPpP#n(C@=>d{qQ^~ciho#a9s z2MAXB=l=EYf(OZ`c;i8N{EZf~7`=N?3uHRM6TF75J+Fw7Bw0pNdxj() zQob@r&Y``PEyNJ`$Cr8zcfeC^Z;$ef*EY|JL0(&*?7bJox?T0!F|Bz#1x?R`aI9qGLgj~RmKS60H?U41zk-#AR4tMldtr*^z^|1 zDGM@y+bb%uq{~Rz;}g<`TvFvoYf6PJsdOe}hB4Y(+d}v8cu_dUVh#9f-ZOUpGO{czk1CRujF#U+Dh4>-^%;boU}g_3{!kF+OiZ{b zgpPNE`}m$C?l#Q7zS03ldF3{hR&LK_XjnVF~q#Ok{fr$yT4tsIg(53S~Tv zz?UmM>C2!`X9T0mNXF(8XCclOl3^vEr29ngC~dig_I5xAp89&+JfVN-&PwwX>)Ey_ z`F>Y_;>2gyIfn8c{tN4n0(a+yXLa7}Hd1$3VJiXZh7{e!czT|3#W zTY15_X};R2N-lE7&13SULFP8KKguex&a<0&-P$e-QQqd&ho9$slS8oGB*dYP-U{m4{YB-Qns{>pIQ`jjW z9pYg^+JIbW5JDn2yF~xx-Xn)tf9ah$b^@H8H*TBhw7QsD`WNrT|BaSOziG%In zkial7P8LlpxFi^N=2ae|kr@hFd`s?tm{{U7e3@HEr diff --git a/main.py b/main.py index fd16202..05d607b 100644 --- a/main.py +++ b/main.py @@ -4,20 +4,22 @@ from ContourExctractor import ContourExtractor from Exporter import Exporter from LayerFactory import LayerFactory from Analyzer import Analyzer +from VideoReader import VideoReader import cv2 #TODO # finden von relevanten Stellen anhand von zu findenen metriken für vergleichsbilder def demo(): print("startup") - resizeWidth = 1024 + resizeWidth = 512 maxLayerLength = 1*60*30 - minLayerLength = 3 + minLayerLength = 30 start = time.time() footagePath = os.path.join(os.path.dirname(__file__), "./generate test footage/3.mp4") #analyzer = Analyzer(footagePath) #print("Time consumed reading video: ", time.time() - start) + contours = ContourExtractor().extractContours(footagePath, resizeWidth) print("Time consumed in working: ", time.time() - start) layerFactory = LayerFactory(contours)