# HG changeset patch # User Laman # Date 2017-01-07 14:01:04 # Node ID 5f4489f36388c29aac33f4ebb9bd4fac87f7c3c9 # Parent 8af597b8f81905e3c6911bce40ecfe7e7182030e restored showing the game state, split out message passing diff --git a/src/core.py b/src/core.py --- a/src/core.py +++ b/src/core.py @@ -1,6 +1,7 @@ import multiprocessing import logging as log import PIL +from util import MsgQueue from gui import gui from image_analyzer import ImageAnalyzer from go import Go @@ -14,35 +15,28 @@ class Core: self.tresW=60.0 self.tresB=30.0 - self._msgQueue=multiprocessing.Queue() - self._guiQueue=multiprocessing.Queue() - self._incomingEvent=multiprocessing.Event() - self._guiEvent=multiprocessing.Event() + self._ownMessages=MsgQueue(self._handleEvent) + self._guiMessages=MsgQueue() self._frame=PIL.Image.open("../images/7.jpg") - self._guiProc=multiprocessing.Process(name="gui", target=gui, args=(self._guiQueue,self._guiEvent,self._msgQueue,self._incomingEvent)) + self._guiProc=multiprocessing.Process(name="gui", target=gui, args=(self._guiMessages,self._ownMessages)) self._guiProc.start() - self._guiQueue.put(("setCurrentFrame",(self._frame,),dict())) - self._guiEvent.set() + self._guiMessages.send("setCurrentFrame",(self._frame,)) def setCorners(self,corners): self.detector.setGridCorners(corners) self.detector.analyze(self._frame) - for r in self.detector.board: log.info(r) + self._guiMessages.send("setGameState",(self.detector.board,)) def setTresholds(self,tresB=None,tresW=None): if tresB is not None: self.tresB=tresB if tresW is not None: self.tresW=tresW + if self.detector.analyze(self._frame): + self._guiMessages.send("setGameState",(self.detector.board,)) def listen(self): - while True: - self._incomingEvent.wait() - msg=self._msgQueue.get() - if self._msgQueue.empty(): - self._incomingEvent.clear() - log.info(msg) - self._handleEvent(msg) + self._ownMessages.listen() def _handleEvent(self,e): actions={"setCorners":self.setCorners, "setTresholds":self.setTresholds} diff --git a/src/gui/__init__.py b/src/gui/__init__.py --- a/src/gui/__init__.py +++ b/src/gui/__init__.py @@ -19,7 +19,6 @@ class MainWindow(tk.Frame): self.currentFrame=None self._boardGrid=None - self.gameState=None self.img=None self._imgSizeCoef=1 @@ -43,13 +42,6 @@ class MainWindow(tk.Frame): # shift compensates possible horizontal or vertical empty margins from unmatching aspect ratios self._imgShift=EPoint(wo-w*self._imgSizeCoef,ho-h*self._imgSizeCoef)/2 - def setGameState(self,gameState): - pass - - def setCallbacks(self,setCorners,setTresholds): - self.cornersCallback=setCorners - self.tresholdsCallback=setTresholds - def _createWidgets(self): # a captured frame with overlay graphics self.imgView=tk.Canvas(self) @@ -83,9 +75,7 @@ class MainWindow(tk.Frame): self._boardGrid=Grid(self.corners.corners) corners=[(c*self._imgSizeCoef+self._imgShift) for c in self.corners.corners] self.parent.sendMsg("setCorners",(corners,)) - # self.boardGrid=Grid(self.corners) - # self.boardView.setBoardGrid(self.boardGrid) - # + self.redrawImgView() ## Redraws the current image and its overlay. @@ -128,8 +118,6 @@ class MainWindow(tk.Frame): ## Handles and presents the game state as detected by the program. class BoardView(tk.Canvas): def __init__(self, master=None): - # self.detector=ImageAnalyzer() - tk.Canvas.__init__(self, master) self.configure(width=360,height=360,background="#ffcc00") @@ -138,25 +126,13 @@ class BoardView(tk.Canvas): self.grid() def redrawState(self,gameState): + # !! will need to remove old stones or redraw the element completely for r,row in enumerate(gameState): for c,point in enumerate(row): self.drawStone(r,c,point) self.grid() - ## Redraws and reananalyzes the board view. - # def redrawState(self,img,sizeCoef,shift): - # self.create_rectangle(0,0,360,360,fill="#ffcc00") - # self.drawGrid() - # - # self.detector.analyze(img,sizeCoef,shift) - # - # for r,row in enumerate(self.detector.board): - # for c,point in enumerate(row): - # self.drawStone(r,c,point) - # - # self.grid() - def drawGrid(self): for i in range(19): self.create_line(18,18*(i+1),360-18,18*(i+1),fill="#000000") # rows @@ -190,38 +166,26 @@ class GUI: self.root = tk.Tk() self.root.title("OneEye {0}.{1}.{2}".format(*config.misc.version)) - self.outcomingQueue=None - self.outcomingEvent=None + self._coreMessages=None self.mainWindow = MainWindow(self,master=self.root) self.root.bind("<>", lambda e: self.mainWindow.redrawImgView()) self.root.bind("<>", lambda e: print("fired receiveState")) - def __call__(self,incomingQueue,incomingEvent,outcomingQueue,outcomingEvent): - self.outcomingQueue=outcomingQueue - self.outcomingEvent=outcomingEvent + def __call__(self,ownMessages,coreMessages): + self._coreMessages=coreMessages - self.listenerThread=threading.Thread(target=lambda: self._listen(incomingQueue,incomingEvent)) + self.listenerThread=threading.Thread(target=lambda: ownMessages.listen(self._handleEvent)) self.listenerThread.start() self.mainWindow.mainloop() - def sendMsg(self,actionName,args=tuple(),kwargs=dict()): - self.outcomingQueue.put((actionName,args,kwargs)) - self.outcomingEvent.set() - - def _listen(self,incomingQueue,incomingEvent): - while True: - incomingEvent.wait() - msg=incomingQueue.get() - if incomingQueue.empty(): - incomingEvent.clear() - log.info(msg) - self._handleEvent(msg) + def sendMsg(self,actionName,args=tuple(),kwargs=None): + self._coreMessages.send(actionName,args,kwargs) def _handleEvent(self,e): - actions={"setCurrentFrame":self._frameHandler} + actions={"setCurrentFrame":self._frameHandler, "setGameState":self._stateHandler} (actionName,args,kwargs)=e return actions[actionName](*args,**kwargs) @@ -230,7 +194,7 @@ class GUI: self.mainWindow.setCurrentFrame(newFrame) self.root.event_generate("<>") - def _stateHandler(self,e): - pass + def _stateHandler(self,gameState): + self.mainWindow.boardView.redrawState(gameState) gui=GUI() diff --git a/src/image_analyzer.py b/src/image_analyzer.py --- a/src/image_analyzer.py +++ b/src/image_analyzer.py @@ -14,7 +14,9 @@ class ImageAnalyzer: # let's not concern ourselves with sizecoef and shift here anymore. we want corners to come already properly recomputed def analyze(self,image): - if self.grid==None: return False + if self.grid==None: + log.info("ImageAnalyzer.analyze() aborted: no grid available.") + return False for r in range(19): for c in range(19): @@ -22,6 +24,9 @@ class ImageAnalyzer: self.board[r][c]=self.analyzePoint(image,r,c,intersection,*(self.grid.stoneSizeAt(r,c))) + boardStr="\n".join(str(row) for row in self.board) + log.info("board analyzed:\n%s",boardStr) + def analyzePoint(self,image,row,col,imageCoords,stoneWidth,stoneHeight): b=w=e=0 diff --git a/src/util.py b/src/util.py new file mode 100644 --- /dev/null +++ b/src/util.py @@ -0,0 +1,28 @@ +import multiprocessing +import logging as log + + +class MsgQueue: + def __init__(self,handler=None): + self._queue=multiprocessing.Queue() + self._event=multiprocessing.Event() + self._handleEvent=handler + + def send(self,actionName,args=tuple(),kwargs=None): + if kwargs is None: kwargs=dict() + self._queue.put((actionName,args,kwargs)) + self._event.set() + + def listen(self,handleEvent=None): + if handleEvent is not None: self._handleEvent=handleEvent + + while True: + self._event.wait() + msg=self._queue.get() + if self._queue.empty(): + self._event.clear() + log.info(msg) + self._handleEvent(msg) + + def setHandler(self,handler): + self._handleEvent=handler