diff --git a/src/grid.py b/src/grid.py --- a/src/grid.py +++ b/src/grid.py @@ -1,72 +1,72 @@ -import numpy -from epoint import EPoint - - -## 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*numpy.matrix(point).transpose()).getA1() - - -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 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] - - p1=numpy.cross(a,b) - p2=numpy.cross(c,d) - vanish1=numpy.cross(p1,p2) - # !! 32 bit int can overflow. keeping it reasonably small. might want to use a cleaner solution - vanish1=EPoint.fromProjective(vanish1).toProjective() # !! EPoint fails with point in infinity - - p3=numpy.cross(a,d) - p4=numpy.cross(b,c) - vanish2=numpy.cross(p3,p4) - vanish2=EPoint.fromProjective(vanish2).toProjective() - - horizon=numpy.cross(vanish1,vanish2) - - horizon=EPoint.fromProjective(horizon).toProjective() - - rectiMatrix=numpy.matrix([horizon,[0,1,0],[0,0,1]]) - rectiMatrixInv=numpy.linalg.inv(rectiMatrix) - - - affineCorners=[EPoint.fromProjective(transformPoint(x,rectiMatrix)) for x in (a,b,c,d)] - x=[affineCorners[0]-affineCorners[3],affineCorners[1]-affineCorners[2],affineCorners[0]-affineCorners[1],affineCorners[3]-affineCorners[2]] - - 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) +import numpy +from epoint import EPoint + + +## 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*numpy.matrix(point).transpose()).getA1() + + +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 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] + + p1=numpy.cross(a,b) + p2=numpy.cross(c,d) + vanish1=numpy.cross(p1,p2) + # !! 32 bit int can overflow. keeping it reasonably small. might want to use a cleaner solution + vanish1=EPoint.fromProjective(vanish1).toProjective() # !! EPoint fails with point in infinity + + p3=numpy.cross(a,d) + p4=numpy.cross(b,c) + vanish2=numpy.cross(p3,p4) + vanish2=EPoint.fromProjective(vanish2).toProjective() + + horizon=numpy.cross(vanish1,vanish2) + + horizon=EPoint.fromProjective(horizon).toProjective() + + rectiMatrix=numpy.matrix([horizon,[0,1,0],[0,0,1]]) + rectiMatrixInv=numpy.linalg.inv(rectiMatrix) + + + affineCorners=[EPoint.fromProjective(transformPoint(x,rectiMatrix)) for x in (a,b,c,d)] + x=[affineCorners[0]-affineCorners[3],affineCorners[1]-affineCorners[2],affineCorners[0]-affineCorners[1],affineCorners[3]-affineCorners[2]] + + 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)