Files
@ 7cb01d4080c9
Branch filter:
Location: OneEye/src/analyzer/corners.py
7cb01d4080c9
3.9 KiB
text/x-python
a hinted neural network (failed)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | import logging
from .epoint import EPoint
log=logging.getLogger(__name__)
class Corners:
def __init__(self,cornerList=[]):
self._corners=list(cornerList)
self._is_canon=False
self._canonizeOrder()
## Adds a new corner if there are less than four, replaces the closest otherwise.
def add(self,x,y):
a=EPoint(x,y)
# for i,c in enumerate(self.corners): # move an improperly placed point
# if a.dist(c)<20:
# self.corners[i]=a
# return
if len(self._corners)<4: # add a new corner
self._corners.append(a)
if len(self._corners)<4:
return
index,minDist=0,float('inf') # replace the corner closest to the clicked point
for i,c in enumerate(self._corners):
if a.dist(c)<minDist:
index,minDist=i,a.dist(c)
self._corners[index]=a
self._canonizeOrder()
## Order the corners (0,1,2,3) so they make a quadrangle with vertices KLMN in counter-clockwise order, K being in the upper left.
#
# For four points ABCD, there are 24 possible permutations corresponding to the desired KLMN.
# When we relax the condition of K being the upper left one, we get six groups of four equivalent permutations. KLMN ~ LMNK ~ MNKL ~ NKLM.
#
# We determine which of the points' triplets are oriented clockwise and which counter-clockwise (minus/plus in the table below)
# and swap them so that all triangles turn counter-clockwise.
#
# xxxx -> KLMN | ABC | ABD | ACD | BCD | index | swap
# ------------ | :-: | :-: | :-: | :-: | ----: | ----
# A BCD | + | + | + | + | 15 | 0
# A BDC | + | + | - | - | 12 | CD
# A CBD | - | + | + | - | 6 | BC
# A CDB | - | - | + | + | 3 | AB
# A DBC | + | - | - | + | 9 | AD
# A DCB | - | - | - | - | 0 | BD
#
# For every non-degenerate quadrangle, there must be 1-3 edges going right-left (from a higher to a lower x coordinate).
# From these pick the one with the lowest slope (dy/dx) and declare its ending point the upper left corner. For the same slope pick the one further left.
#
# @return True for a convex quadrangle, False for concave and degenerate cases.
def _canonizeOrder(self):
def false():
self._is_canon=False
return False
if len(self._corners)!=4: return false()
a,b,c,d=self._corners
abc=doubleTriangleArea(a,b,c)
abd=doubleTriangleArea(a,b,d)
acd=doubleTriangleArea(a,c,d)
bcd=doubleTriangleArea(b,c,d)
if any(x==0 for x in (abc,abd,acd,bcd)): return false() # collinear degenerate
swaps=[(1,3),(0,1),(1,2),(0,3),(2,3),(0,0)]
index=(8 if abc>0 else 0)|(4 if abd>0 else 0)|(2 if acd>0 else 0)|(1 if bcd>0 else 0)
if index%3!=0: return false() # concave degenerate
swap=swaps[index//3]
self._corners[swap[0]], self._corners[swap[1]] = self._corners[swap[1]], self._corners[swap[0]] # counter-clockwise order
kIndex=None
lowestSlope=float("inf")
for i,corner in enumerate(self._corners): # find the NK edge: going right-left with the lowest slope, secondarily the one going down
ii=(i+1)%4
slope=abs(getSlope(corner, self._corners[ii]))
if corner.x>self._corners[ii].x and (slope < lowestSlope or (slope == lowestSlope and corner.y < self._corners[ii].y)):
kIndex=ii
lowestSlope=slope
self._corners= self._corners[kIndex:] + self._corners[:kIndex] # rotate the upper left corner to the first place
self._is_canon=True # success
return True
def scale(self,scale):
self._corners=[c * scale for c in self._corners]
def __iter__(self):
return iter(self._corners)
def __len__(self):
return len(self._corners)
def is_canon(self):
return self._is_canon
## Computes twice the area of the triangle formed by points a,b,c.
#
# @return positive value for points oriented counter-clockwise, negative for clockwise, zero for degenerate cases.
def doubleTriangleArea(a,b,c):
return (a.x-b.x)*(c.y-a.y)-(c.x-a.x)*(a.y-b.y)
def getSlope(a,b):
if(b.x==a.x): return float("inf")
return (b.y-a.y)/(b.x-a.x)
|