Changeset - 928d9a0edc05
[Not reviewed]
default
0 3 0
Laman - 8 years ago 2017-01-09 20:36:13

fix of coordinates computation
3 files changed with 11 insertions and 8 deletions:
0 comments (0 inline, 0 general)
src/core.py
Show inline comments
 
import os
 
import multiprocessing
 
import threading
 
import logging as log
 
import PIL
 
from util import MsgQueue
 
from gui import gui
 
from imageanalyzer import ImageAnalyzer
 
from go import Go
 

	
 

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

	
 
		self._ownMessages=MsgQueue(self._handleEvent)
 
		self._guiMessages=MsgQueue()
 

	
 
		imgPath=os.path.join(os.path.dirname(__file__), "..","images","7.jpg")
 
		imgPath=os.path.join(os.path.dirname(__file__), "..","images","5.jpg")
 
		self._frame=PIL.Image.open(imgPath)
 

	
 
		self._guiProc=multiprocessing.Process(name="gui", target=gui, args=(self._guiMessages,self._ownMessages))
 
		self._guiProc.start()
 
		self._guiMessages.send("setCurrentFrame",(self._frame,))
 
		self._guiMessages.send("setCurrentFrame",(self._frame.copy(),))
 

	
 
	def setCorners(self,corners):
 
		self.detector.setGridCorners(corners)
 
		self.detector.analyze(self._frame)
 
		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):
 
		listenerThread=threading.Thread(target=lambda: self._ownMessages.listen())
 
		listenerThread.start()
 

	
 
	def joinGui(self):
 
		self._guiProc.join()
 
		self._ownMessages.send("kill")
 
		self._ownMessages.send("!kill")
 

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

	
 
		return actions[actionName](*args,**kwargs)
 

	
 
core=Core()
 
core.listen()
 
core.joinGui()
 

	
 
"""
 
core
 
====
 
grid
 
go
 
imageAnalyzer
 

	
 

	
 
gui
 
===
 
corners
 

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

	
 
GUI
 
<- addCorner(corner)
 
-> redrawImgView(img,grid)
 
<- refreshTresholds(tresB,tresW)
 

	
 
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/gui/mainwindow.py
Show inline comments
 
import logging as log
 
import tkinter as tk
 

	
 
import PIL
 
from PIL import ImageTk
 

	
 
import config
 
import imageanalyzer
 
from corners import Corners
 
from epoint import EPoint
 
from grid import Grid
 
from .boardview import BoardView
 

	
 

	
 
class MainWindow(tk.Frame):
 
	def __init__(self,parent,master=None):
 
		self.parent=parent
 
		self.corners=Corners()
 

	
 
		self.currentFrame=None
 
		self._boardGrid=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):
 
		self.currentFrame=frame
 

	
 
		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
 
		wo,ho=frame.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
 

	
 
		frame.thumbnail((w,h)) # resize
 
		self.img=ImageTk.PhotoImage(frame)
 

	
 
	def _createWidgets(self):
 
		# a captured frame with overlay graphics
 
		self.imgView=tk.Canvas(self)
 
		self.imgView.configure(width=480,height=360)
 

	
 
		self.imgView.bind('<1>',lambda e: self.addCorner(e.x,e.y))
 

	
 
		self.imgView.grid(column=0,row=0)
 

	
 
		# board with detected stones
 
		self.boardView= BoardView(self)
 
		self.boardView.grid(column=1,row=0)
 

	
 
		# more controls below the board
 
		self.scaleTresB=tk.Scale(self, orient=tk.HORIZONTAL, length=200, from_=0.0, to=100.0, command=self.refreshTresholds)
 
		self.scaleTresW=tk.Scale(self, orient=tk.HORIZONTAL, length=200, from_=0.0, to=100.0, command=self.refreshTresholds)
 
		self.scaleTresB.set(30.0) # !! proper defaults
 
		self.scaleTresW.set(60.0)
 
		self.scaleTresB.grid(column=0,row=1,columnspan=2)
 
		self.scaleTresW.grid(column=0,row=2,columnspan=2)
 

	
 
		# render everything
 
		self.redrawImgView()
 

	
 
	## Stores a grid corner located at x,y coordinates.
 
	def addCorner(self,x,y):
 
		self.corners.add(x,y)
 
		log.debug("click on %d,%d",x,y)
 
		log.debug("sizeCoef: %f, shift: %d,%d",self._imgSizeCoef,self._imgShift.x,self._imgShift.y)
 
		if self.corners.canonizeOrder():
 
			# 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.redrawImgView()
 

	
 
	## Redraws the current image and its overlay.
 
	def redrawImgView(self):
 
		if self.currentFrame and self.img:
 
			self.imgView.create_image(2,2,anchor="nw",image=self.img)
 
			self.imgView.create_image(240,180,anchor="center",image=self.img)
 

	
 
		for corner in self.corners.corners:
 
			self.markPoint(corner.x,corner.y)
 

	
 
		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]
 
				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]
 
				self.imgView.create_line(a.x,a.y,b.x,b.y,fill='#00ff00')
 

	
 
		if self._boardGrid!=None and config.gui.showBigPoints:
 
			for r in range(19):
 
				for c in range(19):
 
					((r1,c1),(r2,c2))=imageanalyzer.relevantRect(self._boardGrid.intersections[r][c], *(self._boardGrid.stoneSizeAt(r, c)))
 
					self.imgView.create_rectangle(r1,c1,r2,c2,outline="#00ffff")
 

	
 
		self.imgView.grid()
 

	
 
	## Marks a point at the image with a green cross. Used for corners.
 
	def markPoint(self,x,y):
 
		self.imgView.create_line(x-3,y-3,x+4,y+4,fill="#00ff00")
 
		self.imgView.create_line(x-3,y+3,x+4,y-4,fill="#00ff00")
 

	
 
		self.imgView.grid()
 

	
 
	def refreshTresholds(self,_):
 
		self.parent.sendMsg("setTresholds",tuple(),{"tresB":self.scaleTresB.get(), "tresW":self.scaleTresW.get()})
src/util.py
Show inline comments
 
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)
 
			if msg[0]=="kill": break
 
			if msg[0]=="!kill": break
 
			self._handleEvent(msg)
 

	
 
	def setHandler(self,handler):
 
		self._handleEvent=handler
0 comments (0 inline, 0 general)