def __init__(self, 
              bpm_limits = [50,160],
              data_spike_limit = 13.,
              face_detector_smoothness = 10):
     super(findFaceGetPulse, self).__init__()
     
     #-----------assembly-level I/O-----------
     
     #input array
     self.add("frame_in", Array(iotype="in"))
     #output array
     self.add("frame_out", Array(iotype="out"))
     #array of detected faces (as single frame)
     self.add("faces", Array(iotype="out"))
     
     #-----------components-----------
     # Each component we want to use must be added to the assembly, then also
     # added to the driver's workflow 
     
     #splits input color image into R,G,B channels
     self.add("RGBsplitter", RGBSplit())
     self.driver.workflow.add("RGBsplitter")
     
     #converts input color image to grayscale
     self.add("grayscale", Grayscale())
     self.driver.workflow.add("grayscale")        
     
     #equalizes contast on the grayscale'd input image
     self.add("contrast_eq", equalizeContrast())
     self.driver.workflow.add("contrast_eq")       
     
     #finds faces within the grayscale's and contast-adjusted input image
     #Sets smoothness parameter to help prevent 'jitteriness' in the face tracking
     self.add("find_faces", faceDetector(smooth = face_detector_smoothness))
     self.driver.workflow.add("find_faces")
     
     #collects subimage samples of the detected faces
     self.add("grab_faces", frameSlices())
     self.driver.workflow.add("grab_faces")
     
     #collects subimage samples of the detected foreheads
     self.add("grab_foreheads", frameSlices())
     self.driver.workflow.add("grab_foreheads")     
     
     #highlights the locations of detected faces using contrast equalization
     self.add("highlight_faces", VariableEqualizerBlock(channels=[0,1,2]))
     self.driver.workflow.add("highlight_faces")
     
     #highlights the locations of detected foreheads using 
     #contrast equalization (green channel only)
     self.add("highlight_fhd", VariableEqualizerBlock(channels=[1], 
                                                      zerochannels=[0,2]))
     self.driver.workflow.add("highlight_fhd")
     
     #collects data over time to compute a 1d temporal FFT
     # 'n' sets the internal buffer length (number of samples)
     # 'spike_limit' limits the size of acceptable spikes in the raw measured
     # data. When exceeeded due to poor data, the fft component's buffers 
     # are reset
     self.add("fft", BufferFFT(n=425,
                               spike_limit = data_spike_limit))
     self.driver.workflow.add("fft")
     
     #takes in a computed FFT and estimates cardiac data
     # 'bpm_limits' sets the lower and upper limits (in bpm) for heartbeat
     # detection. 50 to 160 bpm is a pretty fair range here.
     self.add("measure_heart", Cardiac(bpm_limits = bpm_limits))
     self.driver.workflow.add("measure_heart")
     
     #toggles flashing of the detected foreheads in sync with the detected 
     #heartbeat. the 'default_a' and 'default_b' set the nominal contrast
     #correction that will occur when phase pulsing isn't enabled.
     #Pulsing is set by toggling the boolean variable 'state'.
     self.add("bpm_flasher", PhaseController(default_a=1., 
                                             default_b=0.,
                                             state = True))
     self.driver.workflow.add("bpm_flasher")   
     
     self.add("show_bpm_text", showBPMtext())
     self.driver.workflow.add("show_bpm_text")
     
     #-----------connections-----------
     # here is where we establish the relationships between the components 
     # that were added above.
     
     #--First, set up the connectivity for components that will do basic
     #--input, decomposition, and annotation of the inputted image frame
     
     # pass image frames from the assembly-level input arrays to the RGB 
     # splitter & grayscale converters (separately)
     self.connect("frame_in", "RGBsplitter.frame_in")
     self.connect("frame_in", "grayscale.frame_in")
     
     #pass grayscaled image to the contrast equalizer
     self.connect("grayscale.frame_out", "contrast_eq.frame_in")
     
     #pass the contrast adjusted grayscale image to the face detector
     self.connect("contrast_eq.frame_out", "find_faces.frame_in")
     
     # now pass our original image frame and the detected faces locations 
     # to the face highlighter
     self.connect("frame_in", "highlight_faces.frame_in")
     self.connect("find_faces.detected", "highlight_faces.rects_in")
     
     # pass the original image frame and detected face locations
     # to the forehead highlighter
     self.connect("highlight_faces.frame_out", "highlight_fhd.frame_in")
     self.connect("find_faces.foreheads", "highlight_fhd.rects_in")
     
     # pass the original image frame and detected face locations
     # to the face subimage collector
     self.connect("find_faces.detected", "grab_faces.rects_in")
     self.connect("contrast_eq.frame_out", "grab_faces.frame_in")
     
     # --Now we set the connectivity for the components that will do the 
     # --actual analysis
     
     #pass the green channel of the original image frame and detected 
     #face locations to the forehead subimage collector
     self.connect("find_faces.foreheads", "grab_foreheads.rects_in")
     self.connect("RGBsplitter.G", "grab_foreheads.frame_in")   
     
     #send the mean of the first detected forehead subimage (green channel)
     #to the buffering FFT component
     #Should probably be an intermediate component here, but that isn't 
     #actually necessary - we can do a connection between expressions in
     #addition to input/output variables.
     #self.connect("grab_foreheads.slices[0]", "fft.data_in")
     self.connect("grab_foreheads.zero_mean", "fft.data_in")
     
     #Send the FFT outputs (the fft & associated freqs in hz) to the cardiac
     #data estimator
     self.connect("fft.fft", "measure_heart.fft_in")
     self.connect("fft.freqs", "measure_heart.freqs_in")
     
     #connect the estimated heartbeat phase to the forehead flashing controller
     self.connect("measure_heart.phase", "bpm_flasher.phase")
     self.connect("fft.ready", "bpm_flasher.state")
     
     #connect the flash controller to the forehead highlighter 
     self.connect("bpm_flasher.alpha", "highlight_fhd.alpha")
     self.connect("bpm_flasher.beta", "highlight_fhd.beta")
     
     #connect collection of all detected faces up to assembly level for output
     self.connect("grab_faces.combined", "faces")
     
     # text display of estimated bpm
     self.connect("highlight_fhd.frame_out", "show_bpm_text.frame_in") 
     self.connect("measure_heart.bpm", "show_bpm_text.bpm")
     self.connect("find_faces.detected[0][0]", "show_bpm_text.x")
     self.connect("find_faces.detected[0][1]", "show_bpm_text.y")
     self.connect("fft.fps", "show_bpm_text.fps")
     self.connect("fft.size", "show_bpm_text.size")
     self.connect("fft.n", "show_bpm_text.n")
     
     self.connect("fft.ready", "show_bpm_text.ready")
     self.connect("show_bpm_text.frame_out", "frame_out") 
     
    def __init__(self,
                 bpm_limits=[50, 160],
                 data_spike_limit=13.,
                 face_detector_smoothness=10):
        super(findFaceGetPulse, self).__init__()

        #-----------assembly-level I/O-----------

        #input array
        self.add("frame_in", Array(iotype="in"))
        #output array
        self.add("frame_out", Array(iotype="out"))
        #array of detected faces (as single frame)
        self.add("faces", Array(iotype="out"))

        #-----------components-----------
        # Each component we want to use must be added to the assembly, then also
        # added to the driver's workflow

        #splits input color image into R,G,B channels
        self.add("RGBsplitter", RGBSplit())
        self.driver.workflow.add("RGBsplitter")

        #converts input color image to grayscale
        self.add("grayscale", Grayscale())
        self.driver.workflow.add("grayscale")

        #equalizes contast on the grayscale'd input image
        self.add("contrast_eq", equalizeContrast())
        self.driver.workflow.add("contrast_eq")

        #finds faces within the grayscale's and contast-adjusted input image
        #Sets smoothness parameter to help prevent 'jitteriness' in the face tracking
        self.add("find_faces", faceDetector(smooth=face_detector_smoothness))
        self.driver.workflow.add("find_faces")

        #collects subimage samples of the detected faces
        self.add("grab_faces", frameSlices())
        self.driver.workflow.add("grab_faces")

        #collects subimage samples of the detected foreheads
        self.add("grab_foreheads", frameSlices())
        self.driver.workflow.add("grab_foreheads")

        #highlights the locations of detected faces using contrast equalization
        self.add("highlight_faces", VariableEqualizerBlock(channels=[0, 1, 2]))
        self.driver.workflow.add("highlight_faces")

        #highlights the locations of detected foreheads using
        #contrast equalization (green channel only)
        self.add("highlight_fhd",
                 VariableEqualizerBlock(channels=[1], zerochannels=[0, 2]))
        self.driver.workflow.add("highlight_fhd")

        #collects data over time to compute a 1d temporal FFT
        # 'n' sets the internal buffer length (number of samples)
        # 'spike_limit' limits the size of acceptable spikes in the raw measured
        # data. When exceeeded due to poor data, the fft component's buffers
        # are reset
        self.add("fft", BufferFFT(n=322, spike_limit=data_spike_limit))
        self.driver.workflow.add("fft")

        #takes in a computed FFT and estimates cardiac data
        # 'bpm_limits' sets the lower and upper limits (in bpm) for heartbeat
        # detection. 50 to 160 bpm is a pretty fair range here.
        self.add("measure_heart", Cardiac(bpm_limits=bpm_limits))
        self.driver.workflow.add("measure_heart")

        #toggles flashing of the detected foreheads in sync with the detected
        #heartbeat. the 'default_a' and 'default_b' set the nominal contrast
        #correction that will occur when phase pulsing isn't enabled.
        #Pulsing is set by toggling the boolean variable 'state'.
        self.add("bpm_flasher",
                 PhaseController(default_a=1., default_b=0., state=True))
        self.driver.workflow.add("bpm_flasher")

        self.add("show_bpm_text", showBPMtext())
        self.driver.workflow.add("show_bpm_text")

        #-----------connections-----------
        # here is where we establish the relationships between the components
        # that were added above.

        #--First, set up the connectivity for components that will do basic
        #--input, decomposition, and annotation of the inputted image frame

        # pass image frames from the assembly-level input arrays to the RGB
        # splitter & grayscale converters (separately)
        self.connect("frame_in", "RGBsplitter.frame_in")
        self.connect("frame_in", "grayscale.frame_in")

        #pass grayscaled image to the contrast equalizer
        self.connect("grayscale.frame_out", "contrast_eq.frame_in")

        #pass the contrast adjusted grayscale image to the face detector
        self.connect("contrast_eq.frame_out", "find_faces.frame_in")

        # now pass our original image frame and the detected faces locations
        # to the face highlighter
        self.connect("frame_in", "highlight_faces.frame_in")
        self.connect("find_faces.detected", "highlight_faces.rects_in")

        # pass the original image frame and detected face locations
        # to the forehead highlighter
        self.connect("highlight_faces.frame_out", "highlight_fhd.frame_in")
        self.connect("find_faces.foreheads", "highlight_fhd.rects_in")

        # pass the original image frame and detected face locations
        # to the face subimage collector
        self.connect("find_faces.detected", "grab_faces.rects_in")
        self.connect("contrast_eq.frame_out", "grab_faces.frame_in")

        # --Now we set the connectivity for the components that will do the
        # --actual analysis

        #pass the green channel of the original image frame and detected
        #face locations to the forehead subimage collector
        self.connect("find_faces.foreheads", "grab_foreheads.rects_in")
        self.connect("RGBsplitter.G", "grab_foreheads.frame_in")

        #send the mean of the first detected forehead subimage (green channel)
        #to the buffering FFT component
        #Should probably be an intermediate component here, but that isn't
        #actually necessary - we can do a connection between expressions in
        #addition to input/output variables.
        self.connect("grab_foreheads.slices[0].mean()", "fft.data_in")

        #Send the FFT outputs (the fft & associated freqs in hz) to the cardiac
        #data estimator
        self.connect("fft.fft", "measure_heart.fft_in")
        self.connect("fft.freqs", "measure_heart.freqs_in")

        #connect the estimated heartbeat phase to the forehead flashing controller
        self.connect("measure_heart.phase", "bpm_flasher.phase")
        self.connect("fft.ready", "bpm_flasher.state")

        #connect the flash controller to the forehead highlighter
        self.connect("bpm_flasher.alpha", "highlight_fhd.alpha")
        self.connect("bpm_flasher.beta", "highlight_fhd.beta")

        #connect collection of all detected faces up to assembly level for output
        self.connect("grab_faces.combined", "faces")

        # text display of estimated bpm
        self.connect("highlight_fhd.frame_out", "show_bpm_text.frame_in")
        self.connect("measure_heart.bpm", "show_bpm_text.bpm")
        self.connect("find_faces.detected[0][0]", "show_bpm_text.x")
        self.connect("find_faces.detected[0][1]", "show_bpm_text.y")
        self.connect("fft.fps", "show_bpm_text.fps")
        self.connect("fft.size", "show_bpm_text.size")
        self.connect("fft.n", "show_bpm_text.n")

        self.connect("fft.ready", "show_bpm_text.ready")
        self.connect("show_bpm_text.frame_out", "frame_out")