cellects 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cellects/__init__.py +0 -0
- cellects/__main__.py +49 -0
- cellects/config/__init__.py +0 -0
- cellects/config/all_vars_dict.py +155 -0
- cellects/core/__init__.py +0 -0
- cellects/core/cellects_paths.py +31 -0
- cellects/core/cellects_threads.py +1451 -0
- cellects/core/motion_analysis.py +2010 -0
- cellects/core/one_image_analysis.py +1061 -0
- cellects/core/one_video_per_blob.py +540 -0
- cellects/core/program_organizer.py +1316 -0
- cellects/core/script_based_run.py +154 -0
- cellects/gui/__init__.py +0 -0
- cellects/gui/advanced_parameters.py +1258 -0
- cellects/gui/cellects.py +189 -0
- cellects/gui/custom_widgets.py +790 -0
- cellects/gui/first_window.py +449 -0
- cellects/gui/if_several_folders_window.py +239 -0
- cellects/gui/image_analysis_window.py +2066 -0
- cellects/gui/required_output.py +232 -0
- cellects/gui/video_analysis_window.py +656 -0
- cellects/icons/__init__.py +0 -0
- cellects/icons/cellects_icon.icns +0 -0
- cellects/icons/cellects_icon.ico +0 -0
- cellects/image_analysis/__init__.py +0 -0
- cellects/image_analysis/cell_leaving_detection.py +54 -0
- cellects/image_analysis/cluster_flux_study.py +102 -0
- cellects/image_analysis/image_segmentation.py +706 -0
- cellects/image_analysis/morphological_operations.py +1635 -0
- cellects/image_analysis/network_functions.py +1757 -0
- cellects/image_analysis/one_image_analysis_threads.py +289 -0
- cellects/image_analysis/progressively_add_distant_shapes.py +508 -0
- cellects/image_analysis/shape_descriptors.py +1016 -0
- cellects/utils/__init__.py +0 -0
- cellects/utils/decorators.py +14 -0
- cellects/utils/formulas.py +637 -0
- cellects/utils/load_display_save.py +1054 -0
- cellects/utils/utilitarian.py +490 -0
- cellects-0.1.2.dist-info/LICENSE.odt +0 -0
- cellects-0.1.2.dist-info/METADATA +132 -0
- cellects-0.1.2.dist-info/RECORD +44 -0
- cellects-0.1.2.dist-info/WHEEL +5 -0
- cellects-0.1.2.dist-info/entry_points.txt +2 -0
- cellects-0.1.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Contains the function: cell_leaving_detection
|
|
3
|
+
This function considers the pixel intensity curve of each covered pixel and assesesed whether a covered pixel retrieved
|
|
4
|
+
-partially at least- its initial intensity.
|
|
5
|
+
"""
|
|
6
|
+
import cv2
|
|
7
|
+
import numpy as np
|
|
8
|
+
from cellects.image_analysis.morphological_operations import cross_33
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def cell_leaving_detection(new_shape, covering_intensity, previous_binary, greyscale_image, fading_coefficient, lighter_background, several_blob_per_arena, erodila_disk, protect_from_fading=None, add_to_fading=None):
|
|
12
|
+
# To look for fading pixels, only consider the internal contour of the shape at t-1
|
|
13
|
+
fading = cv2.erode(previous_binary, erodila_disk)
|
|
14
|
+
fading = previous_binary - fading
|
|
15
|
+
# If the origin state is considered constant: origin pixels will never be fading
|
|
16
|
+
if protect_from_fading is not None:
|
|
17
|
+
fading *= (1 - protect_from_fading)
|
|
18
|
+
if add_to_fading is not None:
|
|
19
|
+
if protect_from_fading is not None:
|
|
20
|
+
add_to_fading[np.nonzero(protect_from_fading)] = 0
|
|
21
|
+
add_to_fading_coord = np.nonzero(add_to_fading)
|
|
22
|
+
fading[add_to_fading_coord] = 1
|
|
23
|
+
if lighter_background:
|
|
24
|
+
covering_intensity[add_to_fading_coord] = 1 / (1 - fading_coefficient) # 0.9 * covering_intensity[add_to_fading_coord] #
|
|
25
|
+
else:
|
|
26
|
+
covering_intensity[add_to_fading_coord] = 255 # 1.1 * covering_intensity[add_to_fading_coord]
|
|
27
|
+
# With a lighter background, fading them if their intensity gets higher than the covering intensity
|
|
28
|
+
if lighter_background:
|
|
29
|
+
fading = fading * np.greater((greyscale_image), (1 - fading_coefficient) * covering_intensity).astype(np.uint8)
|
|
30
|
+
else:
|
|
31
|
+
fading = fading * np.less((greyscale_image), (1 + fading_coefficient) * covering_intensity).astype(np.uint8)
|
|
32
|
+
|
|
33
|
+
if np.any(fading):
|
|
34
|
+
fading = cv2.morphologyEx(fading, cv2.MORPH_CLOSE, cross_33, iterations=1)
|
|
35
|
+
if not several_blob_per_arena:
|
|
36
|
+
# Check if uncov_potentials does not break the shape into several components
|
|
37
|
+
uncov_nb, uncov_shapes = cv2.connectedComponents(fading, ltype=cv2.CV_16U)
|
|
38
|
+
nb, garbage_img = cv2.connectedComponents(new_shape, ltype=cv2.CV_16U)
|
|
39
|
+
i = 0
|
|
40
|
+
while i <= uncov_nb:
|
|
41
|
+
i += 1
|
|
42
|
+
prev_nb = nb
|
|
43
|
+
new_shape[np.nonzero(uncov_shapes == i)] = 0
|
|
44
|
+
nb, garbage_img = cv2.connectedComponents(new_shape, ltype=cv2.CV_16U)
|
|
45
|
+
if nb > prev_nb:
|
|
46
|
+
new_shape[np.nonzero(uncov_shapes == i)] = 1
|
|
47
|
+
nb, garbage_img = cv2.connectedComponents(new_shape, ltype=cv2.CV_16U)
|
|
48
|
+
uncov_shapes = None
|
|
49
|
+
else:
|
|
50
|
+
new_shape[np.nonzero(fading)] = 0
|
|
51
|
+
new_shape = cv2.morphologyEx(new_shape, cv2.MORPH_OPEN, cross_33, iterations=0)
|
|
52
|
+
new_shape = cv2.morphologyEx(new_shape, cv2.MORPH_CLOSE, cross_33)
|
|
53
|
+
|
|
54
|
+
return new_shape, covering_intensity
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
This script contains the class for studying oscillating clusters on videos in 2D
|
|
4
|
+
"""
|
|
5
|
+
import cv2
|
|
6
|
+
import numpy as np
|
|
7
|
+
from numpy import (
|
|
8
|
+
append, float32, sum, mean, zeros, empty, array, nonzero, unique,
|
|
9
|
+
isin, logical_or, logical_not, greater, uint8,
|
|
10
|
+
uint32, min, any, zeros)
|
|
11
|
+
from cellects.image_analysis.morphological_operations import cross_33, get_minimal_distance_between_2_shapes
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ClusterFluxStudy:
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
def __init__(self, dims):
|
|
19
|
+
self.dims = dims
|
|
20
|
+
|
|
21
|
+
self.pixels_data = np.empty((4, 0), dtype=np.uint32)
|
|
22
|
+
self.clusters_id = np.zeros(self.dims[1:], dtype=np.uint32)
|
|
23
|
+
# self.alive_clusters_in_flux = np.empty(0, dtype=np.uint32)#list()
|
|
24
|
+
self.cluster_total_number = 0
|
|
25
|
+
|
|
26
|
+
def update_flux(self, t, contours, current_flux, period_tracking, clusters_final_data):
|
|
27
|
+
# Save the data from pixels that are not anymore in efflux
|
|
28
|
+
lost = np.greater(self.clusters_id > 0, current_flux > 0)
|
|
29
|
+
# Some pixels of that cluster faded, save their data
|
|
30
|
+
lost_data = np.nonzero(lost)
|
|
31
|
+
lost_data = np.array((period_tracking[lost], # lost_coord[0], lost_coord[1],
|
|
32
|
+
self.clusters_id[lost], lost_data[0], lost_data[1]), dtype=np.uint32)
|
|
33
|
+
# Add this to the array containing the data of each cluster that are still alive
|
|
34
|
+
self.pixels_data = np.append(self.pixels_data, lost_data, axis=1)
|
|
35
|
+
# Stop considering these pixels in period_tracking because they switched
|
|
36
|
+
period_tracking[lost] = 0
|
|
37
|
+
current_period_tracking = np.zeros(self.dims[1:], dtype=bool)
|
|
38
|
+
for curr_clust_id in np.unique(current_flux)[1:]:
|
|
39
|
+
# Get all pixels that were in the same flux previously
|
|
40
|
+
curr_clust = current_flux == curr_clust_id
|
|
41
|
+
already = self.clusters_id * curr_clust
|
|
42
|
+
new = np.greater(curr_clust, self.clusters_id > 0)
|
|
43
|
+
|
|
44
|
+
if not np.any(already):
|
|
45
|
+
# It is an entirely new cluster:
|
|
46
|
+
cluster_pixels = new
|
|
47
|
+
self.cluster_total_number += 1
|
|
48
|
+
cluster_name = self.cluster_total_number
|
|
49
|
+
else:
|
|
50
|
+
# Check whether parts of that cluster correspond to several clusters in clusters_id
|
|
51
|
+
cluster_names = np.unique(already)[1:]
|
|
52
|
+
# keep only one cluster name to gather clusters that just became connected
|
|
53
|
+
cluster_name = np.min(cluster_names)
|
|
54
|
+
# Put the same cluster name for new ones and every pixels that were
|
|
55
|
+
# a part of a cluster touching the current cluster
|
|
56
|
+
cluster_pixels = np.logical_or(np.isin(self.clusters_id, cluster_names), new)
|
|
57
|
+
# If they are more than one,
|
|
58
|
+
if len(cluster_names) > 1:
|
|
59
|
+
# Update these cluster names in pixels_data
|
|
60
|
+
self.pixels_data[1, np.isin(self.pixels_data[1, :], cluster_names)] = cluster_name
|
|
61
|
+
# Update clusters_id
|
|
62
|
+
self.clusters_id[cluster_pixels] = cluster_name
|
|
63
|
+
# Update period_tracking
|
|
64
|
+
current_period_tracking[curr_clust] = True
|
|
65
|
+
|
|
66
|
+
period_tracking[current_period_tracking] += 1
|
|
67
|
+
# Remove lost pixels from clusters_id
|
|
68
|
+
self.clusters_id[lost] = 0
|
|
69
|
+
# Find out which clusters are still alive or not
|
|
70
|
+
still_alive_clusters = np.isin(self.pixels_data[1, :], np.unique(self.clusters_id))
|
|
71
|
+
clusters_to_archive = np.unique(self.pixels_data[1, np.logical_not(still_alive_clusters)])
|
|
72
|
+
# store their data in clusters_final_data
|
|
73
|
+
clusters_data = np.zeros((len(clusters_to_archive), 6), dtype=np.float32)
|
|
74
|
+
for clust_i, cluster in enumerate(clusters_to_archive):
|
|
75
|
+
cluster_bool = self.pixels_data[1, :] == cluster
|
|
76
|
+
cluster_size = np.sum(cluster_bool)
|
|
77
|
+
cluster_img = np.zeros(self.dims[1:], dtype=np.uint8)
|
|
78
|
+
cluster_img[self.pixels_data[2, cluster_bool], self.pixels_data[3, cluster_bool]] = 1
|
|
79
|
+
nb, im, stats, centro = cv2.connectedComponentsWithStats(cluster_img)
|
|
80
|
+
if np.any(cv2.dilate(cluster_img, kernel=cross_33, borderType=cv2.BORDER_CONSTANT, borderValue=0) * contours):
|
|
81
|
+
minimal_distance = 1
|
|
82
|
+
else:
|
|
83
|
+
if cluster_size > 200:
|
|
84
|
+
|
|
85
|
+
eroded_cluster_img = cv2.erode(cluster_img, cross_33)
|
|
86
|
+
cluster_img = np.nonzero(cluster_img - eroded_cluster_img)
|
|
87
|
+
contours[cluster_img] = 2
|
|
88
|
+
else:
|
|
89
|
+
contours[self.pixels_data[2, cluster_bool], self.pixels_data[3, cluster_bool]] = 2
|
|
90
|
+
# Get the minimal distance between the border of the cell(s) (noted 1 in contours)
|
|
91
|
+
# and the border of the cluster in the cell(s) (now noted 2 in contours)
|
|
92
|
+
minimal_distance = get_minimal_distance_between_2_shapes(contours)
|
|
93
|
+
data_to_save = np.array([[np.mean(self.pixels_data[0, cluster_bool]), t,
|
|
94
|
+
cluster_size, minimal_distance, centro[1, 0], centro[1, 1]]], dtype=np.float32)
|
|
95
|
+
clusters_data[clust_i,:] = data_to_save
|
|
96
|
+
# and remove their data from pixels_data
|
|
97
|
+
clusters_final_data = np.append(clusters_final_data, clusters_data, axis=0)
|
|
98
|
+
self.pixels_data = self.pixels_data[:, still_alive_clusters]
|
|
99
|
+
|
|
100
|
+
return period_tracking, clusters_final_data
|
|
101
|
+
|
|
102
|
+
|