Пример #1
0
    def _extract_st_rois(input_rois, min_area):
        """ Extract ROIs from the spatio-temporal components

        Parameters
        ----------
        input_rois : ROIList
            list of ROIs
        min_area : int
            The minimum size in number of pixels that an ROI can be.

        Returns
        -------
        rois : list
            A list of sima.ROI ROI objects
        """
        rois = []
        for frame in input_rois:
            img = np.array(frame)
            img[np.where(img > 0)] = 1
            img, seg_count = ndimage.measurements.label(img)
            for i in range(seg_count):
                segment = np.where(img == i + 1)
                if segment[0].size >= min_area:
                    thisroi = np.zeros(img.shape, 'bool')
                    thisroi[segment] = True
                    rois.append(ROI(mask=thisroi, im_shape=thisroi.shape))
        return rois
Пример #2
0
    def apply(self, rois, dataset=None):
        """ Remove overlapping ROIs

        Parameters
        ----------
        rois : list
            list of sima.ROI ROIs
        percent_overlap : float
            percent of the smaller ROIs total area which must be covered in
            order for the ROIs to be evaluated as overlapping

        Returns
        -------
        rois : list
            A list of sima.ROI ROI objects with the overlapping ROIs combined
        """

        for roi in rois:
            roi.mask = roi.mask

        for i in range(len(rois)):  # TODO: more efficient strategy
            for j in [j for j in range(len(rois)) if j != i]:
                if rois[i] is not None and rois[j] is not None:
                    overlap = np.logical_and(rois[i], rois[j])
                    small_area = min(np.size(rois[i]), np.size(rois[j]))

                    if len(np.where(overlap)[0]) > \
                            self.percent_overlap * small_area:
                        new_shape = np.logical_or(rois[i], rois[j])

                        rois[i] = ROI(mask=new_shape.astype('bool'))
                        rois[j] = None
        return ROIList(roi for roi in rois if roi is not None)
Пример #3
0
def simplifyRoi():
    roi_id = request.form.get('roiId')
    frame_shape = json.loads(request.form.get('frame_shape'))
    points = json.loads(request.form.get('points'))

    roi_data = []
    for i, plane in enumerate(points):
        if plane is None or not len(plane):
            continue
        array_dat = np.array(plane)
        z_dims = i * np.ones((array_dat.shape[:2] + (1, )))
        plane_data = np.concatenate((array_dat, z_dims), axis=2)
        roi_data.extend(list(plane_data))
    try:
        roi = ROI(polygons=roi_data, im_shape=frame_shape[:3])
    except:
        return jsonify(result='failed to create ROI')

    smoother = SmoothROIBoundaries()
    roi = smoother.apply([roi])[0]

    convertedRoi = []
    try:
        for i in xrange(roi.im_shape[0]):
            convertedRoi.append([])
    except:
        for i in xrange(np.max(np.array(roi.coords)[:, :, 2])):
            convertedRoi.append([])
    for poly in roi.polygons:
        coords = np.array(poly.exterior.coords)
        plane = int(coords[0, -1])
        coords = coords[:, :2].astype(int).tolist()
        convertedRoi[plane].append(coords)

    return jsonify({roi_id: {'points': convertedRoi}})
Пример #4
0
    def _segment(self, dataset):

        channel = sima.misc.resolve_channels(self._params['channel'],
                                             dataset.channel_names)
        if dataset.savedir is not None:
            pca_path = os.path.join(dataset.savedir,
                                    'opca_' + str(channel) + '.npz')
        else:
            pca_path = None

        if dataset.savedir is not None:
            ica_path = os.path.join(dataset.savedir,
                                    'ica_' + str(channel) + '.npz')
        else:
            ica_path = None

        if self._params['verbose']:
            print('performing PCA...')
        components = self._params['components']
        if isinstance(components, int):
            components = list(range(components))
        _, space_pcs, time_pcs = oPCA.dataset_opca(
            dataset, channel, components[-1] + 1, path=pca_path)
        space_pcs = np.real(space_pcs)

        if self._params['verbose']:
            print('performing ICA...')
        st_components = _stica(
            space_pcs, time_pcs, mu=self._params['mu'], path=ica_path,
            n_components=space_pcs.shape[-1])

        return ROIList([ROI(st_components[..., i]) for i in
                        range(st_components.shape[-1])])
