Changeset - 8af597b8f819
[Not reviewed]
default
0 5 0
Laman - 8 years ago 2017-01-06 20:25:01

further refactoring, got processes passing messages, restored computing grid and analyzing image
5 files changed with 92 insertions and 65 deletions:
0 comments (0 inline, 0 general)
src/core.py
Show inline comments
 
import multiprocessing
 
import logging as log
 
import PIL
 
from corners import Corners
 
from gui import gui
 
from image_analyzer import ImageAnalyzer
 
from go import Go
 

	
 

	
 
class Core:
 
	corners=Corners()
 
	tresW=60.0
 
	tresB=30.0
 
	def __init__(self):
 
		self.grid=None
 
		self.go=Go()
 
		self.detector=ImageAnalyzer()
 
		self.tresW=60.0
 
		self.tresB=30.0
 

	
 
	@staticmethod
 
	def setCorners(corners):
 
		Core.corners=corners
 
		self._msgQueue=multiprocessing.Queue()
 
		self._guiQueue=multiprocessing.Queue()
 
		self._incomingEvent=multiprocessing.Event()
 
		self._guiEvent=multiprocessing.Event()
 

	
 
	@staticmethod
 
	def setTresholds(tresB=None,tresW=None):
 
		if tresB is not None: Core.tresB=tresB
 
		if tresW is not None: Core.tresW=tresW
 
		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.start()
 
		self._guiQueue.put(("setCurrentFrame",(self._frame,),dict()))
 
		self._guiEvent.set()
 

	
 
msgQueue=multiprocessing.Queue()
 
guiQueue=multiprocessing.Queue()
 
incomingEvent=multiprocessing.Event()
 
guiEvent=multiprocessing.Event()
 
	def setCorners(self,corners):
 
		self.detector.setGridCorners(corners)
 
		self.detector.analyze(self._frame)
 
		for r in self.detector.board: log.info(r)
 

	
 
frame=PIL.Image.open("../images/7.jpg")
 
	def setTresholds(self,tresB=None,tresW=None):
 
		if tresB is not None: self.tresB=tresB
 
		if tresW is not None: self.tresW=tresW
 

	
 
guiProc=multiprocessing.Process(name="gui",target=gui,args=(guiQueue,guiEvent,msgQueue,incomingEvent))
 
guiProc.start()
 
guiQueue.put(("setCurrentFrame",(frame,None),dict()))
 
guiEvent.set()
 

	
 
	def listen(self):
 
while True:
 
	incomingEvent.wait()
 
	msg=msgQueue.get()
 
	if msgQueue.empty():
 
		incomingEvent.clear()
 
	print(msg)
 
			self._incomingEvent.wait()
 
			msg=self._msgQueue.get()
 
			if self._msgQueue.empty():
 
				self._incomingEvent.clear()
 
			log.info(msg)
 
			self._handleEvent(msg)
 

	
 
	def _handleEvent(self,e):
 
		actions={"setCorners":self.setCorners, "setTresholds":self.setTresholds}
 
		(actionName,args,kwargs)=e
 

	
 
# !! always pass object copies, don't share instances
 
		return actions[actionName](*args,**kwargs)
 

	
 
core=Core()
 
core.listen()
 

	
 
"""
 
core
 
====
 
corners
 
grid
 
go
 
imageAnalyzer
 
@@ -51,6 +63,8 @@ imageAnalyzer
 

	
 
gui
 
===
 
corners
 

	
 
a) keeps references to important objects and uses them
 
b) gets and sets all relevant data through method calls with core
 

	
 
@@ -61,4 +75,7 @@ GUI
 

	
 
BoardView
 
-> redrawState(go)
 

	
 

	
 
core-gui: just pass messages with relevant data (!! always pass object copies, don't share instances)
 
"""
 
\ No newline at end of file
src/go.py
Show inline comments
 
@@ -6,7 +6,7 @@
 
	## Initializes self.board to a list[r][c]=Go.EMPTY.
 
	def __init__(self,boardSize=19):
 
		self.boardSize=boardSize
 
		self.board=[[Go.EMPTY]*self.boardSize for x in self.board]
 
		self.board=[[Go.EMPTY]*self.boardSize for x in range(boardSize)]
 
 
	## Executes a move.
 
	#
src/grid.py
Show inline comments
 
@@ -4,7 +4,7 @@ from epoint import EPoint
 
 
## Projective transformation of a point with a matrix A.
 
#  
 
#  Takes a point as a horizontal vector and multiplies it transposed with A from left.
 
