Changeset - 7c268e382b96
[Not reviewed]
default
0 2 2
Laman - 6 years ago 2019-02-14 17:18:55

geometry: rewritten Line
4 files changed with 102 insertions and 47 deletions:
0 comments (0 inline, 0 general)
exp/board_detect.py
Show inline comments
 
import sys
 

	
 
sys.path.append("../src")
 

	
 
import os
 
import math
 
import random
 
import logging as log
 

	
 
import cv2 as cv
 
import numpy as np
 
import scipy.cluster
 
import scipy.ndimage
 
import scipy.signal
 

	
 
from geometry import Line, point2lineDistance
 
from geometry import Line
 
from polar_hough import PolarHough
 
from annotations import DataFile,computeBoundingBox
 
from hough import show,prepareEdgeImg,HoughTransform
 
from analyzer.epoint import EPoint
 
from analyzer.corners import Corners
 

	
 
random.seed(361)
 
log.basicConfig(level=log.DEBUG,format="%(message)s")
 

	
 

	
 
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)
 
	log.debug(colors)
 
	(centers,distortion)=scipy.cluster.vq.kmeans(arr,colors)
 
	log.debug("k-means centers: %s",centers)
 
	return centers
 

	
 

	
 
def quantize(img,centers):
 
	origShape=img.shape
 
	data=np.reshape(img,(-1,3))
 
	(keys,dists)=scipy.cluster.vq.vq(data,centers)
 
	pixels=np.array([centers[k] for k in keys],dtype=np.uint8).reshape(origShape)
exp/geometry.py
Show inline comments
 
import math
 

	
 
import numpy as np
 

	
 
from analyzer.epoint import EPoint, homogenize
 
from analyzer.grid import transformPoint
 
from analyzer.epoint import EPoint
 

	
 

	
 
class Line():
 
	def __init__(self,a,b):
 
		self.a=a
 
		self.b=b
 
		self.points={a,b}
 
class Line:
 
	def __init__(self,alpha,d):
 
		self._alpha=alpha
 
		self._d=d
 
		self._sin=math.sin(alpha)
 
		self._cos=math.cos(alpha)
 

	
 
	def getSortedPoints(self):
 
		return tuple(sorted(self.points))
 
	@staticmethod
 
	def fromNormal(a,b,c):
 
		"""ax + by + c = 0"""
 
		norm=-c/abs(c)*math.sqrt(a**2+b**2)
 
		(a_,b_,c_)=(a/norm,b/norm,c/norm)
 
		alpha=math.acos(a_) if b_>=0 else 2*math.pi-math.acos(a_)
 
		return Line(alpha,-c_)
 

	
 
	def computeAngle(self,line):
 
		ab=self.a-self.b
 
		cd=line.a-line.b
 
		alpha=math.atan(ab.y/ab.x)
 
		gamma=math.atan(cd.y/cd.x)
 
		fi=max(alpha,gamma)-min(alpha,gamma)
 
		return min(fi,math.pi-fi)
 
	@staticmethod
 
	def fromPoints(a,b):
 
		return Line.fromNormal(a.y-b.y, b.x-a.x, (b.y-a.y)*a.x+(a.x-b.x)*a.y)
 

	
 
	def toNormal(self):
 
		# https://en.wikipedia.org/wiki/Line_(mathematics)#In_normal_form
 
		"""ax + by + c = 0"""
 
		return (self._cos, self._sin, -self._d)
 

	
 
	def intersect(self,line):
 
		p=self.toProjective()
 
		q=line.toProjective()
 
		return EPoint.fromProjective(np.cross(p,q))
 

	
 
	def toProjective(self):
 
		return homogenize(np.cross(self.a.toProjective(),self.b.toProjective()))
 

	
 
	def transform(self,matrix):
 
		a=EPoint.fromProjective(transformPoint(self.a.toProjective(),matrix))
 
		b=EPoint.fromProjective(transformPoint(self.b.toProjective(),matrix))
 
		if a is None or b is None: return None
 
		return Line(a,b)
 
		if self._alpha==line._alpha: return None
 
		(a,b,c)=self.toNormal()
 
		(d,e,f)=line.toNormal()
 
		x=(b*f-c*e)/(a*e-b*d)
 
		y=(c*d-a*f)/(a*e-b*d)
 
		return EPoint(x,y)
 

	
 
	def score(self,points):
 
		score=len(self.points)
 
		for a in self.points:
 
			closest=sorted(points,key=lambda b: a.dist(b))[:4]
 
			score+=sum(0.01 for b in closest if b in self.points)
 
		return score
 
	def distanceTo(self,point):
 
		# https://en.wikipedia.org/wiki/Point-line_distance#Line_defined_by_an_equation
 
		(a,b,c)=self.toNormal()
 
		return abs(a*point.x+b*point.y+c) # a**2 + b**2 == 1 for Hesse normal form
 

	
 
	def __str__(self): return "({0},{1})".format(self.a,self.b)
 
	def __repr__(self): return "Line({0},{1})".format(repr(self.a),repr(self.b))
 

	
 

	
 
