# HG changeset patch # User Laman # Date 2019-03-02 14:54:49 # Node ID 739df5e211d8c0797c585bccd2d377cd07c214d4 # Parent 184d592b02dd5fb5bf750aec34bb686931c21f0b fixed Hough transform input/ouput coordinates, fixed lines detection diff --git a/exp/geometry.py b/exp/geometry.py --- a/exp/geometry.py +++ b/exp/geometry.py @@ -41,8 +41,24 @@ class Line: (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._alpha,self._d) - def __repr__(self): return "Line({0},{1})".format(repr(self._alpha),repr(self._d)) + def shiftBasis(self,newBasis): + (a,b,c)=self.toNormal() + if a!=0: + point=EPoint(-c/a,0) + else: + point=EPoint(0,-c/b) + (x_,y_)=point-newBasis + c_=-a*x_-b*y_ + return Line.fromNormal(a,b,c_) + + @property + def alpha(self): return self._alpha + + @property + def d(self): return self._d + + def __str__(self): return "Line({0},{1})".format(round(self._alpha,3),round(self._d)) + def __repr__(self): return "Line({0},{1})".format(self._alpha,self._d) def angleDiff(alpha,beta): diff --git a/exp/hough.py b/exp/hough.py --- a/exp/hough.py +++ b/exp/hough.py @@ -34,6 +34,10 @@ class LineBag: class HoughTransform: + """Find line sequences with Hough transform. + + Uses usual image coordinates on input and output, with [0,0] in the upper left corner and [height-1,width-1] in the lower right. + However, internally it uses the usual cartesian coordinates, centered at the image center. [-w/2,-h/2] in the upper left and [w/2,h/2] in the lower right.""" def __init__(self,img): self._angleBandwidth=30 # degrees @@ -58,10 +62,8 @@ class HoughTransform: keys=self._readLineKeys(alpha,beta) for k in peaks: (alphaDeg,d)=keys[k] - alphaRad=alphaDeg*math.pi/180 - baseLine=Line(alphaRad,0) - dd=baseLine.distanceTo(EPoint(*self._center)) # to shift d from the center to 0,0 - res.append(Line(alphaRad, dd+d-self._diagLen//2)) + line=Line(alphaDeg*math.pi/180,d-self._diagLen//2) + res.append(self._transformOutput(line)) i+=1 self.show(img) @@ -77,17 +79,21 @@ class HoughTransform: self._acc[(alphaDeg,d)]+=weight log.debug("Hough updated in %s s",round(datetime.now().timestamp()-start,3)) + def show(self,img=None): + if img is None: img=self._createImg() + show(img,"Hough transform accumulator") + def _computeDist(self,x,y,alphaDeg): alphaRad=alphaDeg*math.pi/180 (x0,y0)=self._center - (dx,dy)=(x-x0,y-y0) + (dx,dy)=(x-x0,y0-y) d=dx*math.cos(alphaRad)+dy*math.sin(alphaRad) return round(d) def _detectLines(self): bag=LineBag() - for alpha in range(0,180,2): - for beta in range(max(alpha-60,0),alpha+60,2): + for alpha in range(0,180+60,2): + for beta in range(max(alpha-60,0),min(alpha+60,180+60),2): accLine=[self._acc[key] for key in self._readLineKeys(alpha,beta)] (peaks,props)=scipy.signal.find_peaks(accLine,prominence=0) (prominences,peaks)=zip(*sorted(zip(props["prominences"],peaks),reverse=True)[:19]) @@ -99,16 +105,19 @@ class HoughTransform: res=[] for i in range(n+1): k=round((alpha*(n-i)+beta*i)/n) - if k<0 or k>=180: + if k>=180: k=k%180 - i=n+1-i + i=n-i res.append((k,i)) return res - def show(self,img=None): - if img is None: img=self._createImg() - - show(img,"Hough transform accumulator") + def _transformOutput(self,line): + (x,y)=self._center + basis=EPoint(-x,y) + shiftedLine=line.shiftBasis(basis) + reflectedLine=Line(math.pi*2-shiftedLine.alpha,shiftedLine.d) + log.debug("%s -> %s",line,reflectedLine) + return reflectedLine def _createImg(self): maxVal=self._acc.max() diff --git a/exp/tests/test_geometry.py b/exp/tests/test_geometry.py --- a/exp/tests/test_geometry.py +++ b/exp/tests/test_geometry.py @@ -65,3 +65,27 @@ class TestLine(TestCase): self.assertAlmostEqual(r.distanceTo(a),1) self.assertAlmostEqual(r.distanceTo(b),1) self.assertAlmostEqual(r.distanceTo(c),0) + + def testShiftBasis(self): + newBasis=EPoint(-200,150) + r=Line(0,-100) + r_=r.shiftBasis(newBasis) + self.assertAlmostEqual(r_._alpha,0) + self.assertAlmostEqual(r_._d,100) + + s=Line(0,100) + s_=s.shiftBasis(newBasis) + self.assertAlmostEqual(s_._alpha,0) + self.assertAlmostEqual(s_._d,300) + + newBasis=EPoint(-100,100) + diag=100*math.sqrt(2) + p=Line(math.pi*3/4,diag/2) + p_=p.shiftBasis(newBasis) + self.assertAlmostEqual(p_._alpha,math.pi*7/4) + self.assertAlmostEqual(p_._d,diag/2) + + q=Line(math.pi*3/4,-diag/2) + q_=q.shiftBasis(newBasis) + self.assertAlmostEqual(q_._alpha,math.pi*7/4) + self.assertAlmostEqual(q_._d,3/2*diag)