#  Takes a point as a horizontal vector, transposes it and multiplies with A from left.
 
#  
 
#  @return transformed point as a numpy.array
 
def transformPoint(point,A):
 
@@ -21,11 +21,12 @@ class Grid:
 
	#
 
	#  The result is stored in grid.intersections, a boardSize*boardSize list with [row][column] coordinates.
 
	#
 
	#  @param corners a properly initialized Corners object. !! Needs a check for the proper initialization.
 
	#  @param corners list of EPoints in ABCD order per corners.Corners.canonizeOrder().
 
	# !! Needs a check for proper initialization.
 
	def __init__(self,corners):
 
		# ad
 
		# bc
 
		a,b,c,d=[c.toProjective() for c in corners.corners]
 
		a,b,c,d=[c.toProjective() for c in corners]
 
 
		p1=numpy.cross(a,b)
 
		p2=numpy.cross(c,d)
 
@@ -60,12 +61,12 @@ class Grid:
 
				affineIntersection=(rowStart*(boardSize-1-c)+rowEnd*c) / (boardSize-1)
 
				self.intersections[r][c]=EPoint.fromProjective(transformPoint(affineIntersection.toProjective(),rectiMatrixInv))
 
 
	def stoneSizeAt(self,r,c,sizeCoef):
 
	def stoneSizeAt(self,r,c):
 
		intersection=self.intersections[r][c]
 
 
		if c>0: width=sizeCoef*(intersection.x-self.intersections[r][c-1].x)
 
		else: width=sizeCoef*(self.intersections[r][c+1].x-intersection.x)
 
		if r>0: height=sizeCoef*(intersection.y-self.intersections[r-1][c].y)
 
		else: height=sizeCoef*(self.intersections[r+1][c].y-intersection.y)
 
		if c>0: width=intersection.x - self.intersections[r][c-1].x
 
		else: width=self.intersections[r][c+1].x - intersection.x
 
		if r>0: height=intersection.y - self.intersections[r-1][c].y
 
		else: height=self.intersections[r+1][c].y - intersection.y
 
 
		return (width,height)
src/gui/__init__.py
Show inline comments
 
import threading
 
import logging as log
 
import tkinter as tk
 
from PIL import ImageTk
 
import PIL
 
 
import config
 
from epoint import EPoint
 
from corners import Corners
 
import image_analyzer
 
from go import Go
 
from grid import Grid
 
 
 
class MainWindow(tk.Frame):
 
@@ -15,23 +18,31 @@ class MainWindow(tk.Frame):
 
		self.corners=Corners()
 
 
		self.currentFrame=None
 
		self.boardGrid=None
 
		self._boardGrid=None
 
		self.gameState=None
 
 
		self.img=None
 
		self._imgSizeCoef=1
 
		self._imgShift=EPoint(0,0)
 
 
		tk.Frame.__init__(self, master)
 
		self.grid(column=0,row=0)
 
		self._createWidgets()
 
 
	def setCurrentFrame(self,frame,grid):
 
	def setCurrentFrame(self,frame):
 
		self.currentFrame=frame
 
		self.boardGrid=grid
 
 
		w=int(self.imgView['width'])
 
		h=int(self.imgView['height'])
 
		self.img=ImageTk.PhotoImage(frame.resize((w,h),resample=PIL.Image.BILINEAR))
 
 
		wo,ho=self.currentFrame.size # o for original
 
		widthRatio=wo/w
 
		heightRatio=ho/h
 
		self._imgSizeCoef=max(widthRatio,heightRatio)
 
		# 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
 
 
@@ -67,7 +78,11 @@ class MainWindow(tk.Frame):
 
	def addCorner(self,x,y):
 
		self.corners.add(x,y)
 
		if self.corners.canonizeOrder():
 
			self.parent.sendMsg("setCorners",(self.corners,))
 
			# transform corners from show coordinates to real coordinates
 
			log.debug(self.corners.corners)
 
			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)
 
		#
 
