Skip to content

Commit

Permalink
- start of documentation process
Browse files Browse the repository at this point in the history
- convert tif rgb into grayscale using .convert('l') /
fonction of pillow
- made change in the test_imagesequence and /
test_regionofinterest (coverage 92% and 100%)
  • Loading branch information
teogale committed Sep 11, 2019
1 parent 7e3190c commit 4fb7d39
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 20 deletions.
2 changes: 1 addition & 1 deletion doc/source/api_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ API Reference
.. testsetup:: *

from neo import SpikeTrain
import quantities as pq
import quantities as pq
2 changes: 1 addition & 1 deletion doc/source/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ associated metadata (units, sampling frequency, etc.).
* :py:class:`SpikeTrain`: A set of action potentials (spikes) emitted by the same unit in a period of time (with optional waveforms).
* :py:class:`Event`: An array of time points representing one or more events in the data.
* :py:class:`Epoch`: An array of time intervals representing one or more periods of time in the data.

* :py:class:`ImageSequence`: A 3 dimension array representing multiple images.

Container objects
-----------------
Expand Down
5 changes: 3 additions & 2 deletions neo/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
.. autoclass:: Epoch
.. autoclass:: SpikeTrain
.. autoclass:: ImageSequence
"""

Expand All @@ -39,11 +40,11 @@
from neo.core.event import Event
from neo.core.epoch import Epoch

from neo.core.spiketrain import SpikeTrain

from neo.core.imagesequence import ImageSequence
from neo.core.regionofinterest import RectangularRegionOfInterest, CircularRegionOfInterest, PolygonRegionOfInterest

from neo.core.spiketrain import SpikeTrain

# Block should always be first in this list
objectlist = [Block, Segment, ChannelIndex,
AnalogSignal, IrregularlySampledSignal,
Expand Down
85 changes: 82 additions & 3 deletions neo/core/imagesequence.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
# -*- coding: utf-8 -*-
"""
This module implements :class:`ImageSequence`, a 3D array.
:class:`ImageSequence` inherits from :class:`basesignal.BaseSignal` which
derives from :class:`BaseNeo`, and from :class:`quantites.Quantity`which
in turn inherits from :class:`numpy.array`.
Inheritance from :class:`numpy.array` is explained here:
http://docs.scipy.org/doc/numpy/user/basics.subclassing.html
In brief:
* Initialization of a new object from constructor happens in :meth:`__new__`.
This is where user-specified attributes are set.
* :meth:`__array_finalize__` is called for all new objects, including those
created by slicing. This is where attributes are copied over from
the old object.
"""

from neo.core.regionofinterest import RegionOfInterest
from neo.core.analogsignal import AnalogSignal, _get_sampling_rate
from neo.core.dataobject import DataObject

import quantities as pq
import numpy as np
Expand All @@ -10,6 +29,56 @@


class ImageSequence(BaseSignal):
"""
Array of three dimension organize as [frame][row][column].
Inherits from :class:`quantities.Quantity`, which in turn inherits from
:class:`numpy.ndarray`.
*usage*::
>>> from neo.core import ImageSequence
>>> import quantities as pq
>>>
>>> img_sequence_array = [[[column for column in range(20)]for row in range(20)]for frame in range(10)]
>>> image_sequence = ImageSequence(img_sequence_array, units='V',
... sampling_rate=1*pq.Hz, spatial_scale=1*pq.micrometer)
>>> image_sequence.all()
ImageSequence
*Required attributes/properties*:
:image_data: (numpy array 3D, or list[frame][row][column]
The data itself
:units: (quantity units)
:sampling_rate: *or* **sampling_period** (quantity scalar) Number of
samples per unit time or
interval beween to samples.
If both are specified, they are
checked for consistency.
:spatial_scale: (quantity scalar) size for a pixel.
*Recommended attributes/properties*:
:name: (str) A label for the dataset.
:description: (str) Text description.
:file_origin: (str) Filesystem path or URL of the original data file.
*Optional attributes/properties*:
:dtype: (numpy dtype or str) Override the dtype of the signal array.
:copy: (bool) True by default.
:array_annotations: (dict) Dict mapping strings to numpy
arrays containing annotations for all data points
Note: Any other additional arguments are assumed to be user-specific
metadata and stored in :attr:`annotations`.
*Properties available on this object*:
:sampling_rate: (quantity scalar) Number of samples per unit time.
(1/:attr:`sampling_period`)
:sampling_period: (quantity scalar) Interval between two samples.
(1/:attr:`quantity scalar`)
:spatial_scales: size of a pixel
"""
# format ImageSequence subclass dataobject
# should be a 3d numerical array
# format data[image_index][y][x]
Expand All @@ -32,6 +101,16 @@ def __new__(cls, image_data, units=None, dtype=None, copy=True, spatial_scale=No
sampling_rate=None, name=None, description=None, file_origin=None, array_annotations=None,
**annotations):

"""
Constructs new :class:`ImageSequence` from data.
This is called whenever a new class:`ImageSequence` is created from
the constructor, but not when slicing.
__array_finalize__ is called on the new object.
"""

if spatial_scale is None:
raise ValueError('spatial_scale is required')
if units == None:
Expand All @@ -50,7 +129,6 @@ def __new__(cls, image_data, units=None, dtype=None, copy=True, spatial_scale=No

return obj


def __array_finalize__spec(self, obj):

self.sampling_rate = getattr(obj, 'sampling_rate', None)
Expand All @@ -61,11 +139,12 @@ def __array_finalize__spec(self, obj):

def signal_from_region(self, *region):


if len(region) == 0:
raise ValueError('no region of interest have been given')

region_pixel = []
for i,b in enumerate(region):
for i, b in enumerate(region):
r = region[i].return_list_pixel()
if r == []:
raise ValueError('region '+str(i)+'is empty')
Expand Down
3 changes: 1 addition & 2 deletions neo/io/asciiimageio.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ def read_block(self, lazy=False, nb_frame=None, nb_row=None, nb_column=None, uni
data[i][y].append(liste_value[nb])
nb += 1


image_sequence = ImageSequence(np.array(data, dtype='float'), units=units,
sampling_rate=sampling_rate, spatial_scale=spatial_scale)
print("creating segment")
Expand All @@ -79,4 +78,4 @@ def read_block(self, lazy=False, nb_frame=None, nb_row=None, nb_column=None, uni
block.segments.append(segment)
print("returning block")

return block
return block
2 changes: 0 additions & 2 deletions neo/io/blkio.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,5 +251,3 @@ def read_header(file_name):
block.segments.append(segment)

return block


10 changes: 7 additions & 3 deletions neo/io/tiffio.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def natural_sort(l):
return sorted(l, key=alphanum_key)

# find all the images in the given directory
# (done) TODO: only load files with the extension .tif or .tiff (see the glob module)
file_name_list = []
# name of extensions to track
types = ["*.tif", "*.tiff"]
Expand All @@ -69,7 +68,12 @@ def natural_sort(l):
list_data_image = []
for file_name in file_name_list:
list_data_image.append(np.array(Image.open(self.filename + "/" + file_name), dtype=np.float))
# todo: find out if this works for colour TIFFs, not just monochrome
list_data_image = np.array(list_data_image)
if len(list_data_image.shape) == 4:
list_data_image = []
for file_name in file_name_list:
list_data_image.append(np.array(Image.open(self.filename + "/" + file_name).convert('L'), dtype=np.float))

print("read block")
image_sequence = ImageSequence(np.stack(list_data_image),
units=units,
Expand All @@ -84,4 +88,4 @@ def natural_sort(l):
segment.block = block
block.segments.append(segment)
print("returning block")
return block
return block
9 changes: 8 additions & 1 deletion neo/test/coretest/test_imagesequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from neo.core.regionofinterest import CircularRegionOfInterest, RectangularRegionOfInterest, PolygonRegionOfInterest
import quantities as pq
import numpy as np
from neo.core import Block,Segment


class TestImageSequence(unittest.TestCase):
Expand Down Expand Up @@ -34,7 +35,7 @@ def test_error_spatial_scale(self):
ImageSequence(self.data, units='V', sampling_rate=500 * pq.Hz)

def test_units(self):
with self.assertRaises(TypeError):
with self.assertRaises(ValueError):
ImageSequence(self.data, sampling_rate=500 * pq.Hz, spatial_scale='m')

# test method will be remove are rename
Expand Down Expand Up @@ -69,7 +70,13 @@ def test_signal_from_region(self):
self.assertIsInstance(l, list)
for i in range(len(l)):
self.assertIsInstance(l[i], object)
with self.assertRaises(ValueError):
ImageSequence(self.data, units='V', sampling_rate=500 * pq.Hz, spatial_scale='m').signal_from_region(RectangularRegionOfInterest(1, 1, 1, 1))
with self.assertRaises(ValueError):
ImageSequence(self.data, units='V', sampling_rate=500 * pq.Hz, spatial_scale='m').signal_from_region()

m = ImageSequence(self.data, units='V', sampling_rate=500 * pq.Hz, spatial_scale='m').view()
print(m.sampling_rate)

if __name__ == "__main__":
unittest.main()
8 changes: 3 additions & 5 deletions neo/test/coretest/test_regionofinterest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ def test_result(self):
class Test_RectangularRegionOfInterest(unittest.TestCase):

def test_result(self):
self.assertEqual(RectangularRegionOfInterest(5,5,2,2).return_list_pixel(),
self.assertEqual(RectangularRegionOfInterest(5, 5, 2, 2).return_list_pixel(),
[[4, 4], [5, 4], [4, 5], [5, 5]])



class Test_PolygonRegionOfInterest(unittest.TestCase):

def test_result(self):
self.assertEqual(PolygonRegionOfInterest((1,1),(1,4),(2,1),(4,1)).return_list_pixel(),
[(1, 1), (1, 2), (1, 3)])
self.assertEqual(PolygonRegionOfInterest((3, 3), (2, 5), (5, 5), (5, 1), (1, 1)).return_list_pixel(),
[(1, 1), (2, 1), (3, 1), (4, 1), (2, 2), (3, 2), (4, 2), (3, 3), (4, 3), (3, 4), (4, 4)])



Expand Down

0 comments on commit 4fb7d39

Please sign in to comment.