Пример #5
0
def _extract_st_rois(frames, min_area=50, spatial_sep=True):
    """ Extract ROIs from the spatio-temporal components

    Parameters
    ----------
    frames : list
        list of arrays containing stICA components
    min_area : int
        The minimum size in number of pixels that an ROI can be. Default: 50
    spatial_sep : bool
        If True, the stICA components will be segmented spatially and
        non-contiguous poitns will be made into sparate ROIs. Default: True

    Returns
    -------
    rois : list
        A list of sima.ROI ROI objects
    """

    rois = []
    for frame_no in range(len(frames)):
        img = np.array(frames[frame_no])

        img[np.where(img > 0)] = 1
        img, seg_count = measurements.label(img)
        component_mask = np.zeros(img.shape, 'bool')

        for i in xrange(seg_count):
            segment = np.where(img == i + 1)
            if segment[0].size >= min_area:
                if spatial_sep:
                    thisroi = np.zeros(img.shape, 'bool')
                    thisroi[segment] = True
                    rois.append(ROI(mask=thisroi, im_shape=thisroi.shape))
                else:
                    component_mask[segment] = True
        if not spatial_sep and np.any(component_mask):
            rois.append(ROI(mask=component_mask, im_shape=thisroi.shape))

        frame_no = frame_no + 1

    return rois
Пример #6
0
    def __call__(self, roi):

        roi_static = []
        roi_cpy = np.array(roi)
        for frame in roi_cpy:
            # copy the component, remove pixels with low weights
            frame[frame < 2 * np.std(frame)] = 0

            # smooth the component via static removal and gaussian blur
            for _ in range(self.x_smoothing):
                check = frame[1:-1, :-2] + frame[1:-1, 2:] + \
                    frame[:-2, 1:-1] + frame[2, 1:-1]
                z = np.zeros(frame.shape)
                z[1:-1, 1:-1] = check
                frame[np.logical_not(z)] = 0

                blurred = ndimage.gaussian_filter(frame, sigma=1)
                frame = blurred + frame

                frame = frame / np.max(frame)
                frame[frame < 2 * np.std(frame)] = 0

            # calculate the remaining static in the component
            static = np.sum(np.abs(frame[1:-1, 1:-1] - frame[:-2, 1:-1])) + \
                np.sum(np.abs(frame[1:-1, 1:-1] - frame[2:, 1:-1])) + \
                np.sum(np.abs(frame[1:-1, 1:-1] - frame[1:-1, :-2])) + \
                np.sum(np.abs(frame[1:-1, 1:-1] - frame[1:-1, 2:])) + \
                np.sum(np.abs(frame[1:-1, 1:-1] - frame[2:, 2:])) + \
                np.sum(np.abs(frame[1:-1, 1:-1] - frame[:-2, 2:])) + \
                np.sum(np.abs(frame[1:-1, 1:-1] - frame[2:, :-2])) + \
                np.sum(np.abs(frame[1:-1, 1:-1] - frame[:-2, :-2]))

            static = np.sum(static) * 2.0 / (frame.shape[0] * frame.shape[1])
            roi_static.append(static)

        # decide if the component should be accepted or rejected
        if np.mean(static) < self.threshold:
            return ROI(mask=roi_cpy), ROI(mask=roi), None
        else:
            return None, None, ROI(mask=roi)
