def QPHIMapStream(bins=(800, 360)):
    ''' Transform the scattering image into a q, phi map.

        Parameters
        ----------
            bins : 2 tuple, optional
                the number of bins to divide into

        **Stream Inputs**
            img : 2d np.ndarray
                the image

            mask : 2d np.ndarray, optional
                the mask

            origin : 2 tuple
                the beam center in the image

            qmap : 2d np.ndarray
                the qmap of the image

        **Stream Outputs**
            sqphi : 2d np.ndarray
                the sqphi map

            qs : 1d np.ndarray
                the q values

            phis : 1d np.ndarray
                the phi values

        Returns
        -------
            sin : Stream instance
                the input stream (see Stream Inputs)

            sout : Stream instance
                the output stream (see Stream Outputs)

        Examples
        --------
        >>> bins = (3, 4)
        >>> sin, sout = QPHIMapStream(bins=bins)
        >>> L = sout.sink_to_list()
        >>> mask = None
        >>> img = np.random.random((10, 10))
        >>> origin = (3, 3)
        >>> sdoc = StreamDoc(kwargs=dict(image=img,
        ...                  origin=origin,
        ...                  mask=mask))
        >>> sin.emit(sdoc)
    '''
    sin = sc.Stream(stream_name="QPHI map Stream")
    sout = scs.map(qphiavg, sin, bins=bins)
    sout = scs.add_attributes(sout, stream_name="qphiavg")

    return sin, sout
def ThumbStream(blur=None, crop=None, resize=None):
    ''' Thumbnail stream

        **Stream Inputs**
            image : 2d np.ndarray
                the image

        **Stream Outputs**
            sin : Stream instance
                the stream input

            sout : Stream instance
                the stream output

        Parameters
        ----------
            blur : float, optional
                the sigma of the Gaussian kernel to convolve image with
                for smoothing
                default is None, no smoothing

            crop : 4 tuple of int, optional
                the boundaries to crop by
                default is None, no cropping

            resize : int, optional
                the factor to resize by
                for example resize=2 performs 2x2 binning of the image

        Stream Inputs
        -------------
            image : 2d np.ndarray
                the image

        Returns
        -------
            sin :
                the stream input

            sout :
                the stream output
    '''
    # TODO add flags to actually process into thumbs
    sin = sc.Stream(stream_name="Thumbnail Stream")
    sout = scs.add_attributes(sin, stream_name="thumb")
    # s1 = sin.add_attributes(stream_name="ThumbStream")
    sout = scs.map(_blur, sout, sigma=blur, remote=True)
    sout = scs.map(_crop, sout, crop=crop, remote=True)
    sout = scs.map(_resize, sout, resize=resize, remote=True)
    # change the key from image to thumb
    sout = scs.select(sout, ('image', 'thumb'))

    return sin, sout
def PeakFindingStream(name='peakfind'):
    ''' Find peaks in 1d line data.

        **Stream Inputs**
            sqx : 1d np.ndarray
                the x domain of the curve

            sqy : 1d np.ndarray
                the y domain of the curve

        **Stream Outputs**
            model: lmfit.Model instance
                The model for the fit

            y_origin:

            inds_peak: list
               the peak indices

            xdata:

            ratio:

            ydata:

            wdata:

            bkgd:

            variance:

            variance_mean:

            peaksx:

            peaksy:

        Parameters
        ----------
        name : str, optional
            name of stream
    '''
    sin = sc.Stream(stream_name="Peak Finder")
    # pkfind stream
    sout = scs.map(call_peak, scs.select(sin, 'sqy', 'sqx'))
    sout = scs.add_attributes(sout, stream_name=name)
    return sin, sout
def ImageTaggingStream():
    ''' Creates an image tagging stream.

        This stream will take in an image and output a tage as to what the
        image is.

        **Stream Inputs**
            image : 2d np.ndarray
                the image to be tagged

        **Stream Outputs**
            tag_name : str
                the name of the tag for the image
    '''
    sin = sc.Stream(stream_name="Image Tagger")
    sout = scs.map(infer, scs.select(sin, 'image'))
    sout = scs.add_attributes(sout, stream_name="image-tag")
    return sin, sout
