# HG changeset patch
# User Laman
# Date 2019-01-22 11:18:50
# Node ID 40cc3b625eb2d6e3d2a44eda7fdb5cdb5d9844ea
# Parent  12717eacf401036ae09046584698ab457ed7f35d

work on polar hough

diff --git a/exp/stone_detect.py b/exp/stone_detect.py
--- a/exp/stone_detect.py
+++ b/exp/stone_detect.py
@@ -4,11 +4,13 @@ sys.path.append("../src")
 import os
 import math
 import random
+import itertools
 
 import cv2 as cv
 import numpy as np
 import scipy.cluster
 import scipy.ndimage
+import scipy.signal
 
 from annotations import DataFile,computeBoundingBox
 from hough import show
@@ -53,6 +55,62 @@ class Line():
 	def __repr__(self): return "Line({0},{1})".format(repr(self.a),repr(self.b))
 
 
+class PolarHough:
+	# http://www.cis.pku.edu.cn/vision/vpdetection/LiPYZ10isvc.pdf
+	def __init__(self,anglePrecision,lengthPrecision):
+		self._anglePrecision=anglePrecision
+		self._lengthPrecision=lengthPrecision
+		self._maxLength=4096
+		n=math.ceil(2*math.pi/anglePrecision)
+		self._acc=[[] for i in range(n)]
+
+	def put(self,item):
+		k=int(item[0]//self._anglePrecision)
+		self._acc[k].append(item)
+
+	def extract(self,count):
+		vanishingPoints=[]
+		angles=self._extractAngles(count)
+		angles=[alpha for (alpha,prominence) in angles]
+		bins=self._mapAngles(angles)
+		for (alpha,bin) in zip(angles,bins):
+			(length,sampleCount)=self._extractLength([dist for (beta,dist) in bin])
+			vanishingPoints.append((alpha,length))
+		return vanishingPoints
+
+	def _extractAngles(self,k):
+		lens=np.array(list(map(len,self._acc)))
+		print(lens)
+		(peakKeys,info)=scipy.signal.find_peaks(lens,prominence=0)
+		res=sorted(zip(info["prominences"],peakKeys),reverse=True)[:k]
+		res=[(key*self._anglePrecision,prominence) for (prominence,key) in res]
+		print("(angle, prominence):",res,"...",[alpha/self._anglePrecision for (alpha,_) in res])
+		return res
+
+	def _mapAngles(self,angles):
+		res=[[] for alpha in angles]
+		for (i,bin) in enumerate(self._acc):
+			beta=i*self._anglePrecision
+			key=min(zip(map(lambda alpha: angleDiff(alpha,beta), angles), itertools.count()))[1]
+			res[key].extend(bin)
+		return res
+
+	def _extractLength(self,arr):
+		acc=np.zeros(self._maxLength+1,dtype=np.int32)
+		for dist in arr:
+			dist=min(dist,self._maxLength)
+			acc[int(dist//self._lengthPrecision)]+=1
+		res=acc.argmax()
+		print("(length, count):",(res*self._lengthPrecision,acc[res]))
+		return (res*self._lengthPrecision,acc[res])
+
+
+def angleDiff(alpha,beta):
+	diff=abs(alpha-beta)
+	if diff>math.pi: diff=2*math.pi-diff
+	return diff
+
+
 def kmeans(img):
 	arr=np.reshape(img,(-1,3)).astype(np.float)
 	colors=np.array([[0,0,0],[255,255,255],[193,165,116]],np.float)
@@ -190,9 +248,9 @@ if __name__=="__main__":
 	kernel=np.ones((3,3),np.uint8)
 	maskB=cv.inRange(rect,centers[0]-unit,centers[0]+unit)
 	maskB=cv.morphologyEx(maskB,cv.MORPH_OPEN,kernel,iterations=1)
-	maskB=cv.erode(maskB,kernel,iterations=2)
+	maskB=cv.erode(maskB,kernel,iterations=4)
 	maskW=cv.inRange(rect,centers[1]-unit,centers[1]+unit)
-	maskW=cv.erode(maskW,kernel,iterations=2)
+	maskW=cv.erode(maskW,kernel,iterations=3)
 
 	show(img,filename)
 	show(maskB,filename)
@@ -241,92 +299,22 @@ if __name__=="__main__":
 		(xb,yb)=line.b
 		cv.line(linesImg,(int(xa),int(ya)),(int(xb),int(yb)),(255,255,0),1)
 	res.sort()
-	# for row in res: print(row)
-	# linePack=[
-	# 	Line(EPoint(174.457,166.127),EPoint(174.96,27.253)),
-	# 	Line(EPoint(191.333,38.075),EPoint(191.485,71.227)),
-	# 	Line(EPoint(210.117,167.092),EPoint(205.0,50.0)),
-	# 	Line(EPoint(127.7,25.6),EPoint(120.172,179.405)),
-	# 	Line(EPoint(127.809,58.481),EPoint(124.324,127.427)),
-	# 	Line(EPoint(85.964,191.64),EPoint(97.68,14.477)),
-	# 	Line(EPoint(56.447,124.662),EPoint(54.889,137.918))
-	# ]
-	# linePack=[
-	# 	Line(EPoint(56.447,124.662),EPoint(139.695,128.104)),
-	# 	Line(EPoint(288.267,74.433),EPoint(191.485,71.227)),
-	# 	Line(EPoint(252.926,29.71),EPoint(174.96,27.253)),
-	# 	Line(EPoint(274.412,120.07),EPoint(41.065,112.759)),
-	# 	Line(EPoint(289.674,108.019),EPoint(26.17,100.538)),
-	# 	Line(EPoint(240.702,107.818),EPoint(41.065,112.759)),
-	# 	Line(EPoint(174.457,166.127),EPoint(88.192,164.5))
-	# ]
-	# for (i,p) in enumerate(linePack):
-	# 	for q in linePack[i+1:]:
-	# 		print(p.intersect(q))
-	# show(linesImg)
-
-	# parallels=[]
-	# for (i,ab) in enumerate(lines):
-	# 	for cd in lines[i+1:]:
-	# 		if ab.computeAngle(cd)>math.pi/4:
-	# 			continue
-	# 		parallels.append((ab,cd))
-	# print("parallel lines candidate pairs:",len(parallels))
-
-	# parallels=list(groupParallels(lines,50,w))
-	# print("parallel triples:",len(parallels))
-	# for (p,q,r) in parallels:
-	# 	print(p,q,r)
-	# 	print(p.intersect(q))
-	# 	print(p.intersect(r))
-	# 	print(q.intersect(r))
-	# 	print()
-	# 	matsImg_=np.copy(matsImg)
-	# 	for pi in (p,q,r):
-	# 		cv.line(matsImg_,(int(pi.a.x),int(pi.a.y)),(int(pi.b.x),int(pi.b.y)),(0,255,255),1)
-	# 	show(matsImg_)
+	show(linesImg)
 
-	# p=Line(corners[0],corners[1])
-	# q=Line(corners[2],corners[3])
-	# r=Line(corners[1],corners[2])
-	# s=Line(corners[3],corners[0])
-	#
-	# matrix=computeRectiMatrix(p,q,r,s)
-	# print(matrix)
-	# for (point,contour) in stoneLocs:
-	# 	point_=EPoint.fromProjective(transformPoint(point.toProjective(),matrix))
-	# 	# print(point,"->",point_)
-	# 	cv.line(matsImg,(int(point.x),int(point.y)),(int(point_.x),int(point_.y)),(0,255,255),1)
-	# points1=np.float32([[p.x-x1,p.y-y1] for p in corners])
-	# points2=np.float32([[0,0],[0,400],[400,400],[400,0]])
-	# print(points1)
-	# print(points2)
-	# mat=cv.getPerspectiveTransform(points1,points2)
-	# print(mat)
-	# show(rect)
-	# warped=cv.warpPerspective(rect,matrix,(400,400))
-	# show(warped)
-
-	# mats=[]
-	# for (i,(p,q)) in enumerate(parallels):
-	# 	for (r,s) in parallels[i+1:]:
-	# 		if p is r or p is s or q is r or q is s:
-	# 			continue
-	# 		matrix=computeRectiMatrix(p,q,r,s)
-	# 		score=scoreMatrix(matrix,p,r,lines)
-	# 		mats.append((score,p,q,r,s,matrix))
-	# mats.sort(key=lambda x: x[0])
-	# for (score,p,q,r,s,matrix) in mats[:4]:
-	# 	print(score,p,q,r,s,matrix)
-	# 	matsImg_=np.copy(matsImg)
-	# 	for ab in (p,q,r,s):
-	# 		((xa,ya),(xb,yb))=(ab.a,ab.b)
-	# 		cv.line(matsImg_,(int(xa),int(ya)),(int(xb),int(yb)),(255,255,0),1)
-	# 	show(matsImg_)
-	# for (score,p,q,r,s,matrix) in mats[-4:]:
-	# 	print(score,p,q,r,s,matrix)
-	# 	matsImg_=np.copy(matsImg)
-	# 	for ab in (p,q,r,s):
-	# 		((xa,ya),(xb,yb))=(ab.a,ab.b)
-	# 		cv.line(matsImg_,(int(xa),int(ya)),(int(xb),int(yb)),(0,0,255),1)
-	# 	show(matsImg_)
+	imgSize=img.shape[:2]
+	print("image size:",imgSize)
+	imgCenter=EPoint(imgSize[1]/2,imgSize[0]/2)-EPoint(x1,y1)
+	polarHough=PolarHough(math.pi/180,10)
+	for (i,ab) in enumerate(lines):
+		for cd in lines[i+1:]:
+			point=ab.intersect(cd)
+			if 0<=point.x<=w and 0<=point.y<=h: continue
+			print(point,"->",point.toPolar(imgCenter))
+			polarHough.put(point.toPolar(imgCenter))
+	vanish=[EPoint.fromPolar(p,imgCenter) for p in polarHough.extract(2)]
+	print(vanish)
+	(a,b,c,d)=corners
+	(p,q,r,s)=(Line(a,b),Line(b,c),Line(c,d),Line(d,a))
+	v1=p.intersect(r)
+	v2=q.intersect(s)
+	print("true vanishing points:",v1,"~",v1.toPolar(imgCenter),"and",v2,"~",v2.toPolar(imgCenter))
diff --git a/src/analyzer/epoint.py b/src/analyzer/epoint.py
--- a/src/analyzer/epoint.py
+++ b/src/analyzer/epoint.py
@@ -24,12 +24,20 @@ class EPoint:
 		if point.item(0)==0: return None
 		return EPoint(point.item(1)/point.item(0),point.item(2)/point.item(0))
 
+	@staticmethod
+	def fromPolar(point,center):
+		(alpha,length)=point
+		x=math.cos(alpha)
+		y=math.sin(alpha)
+		return length*EPoint(x,y)+center
+
 	def toProjective(self):
 		return (1,self._x,self._y)
 
 	def toPolar(self,center):
 		v=self-center
 		alpha=math.atan2(v.y,v.x)
+		if alpha<0: alpha+=2*math.pi
 		k=self.dist(center)
 		return (alpha,k)