Пример #7
0
def updateRoi():
    ds_path = request.form.get('path')
    label = request.form.get('label')
    points = json.loads(request.form.get('points'))
    roi_label = request.form.get('roiLabel')
    roi_id = request.form.get('roiId')

    dataset = ImagingDataset.load(ds_path)
    roi_data = []
    for i, plane in enumerate(points):
        if plane is None or not len(plane):
            continue
        array_dat = np.array(plane)
        z_dims = i * np.ones((array_dat.shape[:2] + (1, )))
        plane_data = np.concatenate((array_dat, z_dims), axis=2)
        roi_data.extend(list(plane_data))

    if len(roi_data) == 0:
        return jsonify(result="no polygons to save")

    for poly in roi_data:
        if poly.shape[0] < 3:
            raise Exception("unable to store polygon with less then 3 points")
    roi = ROI(polygons=roi_data, im_shape=dataset.frame_shape[:3])

    roi.label = roi_label
    roi.id = roi_id
    try:
        rois = dataset.ROIs[label]
    except KeyError:
        rois = []

    rois = filter(lambda r: r.id != roi_id, rois)
    rois.append(roi)
    dataset.add_ROIs(ROIList(rois), label=label)

    return jsonify(result='success')
Пример #8
0
    def __call__(self, roi):
        smoothed_polygons = []
        coords = roi.coords
        for polygon in coords:
            if polygon.shape[0] > self.min_verts:
                plane = polygon[0, -1]
                smoothed_coords = approximate_polygon(polygon[:, :2],
                                                      self.tolerance)
                smoothed_coords = np.hstack((smoothed_coords, plane * np.ones(
                    (smoothed_coords.shape[0], 1))))
            else:
                smoothed_coords = polygon

            smoothed_polygons += [smoothed_coords]

        return ROI(polygons=smoothed_polygons, im_shape=roi.im_shape)
Пример #9
0
    def apply(self, rois, dataset):
        channel = sima.misc.resolve_channels(self._channel,
                                             dataset.channel_names)
        processed_im = _processed_image_ca1pc(dataset, channel,
                                              self._x_diameter,
                                              self._y_diameter)[0]
        shape = processed_im.shape[:2]
        ROIs = ROIList([])
        for roi in rois:
            roi_indices = np.nonzero(roi.mask[0])
            roi_indices = np.ravel_multi_index(roi_indices, shape)

            # pixel values in the cut
            vals = processed_im.flat[roi_indices]

            # indices of those values below the otsu threshold
            # if all values are identical, continue without adding an ROI
            try:
                roi_indices = roi_indices[vals < threshold_otsu(vals)]
            except ValueError:
                continue

            # apply binary opening and closing to the surviving pixels
            # expand the shape by 1 in all directions to correct for edge
            # effects of binary opening/closing
            twoD_indices = [np.unravel_index(x, shape) for x in roi_indices]
            mask = np.zeros([x + 2 for x in shape])
            for indices in twoD_indices:
                mask[indices[0] + 1, indices[1] + 1] = 1
            mask = ndimage.binary_closing(ndimage.binary_opening(mask))
            mask = mask[1:-1, 1:-1]
            roi_indices = np.where(mask.flat)[0]

            # label blobs in each cut
            labeled_array, num_features = measurements.label(mask)
            for feat in range(num_features):
                blob_inds = np.where(labeled_array.flat == feat + 1)[0]

                twoD_indices = [np.unravel_index(x, shape) for x in blob_inds]
                mask = np.zeros(shape)
                for x in twoD_indices:
                    mask[x] = 1

                ROIs.append(ROI(mask=mask))

        return ROIs
Пример #10
0
    def _rois_from_cuts(cls, cuts):
        """Return ROI structures each containing the full extent of a cut.

        Parameters
        ----------
        cuts : list of sima.normcut.CutRegion
            The segmented regions identified by normalized cuts.

        Returns
        -------
        sima.ROI.ROIList
            ROI structures corresponding to each cut.
        """
        ROIs = ROIList([])
        for cut in cuts:
            if len(cut.indices):
                mask = np.zeros(cut.shape)
                for x in cut.indices:
                    mask[np.unravel_index(x, cut.shape)] = 1
                ROIs.append(ROI(mask=mask))
        return ROIs
