forked from gitanat/simple-ocr-opencv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprocessor.py
143 lines (123 loc) · 5.56 KB
/
processor.py
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
def _same_type(a,b):
type_correct=False
if type(a)==type(b):
type_correct=True
try:
if isinstance(a, b):
type_correct=True
except TypeError: #v may not be a class or type, but an int, a string, etc
pass
return type_correct
def _broadcast( src_processor, src_atr_name, dest_processors, dest_atr_name, transform_function):
'''To be used exclusively by create_broadcast.
A broadcast function gets an attribute on the src_processor and
sets it (possibly under a different name) on dest_processors'''
value= getattr( src_processor, src_atr_name)
value= transform_function( value )
for d in dest_processors:
setattr(d, dest_atr_name, value )
def create_broadcast( src_atr_name, dest_processors, dest_atr_name=None, transform_function= lambda x:x):
'''This method creates a function, intended to be called as a
Processor posthook, that copies some of the processor's attributes
to other processors'''
from functools import partial
if dest_atr_name==None:
dest_atr_name= src_atr_name
if not hasattr( dest_processors, "__iter__"): # a single processor was given instead
dest_processors= [dest_processors]
return partial( _broadcast, src_atr_name=src_atr_name, dest_processors=dest_processors, dest_atr_name=dest_atr_name, transform_function=transform_function)
class Parameters( dict ):
def __add__(self, other):
d3= Parameters()
d3.update(self)
d3.update(other)
return d3
class Processor( object ):
'''In goes something, out goes another. Processor.process() models
the behaviour of a function, where there are some stored parameters
in the Processor instance. Further, it optionally calls arbitrary
functions before and after processing (prehooks, posthooks)'''
PARAMETERS= Parameters()
def __init__(self, **args):
'''sets default parameters'''
for k,v in self.PARAMETERS.items():
setattr(self, k, v)
self.set_parameters(**args)
self._prehooks= [] #functions (on input) to be executed before processing
self._poshooks= [] #functions (on output) to be executed after processing
def get_parameters( self ):
'''returns a dictionary with the processor's stored parameters'''
parameter_names= self.PARAMETERS.keys()
parameter_values= [getattr(processor, n) for n in parameter_names]
return dict( zip(parameter_names, parameter_values ) )
def set_parameters( self, **args ):
'''sets the processor stored parameters'''
for k,v in self.PARAMETERS.items():
new_value= args.get(k)
if new_value!=None:
if not _same_type(new_value, v):
raise Exception( "On processor {0}, argument {1} takes something like {2}, but {3} was given".format( self, k, v, new_value))
setattr(self, k, new_value)
not_used= set(args.keys()).difference( set(self.PARAMETERS.keys()))
not_given= set(self.PARAMETERS.keys()).difference( set(args.keys()) )
return not_used, not_given
def _process( self, arguments ):
raise NotImplementedError(str(self.__class__)+"."+"_process")
def add_prehook( self, prehook_function ):
self._prehooks.append( prehook_function )
def add_poshook( self, poshook_function ):
self._poshooks.append( poshook_function )
def process( self, arguments):
self._input= arguments
for prehook in self._prehooks:
prehook( self )
output= self._process(arguments)
self._output= output
for poshook in self._poshooks:
poshook( self )
return output
class DisplayingProcessor( Processor ):
def display(self, display_before=False):
'''Show the last effect this processor had - on a GUI, for
example. If show_before is True, show the "state before
processor" before'''
raise NotImplementedError
class ProcessorStack( Processor ):
'''a stack of processors. Each processor's output is fed to the next'''
def __init__(self, processor_instances=[], **args):
self.set_processor_stack( processor_instances )
Processor.__init__(self, **args)
def set_processor_stack( self, processor_instances ):
assert all( isinstance(x, Processor) for x in processor_instances )
self.processors= processor_instances
def get_parameters( self ):
'''gets from all wrapped processors'''
d= {}
for p in self.processors:
parameter_names= p.PARAMETERS.keys()
parameter_values= [getattr(p, n) for n in parameter_names]
d.update( dict(zip(parameter_names, parameter_values )) )
return d
def set_parameters( self, **args ):
'''sets to all wrapped processors'''
not_used= set()
not_given=set()
for p in self.processors:
nu, ng= p.set_parameters( **args )
not_used= not_used.union(nu)
not_given= not_given.union(ng)
return not_used, not_given
def _process( self, arguments ):
for p in self.processors:
arguments= p.process( arguments )
return arguments
class DisplayingProcessorStack( ProcessorStack ):
def display(self, display_before=False):
if display_before:
pr= self.processors[1:]
self.processors.display( display_before=True )
else:
pr= self.processors
for p in pr:
if hasattr(p, "display"):
p.display( display_before= False )