@@ -78,30 +93,23 @@ class MainWindow(tk.Frame):
 
		if self.currentFrame and self.img:
 
			self.imgView.create_image(2,2,anchor="nw",image=self.img)
 
 
			origWidth,origHeight=self.currentFrame.size
 
			widthRatio=origWidth/self.img.width()
 
			heightRatio=origHeight/self.img.height()
 
			sizeCoef=max(widthRatio,heightRatio)
 
 
			# shift=EPoint(origWidth-self.img.width()*sizeCoef,origHeight-self.img.height()*sizeCoef)/2
 
 
		for corner in self.corners.corners:
 
			self.markPoint(corner.x,corner.y)
 
 
		if self.boardGrid!=None and config.gui.showGrid:
 
		if self._boardGrid!=None and config.gui.showGrid:
 
			for r in range(19):
 
				a=self.boardGrid.intersections[r][0]
 
				b=self.boardGrid.intersections[r][-1]
 
				a=self._boardGrid.intersections[r][0]
 
				b=self._boardGrid.intersections[r][-1]
 
				self.imgView.create_line(a.x,a.y,b.x,b.y,fill='#00ff00')
 
			for c in range(19):
 
				a=self.boardGrid.intersections[0][c]
 
				b=self.boardGrid.intersections[-1][c]
 
				a=self._boardGrid.intersections[0][c]
 
				b=self._boardGrid.intersections[-1][c]
 
				self.imgView.create_line(a.x,a.y,b.x,b.y,fill='#00ff00')
 
 
		if self.boardGrid!=None and config.gui.showBigPoints:
 
		if self._boardGrid!=None and config.gui.showBigPoints:
 
			for r in range(19):
 
				for c in range(19):
 
					((r1,c1),(r2,c2))=image_analyzer.relevantRect(self.boardGrid.intersections[r][c],*(self.boardGrid.stoneSizeAt(r,c,sizeCoef)))
 
					((r1,c1),(r2,c2))=image_analyzer.relevantRect(self._boardGrid.intersections[r][c], *(self._boardGrid.stoneSizeAt(r, c)))
 
					self.imgView.create_rectangle(r1,c1,r2,c2,outline="#00ffff")
 
 
		self.imgView.grid()
 
@@ -121,7 +129,6 @@ class MainWindow(tk.Frame):
 
class BoardView(tk.Canvas):
 
	def __init__(self, master=None):
 
		# self.detector=ImageAnalyzer()
 
		self.boardGrid=None
 
 
		tk.Canvas.__init__(self, master)
 
		self.configure(width=360,height=360,background="#ffcc00")
 
@@ -210,7 +217,7 @@ class GUI:
 
			msg=incomingQueue.get()
 
			if incomingQueue.empty():
 
				incomingEvent.clear()
 
			print(msg)
 
			log.info(msg)
 
			self._handleEvent(msg)
 
 
	def _handleEvent(self,e):
 
@@ -219,8 +226,8 @@ class GUI:
 
 
		return actions[actionName](*args,**kwargs)
 
 
	def _frameHandler(self,newFrame,grid):
 
		self.mainWindow.setCurrentFrame(newFrame,grid)
 
	def _frameHandler(self,newFrame):
 
		self.mainWindow.setCurrentFrame(newFrame)
 
		self.root.event_generate("<<redrawImgView>>")
 
 
	def _stateHandler(self,e):
src/image_analyzer.py
Show inline comments
 
import logging
 
import logging as log
 
from grid import Grid
 
from go import Go
 
 
 
@@ -11,14 +12,15 @@ class ImageAnalyzer:
 
		self.tresB=tresB
 
		self.tresW=tresW
 
 
	def analyze(self,image,sizeCoef,shift):
 
	# 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
 
 
		for r in range(19):
 
			for c in range(19):
 
				intersection=self.grid.intersections[r][c]
 
 
				self.board[r][c]=self.analyzePoint(image,r,c,intersection*sizeCoef+shift,*(self.grid.stoneSizeAt(r,c,sizeCoef)))
 
				self.board[r][c]=self.analyzePoint(image,r,c,intersection,*(self.grid.stoneSizeAt(r,c)))
 
 
	def analyzePoint(self,image,row,col,imageCoords,stoneWidth,stoneHeight):
 
		b=w=e=0
 
@@ -36,14 +38,14 @@ class ImageAnalyzer:
 
				elif 100*I>self.tresW: w+=1
 
				else: e+=1
 
 
		logging.debug("(%d,%d) ... (b=%d,w=%d,e=%d)", row, col, b, w, e)
 
		log.debug("(%d,%d) ... (b=%d,w=%d,e=%d)", row, col, b, w, e)
 
 
		if b>=w and b>=e: return Go.BLACK
 
		if w>=b and w>=e: return Go.WHITE
 
		return Go.EMPTY
 
 
	def setGrid(self,grid):
 
		self.grid=grid
 
	def setGridCorners(self,corners):
 
		self.grid=Grid(corners)
 
 
 
def relevantRect(imageCoords,stoneWidth,stoneHeight):
0 comments (0 inline, 0 general)