Lazyflow operators encapsulate a small part of a computation. The requirements from a user perspective on an operator are.
• Define inputs and outputs of the computation
• Define how properties of the output slots depend on properties of the input slots • Define the computation
• Define how dirty inputs propagate to the outputs of a computation
These requirements are directly reflected in the application programming interface (API) of lazyflow, as we will see in the following sections.
Inheriting from the operator class and defining inputs and outputs
To implement an operator, the user has to derive from the Operator base class and has to imple- ment several methods that define the behaviour of the operator.
from l a z y f l o w.gra ph i m p o r t Operator, InputSlot, O u t p u t S l o t
from l a z y f l o w.sty pe i m p o r t A r r a y L i k e
class S u m O p e r a t o r(O p e r a t o r) :
i n p u t A = I n p u t S l o t(sty pe=A r r a y L i k e)
i n p u t B = I n p u t S l o t(sty pe=A r r a y L i k e)
7.2 Lazyflow operators
def s e t u p O u t p u t s(self) :
pass
def e x e c u t e(self, slot, subindex, roi, r e s u l t) :
pass
def p r o p a g a t e D i r t y(self, slot, subindex, roi) :
pass
The setupOutputs method
This method is called when all InputSlots of an operator are connected and ready. The con- nection partner can either be the OutputSlot of another operator or directly a data source. The method receives no arguments and is responsible for setting up the neccessary meta information for the output slots. Once an operator has set up the meta information of an OutputSlot, this OutputSlot will become ready. Meta information on the OutputSlots can contain such informa- tion as the shape of the OutputSlot or the data type of the OutputSlot. This information is not known beforehand and can only be determined once all InputSlots are connected. The most simple example is a pipe Operator which just copies its input to the output. The shape of the OutputSlot is only known once an InputSlot has been connected.
The execute method
The execute method receives several arguments: slot, subindex, roi and result. The execute method is called, when somebody requests data from an OutputSlot of an operator. The Output- Slot for which data was requested is given in the slot argument. In addition, when requesting data from an OutputSlot the user can specify a region of interest (roi). This region of interest that the user specified is given in the roi argument. The result argument holds a preallocated data area of correct size (compatible with the roi) into which the operator must write the result of its computation.
The propagateDirty method
The propagateDirty method receives as arguments a slot, subindex and a roi. This method is called by the operator base class whenever an InputSlot of the operator is set to dirty. This InputSlot is given in the slot argument. The region of interest of the slot which was set to dirty is given in the roi argument. The responsibility of the operator is to determine which OutputSlot becomes dirty in which region depending on the arguments that it was called with. In a simple case, such as an Operator which just pipes its InputSlot to the OutputSlot, the OutputSlot would be set to dirty in the same region that the InputSlot became dirty.
Simple SumOperator example
Below is a simple but fully functional example of an operator that has two input slots and one output slot. The computation which the operators performs is adding the two inputs.
from l a z y f l o w.gra ph i m p o r t Operator, InputSlot, O u t p u t S l o t
from l a z y f l o w.sty pe i m p o r t A r r a y L i k e class S u m O p e r a t o r(O p e r a t o r) : i n p u t A = I n p u t S l o t(sty pe=A r r a y L i k e) i n p u t B = I n p u t S l o t(sty pe=A r r a y L i k e) o u t p u t = O u t p u t S l o t(sty pe=A r r a y L i k e) def s e t u p O u t p u t s(self) :
# get the s hap e of the o p e r a t o r i n p u t s
s h a p e A = self.i n p u t A.meta.sha pe s h a p e B = self.i n p u t B.meta.sha pe
# c hec k that the i n p u t s have the same sha pe
a s s e r t s h a p e A == s h a p e B
# s etu p the s hap e of the o u t p u t slot
self.o u t p u t.meta.s hap e = s h a p e A
# s etu p the d typ e of the o u t p u t slot
self.o u t p u t.meta.d typ e = self.i n p u t A.meta.dty pe
def e x e c u t e(self, slot, subindex, roi, r e s u l t) :
# the f o l l o w i n g two l ine s r e q u e s t the i n p u t s of the # o p e r a t o r for the s p e c i f i f e d r e g i o n of i n t e r e s t
a = self.i n p u t A.get(roi) .wait()
b = self.i n p u t B.get(roi) .wait()
# the r e s u l t of the c o m p u t a t i o n is w r i t t e n into the # pre - a l l o c a t e d r e s u l t a rr ay
r e s u l t[:] = a+b
def p r o p a g a t e D i r t y(self, slot, subindex, roi) :
# the m e t h o d r e c e i v e s as a r g u m e n t the slot
# w hic h was changed , and the r e g i o n of i n t e r e s t ( roi ) # that was c h a n g e d in the slot
# in this case the m a p p i n g of the dir ty # r e g i o n is simple , it c o r r e s p o n d s e x a c t l y # to the r e g i o n of i n t e r e s t that was c h a n g e d in # one of the i npu t s lot s