"""
ColECM: Collagen ExtraCellular Matrix Simulation
UTILITIES ROUTINE
Created by: Frank Longford
Created on: 01/11/2015
Last Modified: 12/04/2018
"""
from functools import wraps
import logging
import time
from stevedore import ExtensionManager
import numpy as np
logger = logging.getLogger(__name__)
SQRT3 = np.sqrt(3)
SQRT2 = np.sqrt(2)
SQRTPI = np.sqrt(np.pi)
IMAGE_MAX = 255.99999
[docs]class NoiseError(Exception):
def __init__(self, noise, thresh):
self.noise = noise
self.thresh = thresh
self.message = "Image too noisy ({} > {})".format(noise, thresh)
[docs]class NotSupportedError(Exception):
message = "Method not supported by class"
[docs]def logo(version):
logo_text = "\n"
logo_text += " ___ ___ " + '\n'
logo_text += " | \\ | . | " + '\n'
logo_text += " |__/ |__ |__ __ __ " + '\n'
logo_text += " | | | | | | | | |__| " + '\n'
logo_text += " | \\__| | | |__/ | |__ " + '\n'
logo_text += " __/ " + '\n'
logo_text += f"\n Fibrous Tissue Image Toolkit v{version}\n"
return logo_text
[docs]def numpy_remove(list1, list2):
"""
numpy_remove(list1, list2)
Deletes overlapping elements of list2 from list1
"""
return np.delete(list1, np.where(np.isin(list1, list2)))
[docs]def unit_vector(vector, axis=-1):
"""
unit_vector(vector, axis=-1)
Returns unit vector of vector
"""
vector = np.array(vector)
magnitude_2 = np.resize(
np.sum(vector**2, axis=axis), vector.shape)
u_vector = np.sqrt(vector**2 / magnitude_2) * np.sign(vector)
return u_vector
[docs]def label_set(labels, background=0):
"""Return a unique set of non-background values in labels"""
unique_labels = np.unique(labels)
# Remove any labels corresponding to the background
indices = np.where(unique_labels != background)
unique_labels = unique_labels[indices]
return unique_labels
[docs]def nanmean(array_like, weights=None):
if weights is None:
weights = np.ones(array_like.shape)
# Ensure None and NaN objects are filtered out. We need to use
# equality comparison for None at each array element here since
# numpy.where cannot handle identity checks
array_like = np.array(
np.where(
array_like == None, np.nan, array_like # noqa: 501
),
dtype=float
)
weights = np.array(
np.where(
weights == None, np.nan, weights # noqa: 501
),
dtype=float
)
indices = ~np.isnan(array_like) * ~np.isnan(weights)
try:
average = np.average(
array_like[indices], weights=weights[indices])
except ZeroDivisionError:
average = None
return average
[docs]def ring(image, index, sizes, value):
index = np.array(index)
sizes = np.array(sizes)
for size in sizes:
indices = np.concatenate((index - size, index + size))
if indices[0] >= 0:
start = max([indices[1], 0])
end = min([indices[3], image.shape[1]]) + 1
image[indices[0], start: end] = value
if indices[2] < image.shape[0]:
start = max([indices[1], 0])
end = min([indices[3], image.shape[1]]) + 1
image[indices[2], start: end] = value
if indices[1] >= 0:
start = max([indices[0], 0])
end = min([indices[2], image.shape[0]]) + 1
image[start: end, indices[1]] = value
if indices[3] < image.shape[1]:
start = max([indices[0], 0])
end = min([indices[2], image.shape[0]]) + 1
image[start: end, indices[3]] = value
return image
[docs]def clear_border(image, thickness=1):
for i in range(thickness):
image[:, 0 + i] = 0
image[0 + i, :] = 0
image[:, -(1 + i)] = 0
image[-(1 + i), :] = 0
return image
[docs]def flatten_list(list_of_lists):
"""Returned a flattened version of a list of lists"""
flat_list = [
val
for sublist in list_of_lists
for val in sublist
]
return flat_list
[docs]def matrix_split(matrix, nrows, ncols):
"""Split a matrix into sub-matrices"""
assert matrix.ndim == 2
rows = np.array_split(matrix, ncols, axis=0)
grid = []
for item in rows:
grid += np.array_split(item, nrows, axis=-1)
return grid
[docs]def load_plugins():
"""Load PyFibre plugins via Stevedore. """
mgr = ExtensionManager(
namespace='pyfibre.plugins',
invoke_on_load=True
)
plugins = [ext.obj for ext in mgr]
return plugins
[docs]def log_time(message):
"""Use as a decorator around a callable to automatically record
elapsed time to the log. Can be personalised with an extra string
message argument
Example
-------
>>> @log_time(name='TEST')
>>> def function(x, y):
>>> return x * y
>>> ...
>>>
>>> function(2, 3)
6
Will produce a log message:
>>>
INFO: TOTAL TEST TIME .. s
"""
def log_time_decorator(func):
"""Decorator around function to be called"""
@wraps(func)
def function_wrapper(*args, **kwargs):
"""Actual wrapper around callable, including log
instructions"""
start = time.time()
result = func(*args, **kwargs)
logger.info(
# f"TOTAL TIME = "
f"TOTAL {message.upper()} TIME = "
f"{round(time.time() - start, 3)} s")
return result
return function_wrapper
return log_time_decorator