import numpy as np from .epoint import EPoint,homogenize ## Projective transformation of a point with a matrix A. # # 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): return (A*np.matrix(point).transpose()).getA1() def computeRectiMatrix(a,b,c,d): """Computes a matrix mapping a projective space to an affine space. ABCD quadrangle gets transformed to a parallelogram. :param a,b,c,d: projective points""" # ad # bc p1=np.cross(a,b) p2=np.cross(c,d) # 32 bit int can overflow. keeping it reasonably small. might want to use a cleaner solution vanish1=homogenize(np.cross(p1, p2)) p3=np.cross(a,d) p4=np.cross(b,c) vanish2=homogenize(np.cross(p3, p4)) horizon=homogenize(np.cross(vanish1, vanish2)) return np.matrix([horizon,[0,1,0],[0,0,1]]) class Grid: ## Creates a Grid from the provided Corners object. # # Finds the vanishing points of the board lines (corner points define perspectively transformed parallel lines). The vanishing points define the image horizon. # # The horizon can be used to construct a matrix for affine rectification of the image (restoring parallel lines parallelism). We transform the corner points by this matrix, # interpolate them to get proper intersections' coordinates and then transform these back to get their placement at the original image. # # The result is stored in grid.intersections, a boardSize*boardSize list with [row][column] coordinates. # # @param corners iterable of 4 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) rectiMatrix=computeRectiMatrix(a,b,c,d) rectiMatrixInv=np.linalg.inv(rectiMatrix) affineCorners=[EPoint.fromProjective(transformPoint(x,rectiMatrix)) for x in (a,b,c,d)] self.intersections=[] boardSize=19 for r in range(boardSize): self.intersections.append([None]*boardSize) rowStart=(affineCorners[0]*(boardSize-1-r)+affineCorners[1]*r) / (boardSize-1) rowEnd=(affineCorners[3]*(boardSize-1-r)+affineCorners[2]*r) / (boardSize-1) for c in range(boardSize): affineIntersection=(rowStart*(boardSize-1-c)+rowEnd*c) / (boardSize-1) self.intersections[r][c]=EPoint.fromProjective(transformPoint(affineIntersection.toProjective(),rectiMatrixInv)) def stoneSizeAt(self,r,c): intersection=self.intersections[r][c] 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)