def AngularCorrelatorStream(bins=(800, 360)):
    ''' Stream to run angular correlations.

        **Stream Inputs**
            image : 2d np.ndarray
                the image to run the angular correltions on

            mask : 2d np.ndarray
                the mask

            origin : 2 tuple
                the beam center of the image

            bins : tuple
                the number of bins in q and phi

            method : string, optional
                the method to use for the angular correlations
                defaults to 'bgest'

            q_map : the q_map to be used

        **Stream Outputs**
            sin : Stream instance
                the stream input

            sout : Stream instance
                the stream output
    '''
    # TODO : Allow optional kwargs in streams
    sin = sc.Stream(stream_name="Angular Correlation")
    sout = scs.select(sin, ('image', 'image'), ('mask', 'mask'),
                      ('origin', 'origin'), ('q_map', 'r_map'))
    sout = scs.map(angular_corr, sout, bins=bins)
    sout = scs.add_attributes(sout, stream_name="angular-corr")
    return sin, sout
示例#6
0
# L_attributes = sout_attributes.sink_to_list()
sout_primary.connect(sin_attributes)

sout_filled = scs.merge(sc.zip(sout_filled,
                               scs.to_attributes(sout_attributes)))

sin_calib, sout_calib = CalibrationStream()
sout_attributes.connect(sin_calib)
# L_calib = sout_calib.sink_to_list()

# sout_calib2 = sout_calib
# sout_calib = sc.Stream()

# the PrimaryFilteringStream already split the detectors
# s_image = sc.Stream()
s_image = scs.add_attributes(sout_filled, stream_name="image")
# L_image = s_image.sink_to_list()

# TODO : fix and remove this is for pilatus300 should be in mask gen
s_mask = scs.map(generate_mask, sout_attributes)
# L_mask = s_mask.sink_to_list()

# #s_zipped =
# #L_zipped= s_zipped.sink_to_list()
s_imgmaskcalib = scs.merge(sc.zip(s_image, sout_calib, s_mask))

# L_imgmaskcalib = s_imgmaskcalib.sink_to_list()


# some small streams
def get_origin(**kwargs):
def ImageStitchingStream(return_intermediate=False):
    '''
        Image stitching

        **Stream Inputs**
            image : 2d np.ndarray
                the image for the stitching

            mask : 2d np.ndarray
                the mask

            origin : 2 tuple
                the beam center

            stitchback : bool
                whether or not to stitchback to previous image

        **Stream Outputs**
            image : 2d np.ndarray
                the stitched image

            mask : 2d np.ndarray
                the mask from the stitch

            origin : 2 tuple
                the beam center

            stitchback : bool
                whether or not to stitchback to previous image

        Returns
        -------
            sin : Stream instance
                the input stream

            sout : Stream instance
                the output stream

        Parameters
        ----------
            return_intermediate : bool, optional
                decide whether to return intermediate results or not
                defaults to False

        Notes
        -----
        Any normalization of images (for ex: by exposure time) should be done
        before inputting to this stream.

        Examples
        --------
        >>> sin, sout = ImageStitchingStream()
        >>> L = sout.sink_to_list()
        >>> mask = np.ones((10, 10), dtype=np.int64)
        >>> img1 = np.ones_like(mask, dtype=float)
        >>> # 3 rows are higher
        >>> img1[2:4] = 2
        >>> # some arb value
        >>> origin1 = [2, 3]
        >>> # roll along zero axis
        >>> img2 = np.roll(img1, 2, axis=0)
        >>> # rolled by two
        >>> origin2 = [2+2, 3]
        >>> # first image, stitchback can be anything
        >>> sdoc1 = StreamDoc(kwargs=dict(mask=mask, image=img1,
        ...                               origin=origin1,
        ...                               stitchback=False))
        >>> sin.emit(sdoc1)
        >>> # emit a second image and it will be stitched
        >>> sdoc2 = StreamDoc(kwargs=dict(mask=mask, image=img2,
        ...                               origin=origin2,
        ...                               stitchback=True))
        >>> sin.emit(sdoc2)
        >>> # A new image with False stitchback will have output
        >>> # stream output a result
        >>> img3 = np.random.random((10,10))
        >>> origin3 = (0,0)
        >>> sdoc3 = StreamDoc(kwargs=dict(mask=mask, image=img3,
        ...                               origin=origin3,
        ...                               stitchback=False))
        >>> sin.emit(sdoc3)
        >>> len(L) == 1
        True
        >>> # the stitched image is here:
        >>> img = L[0]['kwargs']['image']
    '''

    # TODO : add state. When False returned, need a reason why
    def validate(x):
        if not hasattr(x, 'kwargs'):
            raise ValueError("No kwargs")
        kwargs = x['kwargs']
        expected = ['mask', 'origin', 'stitchback', 'image']
        for key in expected:
            if key not in kwargs:
                message = "{} not in kwargs".format(key)
                raise ValueError(message)
        if not isinstance(kwargs['mask'], np.ndarray):
            message = "mask is not array"
            raise ValueError(message)

        if not isinstance(kwargs['image'], np.ndarray):
            message = "image is not array"
            raise ValueError(message)

        if len(kwargs['origin']) != 2:
            message = "origin not length 2"
            raise ValueError(message)
        return x

    # TODO : remove the add_attributes part and just keep stream_name
    sin = sc.Stream(stream_name="Image Stitching Stream")
    # sout = sc.map(sin, validate)
    # sin.map(lambda x : print("Beginning of stream data\n\n\n"))
    # TODO : remove compute requirement
    # TODO : incomplete
    sout = scs.add_attributes(sin, stream_name="stitch")

    sout = scs.select(sout, ('image', None), ('mask', None), ('origin', None),
                      ('stitchback', None))

    # put all args into a tuple
    def pack(*args):
        return args

    sout = scs.map(pack, sout)
    # sout = scs.map(s3.map(psdm(pack))
    sout = scs.accumulate(_xystitch_accumulate, sout)

    sout = scs.map(scs.star(_xystitch_result), sout)

    def stitchbackcomplete(xtuple):
        ''' only plot images whose stitch is complete, and only involved more
        than one image
        NOTE : *Only* the bool "True" will activate a stitch. "1" does not
        count. This is handled by checking 'is True' and 'is not True'
        '''
        # previous must have been true for stitch to have involved more than
        # one image
        prev = xtuple[0]['kwargs']['stitchback']
        # next must be False (or just not True) to be complete
        next = xtuple[1]['kwargs']['stitchback']

        return next is not True and prev is True

    # swin.map(lambda x : print("result : {}".format(x)), raw=True)

    # only get results where stitch is stopped
    # NOTE : need to compute before filtering here

    # now emit some dummy value to swin, before connecting more to stream
    # swin.emit(dict(attributes=dict(stitchback=0)))

    # TODO : figure out how to filter
    if not return_intermediate:
        # keep previous two results
        sout = sout.sliding_window(2)
        sout = sout.filter(stitchbackcomplete)
        sout = sout.map(lambda x: x[0])

    return sin, sout