def point2lineDistance(a,b,p):
 
	# https://en.wikipedia.org/wiki/Point-line_distance#Line_defined_by_two_points
 
	ab=b-a
 
	num=abs(ab.y*p.x - ab.x*p.y + b.x*a.y - a.x*b.y)
 
	denum=math.sqrt(ab.y**2+ab.x**2)
 
	return num/denum # double_area / side_length == height
 
	def __str__(self): return "({0},{1})".format(self._alpha,self._d)
 
	def __repr__(self): return "Line({0},{1})".format(repr(self._alpha),repr(self._d))
 

	
 

	
 
def angleDiff(alpha,beta):
 
	diff=abs(alpha-beta)
 
	if diff>math.pi: diff=2*math.pi-diff
 
	return diff
exp/tests/__init__.py
Show inline comments
 
new file 100644
exp/tests/test_geometry.py
Show inline comments
 
new file 100644
 
import math
 
import random
 
from unittest import TestCase
 

	
 
from geometry import Line,EPoint
 

	
 
random.seed(361)
 

	
 

	
 
class TestLine(TestCase):
 
	def testFromNormal(self):
 
		p=Line.fromNormal(1,0,-1) # x-1=0
 
		self.assertEqual(p._alpha,0)
 
		self.assertEqual(p._d,1)
 

	
 
		q=Line.fromNormal(1,1,-2) # x+y-2=0
 
		self.assertAlmostEqual(q._alpha,math.pi/4)
 
		self.assertAlmostEqual(q._d,math.sqrt(2))
 

	
 
		r=Line.fromNormal(0,1,1) # y+1=0
 
		self.assertAlmostEqual(r._alpha,math.pi*3/2)
 
		self.assertEqual(r._d,1)
 

	
 
	def testFromPoints(self):
 
		ab=Line.fromPoints(EPoint(1,3),EPoint(1,-1))
 
		self.assertEqual(ab._alpha,0)
 
		self.assertEqual(ab._d,1)
 

	
 
		cd=Line.fromPoints(EPoint(0,2),EPoint(-1,3))
 
		self.assertAlmostEqual(cd._alpha,math.pi/4)
 
		self.assertAlmostEqual(cd._d,math.sqrt(2))
 

	
 
		ef=Line.fromPoints(EPoint(-2,-1),EPoint(-4,-1))
 
		self.assertAlmostEqual(ef._alpha,math.pi*3/2)
 
		self.assertEqual(ef._d,1)
 

	
 
	def testIntersect(self):
 
		for i in range(10):
 
			a=EPoint(random.randint(-100,100),random.randint(-100,100))
 
			b=EPoint(random.randint(-100,100),random.randint(-100,100))
 
			c=EPoint(random.randint(-100,100),random.randint(-100,100))
 
			ab=Line.fromPoints(a,b)
 
			ac=Line.fromPoints(a,c)
 
			a_=ab.intersect(ac)
 
			self.assertAlmostEqual(a.x,a_.x)
 
			self.assertAlmostEqual(a.y,a_.y)
 

	
 
	def testDistanceTo(self):
 
		p=Line(0,1)
 
		q=Line(math.pi/4,math.sqrt(2))
 
		r=Line(math.pi*3/2,1)
 

	
 
		a=EPoint(0,0)
 
		b=EPoint(1,0)
 
		c=EPoint(-1,-1)
 

	
 
		self.assertAlmostEqual(p.distanceTo(a),1)
 
		self.assertAlmostEqual(p.distanceTo(b),0)
 
		self.assertAlmostEqual(p.distanceTo(c),2)
 

	
 
		self.assertAlmostEqual(q.distanceTo(a),math.sqrt(2))
 
		self.assertAlmostEqual(q.distanceTo(b),math.sqrt(2)/2)
 
		self.assertAlmostEqual(q.distanceTo(c),2*math.sqrt(2))
 

	
 
		self.assertAlmostEqual(r.distanceTo(a),1)
 
		self.assertAlmostEqual(r.distanceTo(b),1)
 
		self.assertAlmostEqual(r.distanceTo(c),0)
0 comments (0 inline, 0 general)