diff --git a/src/config.py b/src/config.py --- a/src/config.py +++ b/src/config.py @@ -46,6 +46,7 @@ class misc: _imgDir=file.get("imgDir","../images") imgDir=_imgDir if os.path.isabs(_imgDir) else os.path.join(srcDir,_imgDir) + video=file.get("video",0) class gui: diff --git a/src/core.py b/src/core.py --- a/src/core.py +++ b/src/core.py @@ -9,6 +9,7 @@ from analyzer import ImageAnalyzer from analyzer.framecache import FrameCache from go.core import Go, isLegalPosition from statebag import StateBag +from video import capVideo import config as cfg log=logging.getLogger(__name__) @@ -24,6 +25,7 @@ class Core: self._ownMessages=MsgQueue(self._handleEvent) self._guiMessages=MsgQueue() + self._vidMessages=MsgQueue() self._imgs=sorted(os.listdir(cfg.misc.imgDir)) self._imgIndex=cfg.misc.defaultImage @@ -32,7 +34,12 @@ class Core: self._guiProc=multiprocessing.Process(name="gui", target=gui, args=(self._guiMessages,self._ownMessages)) self._guiProc.start() - self.relativeFrame(0) + self._vidProc=multiprocessing.Process( + name="video", + target=capVideo, + args=(cfg.misc.video, self._vidMessages,self._ownMessages) + ) + self._vidProc.start() def setCorners(self,corners): self.detector.setGridCorners(corners) @@ -50,6 +57,12 @@ class Core: self._guiMessages.send("setCurrentFrame",(self._frame.copy(),gui.PREVIEW)) self.preview() + def putFrame(self,frame): + img=PIL.Image.fromarray(frame) + self._cache.put(img) + self._guiMessages.send("setCurrentFrame",(img,gui.PREVIEW)) # !! RECORDING + # self.analyze() + def sendParams(self): params={ "tresB": self.detector.tresB, @@ -67,7 +80,6 @@ class Core: def analyze(self): if self.detector.analyze(self._frame): - self._cache.put(self._frame) if isLegalPosition(self.detector.board): state=self.states.pushState(self.detector.board) rec=[] @@ -85,8 +97,10 @@ class Core: listenerThread=threading.Thread(target=lambda: self._ownMessages.listen()) listenerThread.start() - def joinGui(self): + def joinChildren(self): self._guiProc.join() + self._vidMessages.send("shutDown") + self._vidProc.join() self._ownMessages.send("!kill",("core",)) def _handleEvent(self,e): @@ -95,6 +109,7 @@ class Core: "setTresholds": self.setTresholds, "prevFrame": lambda: self.relativeFrame(-1), "nextFrame": lambda: self.relativeFrame(1), + "putFrame": self.putFrame, "fetchParams": self.sendParams, "setParams": self.setParams } @@ -102,9 +117,12 @@ class Core: return actions[actionName](*args,**kwargs) -core=Core() -core.listen() -core.joinGui() +if __name__=="__main__": + core=Core() + core.listen() + log.info("OneEye started.") + core.joinChildren() + log.info("Exited correctly.") """ core diff --git a/src/gui/__init__.py b/src/gui/__init__.py --- a/src/gui/__init__.py +++ b/src/gui/__init__.py @@ -73,7 +73,9 @@ class GUI: return actions[actionName](*args,**kwargs) def _frameHandler(self,newFrame,type): - if self._state!=type: return + if self._state!=type: + log.info("ignored setCurrentFrame event, wrong type") + return self.mainWindow.setCurrentFrame(newFrame) self.root.event_generate("<>") diff --git a/src/util.py b/src/util.py --- a/src/util.py +++ b/src/util.py @@ -31,7 +31,9 @@ class MsgQueue: if self._queue.empty(): self._event.clear() log.info(msg) - if msg[0]=="!kill": break + if msg[0]=="!kill": + self._queue.cancel_join_thread() + break self._handleEvent(msg) def setHandler(self,handler): diff --git a/src/video.py b/src/video.py new file mode 100644 --- /dev/null +++ b/src/video.py @@ -0,0 +1,64 @@ +import time +import threading + +import cv2 as cv + + +class VideoCapture: + def __init__(self, video_source=0): + self._ownMessages=None + self._coreMessages=None + self._shutdown=False + + self._vid = cv.VideoCapture(video_source) + if not self._vid.isOpened(): + raise ValueError("Unable to open video source", video_source) + + self.width = self._vid.get(cv.CAP_PROP_FRAME_WIDTH) + self.height = self._vid.get(cv.CAP_PROP_FRAME_HEIGHT) + + def getFrame(self): + if self._vid.isOpened(): + (res,frame) = self._vid.read() + if res: + return (res, cv.cvtColor(frame, cv.COLOR_BGR2RGB)) + else: + return (res,None) + else: + return (False,None) + + def shutDown(self): + self._ownMessages.send("!kill",("video",)) + self._shutdown=True + + def __call__(self,ownMessages,coreMessages): + self._ownMessages=ownMessages + self._coreMessages=coreMessages + + self.listenerThread=threading.Thread(target=lambda: ownMessages.listen(self._handleEvent)) + self.listenerThread.start() + + t=0 + while not self._shutdown: + self._vid.set(cv.CAP_PROP_POS_MSEC,t*1000) + (res,frame)=self.getFrame() + if res: self._coreMessages.send("putFrame",(frame,)) + time.sleep(1) + t+=1 + + def __del__(self): + if self._vid.isOpened(): + self._vid.release() + + def _handleEvent(self,e): + actions={ + "shutDown": self.shutDown + } + (actionName,args,kwargs)=e + + return actions[actionName](*args,**kwargs) + + +def capVideo(stream,ownMessages,coreMessages): + v=VideoCapture(stream) + v(ownMessages,coreMessages)