def LineCutStream(axis=0, name=None):
    ''' Obtain line cuts from a 2D image.

        Just simple slicing. It's a stream mainly to make this more standard.

        Parameters
        ----------
            axis : int, optional
                the axis to obtain linecuts from.
                Default is 0 (so we index rows A[i])
                If 1, the index cols (A[:,i])

            name : str, optional
                the name of the stream

        **Stream Inputs**
            image : 2d np.ndarray
                the image to obtain line cuts from

            y : 1d np.ndarray
                The y (row) values per pixel

            x : The x (column) values per pixel

            vals : list
                the values to obtain the linecuts from

        **Stream Outputs**
            linecuts : list
                a list of line cuts

            linecuts_domain : 1d np.ndarray
                the domain of the line cuts

            linecuts_vals : 1d np.ndarray
                the corresponding value for each line cut

        Returns
        -------
            sin : Stream instance
                the input stream (see Stream Inputs)

            sout : Stream instance
                the output stream (see Stream Outputs)
    '''
    def linecuts(image, y, x, vals, axis=0):
        ''' Can potentially return an empty list of linecuts.'''

        linecuts = list()
        linecuts_vals = list()
        if axis == 1:
            # swap x y and transpose
            tmp = y
            y = x
            x = tmp

        linecuts_domain = x
        for val in vals:
            ind = np.argmin(np.abs(y - val))
            linecuts.append(image[ind])
            linecuts_vals.append(y[ind])

        return dict(linecuts=linecuts,
                    linecuts_domain=linecuts_domain,
                    linecuts_vals=linecuts_vals)

    # the string for the axis
    axisstr = ['y', 'x'][axis]
    if name is None:
        stream_name = 'linecuts-axis{}'.format(axisstr)
    else:
        stream_name = name + "-axis{}".format(axisstr)

    sin = sc.Stream(stream_name=stream_name)
    sout = scs.map(linecuts, sin, axis=axis)

    sout = scs.add_attributes(sout, stream_name=stream_name)
    return sin, sout
