The following class (that was my first class ever in python) was used in an eye tracking context. Imagine a context where you always will have a single gaze-point and some closed contours. How can I return all possible relations between them?
For example, for two contours, the point can be:
- Relation 1: inside contour A and outside contour B;
- Relation 2: inside contour B and outside contour A;
- Relation 3: inside contours A and B;
- Relation 4: outside contours A and B;
In my case, I am using each relation as tags for colors in a context where the number of contours changes.
You can imagine the contours as sets as well, but let's avoid the complexities of an advanced Set Theory.
This problem give us 2 to the power c = number of contours. An Abacus give us the number of columns to the power i = number of lines. So, an abacus seems to be good metaphor, for example:
contours = [c1, c2]
Abacus = ClassAbacus (len(contours))
color_tags = Abacus.Enumerate()
give us a list with all possible tags where + is inside, - is outside and numbers are contours:
['+1+2', '+1-2', '-1+2', '-1-2']
So, now we have reference for 4 colors. We could give a name for each point as such:
import cv2
...
def PolygonTestEx(contours, pt, contours_counter = 0, counter_code = ''):
for x in xrange(1, len(contours) + 1):
Inside = cv2.pointPolygonTest(contours[x -1], pt, False)
# Inside = contours[x]
if Inside > -1:
counter_code = counter_code + '+' + str(x + contours_counter)
else:
counter_code = counter_code + '-' + str(x + contours_counter)
contours_counter = contours_counter + len(contours)
return contours_counter, counter_code
And it should give us the 4 possible states in this context:
Could I write this class with better readability?
Please, fell free to suggest a faster way to do the same or missed common practices in the OOP.
CURRENT_LINE = 0
SIGNS = 1
class BaseError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class ClassAbacus(object):
"""
Recombining tool.
Imagine each char in char_set as digits, or beads, and count them accordingly to a base reference.
Imagine the base as the abacus lines.
'Counter' returns an integer equals to len(char_set) raised to the power x = base, giving the number
of all possible bead states of the "abacus".
'Enumarate' prints each or all states.
"""
def __init__(
self,
char_set = ['+', '-'],
base = 2
):
super(ClassAbacus, self).__init__()
self.Chars = char_set
self.Counter = 0
self.States = []
self.Abacus = []
self.Base = base
if (base + 1) > 2:
self.__Base = base + 1
self.Instantiate()
else:
try:
raise BaseError(1)
except BaseError as e:
print 'Use argument "base" higher then one.', e.value
def doSaveState(self):
state = ''
for column in xrange(0, len(self.Abacus)):
# def addSignTo(state, column, item):
state = state + self.Abacus[column][SIGNS][ self.Abacus[column][CURRENT_LINE] ]
self.States.append(state)
def doLineReset(self, from_column):
to_column = len(self.Abacus)
for column in xrange(from_column, to_column):
self.Abacus[column][CURRENT_LINE] = 0
def doLineIncrement(self, column):
self.Counter += 1
self.doSaveState()
n = self.Abacus[column][CURRENT_LINE]
self.Abacus[column][CURRENT_LINE] = n + 1
def doCount(self, Column):
KeepsCounting = True
HighColumn = len(self.Abacus) -1
LowColumn = 0
if Column < LowColumn:
self.Counter += 1
self.doSaveState()
KeepsCounting = False
else:
ColumnMaxLine = len(self.Abacus[Column][SIGNS]) -1
ColumnCurLine = self.Abacus[Column][CURRENT_LINE]
if ColumnCurLine == ColumnMaxLine:
Column -= 1
KeepsCounting = self.doCount(Column)
return KeepsCounting
if ( Column < HighColumn ) and ( ColumnCurLine < ColumnMaxLine ):
self.doLineIncrement(Column)
self.doLineReset( Column + 1 )
self.doCount(HighColumn)
return KeepsCounting
if ( Column == HighColumn ) and ( ColumnCurLine < ColumnMaxLine ):
self.doLineIncrement(Column)
self.doCount(Column)
return KeepsCounting
def Instantiate(self):
# set the grid of the abacus
for x in xrange(1, self.__Base):
container = []
for char in self.Chars:
# concatenate each char with its base reference
container.append(char + str(x))
self.Abacus.append([0, container])
max_column = max(self.Abacus)
max_index = self.Abacus.index(max_column)
self.doCount(max_index)
def Enumerate(self, index = -1):
container = []
if (index < 0) or (index > self.Counter - 1):
for state in self.States:
container.append(state)
return container
else:
return self.States[index]
For the completeness sake, this class will be called here.