configured sphinx to generate decent api documentation

This was primarily done to detect bad restructuredtext syntax in python code.

This allowed me to detect and fix quite a few errors. In order to fix the orrors in the output document, I also added quite a lot of docstrings, as sphinx autodoc ignores classes and functions that don't have docstrings.

This was my first experience with sphinx but I'm not quite happy with it, as it requires too much verbose and time consuming helps and hinting to produce something decent. Moreobver, it suffers from a lack of examples for non basic usage, such as :
- how to expose to the user the __item__ methods
- how to document multiple return values
- etc.
This commit is contained in:
Guillaume Raffy 2020-04-14 18:58:03 +02:00
parent 463cd9d0d9
commit 97dc74f08c
22 changed files with 425 additions and 172 deletions

View File

@ -0,0 +1,6 @@
The catalog module
------------------
.. automodule:: lipase.catalog
:members:

View File

@ -0,0 +1,5 @@
The circsymdetector module
--------------------------
.. automodule:: lipase.circsymdetector
:members:

View File

@ -17,11 +17,29 @@
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
# #
# import os import os
# import sys import sys
# sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('../../../src'))
# use mock mechanism for modules that sphinx cannot find (eg ij, which is only available in jython)
#import mock # sudo apt install python3-mock
#MOCK_MODULES = ['numpy', 'matplotlib', 'matplotlib.pyplot']
MOCK_MODULES = ['ij', 'ij.process', 'ij.plugin', 'ncsa', 'jarray']
autodoc_mock_imports = MOCK_MODULES
#for mod_name in MOCK_MODULES:
# sys.modules[mod_name] = mock.Mock()
def skip(app, what, name, obj, would_skip, options):
if name == "__init__":
return False
return would_skip
def setup(app):
app.connect("autodoc-skip-member", skip)
# -- General configuration ------------------------------------------------ # -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here. # If your documentation needs a minimal Sphinx version, state it here.
@ -32,6 +50,7 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = ['sphinx.ext.autodoc', extensions = ['sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.doctest', 'sphinx.ext.doctest',
'sphinx.ext.todo', 'sphinx.ext.todo',
'sphinx.ext.coverage', 'sphinx.ext.coverage',
@ -40,6 +59,12 @@ extensions = ['sphinx.ext.autodoc',
'sphinx.ext.viewcode', 'sphinx.ext.viewcode',
'sphinx.ext.githubpages'] 'sphinx.ext.githubpages']
# enable automatic translation of google style comments to rest comments as google style comments are less wordy (see https://brendanhasz.github.io/2019/01/05/sphinx.html#napoleon-extension)
napoleon_google_docstring = True
napoleon_numpy_docstring = True
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ['_templates']
@ -90,7 +115,7 @@ todo_include_todos = True
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
# #
html_theme = 'alabaster' html_theme = 'classic'
# Theme options are theme-specific and customize the look and feel of a theme # Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the # further. For a list of options available for each theme, see the

View File

@ -0,0 +1,7 @@
The hdf5 module
-----------------
.. automodule:: lipase.hdf5.hdf5_data
:members:

View File

@ -0,0 +1,5 @@
The imageengine module
----------------------
.. automodule:: lipase.imageengine
:members:

View File

@ -6,10 +6,20 @@
Welcome to lipase's documentation! Welcome to lipase's documentation!
================================== ==================================
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:caption: Contents: :caption: Contents:
imageengine
catalog
lipase
circsymdetector
traps_detector
template_matcher
maxima_finder
hdf5
telemos
Indices and tables Indices and tables

View File

@ -0,0 +1,6 @@
The lipase module
-----------------
.. automodule:: lipase.lipase
:members:

View File

@ -0,0 +1,5 @@
The maxima_finder module
---------------------------
.. automodule:: lipase.maxima_finder
:members:

View File

@ -0,0 +1,6 @@
The telemos module
------------------
.. automodule:: lipase.telemos
:members:

View File

@ -0,0 +1,6 @@
The template_matcher module
---------------------------
.. automodule:: lipase.template_matcher
:members:

View File

@ -0,0 +1,6 @@
The traps_detector module
-------------------------
.. automodule:: lipase.traps_detector
:members:

View File

@ -1,17 +1,20 @@
import os import os
import json import json
from imageengine import IHyperStack, IImageEngine, PixelType from .imageengine import IHyperStack, IImageEngine, PixelType
class DacMetadata(object): class DacMetadata(object):
"""Represents a display_and_comments.txt metadata file.""" """Represents a display_and_comments.txt metadata file.
display_and_comments.txt is a metadata file stored by micro manager
"""
def __init__(self, dac_id, dac_file_path): def __init__(self, dac_id, dac_file_path):
"""Contructor. """Contructor.
:param str dac_id: eg "res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1" :param str dac_id: eg ``res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1``
:param str dac_file_path: eg "/Users/graffy/ownCloud/ipr/lipase/raw-images/res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/display_and_comments.txt" :param str dac_file_path: eg ``/Users/graffy/ownCloud/ipr/lipase/raw-images/res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/display_and_comments.txt``
""" """
self.dac_id = dac_id self.dac_id = dac_id
self.dac_file_path = dac_file_path self.dac_file_path = dac_file_path
@ -19,16 +22,20 @@ class DacMetadata(object):
self.dac = json.load(dac_file, encoding='latin-1') # note : the micromanager metadata files are encoded in latin-1, not utf8 (see accents in comments) self.dac = json.load(dac_file, encoding='latin-1') # note : the micromanager metadata files are encoded in latin-1, not utf8 (see accents in comments)
def get_channel_name(self, channel_index): def get_channel_name(self, channel_index):
"""Returns the name of the given channel index
"""
channels = self.dac['Channels'] channels = self.dac['Channels']
return channels[channel_index]["Name"] return channels[channel_index]["Name"]
class Sequence(object): class Sequence(object):
"""A sequence of images stored in micro manager format
"""
def __init__(self, catalog, sequence_id, micro_manager_metadata_file_path): def __init__(self, catalog, sequence_id, micro_manager_metadata_file_path):
""" """
:param Catalog catalog: :param ImageCatalog catalog:
:param str sequence_id: eg 'res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0' :param str sequence_id: eg ``res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0``
:param str micro_manager_metadata_file_path: eg '/Users/graffy/ownCloud/ipr/lipase/raw-images/res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0/metadata.txt' :param str micro_manager_metadata_file_path: eg ``/Users/graffy/ownCloud/ipr/lipase/raw-images/res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0/metadata.txt``
""" """
self.catalog = catalog self.catalog = catalog
self.sequence_id = sequence_id self.sequence_id = sequence_id
@ -52,26 +59,36 @@ class Sequence(object):
@property @property
def num_frames(self): def num_frames(self):
"""Gets the number of frames in the sequence
"""
summary = self.mmm['Summary'] summary = self.mmm['Summary']
return int(summary['Frames']) return int(summary['Frames'])
@property @property
def width(self): def width(self):
"""Gets the width of images in the sequence
"""
summary = self.mmm['Summary'] summary = self.mmm['Summary']
return int(summary['Width']) return int(summary['Width'])
@property @property
def height(self): def height(self):
"""Gets the height of images in the sequence
"""
summary = self.mmm['Summary'] summary = self.mmm['Summary']
return int(summary['Height']) return int(summary['Height'])
@property @property
def num_channels(self): def num_channels(self):
"""Gets the number of channels in the sequence
"""
summary = self.mmm['Summary'] summary = self.mmm['Summary']
return int(summary['Channels']) return int(summary['Channels'])
@property @property
def num_slices(self): def num_slices(self):
"""Gets the number of slices in the sequence
"""
summary = self.mmm['Summary'] summary = self.mmm['Summary']
return int(summary['Slices']) return int(summary['Slices'])
@ -81,11 +98,13 @@ class Sequence(object):
return int(summary['BitDepth']) return int(summary['BitDepth'])
def get_root_path(self): def get_root_path(self):
"""Returns the root location of th is sequence
"""
(dir_name, file_name) = os.path.split(self.micro_manager_metadata_file_path) # pylint: disable=unused-variable (dir_name, file_name) = os.path.split(self.micro_manager_metadata_file_path) # pylint: disable=unused-variable
return dir_name return dir_name
def get_image_file_path(self, channel_index, frame_index, slice_index=0): def get_image_file_path(self, channel_index, frame_index, slice_index=0):
''' '''Returnsthe file location of the given image in the sequence
:param int channel_index: :param int channel_index:
:param int frame_index: :param int frame_index:
:param int slice_index: :param int slice_index:
@ -98,7 +117,7 @@ class Sequence(object):
def get_channel_index(self, channel_id): def get_channel_index(self, channel_id):
''' '''
:param str channel_id: :param str channel_id: the identifier of the channel (eg ``'vis'``)
''' '''
summary = self.mmm['Summary'] summary = self.mmm['Summary']
channel_index = summary['ChNames'].index(channel_id) channel_index = summary['ChNames'].index(channel_id)
@ -115,7 +134,7 @@ class Sequence(object):
def get_black(self): def get_black(self):
''' returns the black sequence related to the the sequence self ''' returns the black sequence related to the the sequence self
:return Sequence: :rtype: Sequence
''' '''
seqid_to_black = { seqid_to_black = {
'res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0': 'res_soleil2018/DARK/DARK_40X_60min_1 im pae min_1/Pos0', 'res_soleil2018/GGH/GGH_2018_cin2_phiG_I_327_vis_-40_1/Pos0': 'res_soleil2018/DARK/DARK_40X_60min_1 im pae min_1/Pos0',
@ -127,7 +146,7 @@ class Sequence(object):
def get_white(self): def get_white(self):
''' returns the white sequence related to the the sequence self ''' returns the white sequence related to the the sequence self
:return Sequence: :rtype: Sequence
''' '''
# assert fixme : res_soleil2018/white/white_24112018_2/Pos0 is visible # assert fixme : res_soleil2018/white/white_24112018_2/Pos0 is visible
seqid_to_white = { seqid_to_white = {
@ -143,7 +162,8 @@ class Sequence(object):
:param list(str) selected_channel_ids: :param list(str) selected_channel_ids:
:param list(int) selected_frames: :param list(int) selected_frames:
:param list(int) selected_slices: :param list(int) selected_slices:
:return IHyperStack: the resulting hyperstack :return: the resulting hyperstack
:rtype: IHyperStack
""" """
if selected_frames is None: if selected_frames is None:
selected_frames = range(self.num_frames) selected_frames = range(self.num_frames)
@ -170,6 +190,8 @@ def find_dirs_containing_file(file_name, root_dir):
""" """
:param str file_name: the name of the searched files (eg 'metadata.txt') :param str file_name: the name of the searched files (eg 'metadata.txt')
:param str root_dir: the root directory where we search :param str root_dir: the root directory where we search
:rtype: list(str)
:return: the list of directories that contain the given file
""" """
result = [] result = []
for root, dirs, files in os.walk(root_dir): # pylint: disable=unused-variable for root, dirs, files in os.walk(root_dir): # pylint: disable=unused-variable
@ -178,9 +200,20 @@ def find_dirs_containing_file(file_name, root_dir):
return result return result
class ImageCatalog(object): class ImageCatalog(object):
"""A catalog of micromanager sequences
"""
def __init__(self, raw_images_root): def __init__(self, raw_images_root):
"""Creates a new image catalog and populates it by finding the image sequences in the given root directory
Args:
raw_images_root (str): the root directory that is expected to contain the micromanager formatted sequences.
"""
self.raw_images_root = raw_images_root self.raw_images_root = raw_images_root
self.sequences = {} self.sequences = {}
"""
the dictionary which stores the catalog sequences (dict(str, :py:class:`Sequence`)). The sequences are indexed with the sequence identifiers.
"""
sequence_paths = find_dirs_containing_file('metadata.txt', self.raw_images_root) sequence_paths = find_dirs_containing_file('metadata.txt', self.raw_images_root)
sequence_ids = [ os.path.relpath(sequence_path, raw_images_root) for sequence_path in sequence_paths ] sequence_ids = [ os.path.relpath(sequence_path, raw_images_root) for sequence_path in sequence_paths ]

View File

@ -2,7 +2,7 @@
an image processing technique to produce a 1D signal for each pixel : this 1D signal is obtained by projecting the neighborhood of this pixel on a set of bases (each base is used as a convilution kernel) an image processing technique to produce a 1D signal for each pixel : this 1D signal is obtained by projecting the neighborhood of this pixel on a set of bases (each base is used as a convilution kernel)
https://subversion.ipr.univ-rennes1.fr/repos/main/projects/antipode/src/python/antipode/texori.py https://subversion.ipr.univ-rennes1.fr/repos/main/projects/antipode/src/python/antipode/texori.py
""" """
from imageengine import IImageEngine, PixelType, StackImageFeeder from .imageengine import IImageEngine, PixelType, StackImageFeeder
import math import math
class IProjectorBase(object): class IProjectorBase(object):
@ -22,8 +22,11 @@ class IProjectorBase(object):
pass pass
def create_circle_image(image_size, circle_radius, circle_pos, circle_thickness, background_value=0.0, circle_value=1.0): def create_circle_image(image_size, circle_radius, circle_pos, circle_thickness, background_value=0.0, circle_value=1.0):
""" """Creates an image containing the a circle
:param dict image_size:
:param dict image_size: The width and height of the image to create
:rtype: IImage
""" """
ie = IImageEngine.get_instance() ie = IImageEngine.get_instance()
width = image_size['width'] width = image_size['width']
@ -152,6 +155,8 @@ class CircularSymmetryProjectorBase(object):
class CircularSymmetryDetector: class CircularSymmetryDetector:
"""Method to detect objects exhibiting a circular symmetry
"""
def __init__(self, max_radius, num_angular_sectors, num_radial_sectors=None): def __init__(self, max_radius, num_angular_sectors, num_radial_sectors=None):
""" """
:param float max_radius: in pixels :param float max_radius: in pixels
@ -168,15 +173,16 @@ class CircularSymmetryDetector:
""" Computes for each pixel the radial profile (with this pixel as center) """ Computes for each pixel the radial profile (with this pixel as center)
:param IImage src_image: :param IImage src_image:
:rtype IHyperstack, Image :
:returns: :returns:
- radial_profiles (:py:class:`IHyperstack`) - each radial profile is stored in the channel coordinate of the hyperstack - radial_profiles (:py:class:`~lipase.imageengine.IHyperStack`) - each pixel stores the radial profile for this pixel. The radial profile is a 1D signal stored along the channel axis of the hyperstack, each channel being related to a radius range.
- angular_variance_profiles (:py:class:`IHyperStack`) - each pixel stores the angular variance profile for this pixel. The angular variance profile is a 1D signal stored along the channel axis of the hyperstack, each channel being related to a radius range.
- angular_variance_avg (:py:class:`IImage`) - each pixel stores the average variance of signal along the circles of different diameters in the neighborhood - angular_variance_avg (:py:class:`IImage`) - each pixel stores the average variance of signal along the circles of different diameters in the neighborhood
""" """
# https://stackoverflow.com/questions/39759503/how-to-document-multiple-return-values-using-restructuredtext-in-python-2 # https://stackoverflow.com/questions/39759503/how-to-document-multiple-return-values-using-restructuredtext-in-python-2
ie = IImageEngine.get_instance() ie = IImageEngine.get_instance()
ie.debugger.on_image(src_image, 'src_image') ie.debugger.on_image(src_image, 'src_image')
projector_base = CircularSymmetryProjectorBase(self.max_radius, num_angular_sectors=self.num_angular_sectors, num_radial_sectors=self.num_radial_sectors, oversampling_scale=1) projector_base = CircularSymmetryProjectorBase(self.max_radius, num_angular_sectors=self.num_angular_sectors, num_radial_sectors=self.num_radial_sectors, oversampling_scale=1)
radial_profile_image = ie.create_hyperstack(width=src_image.get_width(), height=src_image.get_height(), num_channels=projector_base.num_radial_sectors, num_slices=1, num_frames=1, pixel_type=PixelType.F32) radial_profile_image = ie.create_hyperstack(width=src_image.get_width(), height=src_image.get_height(), num_channels=projector_base.num_radial_sectors, num_slices=1, num_frames=1, pixel_type=PixelType.F32)
angular_variances_image = ie.create_hyperstack(width=src_image.get_width(), height=src_image.get_height(), num_channels=projector_base.num_radial_sectors, num_slices=1, num_frames=1, pixel_type=PixelType.F32) angular_variances_image = ie.create_hyperstack(width=src_image.get_width(), height=src_image.get_height(), num_channels=projector_base.num_radial_sectors, num_slices=1, num_frames=1, pixel_type=PixelType.F32)
for radius_index in range(projector_base.num_radial_sectors): for radius_index in range(projector_base.num_radial_sectors):

View File

@ -1 +1 @@
from hdf5_data import Group, DataSet, ElementType from .hdf5_data import Group, DataSet, ElementType

View File

@ -6,12 +6,20 @@ note: these structures are intentionally made independent of h5py library as thi
""" """
class ElementType(object): class ElementType(object):
"""The types that can be used for elements of arrays
"""
U1=0 U1=0
"""1 bit boolean"""
U8=1 U8=1
"""8 bits unsigned integer"""
U32=2 U32=2
"""32 bits unsigned integer"""
S32=3 S32=3
"""32 bits signed integer"""
F32=4 F32=4
"""32 bits floating precision number"""
F64=5 F64=5
"""64 bits floating precision number"""
class DataSet(object): class DataSet(object):
""" an hdf5 dataset """ an hdf5 dataset
@ -20,34 +28,64 @@ class DataSet(object):
""" """
:param str name: the name of the dataset :param str name: the name of the dataset
:param tuple(int) size: the size of each dimension of the dataset :param tuple(int) size: the size of each dimension of the dataset
:param ElementType element_type: the type of elements stored in this dataset
""" """
self.name = name self.name = name
"""The name of the dataset (str)
"""
self.size = size self.size = size
"""The size of the dataset (tuple of integers)
"""
self._element_type = element_type self._element_type = element_type
"""The type of elements in this dataset (ElementType)
"""
self._elements = [] self._elements = []
for i in range(self.num_elements): # pylint: disable=unused-variable for i in range(self.num_elements): # pylint: disable=unused-variable
self._elements.append(0) self._elements.append(0)
@property @property
def element_type(self): def element_type(self):
"""Gets the element type of this array
:rtype: ElementType
"""
return self._element_type return self._element_type
@property @property
def dimension(self): def dimension(self):
"""Gets the dimension of the array contained in this dataset
Would return 3 for a 3D dataset.
:rtype: int
"""
return len(self.size) return len(self.size)
@property @property
def elements(self): def elements(self):
"""Gets the elements value in the form of a list
:rtype: list
"""
return self._elements return self._elements
@property @property
def num_elements(self): def num_elements(self):
"""Gets the number of elements in this dataset
:rtype: int
"""
num_elements = 1 num_elements = 1
for i in range(self.dimension): for i in range(self.dimension):
num_elements *= self.size[i] num_elements *= self.size[i]
return num_elements return num_elements
def get_element(self, pos): def get_element(self, pos):
"""Gets the value of the element indexed by pos
:param tuple(int) pos: the index of the element to retreive. This index is expected to be a tuple of integers. The pos argument is expected to have the same length as the number of dimensions of this dataset.
"""
assert len(pos) == len(self.size) assert len(pos) == len(self.size)
return self._elements[self._pos_to_index(pos)] return self._elements[self._pos_to_index(pos)]
@ -56,10 +94,20 @@ class DataSet(object):
return self._elements[self._pos_to_index(pos)] return self._elements[self._pos_to_index(pos)]
def set_element(self, pos, value): def set_element(self, pos, value):
"""Sets the value of the element indexed by pos
:param tuple(int) pos: the index of the element to set. This index is expected to be a tuple of integers. The pos argument is expected to have the same length as the number of dimensions of this dataset.
:param value: the type is expected to be compatible (convertible to) with this dataset's element type
"""
assert len(pos) == len(self.size) assert len(pos) == len(self.size)
self._elements[self._pos_to_index(pos)] = value self._elements[self._pos_to_index(pos)] = value
def __setitem__(self, pos, value): def __setitem__(self, pos, value):
"""Sets the value of the element indexed by pos
:param tuple(int) pos: the index of the element to set. This index is expected to be a tuple of integers. The pos argument is expected to have the same length as the number of dimensions of this dataset.
:param value: the type is expected to be compatible (convertible to) with this dataset's element type
"""
assert len(pos) == len(self.size) assert len(pos) == len(self.size)
self._elements[self._pos_to_index(pos)] = value self._elements[self._pos_to_index(pos)] = value
@ -73,7 +121,10 @@ class DataSet(object):
class Group(object): class Group(object):
"""An hdf5 group
A group can contain datasets and other groups
"""
def __init__(self, name): def __init__(self, name):
""" """
:param str name: the name of the group :param str name: the name of the group
@ -83,19 +134,35 @@ class Group(object):
self._groups = {} self._groups = {}
def add_dataset(self, dataset): def add_dataset(self, dataset):
"""Adds the given dataset to the datasets stored in this group
:param DataSet dataset:
"""
assert isinstance(dataset, DataSet) assert isinstance(dataset, DataSet)
self._datasets[dataset.name] = dataset self._datasets[dataset.name] = dataset
def add_group(self, group): def add_group(self, group):
"""Adds the given group to the groups stored in this group
:param Group group:
"""
assert isinstance(group, Group) assert isinstance(group, Group)
self._datasets[group.name] = group self._datasets[group.name] = group
@property @property
def datasets(self): def datasets(self):
"""
:rtype: dict(str, :py:class:`DataSet`)
"""
return self._datasets return self._datasets
@property @property
def groups(self): def groups(self):
"""
:rtype: dict(str, :py:class:`Group`)
"""
return self._groups return self._groups
def __getitem__(self, dataset_name): def __getitem__(self, dataset_name):

View File

@ -41,7 +41,9 @@ class PixelType:
return PixelType.PIXEL_TYPE_TO_NUM_BITS[ pixel_type ] return PixelType.PIXEL_TYPE_TO_NUM_BITS[ pixel_type ]
class IImage(ABC): class IImage(ABC):
"""An abstact class representing an image (2D matrix of pixels)
"""
@abc.abstractmethod @abc.abstractmethod
def clone(self, clone_pixel_type=None): def clone(self, clone_pixel_type=None):
""" """
@ -73,27 +75,29 @@ class IImage(ABC):
def set_subimage(self, subimage, position): def set_subimage(self, subimage, position):
""" """
:param IImage subimage: the image to copy into self :param IImage subimage: the image to copy into self
:param (int, int) position: where to insert the subimage in self (upper left pixel) :param (int,int) position: where to insert the subimage in self (upper left pixel)
""" """
@abc.abstractmethod @abc.abstractmethod
def get_pixel_type(self): def get_pixel_type(self):
""" """
:rtype PixelType: :rtype: PixelType
""" """
pass pass
@abc.abstractmethod @abc.abstractmethod
def get_value_range(self): def get_value_range(self):
""" """
:rtype (float, float): the min and the max value :rtype: (float, float)
:returns: the min and the max value
""" """
pass pass
@abc.abstractmethod @abc.abstractmethod
def get_mean_value(self): def get_mean_value(self):
""" """
:rtype float: the mean pixel value in the image :rtype float:
:return: the mean pixel value in the image
""" """
pass pass
@ -106,6 +110,11 @@ class IImage(ABC):
""" """
class IHyperStack(ABC): class IHyperStack(ABC):
"""An abstact class representing an hyperstack (5D matrix of pixels)
The name hyperstachk comes from imagej's terminology.
"""
@abc.abstractmethod @abc.abstractmethod
def get_width(self): def get_width(self):
@ -158,17 +167,22 @@ class IImageFeeder(ABC):
def next(self): def next(self):
"""returns the next image in the collection """returns the next image in the collection
for iterator for iterator
:rtype: IImage
""" """
pass pass
@abc.abstractmethod @abc.abstractmethod
def get_num_images(self): def get_num_images(self):
"""Gets the number of images in this collection
"""
pass pass
def create_hyperstack(self): def create_hyperstack(self):
""" """
creates an hyperstack from this image feeder creates an hyperstack from this image feeder
:rtype IHyperStack
:rtype: IHyperStack
""" """
it = iter(self) it = iter(self)
@ -214,7 +228,7 @@ class StackImageFeeder(IImageFeeder):
def __init__(self, hyperstack): def __init__(self, hyperstack):
""" """
:param IHyperStack hyperstack :param IHyperStack hyperstack:
""" """
self.hyperstack = hyperstack self.hyperstack = hyperstack
@ -270,19 +284,29 @@ class StackImageFeeder(IImageFeeder):
class IImageProcessingDebugger(ABC): class IImageProcessingDebugger(ABC):
"""
An abstract image processing debugger.
Its role is to do a specific action on some events related to image processing
"""
def __init__(self): def __init__(self):
pass pass
@abc.abstractmethod @abc.abstractmethod
def on_image(self, image, image_id): def on_image(self, image, image_id):
''' '''This method is called by image processing methods when they have an intermediate image they want to send to the debugger
:param IImage image: :param IImage image:
:param str image_id: :param str image_id:
''' '''
class NullDebugger(IImageProcessingDebugger): class NullDebugger(IImageProcessingDebugger):
"""
This debugger is simply ignoring anything it receives.
Therefore this debugger is to be chosen when we want to disable the debugger.
"""
def __init__(self): def __init__(self):
IImageProcessingDebugger.__init__(self) IImageProcessingDebugger.__init__(self)
@ -335,7 +359,7 @@ class IImageEngine(ABC):
@staticmethod @staticmethod
def get_instance(): def get_instance():
"""Static access method. """Static access method.
:rtype IImageEngine: :rtype: IImageEngine
""" """
assert IImageEngine.__instance is not None assert IImageEngine.__instance is not None
@ -350,13 +374,13 @@ class IImageEngine(ABC):
@abc.abstractmethod @abc.abstractmethod
def create_hyperstack(self, width, height, num_channels, num_slices, num_frames, pixel_type): def create_hyperstack(self, width, height, num_channels, num_slices, num_frames, pixel_type):
""" """
:rtype IHyperStack: :rtype: IHyperStack
""" """
@abc.abstractmethod @abc.abstractmethod
def create_image(self, width, height, pixel_type): def create_image(self, width, height, pixel_type):
""" """
:rtype IImage: :rtype: IImage
""" """
@abc.abstractmethod @abc.abstractmethod
@ -380,7 +404,8 @@ class IImageEngine(ABC):
:param IImage image1: :param IImage image1:
:param IImage image2: :param IImage image2:
:rtype IImage: image1-image2 :rtype: IImage
:return: image1-image2
""" """
@abc.abstractmethod @abc.abstractmethod
@ -390,7 +415,8 @@ class IImageEngine(ABC):
:param IImage image1: :param IImage image1:
:param IImage image2: :param IImage image2:
:rtype IImage: image1*image2 :rtype: IImage
:return: image1*image2
""" """
@abc.abstractmethod @abc.abstractmethod
@ -400,7 +426,8 @@ class IImageEngine(ABC):
:param IImage numerator_image: :param IImage numerator_image:
:param IImage denominator_image: :param IImage denominator_image:
:rtype IImage: numerator_image/denominator_image :rtype: IImage
:return: numerator_image/denominator_image
""" """
@abc.abstractmethod @abc.abstractmethod
@ -409,7 +436,8 @@ class IImageEngine(ABC):
computes the absolute value of each pixel in the input image computes the absolute value of each pixel in the input image
:param IImage image: :param IImage image:
:rtype IImage: an image containing the absolute values of the input image :rtype: IImage
:return: an image containing the absolute values of the input image
""" """
@ -419,7 +447,7 @@ class IImageEngine(ABC):
computes the edge transform using a sobel filter computes the edge transform using a sobel filter
:param IImage image: :param IImage image:
:rtype IImage: :rtype: IImage
""" """
@abc.abstractmethod @abc.abstractmethod
@ -427,7 +455,7 @@ class IImageEngine(ABC):
"""Compute for each pixel position the maximum at this position in all input images. """Compute for each pixel position the maximum at this position in all input images.
:param IImageFeeder image_feeder: :param IImageFeeder image_feeder:
:rtype IImage: :rtype: IImage
""" """
@abc.abstractmethod @abc.abstractmethod
@ -435,7 +463,7 @@ class IImageEngine(ABC):
"""Compute for each pixel position the median value at this position in all input images. """Compute for each pixel position the median value at this position in all input images.
:param IImageFeeder image_feeder: :param IImageFeeder image_feeder:
:rtype IImage: :rtype: IImage
""" """
@abc.abstractmethod @abc.abstractmethod
@ -443,7 +471,7 @@ class IImageEngine(ABC):
"""Compute for each pixel position the mean value at this position in all input images. """Compute for each pixel position the mean value at this position in all input images.
:param IImageFeeder image_feeder: :param IImageFeeder image_feeder:
:rtype IImage: :rtype: IImage
""" """
@abc.abstractmethod @abc.abstractmethod
@ -462,7 +490,7 @@ class IImageEngine(ABC):
:param PixelType or None dst_type: pixel type of the destination image (if None, the pixel type is the same as the source image type) :param PixelType or None dst_type: pixel type of the destination image (if None, the pixel type is the same as the source image type)
:param IImage kernel: convolution kernel (or rather a correlation kernel), a single-channel floating point matrix; if you want to apply different kernels to different channels, split the image into separate color planes using split() and process them individually. :param IImage kernel: convolution kernel (or rather a correlation kernel), a single-channel floating point matrix; if you want to apply different kernels to different channels, split the image into separate color planes using split() and process them individually.
:param tuple(int, int) angor: anchor of the kernel that indicates the relative position of a filtered point within the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor is at the kernel center. :param tuple(int, int) angor: anchor of the kernel that indicates the relative position of a filtered point within the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor is at the kernel center.
:rtype IImage: :rtype: IImage
""" """
@abc.abstractmethod @abc.abstractmethod
@ -480,9 +508,11 @@ class IImageEngine(ABC):
:param IImage image: :param IImage image:
:param int band_width: width of the outer band, in pixels :param int band_width: width of the outer band, in pixels
:rtype IImage: :rtype: IImage
adaptation for the following code from matlab telemosToolbx's estimatedwhiteFluoImageTelemos function adaptation for the following code from matlab telemosToolbx's::
estimatedwhiteFluoImageTelemos function
outer = white_estimate; outer = white_estimate;
white_estimate = white_estimate(4:(end-3),4:(end-3)); white_estimate = white_estimate(4:(end-3),4:(end-3));
outer(1:3,4:(end-3))=repmat(white_estimate(1,:),3,1); # top outer(1:3,4:(end-3))=repmat(white_estimate(1,:),3,1); # top
@ -498,33 +528,37 @@ class IImageEngine(ABC):
""" """
:param IImage src_image: :param IImage src_image:
:param IImage template_image: :param IImage template_image:
:return IImage: similarity image :rtype: IImage
:return: similarity image
""" """
@abc.abstractmethod @abc.abstractmethod
def find_maxima(self, src_image, threshold, tolerance): def find_maxima(self, src_image, threshold, tolerance):
""" """
to understand the meaning of threshold and maxima, I had to look at the source code in https://github.com/imagej/imagej1/blob/master/ij/plugin/filter/MaximumFinder.java#L636 to understand the meaning of threshold and maxima, I had to look at the source code in https://github.com/imagej/imagej1/blob/master/ij/plugin/filter/MaximumFinder.java#L636
1. The algorithm first builds the list of maxima candidates. Only local maxima above this threshold are considered as valid maxima candidates 1. The algorithm first builds the list of maxima candidates. Only local maxima above this threshold are considered as valid maxima candidates
2. Then each maximum candidate is processed to find its neighborhood area, starting from the highest. For ecach candidate, a propagation is performed on neighbours as long as the neighbour value is within the tolerance of the maximum candidate. If another candidate is encountered as a neighbour, then this candidate is removed as it('s been absorbed by the current maximum candidate) 2. Then each maximum candidate is processed to find its neighborhood area, starting from the highest. For ecach candidate, a propagation is performed on neighbours as long as the neighbour value is within the tolerance of the maximum candidate. If another candidate is encountered as a neighbour, then this candidate is removed as it('s been absorbed by the current maximum candidate)
:param IImage src_image: :param IImage src_image:
:param float threshold: local maxima below this value are ignored :param float threshold: local maxima below this value are ignored
:param float tolerance: ignore local maxima if they are in the neighborhood of another maximum. The neighborhood of a maximum is defined by the area that propagates until the the difference between the pixel value and the value of the considered local maximum exceeds tolerance. The higher the tolerance, the more local maxima are removed.... :param float tolerance: ignore local maxima if they are in the neighborhood of another maximum. The neighborhood of a maximum is defined by the area that propagates until the the difference between the pixel value and the value of the considered local maximum exceeds tolerance. The higher the tolerance, the more local maxima are removed....
:return list(Match): maxima :return: maxima
:rtype: list(Match)
""" """
@abc.abstractmethod @abc.abstractmethod
def threshold(self, src_image, threshold_value): def threshold(self, src_image, threshold_value):
""" """
:param float threshold_value: :param float threshold_value:
:rtype IImage: :rtype: IImage
:return: the resulting image
""" """
@abc.abstractmethod @abc.abstractmethod
def auto_threshold(self, src_image): def auto_threshold(self, src_image):
""" """
:rtype IImage: :rtype: IImage
""" """
@abc.abstractmethod @abc.abstractmethod
@ -534,7 +568,8 @@ class IImageEngine(ABC):
:param IImage src_binary_image: :param IImage src_binary_image:
:param (int, int) flood_start_pos: start position of the flood fill :param (int, int) flood_start_pos: start position of the flood fill
:rtype IImage: binary image :rtype: IImage
:return: binary image
""" """
@abc.abstractmethod @abc.abstractmethod
@ -543,7 +578,8 @@ class IImageEngine(ABC):
fills the holes in the given binary image fills the holes in the given binary image
:param IImage src_binary_image: :param IImage src_binary_image:
:rtype IImage: binary image :rtype: IImage
:return: binary image
""" """
@abc.abstractmethod @abc.abstractmethod
@ -552,6 +588,7 @@ class IImageEngine(ABC):
inverts the given image pixel values (black becomes white and white becomes black) inverts the given image pixel values (black becomes white and white becomes black)
:param IImage src_binary_image: :param IImage src_binary_image:
:rtype IImage: binary image :rtype: IImage
:return: binary image
""" """

View File

@ -34,7 +34,7 @@ def clone_processor(src_processor, clone_pixel_type):
""" """
:param Processor processor: :param Processor processor:
:param PixelType clone_pixel_type: :param PixelType clone_pixel_type:
:rtype Processor: :rtype: Processor
""" """
clone_processor = { clone_processor = {
PixelType.U8: src_processor.convertToByteProcessor(), PixelType.U8: src_processor.convertToByteProcessor(),
@ -315,7 +315,7 @@ class IJImageEngine(IImageEngine):
"""Computes for each pixel position the maximum at this position in all input images. """Computes for each pixel position the maximum at this position in all input images.
:param IImageFeeder image_feeder: :param IImageFeeder image_feeder:
:rtype IJImage: :rtype: IJImage
""" """
it = iter(image_feeder) it = iter(image_feeder)
@ -336,7 +336,7 @@ class IJImageEngine(IImageEngine):
"""Computes for each pixel position the median value at this position in all input images. """Computes for each pixel position the median value at this position in all input images.
:param IImageFeeder image_feeder: :param IImageFeeder image_feeder:
:rtype IJmage: :rtype: IJmage
""" """
hyperstack = image_feeder.create_hyperstack() hyperstack = image_feeder.create_hyperstack()
# https://imagej.nih.gov/ij/developer/api/ij/plugin/ZProjector.html # https://imagej.nih.gov/ij/developer/api/ij/plugin/ZProjector.html

View File

@ -11,12 +11,12 @@ from ij.process import ImageStatistics # pylint: disable=import-error
from ij.plugin import ImageCalculator # pylint: disable=import-error from ij.plugin import ImageCalculator # pylint: disable=import-error
from ij.plugin import ZProjector # pylint: disable=import-error from ij.plugin import ZProjector # pylint: disable=import-error
from ij import WindowManager # pylint: disable=import-error from ij import WindowManager # pylint: disable=import-error
from catalog import Sequence, ImageCatalog from .catalog import Sequence, ImageCatalog
import telemos from . import telemos
from imageengine import IImageEngine, IImageProcessingDebugger, NullDebugger, StackImageFeeder, IHyperStack from .imageengine import IImageEngine, IImageProcessingDebugger, NullDebugger, StackImageFeeder, IHyperStack
# greeting = "Hello, " + name + "!" # greeting = "Hello, " + name + "!"
from hdf5.hdf5_data import Group, DataSet, ElementType from .hdf5.hdf5_data import Group, DataSet, ElementType
from imagej.hdf5serializer import save_hdf5_file from .imagej.hdf5serializer import save_hdf5_file
import abc import abc
@ -144,7 +144,7 @@ class IBackgroundEstimator(ABC):
def estimate_background(self, visible_traps_sequence): def estimate_background(self, visible_traps_sequence):
""" """
:param IHyperStack visible_traps_sequence: :param IHyperStack visible_traps_sequence:
:rtype IImage: the estimated background image :rtype: IImage the estimated background image
""" """
pass pass
@ -189,7 +189,7 @@ class GlobulesAreaEstimator(object):
def detect_particles(self, visible_traps_sequence): def detect_particles(self, visible_traps_sequence):
""" """
:param IHyperStack visible_traps_sequence: :param IHyperStack visible_traps_sequence:
:rtype hdf5_data.Group: :rtype: hdf5_data.Group
""" """
background_image = self.background_estimator.estimate_background(visible_traps_sequence) background_image = self.background_estimator.estimate_background(visible_traps_sequence)
ie = IImageEngine.get_instance() ie = IImageEngine.get_instance()

View File

@ -1,5 +1,5 @@
import abc import abc
from imageengine import IImageEngine from .imageengine import IImageEngine
ABC = abc.ABCMeta('ABC', (object,), {}) ABC = abc.ABCMeta('ABC', (object,), {})
@ -14,15 +14,22 @@ class Match(object):
return "(%d, %d) - %f" % (self.x, self.y, self.correlation) return "(%d, %d) - %f" % (self.x, self.y, self.correlation)
class IMaximaFinder(ABC): class IMaximaFinder(ABC):
"""Abstract class for methods aiming at detecting the maxima of an image
"""
@abc.abstractmethod @abc.abstractmethod
def find_maxima(self, image): def find_maxima(self, image):
""" """
:param IImage image: :param IImage image:
:rtype list(Match): :rtype: list(Match)
""" """
class MaximaFinder(IMaximaFinder): class MaximaFinder(IMaximaFinder):
"""
A maxima finder based on imagej's MaximumFinder
Uses the technique implemented in https://github.com/imagej/imagej1/blob/master/ij/plugin/filter/MaximumFinder.java
"""
def __init__(self, threshold, tolerance): def __init__(self, threshold, tolerance):
""" """

View File

@ -1,33 +1,15 @@
"""preprocessing of synchrotron images based on telemosToolbox.""" """preprocessing of synchrotron images based on telemosToolbox."""
from catalog import ImageCatalog, Sequence from .catalog import ImageCatalog, Sequence
from imageengine import IImageEngine, PixelType, FileImageFeeder from .imageengine import IImageEngine, PixelType, FileImageFeeder
class WhiteEstimator(object): class WhiteEstimator(object):
"""
Method that estimates the white from a sequence of images
def __init__(self, open_size, close_size, average_size): This method expects the sequence of images to represen sparse particles moving over a white background
"""
:param int open_size: the diameter of the structuring element used to perform mathematical morphology's opening operator (in pixels)
:param int close_size: the diameter of the structuring element used to perform mathematical morphology's closing operator (in pixels)
"""
self.open_size = open_size
self.close_size = close_size
self.average_size = average_size
def _remove_particles(self, white_estimate): Code adapted from matlab telemosToolbx's estimatewhiteFluoImageTelemos function::
IImageEngine.get_instance().perform_gray_morphology(white_estimate, operator='open', structuring_element_shape='square', structuring_element_radius=(self.open_size + 1) / 2)
IImageEngine.get_instance().perform_gray_morphology(white_estimate, operator='close', structuring_element_shape='square', structuring_element_radius=(self.close_size + 1) / 2)
IImageEngine.get_instance().mean_filter(white_estimate, radius=(self.average_size + 1) / 2)
def estimate_white(self, sequences, channel_ids, dark=None):
"""Estimation of the white fluorescence image shape of synchrotron light from experimental images of Telemos microscope.
:param list(Sequence) sequences: the sequences to consider
:param list(str) channel_ids: the channels to consider, eg ['DM300_327-353_fluo']
:param ImagePlus or None dark:
:rtype ImagePlus:
Code adapted from matlab telemosToolbx's estimatewhiteFluoImageTelemos function
% this function is specific of Telemos images (DISCO line SOLEIL) % this function is specific of Telemos images (DISCO line SOLEIL)
% acquired using micromanager software linked to imageJ % acquired using micromanager software linked to imageJ
@ -114,6 +96,30 @@ class WhiteEstimator(object):
% 27 mai 2019 : offset dark % 27 mai 2019 : offset dark
% 4 juin 2019 : replace exist by isfolder or isfile % 4 juin 2019 : replace exist by isfolder or isfile
% 14 juin : close figure at the end % 14 juin : close figure at the end
"""
def __init__(self, open_size, close_size, average_size):
"""
:param int open_size: the diameter of the structuring element used to perform mathematical morphology's opening operator (in pixels)
:param int close_size: the diameter of the structuring element used to perform mathematical morphology's closing operator (in pixels)
"""
self.open_size = open_size
self.close_size = close_size
self.average_size = average_size
def _remove_particles(self, white_estimate):
IImageEngine.get_instance().perform_gray_morphology(white_estimate, operator='open', structuring_element_shape='square', structuring_element_radius=(self.open_size + 1) / 2)
IImageEngine.get_instance().perform_gray_morphology(white_estimate, operator='close', structuring_element_shape='square', structuring_element_radius=(self.close_size + 1) / 2)
IImageEngine.get_instance().mean_filter(white_estimate, radius=(self.average_size + 1) / 2)
def estimate_white(self, sequences, channel_ids, dark=None):
"""Estimation of the white fluorescence image shape of synchrotron light from experimental images of Telemos microscope.
:param list(Sequence) sequences: the sequences to consider
:param list(str) channel_ids: the channels to consider, eg ['DM300_327-353_fluo']
:param ImagePlus or None dark:
:rtype: ImagePlus
""" """
image_set = FileImageFeeder() image_set = FileImageFeeder()
for sequence in sequences: for sequence in sequences:
@ -170,10 +176,12 @@ class InteractiveWhiteEstimator(WhiteEstimator):
def correct_non_uniform_lighting(non_uniform_sequence, channel_id, white_estimator=WhiteEstimator(open_size=75, close_size=75, average_size=75)): def correct_non_uniform_lighting(non_uniform_sequence, channel_id, white_estimator=WhiteEstimator(open_size=75, close_size=75, average_size=75)):
""" correction of non uniform lighting """ correction of non uniform lighting
:param Sequence non_uniform_sequence: the input sequence, which is expected to have a non uniform lighting :param Sequence non_uniform_sequence: the input sequence, which is expected to have a non uniform lighting
:param str channel_id: :param str channel_id:
:param WhiteEstimator white_estimator: the method used to estimate the light image :param WhiteEstimator white_estimator: the method used to estimate the light image
:return IHyperStack: the hyperstack of images after correction :rtype: IHyperStack
:return: the hyperstack of images after correction
""" """
ie = IImageEngine.get_instance() ie = IImageEngine.get_instance()
@ -235,95 +243,98 @@ def find_white_reference_image(white_estimate, white_z_stack):
:param IImage white_estimate: :param IImage white_estimate:
:param Sequence white_z_stack: :param Sequence white_z_stack:
:param IImageEngine image_engine: the image processor to use :param IImageEngine image_engine: the image processor to use
% this function is specific of Telemos images (DISCO line SOLEIL)
% acquired using micromanager software linked to imageJ
%% input Based on original matlab code::
% nothing : interactive function
%% output % this function is specific of Telemos images (DISCO line SOLEIL)
% zmax : focal plane % acquired using micromanager software linked to imageJ
%% principe %% input
% images were acquired for a given roi which position is found in % nothing : interactive function
% metadata.txt file
% white and dark images were recorded for the full field of view of the DISCO
% TELEMOS camera
%
% correlation between a estimated white fluorescence image estalished from
% actual acquisitions of a given sample and all z plane acquired for the reference TELEMOS white
% image (Matthieu slide or any fluorescent homogeneous image) :
% The estimated white fluorescence image is generallly obtained bt using function whiteFluoImageTelemosestimation %% output
% This is not compulsary as any homogenous sample image hat can roughly show the shape of illumination can be used to find % zmax : focal plane
% the white reference image
% %% principe
% % images were acquired for a given roi which position is found in
% the z plane for which the maximum correlation is observed between estimated white and reference white images is retained. % metadata.txt file
% the white image is then offsetted (its corresponding Dark is subtracted) and copied in the subfolder <WhiteReference> of the sample % white and dark images were recorded for the full field of view of the DISCO
% rootfolder to show that it has been specifically selected for the considered experiment % TELEMOS camera
%The matlab corrcoeff function is used %
% % correlation between a estimated white fluorescence image estalished from
% correlation coefficients are saved in a file called % actual acquisitions of a given sample and all z plane acquired for the reference TELEMOS white
% 'corr.txt' in the subfolder 'WhiteReference' % image (Matthieu slide or any fluorescent homogeneous image) :
%
% % The estimated white fluorescence image is generallly obtained bt using function whiteFluoImageTelemosestimation
% expected input folder hierarchy: % This is not compulsary as any homogenous sample image hat can roughly show the shape of illumination can be used to find
% % the white reference image
% >sampleFolder %
% > PosFolders or RoiFolders %
% > WhiteEstimate % the z plane for which the maximum correlation is observed between estimated white and reference white images is retained.
% >darkFolder % the white image is then offsetted (its corresponding Dark is subtracted) and copied in the subfolder <WhiteReference> of the sample
% >darkFolder.smooth % rootfolder to show that it has been specifically selected for the considered experiment
% >whiteFolder %The matlab corrcoeff function is used
% > darkFolderforWhite %
% > darkFolderforWhite.smooth % correlation coefficients are saved in a file called
% >whiteFolder.smooth % 'corr.txt' in the subfolder 'WhiteReference'
% %
% %
% expected output folder hierarchy: % expected input folder hierarchy:
% %
% >sampleFolder % >sampleFolder
% > PosFolders or RoiFolders % > PosFolders or RoiFolders
% > WhiteEstimate % > WhiteEstimate
% > WhiteReference % >darkFolder
% > white after offset % >darkFolder.smooth
% >darkFolder % >whiteFolder
% >darkFolder.smooth % > darkFolderforWhite
% >whiteFolder % > darkFolderforWhite.smooth
% > darkFolderforWhite % >whiteFolder.smooth
% > darkFolderforWhite.smooth %
% >whiteFolder.smooth %
% expected output folder hierarchy:
%
% >sampleFolder
% > PosFolders or RoiFolders
% > WhiteEstimate
% > WhiteReference
% > white after offset
% >darkFolder
% >darkFolder.smooth
% >whiteFolder
% > darkFolderforWhite
% > darkFolderforWhite.smooth
% >whiteFolder.smooth
%% use %% use
% [zmax]=findWhiteReferenceImageTelemos % [zmax]=findWhiteReferenceImageTelemos
%% Comments %% Comments
% written for proposal 20161050 % written for proposal 20161050
% adapted for proposal 20170043 % adapted for proposal 20170043
%% Author %% Author
% MF Devaux % MF Devaux
% INRA BIA % INRA BIA
% PVPP % PVPP
%% date %% date
% 5 octobre 2017: % 5 octobre 2017:
% 15 decembre 2017 : adapted to take into account the roi known from % 15 decembre 2017 : adapted to take into account the roi known from
% metadata % metadata
% 27 fevrier 2018 : comments details % 27 fevrier 2018 : comments details
% 4 septembre 2018: comments and check and naming of folders % 4 septembre 2018: comments and check and naming of folders
% 12 mars 2019 : save white reference with the same size as white estimate % 12 mars 2019 : save white reference with the same size as white estimate
% 16 avril 2019 : include diagonals to check the relevance of white % 16 avril 2019 : include diagonals to check the relevance of white
% reference % reference
% 20 mai 2019 : track folder % 20 mai 2019 : track folder
% 27 mai 2019 : offset dark % 27 mai 2019 : offset dark
% 4 juin 2019 : replace exist by isfolder or isfile % 4 juin 2019 : replace exist by isfolder or isfile
""" """
raise NotImplementedError() raise NotImplementedError()

View File

@ -1,11 +1,16 @@
from imageengine import IImageEngine from .imageengine import IImageEngine
from maxima_finder import IMaximaFinder from .maxima_finder import IMaximaFinder
class TemplateMatcher(object): class TemplateMatcher(object):
"""
Method to detect a pattern in an image.
This method finds the locations of the given pattern in the image, provided the pattern is replicated without other geometric distortions than translations.
"""
def __init__(self, maxima_finder): def __init__(self, maxima_finder):
""" """
:param IMaximaFinder: maxima_finder :param IMaximaFinder maxima_finder:
""" """
self.maxima_finder = maxima_finder self.maxima_finder = maxima_finder

View File

@ -1,11 +1,11 @@
from catalog import ImageCatalog, Sequence from .catalog import ImageCatalog, Sequence
# from imageengine import Toto # from imageengine import Toto
from imageengine import IImageEngine, Aabb, StackImageFeeder from .imageengine import IImageEngine, Aabb, StackImageFeeder
from imageengine import PixelType from .imageengine import PixelType
from telemos import WhiteEstimator, correct_non_uniform_lighting from .telemos import WhiteEstimator, correct_non_uniform_lighting
from maxima_finder import Match from .maxima_finder import Match
from template_matcher import TemplateMatcher from .template_matcher import TemplateMatcher
class TrapBinarizer(object): class TrapBinarizer(object):