Пример #11
0
    def _segment(self, dataset):

        channel = sima.misc.resolve_channels(self._params['channel'],
                                             dataset.channel_names)
        if dataset.savedir is not None:
            pca_path = os.path.join(dataset.savedir,
                                    'opca_' + str(channel) + '.npz')
        else:
            pca_path = None

        if dataset.savedir is not None:
            ica_path = os.path.join(dataset.savedir,
                                    'ica_' + str(channel) + '.npz')
        else:
            ica_path = None

        if self._params['verbose']:
            print('performing PCA...')
        components = self._params['components']
        if isinstance(components, int):
            components = list(range(components))
        _, space_pcs, time_pcs = oPCA.dataset_opca(
            dataset, channel, components[-1] + 1, path=pca_path)
        space_pcs = np.real(space_pcs)

        # Remove components greater than the number of PCs returned
        # in case more components were asked for than the number of
        # independent dimensions in the dataset.
        components = [c for c in components if c < time_pcs.shape[1]]

        if self._params['verbose']:
            print('performing ICA...')
        st_components = _stica(
            space_pcs, time_pcs, mu=self._params['mu'], path=ica_path,
            n_components=space_pcs.shape[-1])

        return ROIList([ROI(st_components[..., i]) for i in
                        range(st_components.shape[-1])])
Пример #12
0
def _remove_overlapping(rois, percent_overlap=0.9):
    """ Remove overlapping ROIs

    Parameters
    ----------
    rois : list
        list of sima.ROI ROIs
    percent_overlap : float
        percent of the smaller ROIs total area which must be covered in order
        for the ROIs to be evaluated as overlapping

    Returns
    -------
    rois : list
        A list of sima.ROI ROI objects with the overlapping ROIs combined
    """

    if percent_overlap > 0 and percent_overlap <= 1:
        for roi in rois:
            roi.mask = roi.mask

        for i in xrange(len(rois)):
            for j in [j for j in xrange(len(rois)) if j != i]:
                if rois[i] is not None and rois[j] is not None:
                    overlap = np.logical_and(rois[i].mask.toarray(),
                                             rois[j].mask.toarray())
                    small_area = np.min((rois[i].mask.size, rois[j].mask.size))

                    if len(np.where(overlap)[0]) > \
                            percent_overlap * small_area:
                        new_shape = np.logical_or(rois[i].mask.toarray(),
                                                  rois[j].mask.toarray())

                        rois[i] = ROI(mask=new_shape.astype('bool'),
                                      im_shape=rois[i].mask.shape)
                        rois[j] = None
    return ROIList(roi for roi in rois if roi is not None)
Пример #13
0
 def set_z(roi, z):
     old_mask = roi.mask
     return ROI(mask=[
         sparse.lil_matrix(old_mask[0].shape, old_mask[0].dtype)
         for _ in range(z - 1)
     ] + [old_mask[0]])