def CircularAverageStream():
    ''' Circular average stream.

        **Stream Inputs**
            image : 2d np.ndarray
                the image to run circular average on

            calibration : 2D np.ndarray
                the calibration object, with members:
                    q_map : 2d np.ndarray
                        the magnite of the wave vectors

                    r_map : 2d np.ndarray
                        the pixel positions from center

            mask : 2d np.ndarray, optional
                the mask

            bins : int or tuple, optional
                if an int, the number of bins to divide into
                if a list, the bins to use

        **Stream Outputs**

            sqx : 1D np.ndarray
                the q values
            sqxerr : 1D np.ndarray
                the error q values
            sqy : 1D np.ndarray
                the intensities
            sqyerr : 1D np.ndarray
                the error in intensities (approximate)

        Notes
        -----
            Assumes square pixels

            Assumes variance comes from shot noise only (by taking average
            along ring/Npixels)

            If bins is None, it does its best to estimate pixel sizes and make
            the bins a pixel in size. Note, for Ewald curvature this is not
            straightforward. You need both a r_map in pixels from the center
            and the q_map for the actual q values.

        Returns
        -------
        sin : Stream instance
            the source stream (see Stream Inputs)

        sout : Stream instance
            the output stream (see Stream Outputs)

        Examples
        --------
        >>> from streamz import Stream
        >>> from SciStreams import StreamDoc
        >>> import numpy as np
        >>> s = Stream()
        >>> from SciStreams.streams.XS_Streams import CircularAverageStream
        >>> sin, sout = CircularAverageStream()
        >>> s.connect(sin)
        >>> mask = None
        >>> bins = 3
        >>> img = np.random.random((10, 10))
        >>> x = np.linspace(-5, 5, 10)
        >>> X, Y = np.meshgrid(x, x)
        >>> r_map = np.sqrt(X**2 + Y**2)
        >>> q_map = r_map*.12
        >>> class Calib:
        ...     def __init__(self, qmap, rmap):
        ...         self.q_map = qmap
        ...         self.r_map = rmap
        >>> calibration = Calib(q_map, r_map)
        >>> sdoc = StreamDoc(kwargs=dict(image=img,
        ...                  calibration=calibration,
        ...                  mask=mask,
        ...                  bins=bins))
        >>> # emit data as usual
        >>> sin.emit(sdoc)
    '''

    # TODO : extend file to mltiple writers?
    def validate(x):
        kwargs = x['kwargs']
        if 'image' not in kwargs or 'calibration' not in kwargs:
            message = "expected two kwargs: "
            message += "(image, calibration), "
            message += "got {} instead".format(list(kwargs.keys()))
            raise ValueError(message)

        # kwargs are optional so don't validate them
        return x

    sin = sc.Stream(stream_name="Circular Average")
    sout = scs.add_attributes(sin, stream_name="circavg")
    # No validation for now
    # validation should not be necessary, should just throw an error
    # sout = sout.map(validate)
    sout = scs.map(circavg_from_calibration, sout)

    return sin, sout
示例#10
0
def PrimaryFilteringStream():
    ''' Filter the stream for just primary results.

        **Stream Inputs**

            md : dict
                No requirements

            data : dict
                must have a 2D np.ndarray with one of accepted detector
                keys
        **Stream Outputs**
            Two streams are outputted, sout and serr

            sout : the stream with valid data
                Outputs from zero to any number streams
                (depends on how many detectors were found)
                md :
                    detector_key : the detector key (string)
                data :
                    data with only one image as detector key
                    if there was more than one, it selects one of them
                    Note this has unspecified behaviour.
            serr : the stream with bad data. This can be sinked to an error
                stream

        Examples
        --------
        >>> # A typical workflow is as follows:
        >>> # instantiate the main stream input
        >>> from streamz import Stream
        >>> s = Stream()
        >>> # create the filtering stream
        >>> from SciStreams.streams.XS_Streams import PrimaryFilteringStream
        >>> sin, sout = PrimaryFilteringStream()
        >>> s.connect(sin)
        >>> import numpy as np
        >>> # create dummy detector image, from pilatus300
        >>> img = np.random.random((619, 487))
        >>> from SciStreams.core.StreamDoc import StreamDoc
        >>> sdoc = StreamDoc(kwargs=dict(pilatus300_image=img))
        >>> # save result in a list L that you can review later
        >>> L = sout.sink_to_list()
        >>> # emit the data
        >>> s.emit(sdoc)

        Returns
        -------
        sin : Stream instance
            the source stream (see Stream Inputs)

        sout : Stream instance
            the output stream (see Stream Outputs)
    '''
    sin = sc.Stream(stream_name="Primary Filter")
    # a primary filter, data will not go through if does not match attributes
    sout = sin.filter(filter_attributes)
    # get the error streams attributes (to output to some log)
    serr = sin.filter(lambda x: not filter_attributes)
    serr = scs.get_attributes(serr)
    serr = scs.add_attributes(serr, error="primary_filter")
    sout = sc.map(sout, pick_allowed_detectors)
    # turn list into individual streams
    # (if empty list, emits nothing, this is sort of like filter)
    sout = sout.concat()
    # just some checks to see if it's good data, else ignore
    return sin, sout, serr