Skip to content

Commit

Permalink
Merge pull request #187 from scottclowe/rf_rois2masks
Browse files Browse the repository at this point in the history
RF: Migrate duplicated rois2masks code to function in roitools
  • Loading branch information
scottclowe committed Jun 26, 2021
2 parents 30001c6 + f0cd6f7 commit 7a4dcf5
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 94 deletions.
134 changes: 40 additions & 94 deletions fissa/extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,24 @@ def getmean(data):
raise NotImplementedError()

@staticmethod
def rois2masks(rois, data):
def get_frame_size(data):
"""
Determine the shape of each frame within the recording.
Parameters
----------
data : data_type
The same object as returned by :meth:`image2array`.
Returns
-------
shape : tuple of ints
The 2D, y-by-x, shape of each frame in the movie.
"""
raise NotImplementedError()

@classmethod
def rois2masks(cls, rois, data):
"""
Convert ROIs into a collection of binary masks.
Expand All @@ -100,7 +117,7 @@ def rois2masks(rois, data):
--------
fissa.roitools.getmasks, fissa.roitools.readrois
"""
raise NotImplementedError()
return roitools.rois2masks(rois, cls.get_frame_size(data))

@staticmethod
def extracttraces(data, masks):
Expand Down Expand Up @@ -206,45 +223,21 @@ def getmean(data):
return data.mean(axis=0, dtype=np.float64)

@staticmethod
def rois2masks(rois, data):
"""Take the object `rois` and returns it as a list of binary masks.
def get_frame_size(data):
"""
Determine the shape of each frame within the recording.
Parameters
----------
rois : str or :term:`list` of :term:`array_like`
Either a string containing a path to an ImageJ roi zip file,
or a list of arrays encoding polygons, or list of binary arrays
representing masks.
data : :term:`array_like`
Data array as made by :meth:`image2array`. Must be shaped
``(frames, y, x)``.
data : data_type
The same object as returned by :meth:`image2array`.
Returns
-------
masks : :term:`list` of :class:`numpy.ndarray`
List of binary arrays.
shape : tuple of ints
The 2D, y-by-x, shape of each frame in the movie.
"""
# get the image shape
shape = data.shape[1:]

# if it's a list of strings
if isinstance(rois, basestring):
rois = roitools.readrois(rois)

if not isinstance(rois, abc.Sequence):
raise TypeError(
'Wrong ROIs input format: expected a list or sequence, but got'
' a {}'.format(rois.__class__)
)

# if it's a something by 2 array (or vice versa), assume polygons
if np.shape(rois[0])[1] == 2 or np.shape(rois[0])[0] == 2:
return roitools.getmasks(rois, shape)
# if it's a list of bigger arrays, assume masks
elif np.shape(rois[0]) == shape:
return rois

raise ValueError('Wrong ROIs input format: unfamiliar shape.')
return data.shape[-2:]

@staticmethod
def extracttraces(data, masks):
Expand Down Expand Up @@ -359,44 +352,21 @@ def getmean(data):
return memory / n_frames

@staticmethod
def rois2masks(rois, data):
"""Take the object `rois` and returns it as a list of binary masks.
def get_frame_size(data):
"""
Determine the shape of each frame within the recording.
Parameters
----------
rois : str or list of array_like
Either a string containing a path to an ImageJ roi zip file,
or a list of arrays encoding polygons, or list of binary arrays
representing masks.
data : tifffile.TiffFile
Open tifffile.TiffFile object.
data : data_type
The same object as returned by :meth:`image2array`.
Returns
-------
masks : list of numpy.ndarray
List of binary arrays.
shape : tuple of ints
The 2D, y-by-x, shape of each frame in the movie.
"""
# Get the image shape
shape = data.pages[0].shape[-2:]

# If it's a string, parse the string
if isinstance(rois, basestring):
rois = roitools.readrois(rois)

if not isinstance(rois, abc.Sequence):
raise TypeError(
"Wrong ROIs input format: expected a list or sequence, but got"
" a {}".format(rois.__class__)
)