Пример #14
0
    def __call__(self, roi):

        frame = roi.mask[0].todense().copy()

        frame[frame > 0] = 1
        check = frame[:-2, :-2] + frame[1:-1, :-2] + frame[2:, :-2] + \
            frame[:-2, 1:-1] + frame[2:, 1:-1] + frame[:-2:, 2:] + \
            frame[1:-1, 2:] + frame[2:, 2:]
        z = np.zeros(frame.shape)
        z[1:-1, 1:-1] = check

        # initialize and array to hold the new polygon and find the first point
        b = []
        rows, cols = np.where(z > 0)
        p = [cols[0], rows[0]]
        base = p

        # establish an iteration limit to ensue the loop terminates if
        # smoothing is unsuccessful
        limit = 1500

        radius = self.radius

        # store whether the radius of search is increased above the initial
        # value
        tmp_rad = False
        for _ in range(limit - 1):
            b.append(p)
            # find the list of all points at the given radius and adjust to be
            # lined up for clockwise traversal
            x = np.roll(
                np.array(
                    list(p[0] + list(range(-radius, radius))) +
                    [p[0] + radius] * (2 * radius + 1) +
                    list(p[0] + list(range(-radius, radius))[::-1]) +
                    [p[0] - (radius + 1)] * (2 * radius + 1)), -2)
            y = np.roll(
                np.array([p[1] - radius] * (2 * radius) +
                         list(p[1] + list(range(-radius, radius))) +
                         [p[1] + radius] * (2 * radius + 1) +
                         list(p[1] +
                              list(range(-radius, (radius + 1)))[::-1])),
                -radius)

            # insure that the x and y points are within the image
            x[x < 0] = 0
            y[y < 0] = 0
            x[x >= z.shape[1]] = z.shape[1] - 1
            y[y >= z.shape[0]] = z.shape[0] - 1

            vals = z[y, x]

            # ensure that the vals array has a valid transition from 0 to 1
            # otherwise the algorithm has failed
            if len(np.where(np.roll(vals, 1) == 0)[0]) == 0 or \
                    len(np.where(vals > 0)[0]) == 0:
                return roi, False

            idx = np.intersect1d(
                np.where(vals > 0)[0],
                np.where(np.roll(vals, 1) == 0)[0])[0]
            p = [x[idx], y[idx]]

            # check if the traversal is near to the starting point indicating
            # that the algorithm has completed. If less then 3 points are found
            # this is not yet a valid ROI
            if ((p[0] - base[0]) ** 2 + (p[1] - base[1]) ** 2) ** 0.5 < \
                    1.5 * radius and len(b) > 3:
                new_roi = ROI(polygons=[b], im_shape=roi.im_shape)
                if new_roi.mask[0].size != 0:
                    # "well formed ROI"
                    return new_roi, True

            # if p is already in the list of polygon points, increase the
            # radius of search. if radius is already larger then 6, blur the
            # mask and try again
            if p in b:
                if radius > 6:
                    radius = 3
                    z = ndimage.gaussian_filter(z, sigma=1)

                    b = []
                    rows, cols = np.where(z > 0)
                    p = [cols[0], rows[0]]
                    base = p
                    tmp_rad = False

                else:
                    radius = radius + 1
                    tmp_rad = True
                    if len(b) > 3:
                        p = b[-3]
                        del b[-3:]

            elif tmp_rad:
                tmp_rad = False
                radius = 3

        # The maximum number of cycles has completed and no suitable smoothed
        # ROI has been determined
        return roi, False
Пример #15
0
    def _segment(self, dataset):

        channel = sima.misc.resolve_channels(self._params.channel,
                                             dataset.channel_names)
        if dataset.savedir is not None:
            pca_path = os.path.join(dataset.savedir,
                                    'opca_' + str(channel) + '.npz')
        else:
            pca_path = None

        if dataset.savedir is not None:
            ica_path = os.path.join(dataset.savedir,
                                    'ica_' + str(channel) + '.npz')
        else:
            ica_path = None

        if self._params.verbose:
            print 'performing PCA...'
        if isinstance(self._params.components, int):
            self._params.components = range(self._params.components)
        _, space_pcs, time_pcs = _OPCA(dataset,
                                       channel,
                                       self._params.components[-1] + 1,
                                       path=pca_path)
        space_pcs = np.real(
            space_pcs.reshape(dataset.frame_shape[1:3] +
                              (space_pcs.shape[2], )))
        space_pcs = np.array(
            [space_pcs[:, :, i] for i in self._params.components]).transpose(
                (1, 2, 0))
        time_pcs = np.array([time_pcs[:, i]
                             for i in self._params.components]).transpose(
                                 (1, 0))

        if self._params.verbose:
            print 'performing ICA...'
        st_components = _stica(space_pcs,
                               time_pcs,
                               mu=self._params.mu,
                               path=ica_path,
                               n_components=space_pcs.shape[2])

        if self._params.x_smoothing > 0 or self._params.static_threshold > 0:
            accepted, _, _ = _find_useful_components(
                st_components,
                self._params.static_threshold,
                x_smoothing=self._params.x_smoothing)

            if self._params.min_area > 0 or self._params.spatial_sep:
                rois = _extract_st_rois(accepted,
                                        min_area=self._params.min_area,
                                        spatial_sep=self._params.spatial_sep)

            if self._params.smooth_rois:
                if self._params.verbose:
                    print 'smoothing ROIs...'
                rois = [_smooth_roi(roi)[0] for roi in rois]

            if self._params.verbose:
                print 'removing overlapping ROIs...'
            rois = _remove_overlapping(
                rois, percent_overlap=self._params.overlap_per)
        else:
            rois = [
                ROI(st_components[:, :, i])
                for i in xrange(st_components.shape[2])
            ]

        return ROIList(rois)
Пример #16
0
def _load_version0(path):
    """Load a SIMA 0.x dataset

    Parameters
    ----------
    path : str
        The path to the original saved dataset, ending in .sima

    Examples
    --------

    >>> from sima.misc import example_data
    >>> from sima.misc.convert import _load_version0
    >>> ds = _load_version0(example_data())

    """

    def parse_channel(channel):
        """Parse an old format channel stored a dictionary

        Parameters
        ----------
        channel : dict

        Returns
        -------
        result : sima.Sequence
            A sequence equivalent to the old format channel.
        """
        _resolve_paths(channel, path)
        klass = channel.pop('__class__')
        if klass == 'sima.iterables.MultiPageTIFF':
            result = Sequence.create('TIFF', channel['path'])
            try:
                clip = channel['clip']
            except KeyError:
                pass
            else:
                if clip is not None:
                    s = (slice(None), slice(None)) + tuple(
                        slice(*[None if x is 0 else x for x in dim])
                        for dim in clip)
                    result = result[s]
            return result

        elif klass == 'sima.iterables.HDF5':
            raise Exception('TODO')
        else:
            raise Exception('Format not recognized.')

    def parse_sequence(sequence):
        channels = [parse_channel(c) for c in sequence]
        return Sequence.join(channels)

    with open(os.path.join(path, 'dataset.pkl'), 'rb') as f:
        unpickler = Unpickler(f)
        dataset_dict = unpickler.load()
    iterables = dataset_dict.pop('iterables')
    sequences = [parse_sequence(seq) for seq in iterables]

    # Apply displacements if they exist
    try:
        with open(os.path.join(path, 'displacements.pkl'), 'rb') as f:
            displacements = pkl.load(f)
    except IOError:
        pass
    else:
        assert all(np.all(d >= 0) for d in displacements)
        max_disp = np.max(list(chain(*displacements)), axis=0)
        frame_shape = np.array(sequences[0].shape)[1:]
        frame_shape[1:3] += max_disp
        sequences = [
            s.apply_displacements(d.reshape(s.shape[:3] + (2,)), frame_shape)
            for s, d in zip(sequences, displacements)]
        try:
            trim_coords = dataset_dict.pop('_lazy__trim_coords')
        except KeyError:
            try:
                trim_criterion = dataset_dict.pop('trim_criterion')
            except KeyError:
                pass
            else:
                raise Exception(
                    'Parsing of trim_criterion ' + str(trim_criterion) +
                    ' not yet implemented')
        else:
            sequences = [s[:, :, trim_coords[0][0]:trim_coords[1][0],
                           trim_coords[0][1]:trim_coords[1][1]]
                         for s in sequences]
    ds = ImagingDataset(sequences, None)
    ds.savedir = path

    # Add ROIs if they exist
    try:
        with open(os.path.join(path, 'rois.pkl'), 'rb') as f:
            rois = pkl.load(f)
    except IOError:
        pass
    else:
        roi_lists = {}
        for label, roi_list_dict in rois.iteritems():
            roi_list = []
            for roi in roi_list_dict['rois']:
                mask = roi['mask']
                polygons = roi['polygons']
                if mask is not None:
                    new_roi = ROI(mask=mask)
                else:
                    new_roi = ROI(polygons=polygons)
                new_roi.id = roi['id']
                new_roi.label = roi['label']
                new_roi.tags = roi['tags']
                new_roi.im_shape = roi['im_shape']

                roi_list.append(new_roi)
            roi_lists[label] = ROIList(roi_list)
            roi_lists[label].timestamp = roi_list_dict['timestamp']

        for label, roi_list in roi_lists.iteritems():
            ds.add_ROIs(roi_list, label=label)
    return ds