# If it's a something by 2 array (or vice versa), assume polygons
if np.shape(rois[0])[1] == 2 or np.shape(rois[0])[0] == 2:
return roitools.getmasks(rois, shape)
# If it's a list of bigger arrays, assume masks
elif np.shape(rois[0]) == shape:
return rois

raise ValueError("Wrong ROIs input format: unfamiliar shape.")
return data.pages[0].shape[-2:]

@staticmethod
def extracttraces(data, masks):
Expand Down Expand Up @@ -500,45 +470,21 @@ def getmean(data):
return avg

@staticmethod
def rois2masks(rois, data):
def get_frame_size(data):
"""
Take the object `rois` and returns it as a list of binary masks.
Determine the shape of each frame within the recording.
Parameters
----------
rois : str or :term:`list` of :term:`array_like`
Either a string containing a path to an ImageJ roi zip file,
or a list of arrays encoding polygons, or list of binary arrays
representing masks.
data : PIL.Image
An open :class:`PIL.Image` handle to a multi-frame TIFF image.
Returns
-------
masks : list of numpy.ndarray
List of binary arrays.
shape : tuple of ints
The 2D, y-by-x, shape of each frame in the movie.
"""
# get the image shape
shape = data.size[::-1]

# If rois is string, we first need to read the contents of the file
if isinstance(rois, basestring):
rois = roitools.readrois(rois)

if not isinstance(rois, abc.Sequence):
raise TypeError(
'Wrong ROIs input format: expected a list or sequence, but got'
' a {}'.format(rois.__class__)
)

# if it's a something by 2 array (or vice versa), assume polygons
if np.shape(rois[0])[1] == 2 or np.shape(rois[0])[0] == 2:
return roitools.getmasks(rois, shape)
# if it's a list of bigger arrays, assume masks
elif np.shape(rois[0]) == shape:
return rois

raise ValueError('Wrong ROIs input format: unfamiliar shape.')
return data.size[::-1]

@staticmethod
def extracttraces(data, masks):
Expand Down
44 changes: 44 additions & 0 deletions fissa/roitools.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@
from __future__ import division

import numpy as np
from past.builtins import basestring
from skimage.measure import find_contours

try:
from collections import abc
except ImportError:
import collections as abc

from .readimagejrois import read_imagej_roi_zip
from .ROI import poly2mask

Expand Down Expand Up @@ -438,3 +444,41 @@ def find_roi_edge(mask):
outline[i] -= 0.5

return outline


def rois2masks(rois, shape):
"""
Convert ROIs into a list of binary masks.
Parameters
----------
rois : str or list of array_like
Either a string containing a path to an ImageJ roi zip file,
or a list of arrays encoding polygons, or list of binary arrays
representing masks.
shape : array_like
Image shape as a length 2 vector.
Returns
-------
masks : list of numpy.ndarray
List of binary arrays.
"""
# If it's a string, parse the string
if isinstance(rois, basestring):
rois = readrois(rois)

if not isinstance(rois, abc.Sequence):
raise TypeError(
"Wrong ROIs input format: expected a list or sequence, but got"
" a {}".format(rois.__class__)
)

# If it's a something by 2 array (or vice versa), assume polygons
if np.shape(rois[0])[1] == 2 or np.shape(rois[0])[0] == 2:
return getmasks(rois, shape)
# If it's a list of bigger arrays, assume masks
elif np.shape(rois[0]) == shape:
return rois

raise ValueError("Wrong ROIs input format: unfamiliar shape.")
9 changes: 9 additions & 0 deletions fissa/tests/test_extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,15 @@ def test_polys_3d(self):
self.datahandler.rois2masks(polys3d, self.data)


class TestRois2MasksRoitools(BaseTestCase, Rois2MasksTestMixin):
"""Test roitools.rois2masks."""

def setUp(self):
Rois2MasksTestMixin.setUp(self)
self.data = (176, 156)
self.datahandler = roitools


class TestRois2MasksTifffile(BaseTestCase, Rois2MasksTestMixin):
"""Tests for rois2masks using `~extraction.DataHandlerTifffile`."""

Expand Down

0 comments on commit 7a4dcf5

Please sign in to comment.